From cf548d0b8ec8e8817dcb65029498290bbb6f4935 Mon Sep 17 00:00:00 2001 From: Furgo <148809153+furgo16@users.noreply.github.com> Date: Tue, 8 Jul 2025 12:32:22 +0200 Subject: [PATCH] Import: DXF, deduplicate Part primitives creation Create helpers that can be reused when importing entities as top-level geometry and as part of blocks --- src/Mod/Import/App/dxf/ImpExpDxf.cpp | 145 ++++++++++++++------------- src/Mod/Import/App/dxf/ImpExpDxf.h | 2 + 2 files changed, 78 insertions(+), 69 deletions(-) diff --git a/src/Mod/Import/App/dxf/ImpExpDxf.cpp b/src/Mod/Import/App/dxf/ImpExpDxf.cpp index 1c1316e142..104202c564 100644 --- a/src/Mod/Import/App/dxf/ImpExpDxf.cpp +++ b/src/Mod/Import/App/dxf/ImpExpDxf.cpp @@ -100,7 +100,10 @@ Part::Circle* createCirclePrimitive(const TopoDS_Edge& edge, App::Document* doc, Part::Line* createLinePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name); Part::Ellipse* createEllipsePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name); - +Part::Vertex* +createVertexPrimitive(const TopoDS_Vertex& vertex, App::Document* doc, const char* name); +Part::Feature* +createGenericShapeFeature(const TopoDS_Shape& shape, App::Document* doc, const char* name); } // namespace @@ -212,6 +215,31 @@ Part::Line* createLinePrimitive(const TopoDS_Edge& edge, App::Document* doc, con return p; } +// Helper function to create and configure a Part::Vertex primitive from a TopoDS_Vertex +Part::Vertex* +createVertexPrimitive(const TopoDS_Vertex& vertex, App::Document* doc, const char* name) +{ + auto* p = doc->addObject(name); + if (p) { + gp_Pnt pnt = BRep_Tool::Pnt(vertex); + p->X.setValue(pnt.X()); + p->Y.setValue(pnt.Y()); + p->Z.setValue(pnt.Z()); + } + return p; +} + +// Helper function to create a generic Part::Feature for any non-parametric shape +Part::Feature* +createGenericShapeFeature(const TopoDS_Shape& shape, App::Document* doc, const char* name) +{ + auto* p = doc->addObject(name); + if (p) { + p->Shape.setValue(shape); + } + return p; +} + } // namespace TopoDS_Wire ImpExpDxfRead::BuildWireFromPolyline(std::list& vertices, int flags) @@ -306,14 +334,19 @@ TopoDS_Wire ImpExpDxfRead::BuildWireFromPolyline(std::list& vertices return wireBuilder.Wire(); } -void ImpExpDxfRead::CreateFlattenedPolyline(const TopoDS_Wire& wire, const char* name) +Part::Feature* ImpExpDxfRead::createFlattenedPolylineFeature(const TopoDS_Wire& wire, + const char* name) { auto* p = document->addObject(document->getUniqueObjectName(name).c_str()); - p->Shape.setValue(wire); - Collector->AddObject(p, name); + if (p) { + p->Shape.setValue(wire); + IncrementCreatedObjectCount(); + } + return p; } -void ImpExpDxfRead::CreateParametricPolyline(const TopoDS_Wire& wire, const char* name) +Part::Compound* ImpExpDxfRead::createParametricPolylineCompound(const TopoDS_Wire& wire, + const char* name) { auto* p = document->addObject(document->getUniqueObjectName(name).c_str()); IncrementCreatedObjectCount(); @@ -336,13 +369,37 @@ void ImpExpDxfRead::CreateParametricPolyline(const TopoDS_Wire& wire, const char if (segment) { IncrementCreatedObjectCount(); segment->Visibility.setValue(false); - ApplyGuiStyles(static_cast(segment)); + // We apply styles later, depending on the context segments.push_back(segment); } } p->Links.setValues(segments); + return p; +} - Collector->AddObject(p, name); +void ImpExpDxfRead::CreateFlattenedPolyline(const TopoDS_Wire& wire, const char* name) +{ + Part::Feature* p = createFlattenedPolylineFeature(wire, name); + + // Perform the context-specific action of adding it to the collector + if (p) { + Collector->AddObject(p, name); + } +} + +void ImpExpDxfRead::CreateParametricPolyline(const TopoDS_Wire& wire, const char* name) +{ + Part::Compound* p = createParametricPolylineCompound(wire, name); + + // Perform the context-specific actions (applying styles and adding to the document) + if (p) { + // Style the child segments + for (App::DocumentObject* segment : p->Links.getValues()) { + ApplyGuiStyles(static_cast(segment)); + } + // Add the final compound object to the document + Collector->AddObject(p, name); + } } std::map ImpExpDxfRead::PreScan(const std::string& filepath) @@ -659,12 +716,8 @@ void ImpExpDxfRead::ComposeParametricBlock(const std::string& blockName, break; } case GeometryBuilder::PrimitiveType::Point: { - auto* p = document->addObject("Point"); - TopoDS_Vertex v = TopoDS::Vertex(builder.shape); - gp_Pnt pnt = BRep_Tool::Pnt(v); - p->Placement.setValue(Base::Placement(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()), - Base::Rotation())); - newObject = p; + newObject = + createVertexPrimitive(TopoDS::Vertex(builder.shape), document, "Point"); break; } case GeometryBuilder::PrimitiveType::Circle: @@ -697,53 +750,21 @@ void ImpExpDxfRead::ComposeParametricBlock(const std::string& blockName, case GeometryBuilder::PrimitiveType::PolylineFlattened: { // This creates a simple Part::Feature wrapping the wire, which is standard for // block children. - auto* p = document->addObject("Polyline"); - p->Shape.setValue(TopoDS::Wire(builder.shape)); // Ensure it's a TopoDS_Wire - newObject = p; + newObject = + createFlattenedPolylineFeature(TopoDS::Wire(builder.shape), "Polyline"); break; } case GeometryBuilder::PrimitiveType::PolylineParametric: { // This creates a Part::Compound containing line/arc segments. - auto* p = - document->addObject("Polyline"); // Main polyline compound - std::vector segments; - TopExp_Explorer explorer(TopoDS::Wire(builder.shape), - TopAbs_EDGE); // Iterate edges of the wire - - for (; explorer.More(); explorer.Next()) { - TopoDS_Edge edge = TopoDS::Edge(explorer.Current()); - App::DocumentObject* segment = nullptr; - BRepAdaptor_Curve adaptor(edge); - - if (adaptor.GetType() == GeomAbs_Line) { - segment = createLinePrimitive(edge, document, "Segment"); - } - else if (adaptor.GetType() == GeomAbs_Circle) { - auto* arc = createCirclePrimitive(edge, document, "Arc"); - segment = arc; - } - - if (segment) { - // These segments are children of the polyline compound, not top-level - // block children. - IncrementCreatedObjectCount(); // Count this sub-object - segment->Visibility.setValue(false); // Sub-segments are usually hidden - // No layer/style needed here, inherited from the polyline compound or - // handled by block. - // ApplyGuiStyles(static_cast(segment)); - segments.push_back(segment); - } - } - p->Links.setValues(segments); // Link segments to the polyline compound - newObject = p; // The polyline compound itself is the new object for the block + newObject = + createParametricPolylineCompound(TopoDS::Wire(builder.shape), "Polyline"); + // No styling needed here, as the block's instance will control appearance. break; } case GeometryBuilder::PrimitiveType::None: // Default/fallback if not handled default: { // Generic shape, e.g., 3DFACE - auto* p = document->addObject("Shape"); - p->Shape.setValue(builder.shape); - newObject = p; + newObject = createGenericShapeFeature(builder.shape, document, "Shape"); break; } } @@ -1383,14 +1404,8 @@ void ImpExpDxfRead::DrawingEntityCollector::AddGeometry(const GeometryBuilder& b break; } case GeometryBuilder::PrimitiveType::Point: { - newDocObj = Reader.document->addObject( - Reader.document->getUniqueObjectName("Point").c_str()); - if (newDocObj) { - TopoDS_Vertex v = TopoDS::Vertex(builder.shape); - gp_Pnt pnt = BRep_Tool::Pnt(v); - static_cast(newDocObj)->Placement.setValue( - Base::Placement(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()), Base::Rotation())); - } + newDocObj = + createVertexPrimitive(TopoDS::Vertex(builder.shape), Reader.document, "Point"); break; } case GeometryBuilder::PrimitiveType::Ellipse: { @@ -1399,11 +1414,7 @@ void ImpExpDxfRead::DrawingEntityCollector::AddGeometry(const GeometryBuilder& b break; } case GeometryBuilder::PrimitiveType::Spline: { - newDocObj = Reader.document->addObject( - Reader.document->getUniqueObjectName("Spline").c_str()); - if (newDocObj) { - static_cast(newDocObj)->Shape.setValue(builder.shape); - } + newDocObj = createGenericShapeFeature(builder.shape, Reader.document, "Spline"); break; } case GeometryBuilder::PrimitiveType::PolylineFlattened: { @@ -1418,11 +1429,7 @@ void ImpExpDxfRead::DrawingEntityCollector::AddGeometry(const GeometryBuilder& b } case GeometryBuilder::PrimitiveType::None: // Fallback for generic shapes (e.g., 3DFACE) default: { - newDocObj = Reader.document->addObject( - Reader.document->getUniqueObjectName("Shape").c_str()); - if (newDocObj) { - static_cast(newDocObj)->Shape.setValue(builder.shape); - } + newDocObj = createGenericShapeFeature(builder.shape, Reader.document, "Shape"); break; } } diff --git a/src/Mod/Import/App/dxf/ImpExpDxf.h b/src/Mod/Import/App/dxf/ImpExpDxf.h index 0e7edde6e6..9054b253a7 100644 --- a/src/Mod/Import/App/dxf/ImpExpDxf.h +++ b/src/Mod/Import/App/dxf/ImpExpDxf.h @@ -162,6 +162,8 @@ private: void ComposeBlocks(); void ComposeParametricBlock(const std::string& blockName, std::set& composed); void ComposeFlattenedBlock(const std::string& blockName, std::set& composed); + Part::Compound* createParametricPolylineCompound(const TopoDS_Wire& wire, const char* name); + Part::Feature* createFlattenedPolylineFeature(const TopoDS_Wire& wire, const char* name); protected: PyObject* getDraftModule()