From cf3225b50ffc71bf541237785cf68eeca797c78b Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 29 Nov 2022 13:28:00 +0100 Subject: [PATCH] Base: refactoring of InventorBuilder --- src/Base/Builder3D.cpp | 314 +++++++++++++++-------------- src/Base/Builder3D.h | 55 +++-- src/Mod/Mesh/App/Mesh.cpp | 1 - src/Mod/Part/App/TopoShape.cpp | 5 + src/Mod/Points/App/PointsPyImp.cpp | 3 +- 5 files changed, 215 insertions(+), 163 deletions(-) diff --git a/src/Base/Builder3D.cpp b/src/Base/Builder3D.cpp index eb86430873..10e7819073 100644 --- a/src/Base/Builder3D.cpp +++ b/src/Base/Builder3D.cpp @@ -48,9 +48,6 @@ using namespace Base; -//************************************************************************** -// Construction/Destruction - constexpr float valueMinLegal {-1.0F}; constexpr float valueMaxLegal {1.0F}; @@ -92,6 +89,26 @@ std::string DrawStyle::patternAsString() const return str.str(); } +const char* MaterialBinding::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) { @@ -107,85 +124,91 @@ const char* PolygonOffset::styleAsString() const // ----------------------------------------------------------------------------- +std::ostream& operator<<( std::ostream& os, InventorBuilder::Indentation m) +{ + for (int i = 0; i < m.count(); i++) + os << " "; + return os; +} + InventorBuilder::InventorBuilder(std::ostream& output) : result(output) - , indent(0) { result << "#Inventor V2.1 ascii \n\n"; - beginSeparator(); } InventorBuilder:: ~InventorBuilder() { - close(); } -void InventorBuilder::close() +void InventorBuilder::increaseIndent() { - if (indent > 0) { - indent = 0; - endSeparator(); - } + indent.increaseIndent(); +} + +void InventorBuilder::decreaseIndent() +{ + indent.decreaseIndent(); } void InventorBuilder::beginSeparator() { - result << Base::blanks(indent) << "Separator { \n"; - indent += 2; + result << indent << "Separator { \n"; + increaseIndent(); } void InventorBuilder::endSeparator() { - indent-=2; - result << Base::blanks(indent) << "}\n"; + decreaseIndent(); + result << indent << "}\n"; } void InventorBuilder::addInfo(const char* text) { - result << Base::blanks(indent) << "Info { \n"; - result << Base::blanks(indent) << " string \"" << text << "\"\n"; - result << Base::blanks(indent) << "} \n"; + result << indent << "Info { \n"; + result << indent << " string \"" << text << "\"\n"; + result << indent << "} \n"; } void InventorBuilder::addLabel(const char* text) { - result << Base::blanks(indent) << "Label { \n"; - result << Base::blanks(indent) << " label \"" << text << "\"\n"; - result << Base::blanks(indent) << "} \n"; + result << indent << "Label { \n"; + result << indent << " label \"" << text << "\"\n"; + result << indent << "} \n"; } void InventorBuilder::addBaseColor(const ColorRGB& rgb) { - result << Base::blanks(indent) << "BaseColor { \n"; - result << Base::blanks(indent) << " rgb " + result << indent << "BaseColor { \n"; + result << indent << " rgb " << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n'; - result << Base::blanks(indent) << "} \n"; + result << indent << "} \n"; } void InventorBuilder::addMaterial(const ColorRGB& rgb, float transparency) { - result << Base::blanks(indent) << "Material { \n"; - result << Base::blanks(indent) << " diffuseColor " + result << indent << "Material { \n"; + result << indent << " diffuseColor " << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n'; if (transparency > 0) - result << Base::blanks(indent) << " transparency " << transparency << '\n'; - result << Base::blanks(indent) << "} \n"; + result << indent << " transparency " << transparency << '\n'; + result << indent << "} \n"; } void InventorBuilder::beginMaterial() { - result << Base::blanks(indent) << "Material { \n"; - indent += 2; - result << Base::blanks(indent) << "diffuseColor [\n"; - indent += 2; + result << indent << "Material { \n"; + increaseIndent(); + result << indent << "diffuseColor [\n"; + increaseIndent(); } void InventorBuilder::endMaterial() { - indent -= 2; - result << Base::blanks(indent) << "]\n"; - indent -= 2; - result << Base::blanks(indent) << "}\n"; + decreaseIndent(); + result << indent << "]\n"; + decreaseIndent(); + result << indent << "}\n"; } void InventorBuilder::addColor(const ColorRGB& rgb) @@ -193,61 +216,57 @@ void InventorBuilder::addColor(const ColorRGB& rgb) result << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n'; } -void InventorBuilder::addMaterialBinding(const char* bind) +void InventorBuilder::addMaterialBinding(MaterialBinding bind) { - result << Base::blanks(indent) << "MaterialBinding { value " - << bind << " } \n"; + result << indent << "MaterialBinding { value " + << bind.bindingAsString() << " } \n"; } void InventorBuilder::addDrawStyle(DrawStyle drawStyle) { - result << Base::blanks(indent) << "DrawStyle {\n" - << Base::blanks(indent) << " style " << drawStyle.styleAsString() << '\n' - << Base::blanks(indent) << " pointSize " << drawStyle.pointSize << '\n' - << Base::blanks(indent) << " lineWidth " << drawStyle.lineWidth << '\n' - << Base::blanks(indent) << " linePattern " << drawStyle.linePattern << '\n' - << Base::blanks(indent) << "}\n"; + result << indent << "DrawStyle {\n" + << indent << " style " << drawStyle.styleAsString() << '\n' + << indent << " pointSize " << drawStyle.pointSize << '\n' + << indent << " lineWidth " << drawStyle.lineWidth << '\n' + << indent << " linePattern " << drawStyle.linePattern << '\n' + << indent << "}\n"; } void InventorBuilder::addShapeHints(float creaseAngle) { - result << Base::blanks(indent) << "ShapeHints {\n" - << Base::blanks(indent) << " creaseAngle " << creaseAngle << '\n' - << Base::blanks(indent) << "}\n"; + result << indent << "ShapeHints {\n" + << indent << " creaseAngle " << creaseAngle << '\n' + << indent << "}\n"; } void InventorBuilder::addPolygonOffset(PolygonOffset polygonOffset) { - result << Base::blanks(indent) << "PolygonOffset {\n" - << Base::blanks(indent) << " factor " << polygonOffset.factor << '\n' - << Base::blanks(indent) << " units " << polygonOffset.units << '\n' - << Base::blanks(indent) << " styles " << polygonOffset.styleAsString() << '\n' - << Base::blanks(indent) << " on " << (polygonOffset.on ? "TRUE" : "FALSE") << '\n' - << Base::blanks(indent) << "}\n"; + result << indent << "PolygonOffset {\n" + << indent << " factor " << polygonOffset.factor << '\n' + << indent << " units " << polygonOffset.units << '\n' + << indent << " styles " << polygonOffset.styleAsString() << '\n' + << indent << " on " << (polygonOffset.on ? "TRUE" : "FALSE") << '\n' + << indent << "}\n"; } -//************************************************************************** -// points handling - /** * Starts the definition of point set. * If possible don't make too many beginPoints() and endPoints() calls. * Try to put all points in one set. - * @see startPoints() * @see endPoints() */ void InventorBuilder::beginPoints() { - result << Base::blanks(indent) << "Coordinate3 { \n"; - indent += 2; - result << Base::blanks(indent) << "point [ \n"; - indent += 2; + result << indent << "Coordinate3 { \n"; + increaseIndent(); + result << indent << "point [ \n"; + increaseIndent(); } /// insert a point in a point set void InventorBuilder::addPoint(const Vector3f& pnt) { - result << Base::blanks(indent) << pnt.x << " " << pnt.y << " " << pnt.z << ",\n"; + result << indent << pnt.x << " " << pnt.y << " " << pnt.z << ",\n"; } void InventorBuilder::addPoints(const std::vector& points) @@ -259,60 +278,59 @@ void InventorBuilder::addPoints(const std::vector& points) /** * Ends the point set operations and write the resulting inventor string. - * @see startPoints() + * @see beginPoints() */ void InventorBuilder::endPoints() { - indent -= 2; - result << Base::blanks(indent) << "]\n"; - indent -= 2; - result << Base::blanks(indent) << "}\n"; + decreaseIndent(); + result << indent << "]\n"; + decreaseIndent(); + result << indent << "}\n"; } /** * Adds an SoPointSet node after creating an SoCordinate3 node with * beginPoints() and endPoints(). - * @see startPoints() * @see beginPoints() * @see endPoints() */ void InventorBuilder::addPointSet() { - result << Base::blanks(indent) << "PointSet { } \n"; + result << indent << "PointSet { } \n"; } void InventorBuilder::addSinglePoint(const Base::Vector3f &point, DrawStyle drawStyle, const ColorRGB& color) { - result << Base::blanks(indent) << "Separator { "; - result << Base::blanks(indent) << " Material { "; - result << Base::blanks(indent) << " diffuseColor " << color.red() << " "<< color.green() << " "<< color.blue(); - result << Base::blanks(indent) << " }"; - result << Base::blanks(indent) << " MaterialBinding { value PER_PART } "; - result << Base::blanks(indent) << " DrawStyle { pointSize " << drawStyle.pointSize << "} "; - result << Base::blanks(indent) << " Coordinate3 { "; - result << Base::blanks(indent) << " point [ "; + result << indent << "Separator { "; + result << indent << " Material { "; + result << indent << " diffuseColor " << color.red() << " "<< color.green() << " "<< color.blue(); + result << indent << " }"; + result << indent << " MaterialBinding { value PER_PART } "; + result << indent << " DrawStyle { pointSize " << drawStyle.pointSize << "} "; + result << indent << " Coordinate3 { "; + result << indent << " point [ "; result << point.x << " " << point.y << " " << point.z << ","; - result << Base::blanks(indent) << " ] "; - result << Base::blanks(indent) << " }"; - result << Base::blanks(indent) << " PointSet { } "; - result << Base::blanks(indent) <<"}"; + result << indent << " ] "; + result << indent << " }"; + result << indent << " PointSet { } "; + result << indent <<"}"; } /** * Adds a SoLineSet node after creating a SoCordinate3 node with * beginPoints() and endPoints(). - * @see startPoints() * @see beginPoints() * @see endPoints() */ void InventorBuilder::addLineSet() { - result << Base::blanks(indent) << "LineSet { } \n"; + result << indent << "LineSet { } \n"; } -//************************************************************************** -// text handling - +void InventorBuilder::addText(const char * text) +{ + result << indent << " Text2 { string \" " << text << "\" " << "} \n"; +} /** * Add a Text with a given position to the 3D set. The origin is the @@ -323,19 +341,15 @@ void InventorBuilder::addLineSet() */ void InventorBuilder::addText(const Vector3f& pnt, const char * text, const ColorRGB& rgb) { - result << Base::blanks(indent) << "Separator { \n" - << Base::blanks(indent) << " Material { diffuseColor " + result << indent << "Separator { \n" + << indent << " Material { diffuseColor " << rgb.red() << " "<< rgb.green() << " "<< rgb.blue() << "} \n" - << Base::blanks(indent) << " Transform { translation " + << indent << " Transform { translation " << pnt.x << " "<< pnt.y << " "<< pnt.z << "} \n" - << Base::blanks(indent) << " Text2 { string \" " << text << "\" " << "} \n" - << Base::blanks(indent) << "}\n"; - + << indent << " Text2 { string \" " << text << "\" " << "} \n" + << indent << "}\n"; } -//************************************************************************** -// line/arrow handling - void InventorBuilder::addSingleLine(const Base::Line3f& line, Base::DrawStyle drawStyle, const ColorRGB& rgb) { std::string pattern = drawStyle.patternAsString(); @@ -373,26 +387,26 @@ void InventorBuilder::addSingleArrow(const Base::Line3f& line, Base::DrawStyle d rot.Normalize(); float a = Vector3f(0.0f, 1.0f, 0.0f).GetAngle(dir); - result << Base::blanks(indent) << "Separator { \n" - << Base::blanks(indent) << " Material { diffuseColor " + result << indent << "Separator { \n" + << indent << " Material { diffuseColor " << rgb.red() << " "<< rgb.green() << " "<< rgb.blue() << "} \n" - << Base::blanks(indent) << " DrawStyle { lineWidth " + << indent << " DrawStyle { lineWidth " << drawStyle.lineWidth << "} \n" - << Base::blanks(indent) << " Coordinate3 { \n" - << Base::blanks(indent) << " point [ " + << indent << " Coordinate3 { \n" + << indent << " point [ " << line.p1.x << " " << line.p1.y << " " << line.p1.z << "," << pt2s.x << " " << pt2s.y << " " << pt2s.z << " ] \n" - << Base::blanks(indent) << " } \n" - << Base::blanks(indent) << " LineSet { } \n" - << Base::blanks(indent) << " Transform { \n" - << Base::blanks(indent) << " translation " + << indent << " } \n" + << indent << " LineSet { } \n" + << indent << " Transform { \n" + << indent << " translation " << cpt.x << " " << cpt.y << " " << cpt.z << " \n" - << Base::blanks(indent) << " rotation " + << indent << " rotation " << rot.x << " " << rot.y << " " << rot.z << " " << a << '\n' - << Base::blanks(indent) << " } \n" - << Base::blanks(indent) << " Cone { bottomRadius " << coneRadius << " height " << coneLength << "} \n" - << Base::blanks(indent) << "} \n"; + << indent << " } \n" + << indent << " Cone { bottomRadius " << coneRadius << " height " << coneLength << "} \n" + << indent << "} \n"; } /** Add a line defined by a list of points whereat always a pair (i.e. a point and the following point) builds a line. @@ -425,23 +439,21 @@ void InventorBuilder::addLineSet(const std::vector& points, DrawStyle << " } \n"; } -//************************************************************************** -// triangle handling - void InventorBuilder::addIndexedFaceSet(const std::vector& indices) { if (indices.size() < 4) return; - result << Base::blanks(indent) << "IndexedFaceSet { \n" - << Base::blanks(indent) << " coordIndex [ \n"; + result << indent << "IndexedFaceSet { \n" + << indent << " coordIndex [ \n"; - indent += 4; + increaseIndent(); + increaseIndent(); std::vector::const_iterator it_last_f = indices.end()-1; int index=0; for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) { if (index % 8 == 0) - result << Base::blanks(indent); + result << indent; if (it != it_last_f) result << *it << ", "; else @@ -449,22 +461,24 @@ void InventorBuilder::addIndexedFaceSet(const std::vector& indices) if (++index % 8 == 0) result << '\n'; } - indent -= 4; + decreaseIndent(); + decreaseIndent(); - result << Base::blanks(indent) << "} \n"; + result << indent << "} \n"; } void InventorBuilder::addFaceSet(const std::vector& vertices) { - result << Base::blanks(indent) << "FaceSet { \n" - << Base::blanks(indent) << " numVertices [ \n"; + result << indent << "FaceSet { \n" + << indent << " numVertices [ \n"; - indent += 4; + increaseIndent(); + increaseIndent(); std::vector::const_iterator it_last_f = vertices.end()-1; int index=0; for (std::vector::const_iterator it = vertices.begin(); it != vertices.end(); ++it) { if (index % 8 == 0) - result << Base::blanks(indent); + result << indent; if (it != it_last_f) result << *it << ", "; else @@ -472,32 +486,33 @@ void InventorBuilder::addFaceSet(const std::vector& vertices) if (++index % 8 == 0) result << '\n'; } - indent -= 4; + decreaseIndent(); + decreaseIndent(); - result << Base::blanks(indent) << "} \n"; + result << indent << "} \n"; } void InventorBuilder::beginNormal() { - result << Base::blanks(indent) << "Normal { \n"; - indent += 2; - result << Base::blanks(indent) << "vector [ \n"; - indent += 2; + result << indent << "Normal { \n"; + increaseIndent(); + result << indent << "vector [ \n"; + increaseIndent(); } void InventorBuilder::endNormal() { - indent -= 2; - result << Base::blanks(indent) << "]\n"; - indent -= 2; - result << Base::blanks(indent) << "}\n"; + decreaseIndent(); + result << indent << "]\n"; + decreaseIndent(); + result << indent << "}\n"; } void InventorBuilder::addNormalBinding(const char* binding) { - result << Base::blanks(indent) << "NormalBinding {\n" - << Base::blanks(indent) << " value " << binding << '\n' - << Base::blanks(indent) << "}\n"; + result << indent << "NormalBinding {\n" + << indent << " value " << binding << '\n' + << indent << "}\n"; } void InventorBuilder::addSingleTriangle(const Triangle& triangle, DrawStyle drawStyle, const ColorRGB& rgb) @@ -605,20 +620,25 @@ void InventorBuilder::addNurbsSurface(const std::vector& control << " }\n"; } +void InventorBuilder::addCone(float bottomRadius, float height) +{ + result << indent << " Cone { bottomRadius " << bottomRadius << " height " << height << "} \n"; +} + void InventorBuilder::addCylinder(float radius, float height) { - result << Base::blanks(indent) << "Cylinder {\n" - << Base::blanks(indent) << " radius " << radius << "\n" - << Base::blanks(indent) << " height " << height << "\n" - << Base::blanks(indent) << " parts (SIDES | TOP | BOTTOM)\n" - << Base::blanks(indent) << "}\n"; + result << indent << "Cylinder {\n" + << indent << " radius " << radius << "\n" + << indent << " height " << height << "\n" + << indent << " parts (SIDES | TOP | BOTTOM)\n" + << indent << "}\n"; } void InventorBuilder::addSphere(float radius) { - result << Base::blanks(indent) << "Sphere {\n" - << Base::blanks(indent) << " radius " << radius << "\n" - << Base::blanks(indent) << "}\n"; + result << indent << "Sphere {\n" + << indent << " radius " << radius << "\n" + << indent << "}\n"; } void InventorBuilder::addBoundingBox(const Vector3f& pt1, const Vector3f& pt2, DrawStyle drawStyle, const ColorRGB& rgb) @@ -671,13 +691,13 @@ void InventorBuilder::addTransformation(const Base::Placement& transform) double angle{}; transform.getRotation().getValue(rotationaxis, angle); - result << Base::blanks(indent) << "Transform {\n"; - result << Base::blanks(indent) << " translation " + result << indent << "Transform {\n"; + result << indent << " translation " << translation.x << " " << translation.y << " " << translation.z << '\n'; - result << Base::blanks(indent) << " rotation " + result << indent << " rotation " << rotationaxis.x << " " << rotationaxis.y << " " << rotationaxis.z << " " << angle << '\n'; - result << Base::blanks(indent) << "}" << '\n'; + result << indent << "}" << '\n'; } // ----------------------------------------------------------------------------- diff --git a/src/Base/Builder3D.h b/src/Base/Builder3D.h index bc227ac200..bd602c7886 100644 --- a/src/Base/Builder3D.h +++ b/src/Base/Builder3D.h @@ -84,6 +84,25 @@ public: unsigned short linePattern = 0xffff; }; +class BaseExport MaterialBinding +{ +public: + enum class Binding { + Overall = 2, + PerPart = 3, + PerPartIndexed = 4, + PerFace = 5, + PerFaceIndexed = 6, + PerVertex = 7, + PerVertexIndexed = 8, + Default = Overall, + None = Overall + }; + + const char* bindingAsString() const; + Binding value = Binding::Overall; +}; + class BaseExport PolygonOffset { public: @@ -149,11 +168,6 @@ public: * \brief Destruction of an InventorBuilder instance */ virtual ~InventorBuilder(); - /*! - * \brief If needed closes the first opened separator node. - * This method must not be used more than one time for an instance. - */ - void close(); /*! * \brief Sets a separator node. @@ -198,11 +212,9 @@ public: void addColor(const ColorRGB& rgb); /*! * \brief Sets a material binding node. - * \param binding - binding of the material. Allowed values are: - * OVERALL, PER_PART, PER_PART_INDEXED, PER_FACE, PER_FACE_INDEXED, PER_VERTEX, - * PER_VERTEX_INDEXED and DEFAULT. + * \param binding - binding of the material. */ - void addMaterialBinding(const char* binding = "OVERALL"); + void addMaterialBinding(MaterialBinding); /*! * \brief Sets a draw style node. */ @@ -275,6 +287,7 @@ public: void addNurbsSurface(const std::vector& controlPoints, int numUControlPoints, int numVControlPoints, const std::vector& uKnots, const std::vector& vKnots); + void addCone(float bottomRadius, float height); void addCylinder(float radius, float height); void addSphere(float radius); //@} @@ -295,16 +308,34 @@ public: /** @name Text handling */ //@{ /// add a text + void addText(const char * text); void addText(const Vector3f &vec,const char * text, const ColorRGB& rgb = ColorRGB{1.0F, 1.0F, 1.0F}); //@} private: + void increaseIndent(); + void decreaseIndent(); InventorBuilder (const InventorBuilder&); void operator = (const InventorBuilder&); +public: + class Indentation { + int spaces = 0; + public: + void increaseIndent() { + spaces += 2; + } + void decreaseIndent() { + spaces -= 2; + } + int count() { + return spaces; + } + }; + private: std::ostream& result; - int indent; + Indentation indent; }; /** A Builder class for 3D representations on App level @@ -338,10 +369,6 @@ public: Builder3D(); virtual ~Builder3D(); - /** @name point set handling */ - //@{ - //@} - /// clear the string buffer void clear(); diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 48a1b20fad..c1aae8961f 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -558,7 +558,6 @@ void MeshObject::writeInventor(std::ostream& str, float creaseangle) const builder.endPoints(); builder.addIndexedFaceSet(indices); builder.endSeparator(); - builder.close(); } void MeshObject::addFacet(const MeshCore::MeshGeomFacet& facet) diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index a21cd40c55..5d5be9ee3b 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -1047,6 +1047,7 @@ void TopoShape::exportFaceSet(double dev, double ca, std::ostream& str) const { Base::InventorBuilder builder(str); + builder.beginSeparator(); TopExp_Explorer ex; std::size_t numFaces = 0; for (ex.Init(this->_Shape, TopAbs_FACE); ex.More(); ex.Next()) { @@ -1100,11 +1101,13 @@ void TopoShape::exportFaceSet(double dev, double ca, builder.addIndexedFaceSet(indices); builder.endSeparator(); } + builder.endSeparator(); } void TopoShape::exportLineSet(std::ostream& str) const { Base::InventorBuilder builder(str); + builder.beginSeparator(); // get a indexed map of edges TopTools_IndexedMapOfShape M; TopExp::MapShapes(this->_Shape, TopAbs_EDGE, M); @@ -1137,6 +1140,8 @@ void TopoShape::exportLineSet(std::ostream& str) const drawStyle.lineWidth = 2.0F; builder.addLineSet(vertices, drawStyle, Base::ColorRGB{0, 0, 0}); } + + builder.endSeparator(); } Base::BoundBox3d TopoShape::getBoundBox() const diff --git a/src/Mod/Points/App/PointsPyImp.cpp b/src/Mod/Points/App/PointsPyImp.cpp index 641ac8eb0e..1b4dc40317 100644 --- a/src/Mod/Points/App/PointsPyImp.cpp +++ b/src/Mod/Points/App/PointsPyImp.cpp @@ -125,13 +125,14 @@ PyObject* PointsPy::writeInventor(PyObject * args) std::stringstream result; Base::InventorBuilder builder(result); + builder.beginSeparator(); builder.beginPoints(); PointKernel* kernel = getPointKernelPtr(); for (Points::PointKernel::const_iterator it = kernel->begin(); it != kernel->end(); ++it) builder.addPoint(Base::convertTo(*it)); builder.endPoints(); builder.addPointSet(); - builder.close(); + builder.endSeparator(); return Py::new_reference_to(Py::String(result.str())); }