| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <algorithm> |
| | #include <string> |
| | #include <string_view> |
| | #include <boost/algorithm/string.hpp> |
| | #include <boost/algorithm/string/predicate.hpp> |
| | #include <boost/lexical_cast.hpp> |
| | #include <boost/tokenizer.hpp> |
| |
|
| | #include "Builder3D.h" |
| | #include "Console.h" |
| | #include "Exception.h" |
| | #include "FileInfo.h" |
| | #include "Stream.h" |
| |
|
| |
|
| | 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; |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | 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"; |
| | } |
| | } |
| |
|
| | |
| |
|
| | 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"; |
| | } |
| |
|
| | |
| |
|
| | |
| | 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"; |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | Builder3D::Builder3D() |
| | : result {} |
| | , builder {result} |
| | {} |
| |
|
| | |
| | |
| | |
| | |
| | Builder3D::~Builder3D() = default; |
| |
|
| | void Builder3D::clear() |
| | { |
| | |
| | #if defined(_MSC_VER) |
| | result.str().clear(); |
| | #endif |
| | result.clear(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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 |
| | ); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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; |
| |
|
| | |
| | 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&) { |
| | } |
| | } |
| |
|
| | |
| | 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; |
| |
|
| | |
| | std::getline(inp, line); |
| | if (line.find("#Inventor V2.1 ascii") == std::string::npos) { |
| | return false; |
| | } |
| |
|
| | while (std::getline(inp, line)) { |
| | |
| | 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); |
| | } |
| |
|
| | } |
| |
|