Download src/Base/Builder3D.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 34.3 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Base/Builder3D.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Base/Builder3D.cpp
-
curl -L -o Builder3D.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Base/Builder3D.cpp
34.3 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2011 Jürgen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| using namespace Base; | |
| constexpr float valueMinLegal {-1.0F}; | |
| constexpr float valueMaxLegal {1.0F}; | |
| ColorRGB::ColorRGB() | |
| : Rgb {1.0F, 1.0F, 1.0F} | |
| {} | |
| ColorRGB::ColorRGB(float red, float green, float blue) | |
| : Rgb {valueInRange(red), valueInRange(green), valueInRange(blue)} | |
| {} | |
| float ColorRGB::valueInRange(float value) | |
| { | |
| return std::clamp(value, valueMinLegal, valueMaxLegal); | |
| } | |
| const char* DrawStyle::styleAsString() const | |
| { | |
| switch (style) { | |
| case Style::Filled: | |
| return "FILLED"; | |
| case Style::Lines: | |
| return "LINES"; | |
| case Style::Points: | |
| return "POINTS"; | |
| case Style::Invisible: | |
| return "INVISIBLE"; | |
| } | |
| return "FILLED"; | |
| } | |
| std::string DrawStyle::patternAsString() const | |
| { | |
| std::stringstream str; | |
| str << "0x" << std::hex << linePattern; | |
| return str.str(); | |
| } | |
| const char* VertexOrdering::toString() const | |
| { | |
| switch (ordering) { | |
| case Ordering::UnknownOrdering: | |
| return "UNKNOWN_ORDERING"; | |
| case Ordering::Clockwise: | |
| return "CLOCKWISE"; | |
| case Ordering::CounterClockwise: | |
| return "COUNTERCLOCKWISE"; | |
| } | |
| return "UNKNOWN_ORDERING"; | |
| } | |
| const char* ShapeType::toString() const | |
| { | |
| switch (type) { | |
| case Type::UnknownShapeType: | |
| return "UNKNOWN_SHAPE_TYPE"; | |
| case Type::Convex: | |
| return "SOLID"; | |
| } | |
| return "UNKNOWN_SHAPE_TYPE"; | |
| } | |
| const char* BindingElement::bindingAsString() const | |
| { | |
| switch (value) { | |
| case Binding::PerPart: | |
| return "PER_PART"; | |
| case Binding::PerPartIndexed: | |
| return "PER_PART_INDEXED"; | |
| case Binding::PerFace: | |
| return "PER_FACE"; | |
| case Binding::PerFaceIndexed: | |
| return "PER_FACE_INDEXED"; | |
| case Binding::PerVertex: | |
| return "PER_VERTEX"; | |
| case Binding::PerVertexIndexed: | |
| return "PER_VERTEX_INDEXED"; | |
| default: | |
| return "OVERALL"; | |
| } | |
| } | |
| const char* PolygonOffset::styleAsString() const | |
| { | |
| switch (style) { | |
| case Style::Filled: | |
| return "FILLED"; | |
| case Style::Lines: | |
| return "LINES"; | |
| case Style::Points: | |
| return "POINTS"; | |
| } | |
| return "FILLED"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| InventorOutput::InventorOutput(std::ostream& result, Indentation& indent) | |
| : result(result) | |
| , indent(indent) | |
| {} | |
| std::ostream& InventorOutput::stream() | |
| { | |
| return result; | |
| } | |
| std::ostream& InventorOutput::write() | |
| { | |
| result << indent; | |
| return result; | |
| } | |
| std::ostream& InventorOutput::write(const char* str) | |
| { | |
| result << indent << str; | |
| return result; | |
| } | |
| std::ostream& InventorOutput::write(const std::string& str) | |
| { | |
| result << indent << str; | |
| return result; | |
| } | |
| std::ostream& InventorOutput::writeLine() | |
| { | |
| result << indent << '\n'; | |
| return result; | |
| } | |
| std::ostream& InventorOutput::writeLine(const char* str) | |
| { | |
| result << indent << str << '\n'; | |
| return result; | |
| } | |
| std::ostream& InventorOutput::writeLine(const std::string& str) | |
| { | |
| result << indent << str << '\n'; | |
| return result; | |
| } | |
| void InventorOutput::increaseIndent() | |
| { | |
| indent.increaseIndent(); | |
| } | |
| void InventorOutput::decreaseIndent() | |
| { | |
| indent.decreaseIndent(); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| namespace Base | |
| { | |
| template<class type> | |
| struct field_traits | |
| { | |
| }; | |
| template<> | |
| struct field_traits<float> | |
| { | |
| using field_type = float; | |
| static std::ostream& write(std::ostream& out, const field_type& item) | |
| { | |
| out << item; | |
| return out; | |
| } | |
| }; | |
| template<> | |
| struct field_traits<Vector3f> | |
| { | |
| using field_type = Vector3f; | |
| static std::ostream& write(std::ostream& out, const field_type& item) | |
| { | |
| out << item.x << " " << item.y << " " << item.z; | |
| return out; | |
| } | |
| }; | |
| template<> | |
| struct field_traits<ColorRGB> | |
| { | |
| using field_type = ColorRGB; | |
| static std::ostream& write(std::ostream& out, const field_type& item) | |
| { | |
| out << item.red() << " " << item.green() << " " << item.blue(); | |
| return out; | |
| } | |
| }; | |
| /** | |
| * Writes a field type to a stream. | |
| * @author Werner Mayer | |
| */ | |
| class InventorFieldWriter | |
| { | |
| public: | |
| template<typename T> | |
| void write(const char* fieldName, const std::vector<T>& fieldData, InventorOutput& out) const; | |
| }; | |
| template<typename T> | |
| void InventorFieldWriter::write( | |
| const char* fieldName, | |
| const std::vector<T>& fieldData, | |
| InventorOutput& out | |
| ) const | |
| { | |
| if (fieldData.empty()) { | |
| return; | |
| } | |
| if (fieldData.size() == 1) { | |
| out.write() << fieldName << " "; | |
| field_traits<T>::write(out.stream(), fieldData[0]) << '\n'; | |
| } | |
| else { | |
| out.write() << fieldName << " [\n"; | |
| out.increaseIndent(); | |
| for (auto it : fieldData) { | |
| out.write(); | |
| field_traits<T>::write(out.stream(), it) << '\n'; | |
| } | |
| out.decreaseIndent(); | |
| out.write() << "]\n"; | |
| } | |
| } | |
| template<> | |
| void InventorFieldWriter::write<int>( | |
| const char* fieldName, | |
| const std::vector<int>& fieldData, | |
| InventorOutput& out | |
| ) const | |
| { | |
| if (fieldData.empty()) { | |
| return; | |
| } | |
| out.write() << fieldName << " [\n"; | |
| out.increaseIndent(); | |
| std::size_t last_index {fieldData.size()}; | |
| std::size_t index {}; | |
| for (auto it : fieldData) { | |
| if (index % 8 == 0) { | |
| out.write(); | |
| } | |
| if (index < last_index) { | |
| out.stream() << it << ", "; | |
| } | |
| else { | |
| out.stream() << it << " ] \n"; | |
| } | |
| if (++index % 8 == 0) { | |
| out.stream() << '\n'; | |
| } | |
| } | |
| out.decreaseIndent(); | |
| out.write() << "]\n"; | |
| } | |
| } // namespace Base | |
| // ----------------------------------------------------------------------------- | |
| LabelItem::LabelItem(std::string text) | |
| : text(std::move(text)) | |
| {} | |
| void LabelItem::write(InventorOutput& out) const | |
| { | |
| out.write("Label {\n"); | |
| out.write() << " label \"" << text << "\"\n"; | |
| out.write("}\n"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| InfoItem::InfoItem(std::string text) | |
| : text(std::move(text)) | |
| {} | |
| void InfoItem::write(InventorOutput& out) const | |
| { | |
| out.write("Info {\n"); | |
| out.write() << " string \"" << text << "\"\n"; | |
| out.write("}\n"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| BaseColorItem::BaseColorItem(const ColorRGB& rgb) | |
| : rgb(rgb) | |
| {} | |
| void BaseColorItem::write(InventorOutput& out) const | |
| { | |
| out.write("BaseColor {\n"); | |
| out.write() << " rgb " << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n'; | |
| out.write("}\n"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| PointItem::PointItem(const Base::Vector3f& point, DrawStyle drawStyle, const ColorRGB& rgb) | |
| : point(point) | |
| , drawStyle(drawStyle) | |
| , rgb(rgb) | |
| {} | |
| void PointItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "Separator { \n"; | |
| out.write() << " Material { \n"; | |
| out.write() << " diffuseColor " << rgb.red() << " " << rgb.green() << " " << rgb.blue() | |
| << '\n'; | |
| out.write() << " }\n"; | |
| out.write() << " MaterialBinding { value PER_PART }\n"; | |
| out.write() << " DrawStyle { pointSize " << drawStyle.pointSize << "}\n"; | |
| out.write() << " Coordinate3 {\n"; | |
| out.write() << " point [ " << point.x << " " << point.y << " " << point.z << "]\n"; | |
| out.write() << " }\n"; | |
| out.write() << " PointSet { }\n"; | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| LineItem::LineItem(const Base::Line3f& line, DrawStyle drawStyle, const ColorRGB& rgb) | |
| : line(line) | |
| , drawStyle(drawStyle) | |
| , rgb(rgb) | |
| {} | |
| void LineItem::write(InventorOutput& out) const | |
| { | |
| std::string pattern = drawStyle.patternAsString(); | |
| out.write(" Separator { \n"); | |
| out.write() << " Material { diffuseColor " << rgb.red() << " " << rgb.green() << " " | |
| << rgb.blue() << "} \n"; | |
| out.write() << " DrawStyle { lineWidth " << drawStyle.lineWidth << " linePattern " << pattern | |
| << " } \n"; | |
| out.write() << " Coordinate3 { \n"; | |
| out.write() << " point [ "; | |
| out.write() << line.p1.x << " " << line.p1.y << " " << line.p1.z << ","; | |
| out.write() << line.p2.x << " " << line.p2.y << " " << line.p2.z; | |
| out.write() << " ] \n"; | |
| out.write() << " } \n"; | |
| out.write() << " LineSet { } \n"; | |
| out.write() << " } \n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| MultiLineItem::MultiLineItem(std::vector<Vector3f> points, DrawStyle drawStyle, const ColorRGB& rgb) | |
| : points {std::move(points)} | |
| , drawStyle {drawStyle} | |
| , rgb {rgb} | |
| {} | |
| void MultiLineItem::write(InventorOutput& out) const | |
| { | |
| std::string pattern = drawStyle.patternAsString(); | |
| out.write() << "Separator {\n"; | |
| out.write() << " Material { diffuseColor " << rgb.red() << " " << rgb.green() << " " | |
| << rgb.blue() << "}\n"; | |
| out.write() << " DrawStyle { lineWidth " << drawStyle.lineWidth << " linePattern " << pattern | |
| << " }\n"; | |
| out.write() << " Coordinate3 {\n"; | |
| InventorFieldWriter writer; | |
| writer.write<Vector3f>("point", points, out); | |
| out.write() << " }\n"; | |
| out.write() << " LineSet {\n"; | |
| out.write() << " numVertices [ -1 ]\n"; | |
| out.write() << " }\n"; | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| 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"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| BoundingBoxItem::BoundingBoxItem( | |
| const Vector3f& pt1, | |
| const Vector3f& pt2, | |
| DrawStyle drawStyle, | |
| const ColorRGB& rgb | |
| ) | |
| : pt1 {pt1} | |
| , pt2 {pt2} | |
| , drawStyle {drawStyle} | |
| , rgb {rgb} | |
| {} | |
| void BoundingBoxItem::write(InventorOutput& out) const | |
| { | |
| std::vector<Base::Vector3f> points(8); | |
| points[0].Set(pt1.x, pt1.y, pt1.z); | |
| points[1].Set(pt1.x, pt1.y, pt2.z); | |
| points[2].Set(pt1.x, pt2.y, pt1.z); | |
| points[3].Set(pt1.x, pt2.y, pt2.z); | |
| points[4].Set(pt2.x, pt1.y, pt1.z); | |
| points[5].Set(pt2.x, pt1.y, pt2.z); | |
| points[6].Set(pt2.x, pt2.y, pt1.z); | |
| points[7].Set(pt2.x, pt2.y, pt2.z); | |
| std::vector<int> lineset = {0, 2, 6, 4, 0, -1, 1, 5, 7, 3, 1, -1, 7, 6, 2, | |
| 3, 7, -1, 3, 2, 0, 1, 3, -1, 5, 1, 0, 4, 5, -1}; | |
| out.write() << "Separator {\n"; | |
| out.write() << " Material { diffuseColor " << rgb.red() << " " << rgb.green() << " " | |
| << rgb.blue() << "}\n"; | |
| out.write() << " DrawStyle { lineWidth " << drawStyle.lineWidth << "}\n"; | |
| Coordinate3Item coords {points}; | |
| out.increaseIndent(); | |
| coords.write(out); | |
| out.decreaseIndent(); | |
| IndexedLineSetItem indexed {lineset}; | |
| out.increaseIndent(); | |
| indexed.write(out); | |
| out.decreaseIndent(); | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void MaterialItem::setAmbientColor(const std::vector<ColorRGB>& rgb) | |
| { | |
| ambientColor = rgb; | |
| } | |
| void MaterialItem::setDiffuseColor(const std::vector<ColorRGB>& rgb) | |
| { | |
| diffuseColor = rgb; | |
| } | |
| void MaterialItem::setSpecularColor(const std::vector<ColorRGB>& rgb) | |
| { | |
| specularColor = rgb; | |
| } | |
| void MaterialItem::setEmissiveColor(const std::vector<ColorRGB>& rgb) | |
| { | |
| emissiveColor = rgb; | |
| } | |
| void MaterialItem::setShininess(const std::vector<float>& value) | |
| { | |
| shininess = value; | |
| } | |
| void MaterialItem::setTransparency(const std::vector<float>& value) | |
| { | |
| transparency = value; | |
| } | |
| void MaterialItem::write(InventorOutput& out) const | |
| { | |
| beginMaterial(out); | |
| writeAmbientColor(out); | |
| writeDiffuseColor(out); | |
| writeSpecularColor(out); | |
| writeEmissiveColor(out); | |
| writeShininess(out); | |
| writeTransparency(out); | |
| endMaterial(out); | |
| } | |
| void MaterialItem::beginMaterial(InventorOutput& out) const | |
| { | |
| out.writeLine("Material {"); | |
| out.increaseIndent(); | |
| } | |
| void MaterialItem::endMaterial(InventorOutput& out) const | |
| { | |
| out.decreaseIndent(); | |
| out.writeLine("}"); | |
| } | |
| void MaterialItem::writeAmbientColor(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<ColorRGB>("ambientColor", ambientColor, out); | |
| } | |
| void MaterialItem::writeDiffuseColor(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<ColorRGB>("diffuseColor", diffuseColor, out); | |
| } | |
| void MaterialItem::writeSpecularColor(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<ColorRGB>("specularColor", specularColor, out); | |
| } | |
| void MaterialItem::writeEmissiveColor(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<ColorRGB>("emissiveColor", emissiveColor, out); | |
| } | |
| void MaterialItem::writeShininess(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<float>("shininess", shininess, out); | |
| } | |
| void MaterialItem::writeTransparency(InventorOutput& out) const | |
| { | |
| InventorFieldWriter writer; | |
| writer.write<float>("transparency", transparency, out); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| MaterialBindingItem::MaterialBindingItem(BindingElement::Binding bind) | |
| { | |
| value.value = bind; | |
| } | |
| void MaterialBindingItem::setValue(BindingElement::Binding bind) | |
| { | |
| value.value = bind; | |
| } | |
| void MaterialBindingItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "MaterialBinding { value " << value.bindingAsString() << " } \n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| DrawStyleItem::DrawStyleItem(DrawStyle value) | |
| : style {value} | |
| {} | |
| void DrawStyleItem::setValue(DrawStyle value) | |
| { | |
| style = value; | |
| } | |
| void DrawStyleItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "DrawStyle {\n"; | |
| out.write() << " style " << style.styleAsString() << '\n'; | |
| out.write() << " pointSize " << style.pointSize << '\n'; | |
| out.write() << " lineWidth " << style.lineWidth << '\n'; | |
| out.write() << " linePattern " << style.patternAsString() << '\n'; | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| ShapeHintsItem::ShapeHintsItem(float creaseAngle) | |
| : creaseAngle(creaseAngle) | |
| {} | |
| void ShapeHintsItem::setVertexOrdering(VertexOrdering::Ordering value) | |
| { | |
| vertexOrdering.ordering = value; | |
| } | |
| void ShapeHintsItem::setShapeType(ShapeType::Type value) | |
| { | |
| shapeType.type = value; | |
| } | |
| void ShapeHintsItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "ShapeHints {\n"; | |
| out.write() << " creaseAngle " << creaseAngle << '\n'; | |
| out.write() << " vertexOrdering " << vertexOrdering.toString() << '\n'; | |
| out.write() << " shapeType " << shapeType.toString() << '\n'; | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void PolygonOffsetItem::setValue(PolygonOffset value) | |
| { | |
| offset = value; | |
| } | |
| void PolygonOffsetItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "PolygonOffset {\n"; | |
| out.write() << " factor " << offset.factor << '\n'; | |
| out.write() << " units " << offset.units << '\n'; | |
| out.write() << " styles " << offset.styleAsString() << '\n'; | |
| out.write() << " on " << (offset.on ? "TRUE" : "FALSE") << '\n'; | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| Coordinate3Item::Coordinate3Item(std::vector<Vector3f> points) | |
| : points(std::move(points)) | |
| {} | |
| void Coordinate3Item::write(InventorOutput& out) const | |
| { | |
| beginPoint(out); | |
| InventorFieldWriter writer; | |
| writer.write<Vector3f>("point", points, out); | |
| endPoint(out); | |
| } | |
| void Coordinate3Item::beginPoint(InventorOutput& out) const | |
| { | |
| out.writeLine("Coordinate3 {"); | |
| out.increaseIndent(); | |
| } | |
| void Coordinate3Item::endPoint(InventorOutput& out) const | |
| { | |
| out.decreaseIndent(); | |
| out.writeLine("}"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void PointSetItem::write(InventorOutput& out) const | |
| { | |
| out.writeLine("PointSet { }"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void LineSetItem::write(InventorOutput& out) const | |
| { | |
| out.writeLine("LineSet { }"); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| FaceSetItem::FaceSetItem(std::vector<int> indices) | |
| : indices(std::move(indices)) | |
| {} | |
| void FaceSetItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "FaceSet {\n"; | |
| out.increaseIndent(); | |
| InventorFieldWriter writer; | |
| writer.write<int>("numVertices", indices, out); | |
| out.decreaseIndent(); | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| IndexedLineSetItem::IndexedLineSetItem(std::vector<int> indices) | |
| : indices(std::move(indices)) | |
| {} | |
| void IndexedLineSetItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "IndexedLineSet {\n"; | |
| out.increaseIndent(); | |
| InventorFieldWriter writer; | |
| writer.write<int>("coordIndex", indices, out); | |
| out.decreaseIndent(); | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| IndexedFaceSetItem::IndexedFaceSetItem(std::vector<int> indices) | |
| : indices(std::move(indices)) | |
| {} | |
| void IndexedFaceSetItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "IndexedFaceSet {\n"; | |
| out.increaseIndent(); | |
| InventorFieldWriter writer; | |
| writer.write<int>("coordIndex", indices, out); | |
| out.decreaseIndent(); | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| NormalItem::NormalItem(std::vector<Base::Vector3f> vec) | |
| : vector(std::move(vec)) | |
| {} | |
| void NormalItem::write(InventorOutput& out) const | |
| { | |
| beginNormal(out); | |
| InventorFieldWriter writer; | |
| writer.write<Vector3f>("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"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| void NurbsSurfaceItem::setControlPoints(int numU, int numV) | |
| { | |
| numUControlPoints = numU; | |
| numVControlPoints = numV; | |
| } | |
| void NurbsSurfaceItem::setKnotVector(const std::vector<float>& uKnots, const std::vector<float>& vKnots) | |
| { | |
| uKnotVector = uKnots; | |
| vKnotVector = vKnots; | |
| } | |
| void NurbsSurfaceItem::write(InventorOutput& out) const | |
| { | |
| out.write() << "NurbsSurface {\n"; | |
| out.write() << " numUControlPoints " << numUControlPoints << '\n'; | |
| out.write() << " numVControlPoints " << numVControlPoints << '\n'; | |
| out.increaseIndent(); | |
| InventorFieldWriter writer; | |
| writer.write<float>("uKnotVector", uKnotVector, out); | |
| writer.write<float>("vKnotVector", vKnotVector, out); | |
| out.decreaseIndent(); | |
| out.write() << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| Text2Item::Text2Item(std::string string) | |
| : string(std::move(string)) | |
| {} | |
| void Text2Item::write(InventorOutput& out) const | |
| { | |
| out.write() << "Text2 { string \"" << string << "\" " | |
| << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| // NOLINTNEXTLINE | |
| TransformItem::TransformItem(const Base::Placement& placement) | |
| : placement(placement) | |
| {} | |
| TransformItem::TransformItem(const Matrix4D& transform) | |
| { | |
| placement.fromMatrix(transform); | |
| } | |
| void TransformItem::write(InventorOutput& out) const | |
| { | |
| Base::Vector3d translation = placement.getPosition(); | |
| Base::Vector3d rotationaxis; | |
| double angle {}; | |
| placement.getRotation().getValue(rotationaxis, angle); | |
| out.write() << "Transform {\n"; | |
| out.write() << " translation " << translation.x << " " << translation.y << " " << translation.z | |
| << '\n'; | |
| out.write() << " rotation " << rotationaxis.x << " " << rotationaxis.y << " " << rotationaxis.z | |
| << " " << angle << '\n'; | |
| out.write() << "}" << '\n'; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| InventorBuilder::InventorBuilder(std::ostream& str) | |
| : result(str) | |
| { | |
| addHeader(); | |
| } | |
| InventorBuilder::~InventorBuilder() = default; | |
| void InventorBuilder::addHeader() | |
| { | |
| result << "#Inventor V2.1 ascii \n\n"; | |
| } | |
| void InventorBuilder::increaseIndent() | |
| { | |
| indent.increaseIndent(); | |
| } | |
| void InventorBuilder::decreaseIndent() | |
| { | |
| indent.decreaseIndent(); | |
| } | |
| void InventorBuilder::addNode(const NodeItem& node) | |
| { | |
| InventorOutput out(result, indent); | |
| node.write(out); | |
| } | |
| void InventorBuilder::beginSeparator() | |
| { | |
| result << indent << "Separator { \n"; | |
| increaseIndent(); | |
| } | |
| void InventorBuilder::endSeparator() | |
| { | |
| decreaseIndent(); | |
| result << indent << "}\n"; | |
| } | |
| // ----------------------------------------------------------------------------- | |
| /** | |
| * A constructor. | |
| * A more elaborate description of the constructor. | |
| */ | |
| Builder3D::Builder3D() | |
| : result {} | |
| , builder {result} | |
| {} | |
| /** | |
| * A destructor. | |
| * A more elaborate description of the destructor. | |
| */ | |
| Builder3D::~Builder3D() = default; | |
| void Builder3D::clear() | |
| { | |
| // under gcc stringstream::str() returns a copy not a reference | |
| result.str().clear(); | |
| result.clear(); | |
| } | |
| /** | |
| * Save the resulting inventor 3D representation to the Console().log() facility. | |
| * In DEBUG mode the Gui (if running) will trigger on that and show the representation in | |
| * the active Viewer/Document. It shows only one representation on time. If you need to | |
| * show more then one representation use saveToFile() instead. | |
| * @see saveToFile() | |
| */ | |
| void Builder3D::saveToLog() | |
| { | |
| ILogger* obs = Base::Console().get("StatusBar"); | |
| if (obs) { | |
| obs->sendLog( | |
| "Builder3D", | |
| result.str(), | |
| Base::LogStyle::Log, | |
| Base::IntendedRecipient::Developer, | |
| Base::ContentType::Untranslatable | |
| ); | |
| } | |
| } | |
| /** | |
| * Save the resulting inventor 3D representation to a file. Ending should be *.iv. | |
| * That enables you to show the result in a Inventor Viewer or in FreeCAD by: | |
| * /code | |
| * Gui.document().addAnnotation("Debug","MyFile.iv") | |
| * /endcode | |
| * @see saveToFile() | |
| */ | |
| void Builder3D::saveToFile(const char* FileName) | |
| { | |
| Base::FileInfo fi(FileName); | |
| Base::ofstream file(fi); | |
| if (!file) { | |
| throw FileException("Cannot open file"); | |
| } | |
| file << result.str(); | |
| } | |
| void Builder3D::addNode(const NodeItem& item) | |
| { | |
| builder.addNode(item); | |
| } | |
| void Builder3D::beginSeparator() | |
| { | |
| builder.beginSeparator(); | |
| } | |
| void Builder3D::endSeparator() | |
| { | |
| builder.endSeparator(); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| template<typename T> | |
| std::vector<T> InventorLoader::readData(const char* fieldName) const | |
| { | |
| std::vector<T> fieldValues; | |
| std::string str; | |
| // search for 'fieldName' and '[' | |
| bool found = false; | |
| while (std::getline(inp, str)) { | |
| std::string::size_type point = str.find(fieldName); | |
| std::string::size_type open = str.find('['); | |
| if (point != std::string::npos && open > point) { | |
| str = str.substr(open); | |
| found = true; | |
| break; | |
| } | |
| } | |
| if (!found) { | |
| return {}; | |
| } | |
| do { | |
| boost::char_separator<char> sep(" ,"); | |
| boost::tokenizer<boost::char_separator<char>> tokens(str, sep); | |
| std::vector<std::string> token_results; | |
| token_results.assign(tokens.begin(), tokens.end()); | |
| for (const auto& it : token_results) { | |
| try { | |
| T value = boost::lexical_cast<T>(it); | |
| fieldValues.emplace_back(value); | |
| } | |
| catch (const boost::bad_lexical_cast&) { | |
| } | |
| } | |
| // search for ']' to finish the reading | |
| if (str.find(']') != std::string::npos) { | |
| break; | |
| } | |
| } while (std::getline(inp, str)); | |
| return fieldValues; | |
| } | |
| std::vector<Vector3f> InventorLoader::convert(const std::vector<float>& data) const | |
| { | |
| if (data.size() % 3 != 0) { | |
| throw std::string("Reading failed"); | |
| } | |
| std::size_t len = data.size() / 3; | |
| std::vector<Vector3f> points; | |
| points.reserve(len); | |
| for (std::size_t i = 0; i < len; i++) { | |
| float x = data[3 * i]; | |
| float y = data[3 * i + 1]; | |
| float z = data[3 * i + 2]; | |
| points.emplace_back(x, y, z); | |
| } | |
| return points; | |
| } | |
| std::vector<InventorLoader::Face> InventorLoader::convert(const std::vector<int32_t>& data) const | |
| { | |
| std::vector<Face> faces; | |
| faces.reserve(data.size()); | |
| int32_t coordIndex = 0; | |
| for (const auto it : data) { | |
| if (it == 3) { | |
| faces.emplace_back(coordIndex, coordIndex + 1, coordIndex + 2); | |
| } | |
| else if (it == 4) { | |
| faces.emplace_back(coordIndex, coordIndex + 1, coordIndex + 2); | |
| faces.emplace_back(coordIndex, coordIndex + 2, coordIndex + 3); | |
| } | |
| coordIndex += it; | |
| } | |
| return faces; | |
| } | |
| std::vector<std::vector<int32_t>> InventorLoader::split(const std::vector<int32_t>& data) | |
| { | |
| std::vector<std::vector<int32_t>> splitdata; | |
| std::vector<int32_t>::const_iterator begin = data.cbegin(); | |
| std::vector<int32_t>::const_iterator it = begin; | |
| while ((it = std::find(begin, data.cend(), -1)) != data.cend()) { | |
| splitdata.emplace_back(begin, it); | |
| begin = it; | |
| std::advance(begin, 1); | |
| } | |
| return splitdata; | |
| } | |
| std::vector<InventorLoader::Face> InventorLoader::convert( | |
| const std::vector<std::vector<int32_t>>& coordIndex | |
| ) const | |
| { | |
| std::vector<Face> faces; | |
| faces.reserve(coordIndex.size()); | |
| for (const auto& it : coordIndex) { | |
| if (it.size() == 3) { | |
| faces.emplace_back(it[0], it[1], it[2]); | |
| } | |
| else if (it.size() == 4) { | |
| faces.emplace_back(it[0], it[1], it[2]); | |
| faces.emplace_back(it[0], it[2], it[3]); | |
| } | |
| } | |
| return faces; | |
| } | |
| void InventorLoader::readNormals() | |
| { | |
| auto data = readData<float>("vector"); | |
| vector = convert(data); | |
| } | |
| void InventorLoader::readCoords() | |
| { | |
| auto data = readData<float>("point"); | |
| points = convert(data); | |
| } | |
| void InventorLoader::readIndexedFaceSet() | |
| { | |
| auto data = readData<int32_t>("coordIndex"); | |
| faces = convert(split(data)); | |
| } | |
| void InventorLoader::readFaceSet() | |
| { | |
| auto data = readData<int32_t>("numVertices"); | |
| faces = convert(data); | |
| isnonindexed = true; | |
| } | |
| bool InventorLoader::read() | |
| { | |
| if (!inp || inp.bad()) { | |
| return false; | |
| } | |
| std::string line; | |
| // Verify it's an Inventor 2.1 file | |
| std::getline(inp, line); | |
| if (line.find("#Inventor V2.1 ascii") == std::string::npos) { | |
| return false; | |
| } | |
| while (std::getline(inp, line)) { | |
| // read the normals if they are defined | |
| if (line.find("Normal {") != std::string::npos) { | |
| readNormals(); | |
| } | |
| else if (line.find("Coordinate3 {") != std::string::npos) { | |
| readCoords(); | |
| } | |
| else if (line.find("IndexedFaceSet {") != std::string::npos) { | |
| readIndexedFaceSet(); | |
| break; | |
| } | |
| else if (line.find("FaceSet {") != std::string::npos) { | |
| readFaceSet(); | |
| break; | |
| } | |
| } | |
| return true; | |
| } | |
| bool InventorLoader::isValid() const | |
| { | |
| int32_t value {static_cast<int32_t>(points.size())}; | |
| auto inRange = [value](const Face& face) { | |
| if (face.p1 < 0 || face.p1 >= value) { | |
| return false; | |
| } | |
| if (face.p2 < 0 || face.p2 >= value) { | |
| return false; | |
| } | |
| if (face.p3 < 0 || face.p3 >= value) { | |
| return false; | |
| } | |
| return true; | |
| }; | |
| return std::all_of(faces.cbegin(), faces.cend(), [&inRange](const Face& face) { | |
| return inRange(face); | |
| }); | |
| } | |
| namespace Base | |
| { | |
| BaseExport Vector3f stringToVector(std::string str) | |
| { | |
| std::string_view view = str; | |
| if (!boost::starts_with(view, "(") || !boost::ends_with(str, ")")) { | |
| throw std::runtime_error("string is not a tuple"); | |
| } | |
| view.remove_prefix(1); | |
| view.remove_suffix(1); | |
| str = view; | |
| boost::char_separator<char> sep(" ,"); | |
| boost::tokenizer<boost::char_separator<char>> tokens(str, sep); | |
| std::vector<std::string> token_results; | |
| token_results.assign(tokens.begin(), tokens.end()); | |
| if (token_results.size() != 3) { | |
| throw std::runtime_error("not a tuple of three floats"); | |
| } | |
| Base::Vector3f vec; | |
| vec.x = boost::lexical_cast<float>(token_results.at(0)); | |
| vec.y = boost::lexical_cast<float>(token_results.at(1)); | |
| vec.z = boost::lexical_cast<float>(token_results.at(2)); | |
| return vec; | |
| } | |
| BaseExport std::string vectorToString(Vector3f vec) | |
| { | |
| return fmt::format("({},{},{})", vec.x, vec.y, vec.z); | |
| } | |
| } // namespace Base | |