| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <Standard_Version.hxx> |
| | #if OCC_VERSION_HEX < 0x070600 |
| | # include <BRepAdaptor_HCurve.hxx> |
| | #endif |
| | #include <Approx_Curve3d.hxx> |
| | #include <BRepAdaptor_CompCurve.hxx> |
| | #include <BRepAdaptor_Curve.hxx> |
| | #include <BRepBuilderAPI_MakeEdge.hxx> |
| | #include <BRepBuilderAPI_MakeVertex.hxx> |
| | #include <BRepBuilderAPI_MakeWire.hxx> |
| | #include <BRepBuilderAPI_Transform.hxx> |
| | #include <BRepBuilderAPI_GTransform.hxx> |
| | #include <BRep_Tool.hxx> |
| | #include <BRep_Builder.hxx> |
| | #include <GCPnts_UniformAbscissa.hxx> |
| | #include <GeomAPI_Interpolate.hxx> |
| | #include <GeomAPI_PointsToBSpline.hxx> |
| | #include <Geom_Circle.hxx> |
| | #include <Geom_Ellipse.hxx> |
| | #include <Geom_Line.hxx> |
| | #include <Geom_BSplineCurve.hxx> |
| | #include <TColgp_Array1OfPnt.hxx> |
| | #include <TopExp.hxx> |
| | #include <TopExp_Explorer.hxx> |
| | #include <TopoDS.hxx> |
| | #include <TopoDS_Compound.hxx> |
| | #include <TopoDS_Edge.hxx> |
| | #include <TopoDS_Shape.hxx> |
| | #include <TopoDS_Vertex.hxx> |
| | #include <TopoDS_Wire.hxx> |
| | #include <gp_Ax1.hxx> |
| | #include <gp_Ax2.hxx> |
| | #include <gp_Circ.hxx> |
| | #include <gp_Dir.hxx> |
| | #include <gp_Elips.hxx> |
| | #include <gp_Pnt.hxx> |
| | #include <gp_Trsf.hxx> |
| | #include <Precision.hxx> |
| | #include <gp_Vec.hxx> |
| |
|
| | #include <fstream> |
| | #include <App/Annotation.h> |
| | #include <App/Application.h> |
| | #include <App/Document.h> |
| | #include <App/DocumentObjectGroup.h> |
| | #include <App/DocumentObjectPy.h> |
| | #include <App/FeaturePythonPyImp.h> |
| | #include <Base/Console.h> |
| | #include <Base/Interpreter.h> |
| | #include <Base/Matrix.h> |
| | #include <Base/Parameter.h> |
| | #include <Base/Vector3D.h> |
| | #include <Base/PlacementPy.h> |
| | #include <Mod/Part/App/PartFeature.h> |
| | #include <Mod/Part/App/FeatureCompound.h> |
| | #include <Mod/Part/App/PrimitiveFeature.h> |
| | #include <Mod/Part/App/FeaturePartCircle.h> |
| | #include <App/Link.h> |
| | #include <App/FeaturePython.h> |
| | #include <Base/Tools.h> |
| |
|
| | #include "ImpExpDxf.h" |
| |
|
| |
|
| | using namespace Import; |
| |
|
| | #if OCC_VERSION_HEX >= 0x070600 |
| | using BRepAdaptor_HCurve = BRepAdaptor_Curve; |
| | #endif |
| |
|
| | namespace |
| | { |
| |
|
| | Part::Circle* createCirclePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name); |
| | 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 |
| | { |
| |
|
| | |
| | Part::Ellipse* createEllipsePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name) |
| | { |
| | auto* p = doc->addObject<Part::Ellipse>(name); |
| | if (!p) { |
| | return nullptr; |
| | } |
| |
|
| | TopLoc_Location loc; |
| | Standard_Real first, last; |
| | Handle(Geom_Curve) aCurve = BRep_Tool::Curve(edge, loc, first, last); |
| |
|
| | if (aCurve->IsInstance(Geom_Ellipse::get_type_descriptor())) { |
| | Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(aCurve); |
| |
|
| | |
| | p->MajorRadius.setValue(ellipse->MajorRadius()); |
| | p->MinorRadius.setValue(ellipse->MinorRadius()); |
| |
|
| | |
| | |
| | gp_Ax2 axis = ellipse->Position().Transformed(loc.Transformation()); |
| | gp_Pnt center = axis.Location(); |
| | gp_Dir xDir = axis.XDirection(); |
| | gp_Dir yDir = axis.YDirection(); |
| | gp_Dir zDir = axis.Direction(); |
| |
|
| | Base::Placement plc; |
| | plc.setPosition(Base::Vector3d(center.X(), center.Y(), center.Z())); |
| | plc.setRotation( |
| | Base::Rotation::makeRotationByAxes( |
| | Base::Vector3d(xDir.X(), xDir.Y(), xDir.Z()), |
| | Base::Vector3d(yDir.X(), yDir.Y(), yDir.Z()), |
| | Base::Vector3d(zDir.X(), zDir.Y(), zDir.Z()) |
| | ) |
| | ); |
| | p->Placement.setValue(plc); |
| |
|
| | |
| | BRep_Tool::Range(edge, first, last); |
| | p->Angle1.setValue(Base::toDegrees(first)); |
| | p->Angle2.setValue(Base::toDegrees(last)); |
| | } |
| | return p; |
| | } |
| |
|
| | |
| | Part::Circle* createCirclePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name) |
| | { |
| | auto* p = doc->addObject<Part::Circle>(name); |
| | if (!p) { |
| | return nullptr; |
| | } |
| |
|
| | TopLoc_Location loc; |
| | Standard_Real first, last; |
| | Handle(Geom_Curve) aCurve = BRep_Tool::Curve(edge, loc, first, last); |
| |
|
| | if (aCurve->IsInstance(Geom_Circle::get_type_descriptor())) { |
| | Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(aCurve); |
| | p->Radius.setValue(circle->Radius()); |
| |
|
| | |
| | gp_Ax2 axis = circle->Position().Transformed(loc.Transformation()); |
| | gp_Pnt center = axis.Location(); |
| | gp_Dir xDir = axis.XDirection(); |
| | gp_Dir yDir = axis.YDirection(); |
| | gp_Dir zDir = axis.Direction(); |
| |
|
| | Base::Placement plc; |
| | plc.setPosition(Base::Vector3d(center.X(), center.Y(), center.Z())); |
| | plc.setRotation( |
| | Base::Rotation::makeRotationByAxes( |
| | Base::Vector3d(xDir.X(), xDir.Y(), xDir.Z()), |
| | Base::Vector3d(yDir.X(), yDir.Y(), yDir.Z()), |
| | Base::Vector3d(zDir.X(), zDir.Y(), zDir.Z()) |
| | ) |
| | ); |
| | p->Placement.setValue(plc); |
| |
|
| | |
| | BRep_Tool::Range(edge, first, last); |
| | p->Angle1.setValue(Base::toDegrees(first)); |
| | p->Angle2.setValue(Base::toDegrees(last)); |
| | } |
| | return p; |
| | } |
| |
|
| | |
| | Part::Line* createLinePrimitive(const TopoDS_Edge& edge, App::Document* doc, const char* name) |
| | { |
| | auto* p = doc->addObject<Part::Line>(name); |
| | if (!p) { |
| | return nullptr; |
| | } |
| |
|
| | TopoDS_Vertex v1, v2; |
| | TopExp::Vertices(edge, v1, v2); |
| | gp_Pnt p1 = BRep_Tool::Pnt(v1); |
| | gp_Pnt p2 = BRep_Tool::Pnt(v2); |
| |
|
| | p->X1.setValue(p1.X()); |
| | p->Y1.setValue(p1.Y()); |
| | p->Z1.setValue(p1.Z()); |
| | p->X2.setValue(p2.X()); |
| | p->Y2.setValue(p2.Y()); |
| | p->Z2.setValue(p2.Z()); |
| |
|
| | return p; |
| | } |
| |
|
| | |
| | Part::Vertex* createVertexPrimitive(const TopoDS_Vertex& vertex, App::Document* doc, const char* name) |
| | { |
| | auto* p = doc->addObject<Part::Vertex>(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; |
| | } |
| |
|
| | |
| | Part::Feature* createGenericShapeFeature(const TopoDS_Shape& shape, App::Document* doc, const char* name) |
| | { |
| | auto* p = doc->addObject<Part::Feature>(name); |
| | if (p) { |
| | p->Shape.setValue(shape); |
| | } |
| | return p; |
| | } |
| |
|
| | } |
| |
|
| | TopoDS_Wire ImpExpDxfRead::BuildWireFromPolyline(std::list<VertexInfo>& vertices, int flags) |
| | { |
| | BRepBuilderAPI_MakeWire wireBuilder; |
| | bool is_closed = ((flags & 1) != 0); |
| | if (vertices.empty()) { |
| | return wireBuilder.Wire(); |
| | } |
| |
|
| | auto it = vertices.begin(); |
| | auto prev_it = it++; |
| |
|
| | while (it != vertices.end()) { |
| | const VertexInfo& start_vertex = *prev_it; |
| | const VertexInfo& end_vertex = *it; |
| | TopoDS_Edge edge; |
| |
|
| | if (start_vertex.bulge == 0.0) { |
| | edge = BRepBuilderAPI_MakeEdge( |
| | makePoint(start_vertex.location), |
| | makePoint(end_vertex.location) |
| | ) |
| | .Edge(); |
| | } |
| | else { |
| | double cot = ((1.0 / start_vertex.bulge) - start_vertex.bulge) / 2.0; |
| | double center_x = ((start_vertex.location.x + end_vertex.location.x) |
| | - (end_vertex.location.y - start_vertex.location.y) * cot) |
| | / 2.0; |
| | double center_y = ((start_vertex.location.y + end_vertex.location.y) |
| | + (end_vertex.location.x - start_vertex.location.x) * cot) |
| | / 2.0; |
| | double center_z = (start_vertex.location.z + end_vertex.location.z) / 2.0; |
| | Base::Vector3d center(center_x, center_y, center_z); |
| |
|
| | gp_Pnt p0 = makePoint(start_vertex.location); |
| | gp_Pnt p1 = makePoint(end_vertex.location); |
| | gp_Dir up(0, 0, 1); |
| | if (start_vertex.bulge < 0) { |
| | up.Reverse(); |
| | } |
| | gp_Pnt pc = makePoint(center); |
| | gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); |
| | if (circle.Radius() > 1e-9) { |
| | edge = BRepBuilderAPI_MakeEdge(circle, p0, p1).Edge(); |
| | } |
| | } |
| |
|
| | if (!edge.IsNull()) { |
| | wireBuilder.Add(edge); |
| | } |
| | prev_it = it++; |
| | } |
| |
|
| | if (is_closed && vertices.size() > 1) { |
| | const VertexInfo& start_vertex = vertices.back(); |
| | const VertexInfo& end_vertex = vertices.front(); |
| |
|
| | |
| | |
| | gp_Pnt p0 = makePoint(start_vertex.location); |
| | gp_Pnt p1 = makePoint(end_vertex.location); |
| | double distance = p0.Distance(p1); |
| |
|
| | if (distance > Precision::Confusion()) { |
| | TopoDS_Edge edge; |
| |
|
| | if (start_vertex.bulge == 0.0) { |
| | edge = BRepBuilderAPI_MakeEdge(p0, p1).Edge(); |
| | } |
| | else { |
| | double cot = ((1.0 / start_vertex.bulge) - start_vertex.bulge) / 2.0; |
| | double center_x = ((start_vertex.location.x + end_vertex.location.x) |
| | - (end_vertex.location.y - start_vertex.location.y) * cot) |
| | / 2.0; |
| | double center_y = ((start_vertex.location.y + end_vertex.location.y) |
| | + (end_vertex.location.x - start_vertex.location.x) * cot) |
| | / 2.0; |
| | double center_z = (start_vertex.location.z + end_vertex.location.z) / 2.0; |
| | Base::Vector3d center(center_x, center_y, center_z); |
| |
|
| | gp_Dir up(0, 0, 1); |
| | if (start_vertex.bulge < 0) { |
| | up.Reverse(); |
| | } |
| | gp_Pnt pc = makePoint(center); |
| | gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); |
| | if (circle.Radius() > 1e-9) { |
| | edge = BRepBuilderAPI_MakeEdge(circle, p0, p1).Edge(); |
| | } |
| | } |
| | if (!edge.IsNull()) { |
| | wireBuilder.Add(edge); |
| | } |
| | } |
| | } |
| |
|
| | return wireBuilder.Wire(); |
| | } |
| |
|
| | Part::Feature* ImpExpDxfRead::createFlattenedPolylineFeature(const TopoDS_Wire& wire, const char* name) |
| | { |
| | auto* p = document->addObject<Part::Feature>(document->getUniqueObjectName(name).c_str()); |
| | if (p) { |
| | p->Shape.setValue(wire); |
| | IncrementCreatedObjectCount(); |
| | } |
| | return p; |
| | } |
| |
|
| | Part::Compound* ImpExpDxfRead::createParametricPolylineCompound(const TopoDS_Wire& wire, const char* name) |
| | { |
| | auto* p = document->addObject<Part::Compound>(document->getUniqueObjectName(name).c_str()); |
| | IncrementCreatedObjectCount(); |
| |
|
| | std::vector<App::DocumentObject*> segments; |
| | TopExp_Explorer explorer(wire, TopAbs_EDGE); |
| |
|
| | 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) { |
| | segment = createCirclePrimitive(edge, document, "Arc"); |
| | } |
| |
|
| | if (segment) { |
| | IncrementCreatedObjectCount(); |
| | segment->Visibility.setValue(false); |
| | |
| | segments.push_back(segment); |
| | } |
| | } |
| | p->Links.setValues(segments); |
| | return p; |
| | } |
| |
|
| | void ImpExpDxfRead::CreateFlattenedPolyline(const TopoDS_Wire& wire, const char* name) |
| | { |
| | Part::Feature* p = createFlattenedPolylineFeature(wire, name); |
| |
|
| | |
| | if (p) { |
| | Collector->AddObject(p, name); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::CreateParametricPolyline(const TopoDS_Wire& wire, const char* name) |
| | { |
| | Part::Compound* p = createParametricPolylineCompound(wire, name); |
| |
|
| | |
| | if (p) { |
| | |
| | for (App::DocumentObject* segment : p->Links.getValues()) { |
| | ApplyGuiStyles(static_cast<Part::Feature*>(segment)); |
| | } |
| | |
| | Collector->AddObject(p, name); |
| | } |
| | } |
| |
|
| | std::map<std::string, int> ImpExpDxfRead::PreScan(const std::string& filepath) |
| | { |
| | std::map<std::string, int> counts; |
| | std::ifstream ifs(filepath); |
| | if (!ifs) { |
| | |
| | return counts; |
| | } |
| |
|
| | std::string line; |
| | bool next_is_entity_name = false; |
| |
|
| | while (std::getline(ifs, line)) { |
| | |
| | if (!line.empty() && line.back() == '\r') { |
| | line.pop_back(); |
| | } |
| |
|
| | if (next_is_entity_name) { |
| | |
| | counts[line]++; |
| | next_is_entity_name = false; |
| | } |
| | else if (line == " 0") { |
| | next_is_entity_name = true; |
| | } |
| | } |
| | return counts; |
| | } |
| |
|
| | |
| | |
| | ImpExpDxfRead::ImpExpDxfRead(const std::string& filepath, App::Document* pcDoc) |
| | : CDxfRead(filepath) |
| | , document(pcDoc) |
| | { |
| | setOptionSource("User parameter:BaseApp/Preferences/Mod/Draft"); |
| | setOptions(); |
| | } |
| |
|
| | void ImpExpDxfRead::StartImport() |
| | { |
| | CDxfRead::StartImport(); |
| | |
| | m_blockDefinitionGroup = static_cast<App::DocumentObjectGroup*>( |
| | document->addObject("App::DocumentObjectGroup", "_BlockDefinitions") |
| | ); |
| | m_blockDefinitionGroup->Visibility.setValue(false); |
| | |
| | m_unreferencedBlocksGroup = static_cast<App::DocumentObjectGroup*>( |
| | document->addObject("App::DocumentObjectGroup", "_UnreferencedBlocks") |
| | ); |
| | m_unreferencedBlocksGroup->Visibility.setValue(false); |
| | } |
| |
|
| | bool ImpExpDxfRead::ReadEntitiesSection() |
| | { |
| | |
| | |
| | ComposeBlocks(); |
| |
|
| | DrawingEntityCollector collector(*this); |
| | if (m_importMode == ImportMode::FusedShapes) { |
| | std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>> ShapesToCombine; |
| | { |
| | ShapeSavingEntityCollector savingCollector(*this, ShapesToCombine); |
| | if (!CDxfRead::ReadEntitiesSection()) { |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | |
| | for (auto& shapeSet : ShapesToCombine) { |
| | m_entityAttributes = shapeSet.first; |
| | CombineShapes( |
| | shapeSet.second, |
| | m_entityAttributes.m_Layer == nullptr ? "Compound" |
| | : m_entityAttributes.m_Layer->Name.c_str() |
| | ); |
| | } |
| | } |
| | else { |
| | if (!CDxfRead::ReadEntitiesSection()) { |
| | return false; |
| | } |
| | } |
| | if (m_preserveLayers) { |
| | for (auto& layerEntry : Layers) { |
| | ((Layer*)layerEntry.second)->FinishLayer(); |
| | } |
| | } |
| | return true; |
| | } |
| |
|
| | void ImpExpDxfRead::CombineShapes(std::list<TopoDS_Shape>& shapes, const char* nameBase) const |
| | { |
| | BRep_Builder builder; |
| | TopoDS_Compound comp; |
| | builder.MakeCompound(comp); |
| | for (const auto& sh : shapes) { |
| | if (!sh.IsNull()) { |
| | builder.Add(comp, sh); |
| | } |
| | } |
| | if (!comp.IsNull()) { |
| | Collector->AddObject(comp, nameBase); |
| | } |
| | } |
| |
|
| | TopoDS_Shape ImpExpDxfRead::CombineShapesToCompound(const std::list<TopoDS_Shape>& shapes) const |
| | { |
| | if (shapes.empty()) { |
| | return TopoDS_Shape(); |
| | } |
| | BRep_Builder builder; |
| | TopoDS_Compound comp; |
| | builder.MakeCompound(comp); |
| | for (const auto& sh : shapes) { |
| | if (!sh.IsNull()) { |
| | builder.Add(comp, sh); |
| | } |
| | } |
| | return comp; |
| | } |
| |
|
| | void ImpExpDxfRead::setOptions() |
| | { |
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( |
| | getOptionSource().c_str() |
| | ); |
| | m_stats.importSettings.clear(); |
| |
|
| | m_preserveLayers = hGrp->GetBool("dxfUseDraftVisGroups", true); |
| | m_stats.importSettings["Use layers"] = m_preserveLayers ? "Yes" : "No"; |
| |
|
| | m_preserveColors = hGrp->GetBool("dxfGetOriginalColors", true); |
| | m_stats.importSettings["Use colors from the DXF file"] = m_preserveColors ? "Yes" : "No"; |
| |
|
| | |
| | int mode = hGrp->GetInt("DxfImportMode", static_cast<int>(ImportMode::IndividualShapes)); |
| | m_importMode = static_cast<ImportMode>(mode); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool joinGeometry = hGrp->GetBool("joingeometry", false); |
| | m_stats.importSettings["Join geometry"] = joinGeometry ? "Yes" : "No"; |
| |
|
| | double scaling = hGrp->GetFloat("dxfScaling", 1.0); |
| | SetAdditionalScaling(scaling); |
| | m_stats.importSettings["Manual scaling factor"] = std::to_string(scaling); |
| |
|
| | m_importAnnotations = hGrp->GetBool("dxftext", false); |
| | m_stats.importSettings["Import texts and dimensions"] = m_importAnnotations ? "Yes" : "No"; |
| |
|
| | m_importPoints = hGrp->GetBool("dxfImportPoints", true); |
| | m_stats.importSettings["Import points"] = m_importPoints ? "Yes" : "No"; |
| |
|
| | m_importPaperSpaceEntities = hGrp->GetBool("dxflayout", false); |
| | m_stats.importSettings["Import layout objects"] = m_importPaperSpaceEntities ? "Yes" : "No"; |
| |
|
| | m_importHiddenBlocks = hGrp->GetBool("dxfstarblocks", false); |
| | m_stats.importSettings["Import hidden blocks"] = m_importHiddenBlocks ? "Yes" : "No"; |
| |
|
| | |
| | |
| | |
| | |
| | } |
| |
|
| | void ImpExpDxfRead::ComposeFlattenedBlock(const std::string& blockName, std::set<std::string>& composed) |
| | { |
| | |
| | if (composed.count(blockName)) { |
| | return; |
| | } |
| |
|
| | |
| | auto it = this->Blocks.find(blockName); |
| | if (it == this->Blocks.end()) { |
| | ImportError("Block '%s' is referenced but not defined. Skipping.", blockName.c_str()); |
| | return; |
| | } |
| | const Block& blockData = it->second; |
| |
|
| | |
| | std::list<TopoDS_Shape> shapeCollection; |
| |
|
| | |
| | for (const auto& [attributes, builderList] : blockData.GeometryBuilders) { |
| | for (const auto& builder : builderList) { |
| | shapeCollection.push_back(builder.shape); |
| | } |
| | } |
| |
|
| | |
| | for (const auto& insertAttrPair : blockData.Inserts) { |
| | for (const auto& nestedInsert : insertAttrPair.second) { |
| | |
| | ComposeFlattenedBlock(nestedInsert.Name, composed); |
| | |
| | m_referencedBlocks.insert(nestedInsert.Name); |
| |
|
| | |
| | auto shape_it = m_flattenedBlockShapes.find(nestedInsert.Name); |
| | if (shape_it != m_flattenedBlockShapes.end()) { |
| | if (!shape_it->second.IsNull()) { |
| | |
| | Part::TopoShape nestedShape(shape_it->second); |
| | |
| | Base::Placement pl( |
| | nestedInsert.Point, |
| | Base::Rotation(Base::Vector3d(0, 0, 1), nestedInsert.Rotation) |
| | ); |
| | Base::Matrix4D transform = pl.toMatrix(); |
| | transform.scale(nestedInsert.Scale); |
| | nestedShape.transformShape(transform, true, true); |
| | shapeCollection.push_back(nestedShape.getShape()); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | TopoDS_Shape finalShape = CombineShapesToCompound(shapeCollection); |
| | m_flattenedBlockShapes[blockName] = finalShape; |
| |
|
| | |
| | if (!finalShape.IsNull()) { |
| | std::string featureName = "BLOCK_" + blockName; |
| | auto blockFeature = document->addObject<Part::Feature>( |
| | document->getUniqueObjectName(featureName.c_str()).c_str() |
| | ); |
| | blockFeature->Shape.setValue(finalShape); |
| | blockFeature->Visibility.setValue(false); |
| | m_blockDefinitionGroup->addObject(blockFeature); |
| | this->m_blockDefinitions[blockName] = blockFeature; |
| | } |
| |
|
| | |
| | composed.insert(blockName); |
| | } |
| |
|
| | void ImpExpDxfRead::ComposeParametricBlock(const std::string& blockName, std::set<std::string>& composed) |
| | { |
| | |
| | if (composed.count(blockName)) { |
| | return; |
| | } |
| |
|
| | |
| | auto it = this->Blocks.find(blockName); |
| | if (it == this->Blocks.end()) { |
| | ImportError("Block '%s' is referenced but not defined. Skipping.", blockName.c_str()); |
| | return; |
| | } |
| | const Block& blockData = it->second; |
| |
|
| | |
| | std::string compName = "BLOCK_" + blockName; |
| | auto blockCompound = document->addObject<Part::Compound>( |
| | document->getUniqueObjectName(compName.c_str()).c_str() |
| | ); |
| | m_blockDefinitionGroup->addObject(blockCompound); |
| | IncrementCreatedObjectCount(); |
| | blockCompound->Visibility.setValue(false); |
| | this->m_blockDefinitions[blockName] = blockCompound; |
| |
|
| | std::vector<App::DocumentObject*> childObjects; |
| |
|
| | |
| | for (const auto& insertAttrPair : blockData.Inserts) { |
| | for (const auto& nestedInsert : insertAttrPair.second) { |
| | |
| | ComposeParametricBlock(nestedInsert.Name, composed); |
| | |
| | m_referencedBlocks.insert(nestedInsert.Name); |
| |
|
| | |
| | auto baseObjIt = m_blockDefinitions.find(nestedInsert.Name); |
| | if (baseObjIt != m_blockDefinitions.end()) { |
| | |
| | std::string linkName = "Link_" + nestedInsert.Name; |
| | auto link = document->addObject<App::Link>( |
| | document->getUniqueObjectName(linkName.c_str()).c_str() |
| | ); |
| | link->setLink(-1, baseObjIt->second); |
| | link->LinkTransform.setValue(false); |
| |
|
| | |
| | Base::Placement pl( |
| | nestedInsert.Point, |
| | Base::Rotation(Base::Vector3d(0, 0, 1), nestedInsert.Rotation) |
| | ); |
| | link->Placement.setValue(pl); |
| | link->ScaleVector.setValue(nestedInsert.Scale); |
| | link->Visibility.setValue(false); |
| | IncrementCreatedObjectCount(); |
| | childObjects.push_back(link); |
| | } |
| | } |
| | } |
| |
|
| | |
| | for (const auto& [attributes, builderList] : blockData.GeometryBuilders) { |
| | this->m_entityAttributes = attributes; |
| |
|
| | for (const auto& builder : builderList) { |
| | App::DocumentObject* newObject = nullptr; |
| | switch (builder.type) { |
| | |
| | case GeometryBuilder::PrimitiveType::Line: { |
| | newObject = createLinePrimitive(TopoDS::Edge(builder.shape), document, "Line"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Point: { |
| | newObject = createVertexPrimitive(TopoDS::Vertex(builder.shape), document, "Point"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Circle: |
| | case GeometryBuilder::PrimitiveType::Arc: { |
| | const char* name = (builder.type == GeometryBuilder::PrimitiveType::Circle) |
| | ? "Circle" |
| | : "Arc"; |
| | auto* p = createCirclePrimitive(TopoDS::Edge(builder.shape), document, name); |
| | if (!p) { |
| | break; |
| | } |
| | if (builder.type == GeometryBuilder::PrimitiveType::Circle) { |
| | p->Angle1.setValue(0.0); |
| | p->Angle2.setValue(360.0); |
| | } |
| | newObject = p; |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Ellipse: { |
| | newObject |
| | = createEllipsePrimitive(TopoDS::Edge(builder.shape), document, "Ellipse"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Spline: { |
| | |
| | auto* p = document->addObject<Part::Feature>("Spline"); |
| | p->Shape.setValue(builder.shape); |
| | newObject = p; |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::PolylineFlattened: { |
| | |
| | |
| | newObject = createFlattenedPolylineFeature(TopoDS::Wire(builder.shape), "Polyline"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::PolylineParametric: { |
| | |
| | newObject |
| | = createParametricPolylineCompound(TopoDS::Wire(builder.shape), "Polyline"); |
| | |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::None: |
| | default: { |
| | |
| | newObject = createGenericShapeFeature(builder.shape, document, "Shape"); |
| | break; |
| | } |
| | } |
| |
|
| | if (newObject) { |
| | IncrementCreatedObjectCount(); |
| | newObject->Visibility.setValue(false); |
| | |
| | |
| | ApplyGuiStyles(static_cast<Part::Feature*>(newObject)); |
| | |
| | childObjects.push_back(newObject); |
| | } |
| | } |
| | } |
| |
|
| | |
| | if (!childObjects.empty()) { |
| | blockCompound->Links.setValues(childObjects); |
| | } |
| |
|
| | |
| | composed.insert(blockName); |
| | } |
| |
|
| | void ImpExpDxfRead::ComposeBlocks() |
| | { |
| | std::set<std::string> composedBlocks; |
| |
|
| | if (m_importMode == ImportMode::FusedShapes) { |
| | |
| | for (const auto& pair : this->Blocks) { |
| | if (composedBlocks.find(pair.first) == composedBlocks.end()) { |
| | ComposeFlattenedBlock(pair.first, composedBlocks); |
| | } |
| | } |
| | } |
| | else { |
| | |
| | for (const auto& pair : this->Blocks) { |
| | if (composedBlocks.find(pair.first) == composedBlocks.end()) { |
| | ComposeParametricBlock(pair.first, composedBlocks); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::FinishImport() |
| | { |
| | |
| | |
| | |
| |
|
| | std::vector<App::DocumentObject*> referenced; |
| | std::vector<App::DocumentObject*> unreferenced; |
| |
|
| | for (const auto& pair : m_blockDefinitions) { |
| | const std::string& blockName = pair.first; |
| | App::DocumentObject* blockObj = pair.second; |
| |
|
| | bool is_referenced = (m_referencedBlocks.find(blockName) != m_referencedBlocks.end()); |
| |
|
| | |
| | |
| | |
| | if (is_referenced || (blockName.rfind('*', 0) == 0)) { |
| | referenced.push_back(blockObj); |
| | } |
| | else { |
| | unreferenced.push_back(blockObj); |
| | } |
| | } |
| |
|
| | |
| | |
| | m_blockDefinitionGroup->Group.setValues(referenced); |
| | m_unreferencedBlocksGroup->Group.setValues(unreferenced); |
| |
|
| | |
| | |
| | if (unreferenced.empty()) { |
| | try { |
| | document->removeObject(m_unreferencedBlocksGroup->getNameInDocument()); |
| | } |
| | catch (const Base::Exception& e) { |
| | |
| | e.reportException(); |
| | } |
| | } |
| | else { |
| | m_unreferencedBlocksGroup->Visibility.setValue(false); |
| | } |
| |
|
| | |
| | |
| | if (m_blockDefinitionGroup && m_blockDefinitionGroup->Group.getValues().empty()) { |
| | try { |
| | document->removeObject(m_blockDefinitionGroup->getNameInDocument()); |
| | } |
| | catch (const Base::Exception& e) { |
| | e.reportException(); |
| | } |
| | } |
| |
|
| | |
| | CDxfRead::FinishImport(); |
| | } |
| |
|
| | bool ImpExpDxfRead::OnReadBlock(const std::string& name, int flags) |
| | { |
| | |
| | if ((flags & 0x04) != 0) { |
| | UnsupportedFeature("External (xref) BLOCK"); |
| | return SkipBlockContents(); |
| | } |
| |
|
| | |
| | bool isAnonymous = (name.find('*') == 0); |
| | if (isAnonymous) { |
| | if (name.size() > 1) { |
| | char type = std::toupper(name[1]); |
| | if (type == 'D') { |
| | m_stats.systemBlockCounts["Dimension-related (*D)"]++; |
| | } |
| | else if (type == 'H' || type == 'X') { |
| | m_stats.systemBlockCounts["Hatch-related (*H, *X)"]++; |
| | } |
| | else { |
| | m_stats.systemBlockCounts["Other System Blocks"]++; |
| | } |
| | } |
| | else { |
| | m_stats.systemBlockCounts["Other System Blocks"]++; |
| | } |
| |
|
| | if (!m_importHiddenBlocks) { |
| | return SkipBlockContents(); |
| | } |
| | } |
| | else { |
| | m_stats.entityCounts["BLOCK"]++; |
| | } |
| |
|
| | |
| | if (this->Blocks.count(name)) { |
| | ImportError("Duplicate block name '%s' found. Ignoring subsequent definition.", name.c_str()); |
| | return SkipBlockContents(); |
| | } |
| |
|
| | |
| | |
| | auto& temporaryBlock = Blocks.emplace(std::make_pair(name, Block(name, flags))).first->second; |
| | BlockDefinitionCollector blockCollector( |
| | *this, |
| | temporaryBlock.GeometryBuilders, |
| | temporaryBlock.Inserts |
| | ); |
| | if (!ReadBlockContents()) { |
| | return false; |
| | } |
| |
|
| | |
| | |
| | return true; |
| | } |
| |
|
| | void ImpExpDxfRead::OnReadLine(const Base::Vector3d& start, const Base::Vector3d& end, bool ) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | gp_Pnt p0 = makePoint(start); |
| | gp_Pnt p1 = makePoint(end); |
| | if (p0.IsEqual(p1, 1e-8)) { |
| | return; |
| | } |
| | TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(p0, p1).Edge(); |
| | GeometryBuilder builder(edge); |
| |
|
| | |
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | |
| | builder.type = GeometryBuilder::PrimitiveType::Line; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | |
| | |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| |
|
| | Collector->AddGeometry(builder); |
| | } |
| |
|
| |
|
| | void ImpExpDxfRead::OnReadPoint(const Base::Vector3d& start) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| | TopoDS_Vertex vertex = BRepBuilderAPI_MakeVertex(makePoint(start)).Vertex(); |
| | GeometryBuilder builder(vertex); |
| |
|
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | builder.type = GeometryBuilder::PrimitiveType::Point; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| | Collector->AddGeometry(builder); |
| | } |
| |
|
| |
|
| | void ImpExpDxfRead::OnReadArc( |
| | const Base::Vector3d& start, |
| | const Base::Vector3d& end, |
| | const Base::Vector3d& center, |
| | bool dir, |
| | bool |
| | ) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | gp_Pnt p0 = makePoint(start); |
| | gp_Pnt p1 = makePoint(end); |
| | gp_Dir up(0, 0, 1); |
| | if (!dir) { |
| | up.Reverse(); |
| | } |
| | gp_Pnt pc = makePoint(center); |
| | gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); |
| | if (circle.Radius() < 1e-9) { |
| | Base::Console().warning("ImpExpDxf - ignore degenerate arc of circle\n"); |
| | return; |
| | } |
| |
|
| | TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle, p0, p1).Edge(); |
| | GeometryBuilder builder(edge); |
| |
|
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | builder.type = GeometryBuilder::PrimitiveType::Arc; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| | Collector->AddGeometry(builder); |
| | } |
| |
|
| |
|
| | void ImpExpDxfRead::OnReadCircle(const Base::Vector3d& start, const Base::Vector3d& center, bool dir, bool ) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | gp_Pnt p0 = makePoint(start); |
| | gp_Dir up(0, 0, 1); |
| | if (!dir) { |
| | up.Reverse(); |
| | } |
| | gp_Pnt pc = makePoint(center); |
| | gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); |
| | if (circle.Radius() < 1e-9) { |
| | Base::Console().warning("ImpExpDxf - ignore degenerate circle\n"); |
| | return; |
| | } |
| |
|
| | TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle).Edge(); |
| | GeometryBuilder builder(edge); |
| |
|
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | builder.type = GeometryBuilder::PrimitiveType::Circle; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| | Collector->AddGeometry(builder); |
| | } |
| |
|
| |
|
| | Handle(Geom_BSplineCurve) getSplineFromPolesAndKnots(struct SplineData& sd) |
| | { |
| | std::size_t numPoles = sd.control_points; |
| | if (sd.controlx.size() > numPoles || sd.controly.size() > numPoles |
| | || sd.controlz.size() > numPoles || sd.weight.size() > numPoles) { |
| | return nullptr; |
| | } |
| |
|
| | |
| | TColgp_Array1OfPnt occpoles(1, sd.control_points); |
| | int index = 1; |
| | for (auto coordinate : sd.controlx) { |
| | occpoles(index++).SetX(coordinate); |
| | } |
| |
|
| | index = 1; |
| | for (auto coordinate : sd.controly) { |
| | occpoles(index++).SetY(coordinate); |
| | } |
| |
|
| | index = 1; |
| | for (auto coordinate : sd.controlz) { |
| | occpoles(index++).SetZ(coordinate); |
| | } |
| |
|
| | |
| | std::set<double> unique; |
| | unique.insert(sd.knot.begin(), sd.knot.end()); |
| |
|
| | int numKnots = int(unique.size()); |
| | TColStd_Array1OfInteger occmults(1, numKnots); |
| | TColStd_Array1OfReal occknots(1, numKnots); |
| | index = 1; |
| | for (auto knot : unique) { |
| | occknots(index) = knot; |
| | occmults(index) = (int)std::count(sd.knot.begin(), sd.knot.end(), knot); |
| | index++; |
| | } |
| |
|
| | |
| | TColStd_Array1OfReal occweights(1, sd.control_points); |
| | if (sd.weight.size() == std::size_t(sd.control_points)) { |
| | index = 1; |
| | for (auto weight : sd.weight) { |
| | occweights(index++) = weight; |
| | } |
| | } |
| | else { |
| | |
| | for (int i = occweights.Lower(); i <= occweights.Upper(); i++) { |
| | occweights(i) = 1.0; |
| | } |
| | } |
| |
|
| | Standard_Boolean periodic = sd.flag == 2; |
| | Handle(Geom_BSplineCurve) geom |
| | = new Geom_BSplineCurve(occpoles, occweights, occknots, occmults, sd.degree, periodic); |
| | return geom; |
| | } |
| |
|
| | Handle(Geom_BSplineCurve) getInterpolationSpline(struct SplineData& sd) |
| | { |
| | std::size_t numPoints = sd.fit_points; |
| | if (sd.fitx.size() > numPoints || sd.fity.size() > numPoints || sd.fitz.size() > numPoints) { |
| | return nullptr; |
| | } |
| |
|
| | |
| | Handle(TColgp_HArray1OfPnt) fitpoints = new TColgp_HArray1OfPnt(1, sd.fit_points); |
| | int index = 1; |
| | for (auto coordinate : sd.fitx) { |
| | fitpoints->ChangeValue(index++).SetX(coordinate); |
| | } |
| |
|
| | index = 1; |
| | for (auto coordinate : sd.fity) { |
| | fitpoints->ChangeValue(index++).SetY(coordinate); |
| | } |
| |
|
| | index = 1; |
| | for (auto coordinate : sd.fitz) { |
| | fitpoints->ChangeValue(index++).SetZ(coordinate); |
| | } |
| |
|
| | Standard_Boolean periodic = sd.flag == 2; |
| | GeomAPI_Interpolate interp(fitpoints, periodic, Precision::Confusion()); |
| | interp.Perform(); |
| | return interp.Curve(); |
| | } |
| |
|
| | void ImpExpDxfRead::OnReadSpline(struct SplineData& sd) |
| | { |
| | |
| | |
| | |
| |
|
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | try { |
| | Handle(Geom_BSplineCurve) geom; |
| | if (sd.control_points > 0) { |
| | geom = getSplineFromPolesAndKnots(sd); |
| | } |
| | else if (sd.fit_points > 0) { |
| | geom = getInterpolationSpline(sd); |
| | } |
| |
|
| | if (!geom.IsNull()) { |
| | TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(geom).Edge(); |
| | GeometryBuilder builder(edge); |
| |
|
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | builder.type = GeometryBuilder::PrimitiveType::Spline; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| | Collector->AddGeometry(builder); |
| | } |
| | } |
| | catch (const Standard_Failure&) { |
| | Base::Console().warning("ImpExpDxf - failed to create bspline\n"); |
| | } |
| | } |
| |
|
| | |
| | void ImpExpDxfRead::OnReadEllipse( |
| | const Base::Vector3d& center, |
| | double major_radius, |
| | double minor_radius, |
| | double rotation, |
| | double , |
| | double , |
| | bool dir |
| | ) |
| | |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | gp_Dir up(0, 0, 1); |
| | if (!dir) { |
| | up.Reverse(); |
| | } |
| | gp_Pnt pc = makePoint(center); |
| | gp_Elips ellipse(gp_Ax2(pc, up), major_radius, minor_radius); |
| | ellipse.Rotate(gp_Ax1(pc, up), rotation); |
| | if (ellipse.MinorRadius() < 1e-9) { |
| | Base::Console().warning("ImpExpDxf - ignore degenerate ellipse\n"); |
| | return; |
| | } |
| |
|
| | TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(ellipse).Edge(); |
| | GeometryBuilder builder(edge); |
| |
|
| | switch (m_importMode) { |
| | case ImportMode::EditableDraft: |
| | case ImportMode::EditablePrimitives: |
| | |
| | builder.type = GeometryBuilder::PrimitiveType::Ellipse; |
| | break; |
| | case ImportMode::IndividualShapes: |
| | case ImportMode::FusedShapes: |
| | default: |
| | |
| | |
| | builder.type = GeometryBuilder::PrimitiveType::None; |
| | break; |
| | } |
| | Collector->AddGeometry(builder); |
| | } |
| |
|
| | void ImpExpDxfRead::OnReadText( |
| | const Base::Vector3d& point, |
| | const double height, |
| | const std::string& text, |
| | const double rotation |
| | ) |
| | { |
| | if (shouldSkipEntity() || !m_importAnnotations) { |
| | return; |
| | } |
| |
|
| | auto* p = static_cast<App::FeaturePython*>(document->addObject("App::FeaturePython", "Text")); |
| | if (p) { |
| | p->addDynamicProperty("App::PropertyString", "DxfEntityType", "Internal", "DXF entity type"); |
| | static_cast<App::PropertyString*>(p->getPropertyByName("DxfEntityType"))->setValue("TEXT"); |
| |
|
| | p->addDynamicProperty("App::PropertyStringList", "Text", "Data", "Text content"); |
| | |
| | std::vector<std::string> text_values = {text}; |
| | static_cast<App::PropertyStringList*>(p->getPropertyByName("Text"))->setValues(text_values); |
| |
|
| | p->addDynamicProperty("App::PropertyFloat", "DxfTextHeight", "Internal", "Original text height"); |
| | static_cast<App::PropertyFloat*>(p->getPropertyByName("DxfTextHeight"))->setValue(height); |
| |
|
| | p->addDynamicProperty("App::PropertyPlacement", "Placement", "Base", "Object placement"); |
| | Base::Placement pl; |
| | pl.setPosition(point); |
| | pl.setRotation(Base::Rotation(Base::Vector3d(0, 0, 1), Base::toRadians(rotation))); |
| | static_cast<App::PropertyPlacement*>(p->getPropertyByName("Placement"))->setValue(pl); |
| |
|
| | Collector->AddObject(p, "Text"); |
| | } |
| | } |
| |
|
| |
|
| | void ImpExpDxfRead::OnReadInsert( |
| | const Base::Vector3d& point, |
| | const Base::Vector3d& scale, |
| | const std::string& name, |
| | double rotation |
| | ) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | |
| | |
| | |
| | Collector->AddInsert(point, scale, name, rotation); |
| | } |
| |
|
| |
|
| | void ImpExpDxfRead::OnReadDimension( |
| | const Base::Vector3d& start, |
| | const Base::Vector3d& end, |
| | const Base::Vector3d& point, |
| | int dimensionType, |
| | double rotation |
| | ) |
| | { |
| | if (shouldSkipEntity() || !m_importAnnotations) { |
| | return; |
| | } |
| |
|
| | auto* p = static_cast<App::FeaturePython*>(document->addObject("App::FeaturePython", "Dimension")); |
| | if (p) { |
| | p->addDynamicProperty("App::PropertyString", "DxfEntityType", "Internal", "DXF entity type"); |
| | static_cast<App::PropertyString*>(p->getPropertyByName("DxfEntityType"))->setValue("DIMENSION"); |
| |
|
| | p->addDynamicProperty("App::PropertyVector", "Start", "Data", "Start point of dimension"); |
| | static_cast<App::PropertyVector*>(p->getPropertyByName("Start"))->setValue(start); |
| |
|
| | p->addDynamicProperty("App::PropertyVector", "End", "Data", "End point of dimension"); |
| | static_cast<App::PropertyVector*>(p->getPropertyByName("End"))->setValue(end); |
| |
|
| | p->addDynamicProperty("App::PropertyVector", "Dimline", "Data", "Point on dimension line"); |
| | static_cast<App::PropertyVector*>(p->getPropertyByName("Dimline"))->setValue(point); |
| |
|
| | p->addDynamicProperty( |
| | "App::PropertyInteger", |
| | "DxfDimensionType", |
| | "Internal", |
| | "Original dimension type flag" |
| | ); |
| | static_cast<App::PropertyInteger*>(p->getPropertyByName("DxfDimensionType")) |
| | ->setValue(dimensionType); |
| |
|
| | p->addDynamicProperty( |
| | "App::PropertyAngle", |
| | "DxfRotation", |
| | "Internal", |
| | "Original dimension rotation" |
| | ); |
| | |
| | static_cast<App::PropertyAngle*>(p->getPropertyByName("DxfRotation"))->setValue(rotation); |
| |
|
| | p->addDynamicProperty("App::PropertyPlacement", "Placement", "Base", "Object placement"); |
| | Base::Placement pl; |
| | |
| | |
| | pl.setRotation(Base::Rotation(OCSOrientationTransform)); |
| | static_cast<App::PropertyPlacement*>(p->getPropertyByName("Placement"))->setValue(pl); |
| |
|
| | Collector->AddObject(p, "Dimension"); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::OnReadPolyline(std::list<VertexInfo>& vertices, int flags) |
| | { |
| | if (shouldSkipEntity()) { |
| | return; |
| | } |
| |
|
| | if (vertices.size() < 2 && (flags & 1) == 0) { |
| | return; |
| | } |
| |
|
| | TopoDS_Wire wire = BuildWireFromPolyline(vertices, flags); |
| | if (wire.IsNull()) { |
| | return; |
| | } |
| |
|
| | if (m_importMode == ImportMode::EditableDraft) { |
| | GeometryBuilder builder(wire); |
| | builder.type = GeometryBuilder::PrimitiveType::PolylineFlattened; |
| | Collector->AddGeometry(builder); |
| | } |
| | else if (m_importMode == ImportMode::EditablePrimitives) { |
| | GeometryBuilder builder(wire); |
| | builder.type = GeometryBuilder::PrimitiveType::PolylineParametric; |
| | Collector->AddGeometry(builder); |
| | } |
| | else { |
| | Collector->AddObject(wire, "Polyline"); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::DrawingEntityCollector::AddGeometry(const GeometryBuilder& builder) |
| | { |
| | App::DocumentObject* newDocObj = nullptr; |
| |
|
| | switch (builder.type) { |
| | case GeometryBuilder::PrimitiveType::Line: { |
| | newDocObj = createLinePrimitive(TopoDS::Edge(builder.shape), Reader.document, "Line"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Circle: { |
| | auto* p = createCirclePrimitive(TopoDS::Edge(builder.shape), Reader.document, "Circle"); |
| | if (p) { |
| | p->Angle1.setValue(0.0); |
| | p->Angle2.setValue(360.0); |
| | } |
| | newDocObj = p; |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Arc: { |
| | newDocObj = createCirclePrimitive(TopoDS::Edge(builder.shape), Reader.document, "Arc"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Point: { |
| | newDocObj = createVertexPrimitive(TopoDS::Vertex(builder.shape), Reader.document, "Point"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Ellipse: { |
| | newDocObj = createEllipsePrimitive(TopoDS::Edge(builder.shape), Reader.document, "Ellipse"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::Spline: { |
| | newDocObj = createGenericShapeFeature(builder.shape, Reader.document, "Spline"); |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::PolylineFlattened: { |
| | Reader.CreateFlattenedPolyline(TopoDS::Wire(builder.shape), "Polyline"); |
| | newDocObj = nullptr; |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::PolylineParametric: { |
| | Reader.CreateParametricPolyline(TopoDS::Wire(builder.shape), "Polyline"); |
| | newDocObj = nullptr; |
| | break; |
| | } |
| | case GeometryBuilder::PrimitiveType::None: |
| | default: { |
| | newDocObj = createGenericShapeFeature(builder.shape, Reader.document, "Shape"); |
| | break; |
| | } |
| | } |
| |
|
| | |
| | if (newDocObj) { |
| | Reader.IncrementCreatedObjectCount(); |
| | Reader._addOriginalLayerProperty(newDocObj); |
| | Reader.MoveToLayer(newDocObj); |
| | Reader.ApplyGuiStyles(static_cast<Part::Feature*>(newDocObj)); |
| | } |
| | } |
| |
|
| | ImpExpDxfRead::Layer::Layer( |
| | const std::string& name, |
| | ColorIndex_t color, |
| | std::string&& lineType, |
| | PyObject* drawingLayer |
| | ) |
| | : CDxfRead::Layer(name, color, std::move(lineType)) |
| | , DraftLayerView( |
| | drawingLayer == nullptr ? Py_None : PyObject_GetAttrString(drawingLayer, "ViewObject") |
| | ) |
| | , GroupContents( |
| | drawingLayer == nullptr ? nullptr |
| | : dynamic_cast<App::PropertyLinkListHidden*>( |
| | (((App::FeaturePythonPyT<App::DocumentObjectPy>*)drawingLayer) |
| | ->getPropertyContainerPtr()) |
| | ->getDynamicPropertyByName("Group") |
| | ) |
| | ) |
| | {} |
| | ImpExpDxfRead::Layer::~Layer() |
| | { |
| | Py_XDECREF(DraftLayerView); |
| | } |
| |
|
| | void ImpExpDxfRead::Layer::FinishLayer() const |
| | { |
| | if (GroupContents != nullptr) { |
| | |
| | |
| | |
| | |
| | GroupContents->setValue(Contents); |
| | } |
| | if (DraftLayerView != Py_None && Hidden) { |
| | |
| | |
| | |
| | PyObject_CallMethod(DraftLayerView, "hide", nullptr); |
| | } |
| | } |
| |
|
| | CDxfRead::Layer* ImpExpDxfRead::MakeLayer(const std::string& name, ColorIndex_t color, std::string&& lineType) |
| | { |
| | if (m_preserveLayers) { |
| | |
| | Base::Color appColor = ObjectColor(color); |
| | PyObject* draftModule = nullptr; |
| | PyObject* layer = nullptr; |
| | draftModule = getDraftModule(); |
| | if (draftModule != nullptr) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | layer = |
| | |
| | |
| | (Base::PyObjectBase*)PyObject_CallMethod( |
| | draftModule, |
| | "make_layer", |
| | "s(fff)(fff)fs", |
| | name.c_str(), |
| | appColor.r, |
| | appColor.g, |
| | appColor.b, |
| | appColor.r, |
| | appColor.g, |
| | appColor.b, |
| | 2.0, |
| | "Solid" |
| | ); |
| | } |
| | auto result = new Layer(name, color, std::move(lineType), layer); |
| | if (result->DraftLayerView != Py_None) { |
| | |
| | PyObject* overrideValue = m_preserveColors ? Py_True : Py_False; |
| | PyObject_SetAttrString(result->DraftLayerView, "OverrideLineColorChildren", overrideValue); |
| | PyObject_SetAttrString( |
| | result->DraftLayerView, |
| | "OverrideShapeAppearanceChildren", |
| | overrideValue |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | return result; |
| | } |
| | return CDxfRead::MakeLayer(name, color, std::move(lineType)); |
| | } |
| | void ImpExpDxfRead::MoveToLayer(App::DocumentObject* object) const |
| | { |
| | if (m_preserveLayers) { |
| | static_cast<Layer*>(m_entityAttributes.m_Layer)->Contents.push_back(object); |
| | } |
| | |
| | |
| | } |
| |
|
| |
|
| | std::string ImpExpDxfRead::Deformat(const char* text) |
| | { |
| | |
| | std::stringstream ss; |
| | bool escape = false; |
| | bool longescape = false; |
| | for (unsigned int i = 0; i < strlen(text); i++) { |
| | char ch = text[i]; |
| | if (ch == '\\') { |
| | escape = true; |
| | } |
| | else if (escape) { |
| | if (longescape) { |
| | if (ch == ';') { |
| | escape = false; |
| | longescape = false; |
| | } |
| | } |
| | else if ((ch == 'H') || (ch == 'h') || (ch == 'Q') || (ch == 'q') || (ch == 'W') |
| | || (ch == 'w') || (ch == 'F') || (ch == 'f') || (ch == 'A') || (ch == 'a') |
| | || (ch == 'C') || (ch == 'c') || (ch == 'T') || (ch == 't')) { |
| | longescape = true; |
| | } |
| | else { |
| | if ((ch == 'P') || (ch == 'p')) { |
| | ss << "\n"; |
| | } |
| | escape = false; |
| | } |
| | } |
| | else if ((ch != '{') && (ch != '}')) { |
| | ss << ch; |
| | } |
| | } |
| | return ss.str(); |
| | } |
| |
|
| | void ImpExpDxfRead::_addOriginalLayerProperty(App::DocumentObject* obj) |
| | { |
| | if (obj && m_entityAttributes.m_Layer) { |
| | obj->addDynamicProperty( |
| | "App::PropertyString", |
| | "OriginalLayer", |
| | "Internal", |
| | "Layer name from the original DXF file.", |
| | App::Property::Hidden |
| | ); |
| | static_cast<App::PropertyString*>(obj->getPropertyByName("OriginalLayer")) |
| | ->setValue(m_entityAttributes.m_Layer->Name.c_str()); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::DrawingEntityCollector::AddObject(const TopoDS_Shape& shape, const char* nameBase) |
| | { |
| | auto pcFeature = Reader.document->addObject<Part::Feature>(nameBase); |
| |
|
| | if (pcFeature) { |
| | Reader.IncrementCreatedObjectCount(); |
| | pcFeature->Shape.setValue(shape); |
| | Reader._addOriginalLayerProperty(pcFeature); |
| | Reader.MoveToLayer(pcFeature); |
| | Reader.ApplyGuiStyles(pcFeature); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::DrawingEntityCollector::AddObject(App::DocumentObject* obj, const char* ) |
| | { |
| | Reader.MoveToLayer(obj); |
| | Reader._addOriginalLayerProperty(obj); |
| |
|
| | |
| | |
| | if (auto feature = dynamic_cast<Part::Feature*>(obj)) { |
| | Reader.ApplyGuiStyles(feature); |
| | } |
| | else if (auto pyFeature = dynamic_cast<App::FeaturePython*>(obj)) { |
| | Reader.ApplyGuiStyles(pyFeature); |
| | } |
| | else if (auto link = dynamic_cast<App::Link*>(obj)) { |
| | Reader.ApplyGuiStyles(link); |
| | } |
| | } |
| |
|
| | void ImpExpDxfRead::DrawingEntityCollector::AddObject(FeaturePythonBuilder shapeBuilder) |
| | { |
| | Reader.IncrementCreatedObjectCount(); |
| | App::FeaturePython* shape = shapeBuilder(Reader.OCSOrientationTransform); |
| | if (shape != nullptr) { |
| | Reader._addOriginalLayerProperty(shape); |
| | } |
| | } |
| |
|
| | |
| | |
| |
|
| | void gPntToTuple(double result[3], gp_Pnt& p) |
| | { |
| | result[0] = p.X(); |
| | result[1] = p.Y(); |
| | result[2] = p.Z(); |
| | } |
| |
|
| | point3D gPntTopoint3D(gp_Pnt& p) |
| | { |
| | point3D result = {p.X(), p.Y(), p.Z()}; |
| | return result; |
| | } |
| |
|
| | ImpExpDxfWrite::ImpExpDxfWrite(std::string filepath) |
| | : CDxfWrite(filepath.c_str()) |
| | { |
| | setOptionSource("User parameter:BaseApp/Preferences/Mod/Draft"); |
| | setOptions(); |
| | } |
| |
|
| | ImpExpDxfWrite::~ImpExpDxfWrite() = default; |
| |
|
| | void ImpExpDxfWrite::setOptions() |
| | { |
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( |
| | getOptionSource().c_str() |
| | ); |
| | optionMaxLength = hGrp->GetFloat("maxsegmentlength", 5.0); |
| | optionExpPoints = hGrp->GetBool("ExportPoints", false); |
| | m_version = hGrp->GetInt("DxfVersionOut", 14); |
| | optionPolyLine = hGrp->GetBool("DiscretizeEllipses", false); |
| | m_polyOverride = hGrp->GetBool("DiscretizeEllipses", false); |
| | setDataDir(App::Application::getResourceDir() + "Mod/Import/DxfPlate/"); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportShape(const TopoDS_Shape input) |
| | { |
| | |
| | TopExp_Explorer edges(input, TopAbs_EDGE); |
| | for (int i = 1; edges.More(); edges.Next(), i++) { |
| | const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); |
| | BRepAdaptor_Curve adapt(edge); |
| | if (adapt.GetType() == GeomAbs_Circle) { |
| | double f = adapt.FirstParameter(); |
| | double l = adapt.LastParameter(); |
| | gp_Pnt start = adapt.Value(f); |
| | gp_Pnt e = adapt.Value(l); |
| | if (fabs(l - f) > 1.0 && start.SquareDistance(e) < 0.001) { |
| | exportCircle(adapt); |
| | } |
| | else { |
| | exportArc(adapt); |
| | } |
| | } |
| | else if (adapt.GetType() == GeomAbs_Ellipse) { |
| | double f = adapt.FirstParameter(); |
| | double l = adapt.LastParameter(); |
| | gp_Pnt start = adapt.Value(f); |
| | gp_Pnt e = adapt.Value(l); |
| | if (fabs(l - f) > 1.0 && start.SquareDistance(e) < 0.001) { |
| | if (m_polyOverride) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else if (optionPolyLine) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else { |
| | if (m_version < 14) { |
| | exportPolyline(adapt); |
| | } |
| | else { |
| | exportEllipse(adapt); |
| | } |
| | } |
| | } |
| | else { |
| | if (m_polyOverride) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else if (optionPolyLine) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else { |
| | if (m_version < 14) { |
| | exportPolyline(adapt); |
| | } |
| | else { |
| | exportEllipseArc(adapt); |
| | } |
| | } |
| | } |
| | } |
| | else if (adapt.GetType() == GeomAbs_BSplineCurve) { |
| | if (m_polyOverride) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else if (optionPolyLine) { |
| | if (m_version >= 14) { |
| | exportLWPoly(adapt); |
| | } |
| | else { |
| | exportPolyline(adapt); |
| | } |
| | } |
| | else { |
| | if (m_version < 14) { |
| | exportPolyline(adapt); |
| | } |
| | else { |
| | exportBSpline(adapt); |
| | } |
| | } |
| | } |
| | else if (adapt.GetType() == GeomAbs_BezierCurve) { |
| | exportBCurve(adapt); |
| | } |
| | else if (adapt.GetType() == GeomAbs_Line) { |
| | exportLine(adapt); |
| | } |
| | else { |
| | Base::Console().warning( |
| | "ImpExpDxf - unknown curve type: %d\n", |
| | static_cast<int>(adapt.GetType()) |
| | ); |
| | } |
| | } |
| |
|
| | if (optionExpPoints) { |
| | TopExp_Explorer verts(input, TopAbs_VERTEX); |
| | std::vector<gp_Pnt> duplicates; |
| | for (int i = 1; verts.More(); verts.Next(), i++) { |
| | const TopoDS_Vertex& v = TopoDS::Vertex(verts.Current()); |
| | gp_Pnt p = BRep_Tool::Pnt(v); |
| | duplicates.push_back(p); |
| | } |
| |
|
| | std::sort(duplicates.begin(), duplicates.end(), ImpExpDxfWrite::gp_PntCompare); |
| | auto newEnd = std::unique(duplicates.begin(), duplicates.end(), ImpExpDxfWrite::gp_PntEqual); |
| | std::vector<gp_Pnt> uniquePts(duplicates.begin(), newEnd); |
| | for (auto& p : uniquePts) { |
| | double point[3] = {0, 0, 0}; |
| | gPntToTuple(point, p); |
| | writePoint(point); |
| | } |
| | } |
| | } |
| |
|
| | bool ImpExpDxfWrite::gp_PntEqual(gp_Pnt p1, gp_Pnt p2) |
| | { |
| | bool result = false; |
| | if (p1.IsEqual(p2, Precision::Confusion())) { |
| | result = true; |
| | } |
| | return result; |
| | } |
| |
|
| | |
| | bool ImpExpDxfWrite::gp_PntCompare(gp_Pnt p1, gp_Pnt p2) |
| | { |
| | bool result = false; |
| | if (!(p1.IsEqual(p2, Precision::Confusion()))) { |
| | if (!(fabs(p1.X() - p2.X()) < Precision::Confusion())) { |
| | result = p1.X() < p2.X(); |
| | } |
| | else if (!(fabs(p1.Y() - p2.Y()) < Precision::Confusion())) { |
| | result = p1.Y() < p2.Y(); |
| | } |
| | else { |
| | result = p1.Z() < p2.Z(); |
| | } |
| | } |
| | return result; |
| | } |
| |
|
| |
|
| | void ImpExpDxfWrite::exportCircle(BRepAdaptor_Curve& c) |
| | { |
| | gp_Circ circ = c.Circle(); |
| | gp_Pnt p = circ.Location(); |
| | double center[3] = {0, 0, 0}; |
| | gPntToTuple(center, p); |
| |
|
| | double radius = circ.Radius(); |
| |
|
| | writeCircle(center, radius); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportEllipse(BRepAdaptor_Curve& c) |
| | { |
| | gp_Elips ellp = c.Ellipse(); |
| | gp_Pnt p = ellp.Location(); |
| | double center[3] = {0, 0, 0}; |
| | gPntToTuple(center, p); |
| |
|
| | double major = ellp.MajorRadius(); |
| | double minor = ellp.MinorRadius(); |
| |
|
| | gp_Dir xaxis = ellp.XAxis().Direction(); |
| | |
| | double rotation = xaxis.AngleWithRef(gp_Dir(0, 1, 0), gp_Dir(0, 0, 1)); |
| |
|
| | |
| | |
| | writeEllipse(center, major, minor, rotation, 0.0, 6.28318, true); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportArc(BRepAdaptor_Curve& c) |
| | { |
| | gp_Circ circ = c.Circle(); |
| | gp_Pnt p = circ.Location(); |
| | double center[3] = {0, 0, 0}; |
| | gPntToTuple(center, p); |
| |
|
| | double f = c.FirstParameter(); |
| | double l = c.LastParameter(); |
| | gp_Pnt s = c.Value(f); |
| | double start[3]; |
| | gPntToTuple(start, s); |
| | gp_Pnt m = c.Value((l + f) / 2.0); |
| | gp_Pnt e = c.Value(l); |
| | double end[3] = {0, 0, 0}; |
| | gPntToTuple(end, e); |
| |
|
| | gp_Vec v1(m, s); |
| | gp_Vec v2(m, e); |
| | gp_Vec v3(0, 0, 1); |
| | double a = v3.DotCross(v1, v2); |
| |
|
| | bool dir = (a < 0) ? true : false; |
| | writeArc(start, end, center, dir); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportEllipseArc(BRepAdaptor_Curve& c) |
| | { |
| | gp_Elips ellp = c.Ellipse(); |
| | gp_Pnt p = ellp.Location(); |
| | double center[3] = {0, 0, 0}; |
| | gPntToTuple(center, p); |
| |
|
| | double major = ellp.MajorRadius(); |
| | double minor = ellp.MinorRadius(); |
| |
|
| | gp_Dir xaxis = ellp.XAxis().Direction(); |
| | |
| | double rotation = xaxis.AngleWithRef(gp_Dir(0, 1, 0), gp_Dir(0, 0, 1)); |
| |
|
| | double f = c.FirstParameter(); |
| | double l = c.LastParameter(); |
| | gp_Pnt s = c.Value(f); |
| | gp_Pnt m = c.Value((l + f) / 2.0); |
| | gp_Pnt e = c.Value(l); |
| |
|
| | gp_Vec v1(m, s); |
| | gp_Vec v2(m, e); |
| | gp_Vec v3(0, 0, 1); |
| | double a = v3.DotCross(v1, v2); |
| | |
| | |
| | |
| |
|
| | double startAngle = fmod(f, 2.0 * std::numbers::pi); |
| | double endAngle = fmod(l, 2.0 * std::numbers::pi); |
| | bool endIsCW = (a < 0) ? true : false; |
| | |
| | if (!endIsCW) { |
| | startAngle = -startAngle; |
| | endAngle = -endAngle; |
| | } |
| |
|
| | writeEllipse(center, major, minor, rotation, startAngle, endAngle, endIsCW); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportBSpline(BRepAdaptor_Curve& c) |
| | { |
| | SplineDataOut sd; |
| | Handle(Geom_BSplineCurve) spline; |
| | double f, l; |
| | gp_Pnt s, ePt; |
| |
|
| | Standard_Real tol3D = 0.001; |
| | Standard_Integer maxDegree = 3, maxSegment = 200; |
| | Handle(BRepAdaptor_HCurve) hCurve = new BRepAdaptor_HCurve(c); |
| | Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree); |
| | if (approx.IsDone() && approx.HasResult()) { |
| | spline = approx.Curve(); |
| | } |
| | else { |
| | if (approx.HasResult()) { |
| | spline = approx.Curve(); |
| | Base::Console().message("DxfWrite::exportBSpline - result not within tolerance\n"); |
| | } |
| | else { |
| | f = c.FirstParameter(); |
| | l = c.LastParameter(); |
| | s = c.Value(f); |
| | ePt = c.Value(l); |
| | Base::Console().message( |
| | "DxfWrite::exportBSpline - no result- from:(%.3f,%.3f) to:(%.3f,%.3f)\n", |
| | s.X(), |
| | s.Y(), |
| | ePt.X(), |
| | ePt.Y() |
| | ); |
| | TColgp_Array1OfPnt controlPoints(0, 1); |
| | controlPoints.SetValue(0, s); |
| | controlPoints.SetValue(1, ePt); |
| | spline = GeomAPI_PointsToBSpline(controlPoints, 1).Curve(); |
| | } |
| | } |
| | |
| | sd.norm.x = 0.0; |
| | sd.norm.y = 0.0; |
| | sd.norm.z = 1.0; |
| |
|
| | sd.flag = spline->IsClosed(); |
| | sd.flag += spline->IsPeriodic() * 2; |
| | sd.flag += spline->IsRational() * 4; |
| | sd.flag += 8; |
| |
|
| | sd.degree = spline->Degree(); |
| | sd.control_points = spline->NbPoles(); |
| | sd.knots = spline->NbKnots(); |
| | gp_Pnt p; |
| | spline->D0(spline->FirstParameter(), p); |
| | sd.starttan = gPntTopoint3D(p); |
| | spline->D0(spline->LastParameter(), p); |
| | sd.endtan = gPntTopoint3D(p); |
| |
|
| | |
| | Standard_Integer m = 0; |
| | if (spline->IsPeriodic()) { |
| | m = spline->NbPoles() + 2 * spline->Degree() - spline->Multiplicity(1) + 2; |
| | } |
| | else { |
| | for (int i = 1; i <= spline->NbKnots(); i++) { |
| | m += spline->Multiplicity(i); |
| | } |
| | } |
| | TColStd_Array1OfReal knotsequence(1, m); |
| | spline->KnotSequence(knotsequence); |
| | for (int i = knotsequence.Lower(); i <= knotsequence.Upper(); i++) { |
| | sd.knot.push_back(knotsequence(i)); |
| | } |
| | sd.knots = knotsequence.Length(); |
| |
|
| | TColgp_Array1OfPnt poles(1, spline->NbPoles()); |
| | spline->Poles(poles); |
| | for (int i = poles.Lower(); i <= poles.Upper(); i++) { |
| | sd.control.push_back(gPntTopoint3D(poles(i))); |
| | } |
| | |
| |
|
| | writeSpline(sd); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportBCurve(BRepAdaptor_Curve& c) |
| | { |
| | (void)c; |
| | Base::Console().message("BCurve dxf export not yet supported\n"); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportLine(BRepAdaptor_Curve& c) |
| | { |
| | double f = c.FirstParameter(); |
| | double l = c.LastParameter(); |
| | gp_Pnt s = c.Value(f); |
| | double start[3] = {0, 0, 0}; |
| | gPntToTuple(start, s); |
| | gp_Pnt e = c.Value(l); |
| | double end[3] = {0, 0, 0}; |
| | gPntToTuple(end, e); |
| | writeLine(start, end); |
| | } |
| |
|
| | |
| | |
| | bool ImpExpDxfWrite::discretizeCurveToPolyline(BRepAdaptor_Curve& c, LWPolyDataOut& pd) const |
| | { |
| | pd.Flag = c.IsClosed(); |
| | pd.Elev = 0.0; |
| | pd.Thick = 0.0; |
| | pd.Extr.x = 0.0; |
| | pd.Extr.y = 0.0; |
| | pd.Extr.z = 1.0; |
| | pd.nVert = 0; |
| |
|
| | GCPnts_UniformAbscissa discretizer; |
| | discretizer.Initialize(c, optionMaxLength); |
| |
|
| | if (!discretizer.IsDone() || discretizer.NbPoints() <= 0) { |
| | return false; |
| | } |
| |
|
| | int nbPoints = discretizer.NbPoints(); |
| | |
| | int endIndex = nbPoints; |
| | if (pd.Flag && nbPoints > 1) { |
| | gp_Pnt pFirst = c.Value(discretizer.Parameter(1)); |
| | gp_Pnt pLast = c.Value(discretizer.Parameter(nbPoints)); |
| | if (pFirst.Distance(pLast) < Precision::Confusion()) { |
| | endIndex = nbPoints - 1; |
| | } |
| | } |
| |
|
| | for (int i = 1; i <= endIndex; i++) { |
| | gp_Pnt p = c.Value(discretizer.Parameter(i)); |
| | pd.Verts.push_back(gPntTopoint3D(p)); |
| | } |
| | pd.nVert = static_cast<int>(pd.Verts.size()); |
| |
|
| | return true; |
| | } |
| |
|
| | void ImpExpDxfWrite::exportLWPoly(BRepAdaptor_Curve& c) |
| | { |
| | LWPolyDataOut pd; |
| | if (discretizeCurveToPolyline(c, pd)) { |
| | writeLWPolyLine(pd); |
| | } |
| | } |
| |
|
| | void ImpExpDxfWrite::exportPolyline(BRepAdaptor_Curve& c) |
| | { |
| | LWPolyDataOut pd; |
| | if (discretizeCurveToPolyline(c, pd)) { |
| | writePolyline(pd); |
| | } |
| | } |
| |
|
| | void ImpExpDxfWrite::exportText( |
| | const char* text, |
| | Base::Vector3d position1, |
| | Base::Vector3d position2, |
| | double size, |
| | int just |
| | ) |
| | { |
| | double location1[3] = {0, 0, 0}; |
| | location1[0] = position1.x; |
| | location1[1] = position1.y; |
| | location1[2] = position1.z; |
| | double location2[3] = {0, 0, 0}; |
| | location2[0] = position2.x; |
| | location2[1] = position2.y; |
| | location2[2] = position2.z; |
| |
|
| | writeText(text, location1, location2, size, just); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportLinearDim( |
| | Base::Vector3d textLocn, |
| | Base::Vector3d lineLocn, |
| | Base::Vector3d extLine1Start, |
| | Base::Vector3d extLine2Start, |
| | char* dimText, |
| | int type |
| | ) |
| | { |
| | double text[3] = {0, 0, 0}; |
| | text[0] = textLocn.x; |
| | text[1] = textLocn.y; |
| | text[2] = textLocn.z; |
| | double line[3] = {0, 0, 0}; |
| | line[0] = lineLocn.x; |
| | line[1] = lineLocn.y; |
| | line[2] = lineLocn.z; |
| | double ext1[3] = {0, 0, 0}; |
| | ext1[0] = extLine1Start.x; |
| | ext1[1] = extLine1Start.y; |
| | ext1[2] = extLine1Start.z; |
| | double ext2[3] = {0, 0, 0}; |
| | ext2[0] = extLine2Start.x; |
| | ext2[1] = extLine2Start.y; |
| | ext2[2] = extLine2Start.z; |
| | writeLinearDim(text, line, ext1, ext2, dimText, type); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportAngularDim( |
| | Base::Vector3d textLocn, |
| | Base::Vector3d lineLocn, |
| | Base::Vector3d extLine1End, |
| | Base::Vector3d extLine2End, |
| | Base::Vector3d apexPoint, |
| | char* dimText |
| | ) |
| | { |
| | double text[3] = {0, 0, 0}; |
| | text[0] = textLocn.x; |
| | text[1] = textLocn.y; |
| | text[2] = textLocn.z; |
| | double line[3] = {0, 0, 0}; |
| | line[0] = lineLocn.x; |
| | line[1] = lineLocn.y; |
| | line[2] = lineLocn.z; |
| | double ext1[3] = {0, 0, 0}; |
| | ext1[0] = extLine1End.x; |
| | ext1[1] = extLine1End.y; |
| | ext1[2] = extLine1End.z; |
| | double ext2[3] = {0, 0, 0}; |
| | ext2[0] = extLine2End.x; |
| | ext2[1] = extLine2End.y; |
| | ext2[2] = extLine2End.z; |
| | double apex[3] = {0, 0, 0}; |
| | apex[0] = apexPoint.x; |
| | apex[1] = apexPoint.y; |
| | apex[2] = apexPoint.z; |
| | writeAngularDim(text, line, apex, ext1, apex, ext2, dimText); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportRadialDim( |
| | Base::Vector3d centerPoint, |
| | Base::Vector3d textLocn, |
| | Base::Vector3d arcPoint, |
| | char* dimText |
| | ) |
| | { |
| | double center[3] = {0, 0, 0}; |
| | center[0] = centerPoint.x; |
| | center[1] = centerPoint.y; |
| | center[2] = centerPoint.z; |
| | double text[3] = {0, 0, 0}; |
| | text[0] = textLocn.x; |
| | text[1] = textLocn.y; |
| | text[2] = textLocn.z; |
| | double arc[3] = {0, 0, 0}; |
| | arc[0] = arcPoint.x; |
| | arc[1] = arcPoint.y; |
| | arc[2] = arcPoint.z; |
| | writeRadialDim(center, text, arc, dimText); |
| | } |
| |
|
| | void ImpExpDxfWrite::exportDiametricDim( |
| | Base::Vector3d textLocn, |
| | Base::Vector3d arcPoint1, |
| | Base::Vector3d arcPoint2, |
| | char* dimText |
| | ) |
| | { |
| | double text[3] = {0, 0, 0}; |
| | text[0] = textLocn.x; |
| | text[1] = textLocn.y; |
| | text[2] = textLocn.z; |
| | double arc1[3] = {0, 0, 0}; |
| | arc1[0] = arcPoint1.x; |
| | arc1[1] = arcPoint1.y; |
| | arc1[2] = arcPoint1.z; |
| | double arc2[3] = {0, 0, 0}; |
| | arc2[0] = arcPoint2.x; |
| | arc2[1] = arcPoint2.y; |
| | arc2[2] = arcPoint2.z; |
| | writeDiametricDim(text, arc1, arc2, dimText); |
| | } |
| |
|
| | Py::Object ImpExpDxfRead::getStatsAsPyObject() |
| | { |
| | |
| | Py::Dict statsDict; |
| |
|
| | |
| | statsDict.setItem("dxfVersion", Py::String(m_stats.dxfVersion)); |
| | statsDict.setItem("dxfEncoding", Py::String(m_stats.dxfEncoding)); |
| | statsDict.setItem("scalingSource", Py::String(m_stats.scalingSource)); |
| | statsDict.setItem("fileUnits", Py::String(m_stats.fileUnits)); |
| | statsDict.setItem("finalScalingFactor", Py::Float(m_stats.finalScalingFactor)); |
| | statsDict.setItem("importTimeSeconds", Py::Float(m_stats.importTimeSeconds)); |
| | statsDict.setItem("totalEntitiesCreated", Py::Long(m_stats.totalEntitiesCreated)); |
| |
|
| | |
| | Py::Dict entityCountsDict; |
| | for (const auto& pair : m_stats.entityCounts) { |
| | entityCountsDict.setItem(pair.first.c_str(), Py::Long(pair.second)); |
| | } |
| | statsDict.setItem("entityCounts", entityCountsDict); |
| |
|
| | |
| | Py::Dict importSettingsDict; |
| | for (const auto& pair : m_stats.importSettings) { |
| | importSettingsDict.setItem(pair.first.c_str(), Py::String(pair.second)); |
| | } |
| | statsDict.setItem("importSettings", importSettingsDict); |
| |
|
| | |
| | Py::Dict unsupportedFeaturesDict; |
| | for (const auto& pair : m_stats.unsupportedFeatures) { |
| | Py::List occurrencesList; |
| | for (const auto& occurrence : pair.second) { |
| | Py::Tuple infoTuple(2); |
| | infoTuple.setItem(0, Py::Long(occurrence.first)); |
| | infoTuple.setItem(1, Py::String(occurrence.second)); |
| | occurrencesList.append(infoTuple); |
| | } |
| | unsupportedFeaturesDict.setItem(pair.first.c_str(), occurrencesList); |
| | } |
| | statsDict.setItem("unsupportedFeatures", unsupportedFeaturesDict); |
| |
|
| | |
| | Py::Dict systemBlockCountsDict; |
| | for (const auto& pair : m_stats.systemBlockCounts) { |
| | systemBlockCountsDict.setItem(pair.first.c_str(), Py::Long(pair.second)); |
| | } |
| | statsDict.setItem("systemBlockCounts", systemBlockCountsDict); |
| |
|
| | |
| | return statsDict; |
| | } |
| |
|