diff --git a/src/Base/Builder3D.cpp b/src/Base/Builder3D.cpp index e03a99a3c1..d5c14e8423 100644 --- a/src/Base/Builder3D.cpp +++ b/src/Base/Builder3D.cpp @@ -89,7 +89,7 @@ std::string DrawStyle::patternAsString() const return str.str(); } -const char* MaterialBinding::bindingAsString() const +const char* BindingElement::bindingAsString() const { switch (value) { case Binding::PerPart: @@ -178,6 +178,25 @@ void InventorOutput::decreaseIndent() // ----------------------------------------------------------------------------- +void NodeItem::writeField(const char* field, const std::vector& vec, InventorOutput& out) const +{ + if (vec.empty()) + return; + + if (vec.size() == 1) { + out.write() << field << " " << vec[0].x << " " << vec[0].y << " " << vec[0].z << '\n'; + } + else { + out.write() << field << " [\n"; + out.increaseIndent(); + for (auto it : vec) { + out.write() << it.x << " " << it.y << " " << it.z << '\n'; + } + out.decreaseIndent(); + out.write() << "]\n"; + } +} + void NodeItem::writeField(const char* field, const std::vector& rgb, InventorOutput& out) const { if (rgb.empty()) @@ -312,6 +331,56 @@ void LineItem::write(InventorOutput& out) const // ----------------------------------------------------------------------------- +ArrowItem::ArrowItem(const Base::Line3f& line, DrawStyle drawStyle, const ColorRGB& rgb) + : line(line) + , drawStyle(drawStyle) + , rgb(rgb) +{ + +} + +void ArrowItem::write(InventorOutput& out) const +{ + float length = line.Length(); + float coneLength = length / 10.0F; + float coneRadius = coneLength / 2.0F; + float sf1 = length - coneLength; + float sf2 = length - coneLength/2.0F; + + Vector3f dir = line.GetDirection(); + dir.Normalize(); + dir.Scale(sf1, sf1, sf1); + Vector3f pt2s = line.p1 + dir; + dir.Normalize(); + dir.Scale(sf2, sf2, sf2); + Vector3f cpt = line.p1 + dir; + + Vector3f rot = Vector3f(0.0f, 1.0f, 0.0f) % dir; + rot.Normalize(); + float angle = Vector3f(0.0f, 1.0f, 0.0f).GetAngle(dir); + + out.write() << "Separator {\n"; + out.write() << " Material { diffuseColor " << rgb.red() << " "<< rgb.green() << " "<< rgb.blue() << "}\n"; + out.write() << " DrawStyle { lineWidth " << drawStyle.lineWidth << " }\n"; + out.write() << " Coordinate3 {\n"; + out.write() << " point [ "; + out.write() << line.p1.x << " " << line.p1.y << " " << line.p1.z << ", "; + out.write() << pt2s.x << " " << pt2s.y << " " << pt2s.z; + out.write() << " ]\n"; + out.write() << " }\n"; + out.write() << " LineSet { }\n"; + out.write() << " Transform { \n"; + out.write() << " translation " + << cpt.x << " " << cpt.y << " " << cpt.z << '\n'; + out.write() << " rotation " + << rot.x << " " << rot.y << " " << rot.z << " " << angle << '\n'; + out.write() << " }\n"; + out.write() << " Cone { bottomRadius " << coneRadius << " height " << coneLength << "} \n"; + out.write() << "}\n"; +} + +// ----------------------------------------------------------------------------- + void MaterialItem::setAmbientColor(const std::vector& rgb) { ambientColor = rgb; @@ -398,15 +467,15 @@ void MaterialItem::writeTransparency(InventorOutput& out) const // ----------------------------------------------------------------------------- -MaterialBindingItem::MaterialBindingItem(MaterialBinding bind) : bind(bind) +void MaterialBindingItem::setValue(BindingElement::Binding bind) { - + value.value = bind; } void MaterialBindingItem::write(InventorOutput& out) const { out.write() << "MaterialBinding { value " - << bind.bindingAsString() << " } \n"; + << value.bindingAsString() << " } \n"; } // ----------------------------------------------------------------------------- @@ -466,6 +535,95 @@ void PointSetItem::write(InventorOutput& out) const // ----------------------------------------------------------------------------- +void NormalItem::setVector(const std::vector& vec) +{ + vector = vec; +} + +void NormalItem::write(InventorOutput& out) const +{ + beginNormal(out); + writeField("vector", vector, out); + endNormal(out); +} + +void NormalItem::beginNormal(InventorOutput& out) const +{ + out.writeLine("Normal {"); + out.increaseIndent(); +} + +void NormalItem::endNormal(InventorOutput& out) const +{ + out.decreaseIndent(); + out.writeLine("}"); +} + +// ----------------------------------------------------------------------------- + +void NormalBindingItem::setValue(BindingElement::Binding bind) +{ + value.value = bind; +} + +void NormalBindingItem::write(InventorOutput& out) const +{ + out.write() << "NormalBinding { value " + << value.bindingAsString() << " }\n"; +} + +// ----------------------------------------------------------------------------- + +void CylinderItem::setRadius(float value) +{ + radius = value; +} + +void CylinderItem::setHeight(float value) +{ + height = value; +} + +void CylinderItem::write(InventorOutput& out) const +{ + out.write() << "Cylinder {\n"; + out.write() << " radius " << radius << "\n"; + out.write() << " height " << height << "\n"; + out.write() << " parts (SIDES | TOP | BOTTOM)\n"; + out.write() << "}\n"; +} + +// ----------------------------------------------------------------------------- + +void ConeItem::setBottomRadius(float value) +{ + bottomRadius = value; +} + +void ConeItem::setHeight(float value) +{ + height = value; +} + +void ConeItem::write(InventorOutput& out) const +{ + out.write() << "Cone { bottomRadius " << bottomRadius << " height " << height << " }\n"; +} + +// ----------------------------------------------------------------------------- + +void SphereItem::setRadius(float value) +{ + radius = value; +} + +void SphereItem::write(InventorOutput& out) const +{ + out.write() << "Sphere { radius " << radius << " }\n"; +} + +// ----------------------------------------------------------------------------- + InventorBuilder::InventorBuilder(std::ostream& output) : result(output) { @@ -557,7 +715,7 @@ void InventorBuilder::addColor(const ColorRGB& rgb) result << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n'; } -void InventorBuilder::addMaterialBinding(MaterialBinding bind) +void InventorBuilder::addMaterialBinding(BindingElement bind) { result << indent << "MaterialBinding { value " << bind.bindingAsString() << " } \n"; diff --git a/src/Base/Builder3D.h b/src/Base/Builder3D.h index fc92f4f346..e6fff19450 100644 --- a/src/Base/Builder3D.h +++ b/src/Base/Builder3D.h @@ -84,7 +84,7 @@ public: unsigned short linePattern = 0xffff; }; -class BaseExport MaterialBinding +class BaseExport BindingElement { public: enum class Binding { @@ -192,6 +192,7 @@ public: virtual void write(InventorOutput& out) const = 0; protected: + void writeField(const char* field, const std::vector& vec, InventorOutput& out) const; void writeField(const char* field, const std::vector& rgb, InventorOutput& out) const; void writeField(const char* field, const std::vector& value, InventorOutput& out) const; }; @@ -259,6 +260,18 @@ private: ColorRGB rgb; }; +class BaseExport ArrowItem : public NodeItem +{ +public: + explicit ArrowItem(const Base::Line3f& line, DrawStyle drawStyle, const ColorRGB& rgb = ColorRGB{1.0F, 1.0F, 1.0F}); + void write(InventorOutput& out) const override; + +private: + Base::Line3f line; + DrawStyle drawStyle; + ColorRGB rgb; +}; + /*! * \brief The MaterialItem class supports the SoMaterial node. */ @@ -298,11 +311,12 @@ private: class BaseExport MaterialBindingItem : public NodeItem { public: - explicit MaterialBindingItem(MaterialBinding bind); + MaterialBindingItem() = default; + void setValue(BindingElement::Binding bind); void write(InventorOutput& out) const override; private: - MaterialBinding bind; + BindingElement value; }; /*! @@ -353,6 +367,79 @@ public: void write(InventorOutput& out) const override; }; +/*! + * \brief The NormalItem class supports the SoNormal node. + */ +class BaseExport NormalItem : public NodeItem +{ +public: + explicit NormalItem() = default; + void setVector(const std::vector& vec); + void write(InventorOutput& out) const override; + +private: + void beginNormal(InventorOutput& out) const; + void endNormal(InventorOutput& out) const; + std::vector vector; +}; + +/*! + * \brief The MaterialBindingItem class supports the SoMaterialBinding node. + */ +class BaseExport NormalBindingItem : public NodeItem +{ +public: + NormalBindingItem() = default; + void setValue(BindingElement::Binding bind); + void write(InventorOutput& out) const override; + +private: + BindingElement value; +}; + +/*! + * \brief The CylinderItem class supports the SoCylinder node. + */ +class BaseExport CylinderItem : public NodeItem +{ +public: + void setRadius(float); + void setHeight(float); + void write(InventorOutput& out) const override; + +private: + float radius = 2.0F; + float height = 10.0F; +}; + +/*! + * \brief The ConeItem class supports the SoCone node. + */ +class BaseExport ConeItem : public NodeItem +{ +public: + void setBottomRadius(float); + void setHeight(float); + void write(InventorOutput& out) const override; + +private: + float bottomRadius = 2.0F; + float height = 10.0F; +}; + +/*! + * \brief The SphereItem class supports the SoSphere node. + */ +class BaseExport SphereItem : public NodeItem +{ +public: + void setRadius(float); + void write(InventorOutput& out) const override; + +private: + float radius = 2.0F; +}; + /** * This class does basically the same as Builder3D except that it writes the data * directly into a given stream without buffering the output data in a string stream. @@ -423,7 +510,7 @@ public: * \brief Sets a material binding node. * \param binding - binding of the material. */ - void addMaterialBinding(MaterialBinding); + void addMaterialBinding(BindingElement); /*! * \brief Sets a draw style node. */ diff --git a/tests/src/InventorBuilder.cpp b/tests/src/InventorBuilder.cpp index 9d990dca61..a5fd2219da 100644 --- a/tests/src/InventorBuilder.cpp +++ b/tests/src/InventorBuilder.cpp @@ -73,7 +73,7 @@ private Q_SLOTS: { QFETCH(QString, result); - Base::MaterialBindingItem item{Base::MaterialBinding{}}; + Base::MaterialBindingItem item; builder.addNode(item); QString string = QString::fromStdString(output.str()); @@ -292,6 +292,29 @@ R"(PolygonOffset { QCOMPARE(string, result); } + void test_Normal_data() + { + auto result = +R"(Normal { + vector 1 0 0.5 +} +)"; + QTest::addColumn("result"); + QTest::newRow("Normal") << result; + } + + void test_Normal() + { + QFETCH(QString, result); + + Base::NormalItem item; + item.setVector({Base::Vector3f{1,0,0.5}}); + builder.addNode(item); + QString string = QString::fromStdString(output.str()); + + QCOMPARE(string, result); + } + void test_LineItem() { Base::Line3f line; @@ -303,6 +326,19 @@ R"(PolygonOffset { QVERIFY(node != nullptr); } + void test_ArrowItem() + { + Base::Line3f line; + line.p2.z = 10; + Base::DrawStyle style; + Base::ArrowItem item{line, style}; + builder.addNode(item); + + qDebug() << QString::fromStdString(output.str()); + SoNode* node = loadBuffer(output.str()); + QVERIFY(node != nullptr); + } + void test_PointItem() { Base::Vector3f pnt; @@ -314,6 +350,90 @@ R"(PolygonOffset { QVERIFY(node != nullptr); } + void test_NormalBinding_data() + { + auto result = "NormalBinding { value PER_PART }\n"; + QTest::addColumn("result"); + QTest::newRow("NormalBinding") << result; + } + + void test_NormalBinding() + { + QFETCH(QString, result); + + Base::NormalBindingItem item; + item.setValue(Base::BindingElement::Binding::PerPart); + builder.addNode(item); + QString string = QString::fromStdString(output.str()); + + QCOMPARE(string, result); + } + + void test_Cylinder_data() + { + auto result = +R"(Cylinder { + radius 3 + height 7 + parts (SIDES | TOP | BOTTOM) +} +)"; + QTest::addColumn("result"); + QTest::newRow("Cylinder") << result; + } + + void test_Cylinder() + { + QFETCH(QString, result); + + Base::CylinderItem item; + item.setRadius(3); + item.setHeight(7); + builder.addNode(item); + QString string = QString::fromStdString(output.str()); + + QCOMPARE(string, result); + } + + void test_Cone_data() + { + auto result = "Cone { bottomRadius 2 height 10 }\n"; + QTest::addColumn("result"); + QTest::newRow("Cone") << result; + } + + void test_Cone() + { + QFETCH(QString, result); + + Base::ConeItem item; + item.setBottomRadius(2); + item.setHeight(10); + builder.addNode(item); + QString string = QString::fromStdString(output.str()); + + QCOMPARE(string, result); + } + + void test_Sphere_data() + { + auto result = "Sphere { radius 4 }\n"; + QTest::addColumn("result"); + QTest::newRow("Sphere") << result; + } + + void test_Sphere() + { + QFETCH(QString, result); + + Base::SphereItem item; + item.setRadius(4); + builder.addNode(item); + QString string = QString::fromStdString(output.str()); + + QCOMPARE(string, result); + } + private: std::stringstream output; Base::InventorBuilder builder;