#include "SketchFeature.h" #include "SketchObject.h" #include "SketchLine.h" #include "SketchRectangle.h" #include "SketchCircle.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SketchFeature::SketchFeature(const QString& name) : Feature(name) { } SketchFeature::~SketchFeature() { qDeleteAll(m_objects); } QString SketchFeature::type() const { return "Sketch"; } void SketchFeature::setPlane(SketchPlane plane) { m_plane = plane; } SketchFeature::SketchPlane SketchFeature::plane() const { return m_plane; } const TopoDS_Shape& SketchFeature::shape() const { return m_shape; } void SketchFeature::buildShape() { m_shape.Nullify(); QList lineEdges; QList faces; gp_Pln sketchPlane; switch (m_plane) { case SketchPlane::XY: sketchPlane = gp_Pln(gp::Origin(), gp::DY()); break; case SketchPlane::XZ: sketchPlane = gp_Pln(gp::Origin(), gp::DZ()); break; case SketchPlane::YZ: sketchPlane = gp_Pln(gp::Origin(), gp::DX()); break; } for (SketchObject* obj : m_objects) { if (auto line = dynamic_cast(obj)) { BRepBuilderAPI_MakeEdge makeEdge(line->startPoint(), line->endPoint()); if (makeEdge.IsDone()) { lineEdges.append(makeEdge.Edge()); } } else if (auto rect = dynamic_cast(obj)) { const gp_Pnt& c1 = rect->corner1(); const gp_Pnt& c2 = rect->corner2(); gp_Pnt other_corner1, other_corner2; if (m_plane == SketchPlane::XY) { other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z()); other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z()); } else if (m_plane == SketchPlane::XZ) { other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z()); other_corner2.SetCoord(c1.X(), c2.Y(), c1.Z()); } else { // YZ other_corner1.SetCoord(c1.X(), c2.Y(), c1.Z()); other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z()); } BRepBuilderAPI_MakeEdge me1(c1, other_corner1); BRepBuilderAPI_MakeEdge me2(other_corner1, c2); BRepBuilderAPI_MakeEdge me3(c2, other_corner2); BRepBuilderAPI_MakeEdge me4(other_corner2, c1); if (me1.IsDone() && me2.IsDone() && me3.IsDone() && me4.IsDone()) { BRepBuilderAPI_MakeWire wireBuilder(me1.Edge(), me2.Edge(), me3.Edge(), me4.Edge()); if (wireBuilder.IsDone()) { BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire()); if (faceBuilder.IsDone()) { faces.append(faceBuilder.Face()); } } } } else if (auto circle = dynamic_cast(obj)) { const gp_Pnt& center = circle->center(); double radius = circle->radius(); gp_Dir normal; switch (m_plane) { case SketchPlane::XY: normal = gp::DY(); break; case SketchPlane::XZ: normal = gp::DZ(); break; case SketchPlane::YZ: normal = gp::DX(); break; } gp_Ax2 axis(center, normal); gp_Circ circ(axis, radius); BRepBuilderAPI_MakeEdge makeEdge(circ); if (makeEdge.IsDone()) { TopoDS_Edge edge = makeEdge.Edge(); BRepBuilderAPI_MakeWire wireBuilder(edge); if(wireBuilder.IsDone()) { BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire()); if (faceBuilder.IsDone()) { faces.append(faceBuilder.Face()); } } } } } if (!lineEdges.isEmpty()) { qDebug() << "buildShape: processing" << lineEdges.size() << "line edges"; BRepOffsetAPI_MakeFilling faceMaker; for (const TopoDS_Edge& edge : lineEdges) { faceMaker.Add(edge, GeomAbs_C0); } faceMaker.Build(); if (faceMaker.IsDone()) { TopExp_Explorer explorer(faceMaker.Shape(), TopAbs_FACE); int facesAdded = 0; for (; explorer.More(); explorer.Next()) { faces.append(TopoDS::Face(explorer.Current())); facesAdded++; } qDebug() << "buildShape: added" << facesAdded << "face(s) using MakeFilling"; } else { qDebug() << "buildShape: MakeFilling failed"; } } qDebug() << "buildShape: total faces created:" << faces.size(); if (faces.isEmpty()) { return; } if (faces.size() == 1) { m_shape = faces.first(); } else { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); for (const auto& face : faces) { builder.Add(compound, face); } m_shape = compound; } } void SketchFeature::addObject(SketchObject* object) { m_objects.append(object); } const QList& SketchFeature::objects() const { return m_objects; } void SketchFeature::read(const QJsonObject& json) { Feature::read(json); if (json.contains("plane") && json["plane"].isString()) { QString planeStr = json["plane"].toString(); if (planeStr == "XY") m_plane = SketchPlane::XY; else if (planeStr == "XZ") m_plane = SketchPlane::XZ; else if (planeStr == "YZ") m_plane = SketchPlane::YZ; } if (json.contains("objects") && json["objects"].isArray()) { QJsonArray objectsArray = json["objects"].toArray(); qDeleteAll(m_objects); m_objects.clear(); for (const QJsonValue& value : objectsArray) { QJsonObject objectJson = value.toObject(); if (objectJson.contains("type") && objectJson["type"].isString()) { QString type = objectJson["type"].toString(); if (type == "Line") { auto line = new SketchLine(); line->read(objectJson); m_objects.append(line); } else if (type == "Rectangle") { auto rect = new SketchRectangle(); rect->read(objectJson); m_objects.append(rect); } } } } } void SketchFeature::write(QJsonObject& json) const { Feature::write(json); QString planeStr; switch (m_plane) { case SketchPlane::XY: planeStr = "XY"; break; case SketchPlane::XZ: planeStr = "XZ"; break; case SketchPlane::YZ: planeStr = "YZ"; break; } json["plane"] = planeStr; QJsonArray objectsArray; for (const auto& object : m_objects) { QJsonObject objectJson; object->write(objectJson); objectsArray.append(objectJson); } json["objects"] = objectsArray; }