diff --git a/src/Mod/Sketcher/App/GeoEnum.h b/src/Mod/Sketcher/App/GeoEnum.h index 5c6c0a7309..ea58f7164f 100644 --- a/src/Mod/Sketcher/App/GeoEnum.h +++ b/src/Mod/Sketcher/App/GeoEnum.h @@ -68,7 +68,7 @@ enum GeoEnum HAxis = -1, // GeoId of the Horizontal Axis VAxis = -2, // GeoId of the Vertical Axis RefExt = -3,// Starting GeoID of external geometry ( negative geoIds starting at this index) - GeoUndef = -2000,// GeoId of an undefined Geometry (uninitialised or unused GeoId) + GeoUndef = -2000// GeoId of an undefined Geometry (uninitialised or unused GeoId) }; /*! diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 1ee51bf747..5fc7bdcbf4 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -57,11 +58,16 @@ #include #endif +#include + #include #include +#include #include #include #include +#include +#include #include #include #include @@ -73,6 +79,7 @@ #include #include #include +#include #include "SketchObject.h" #include "SketchObjectPy.h" @@ -238,6 +245,64 @@ App::DocumentObjectExecReturn* SketchObject::execute() return App::DocumentObject::StdReturn; } +void SketchObject::buildShape() +{ + // Shape.setValue(solvedSketch.toShape()); + // We use the following instead to map element names + + std::vector shapes; + std::vector vertices; + int i=0; + for(auto geo : getInternalGeometry()) { + ++i; + if(GeometryFacade::getConstruction(geo)) + continue; + if (geo->isDerivedFrom(Part::GeomPoint::getClassTypeId())) { + vertices.emplace_back(TopoDS::Vertex(geo->toShape())); + int idx = getVertexIndexGeoPos(i-1, PointPos::start); + std::string name = convertSubName(Data::IndexedName::fromConst("Vertex", idx+1), false); + // vertices.back().setElementName(Data::IndexedName::fromConst("Vertex", 1), + // Data::MappedName::fromRawData(name.c_str())); + } else + shapes.push_back(getEdge(geo,convertSubName( + Data::IndexedName::fromConst("Edge", i), false).c_str())); + } + + // FIXME: Commented since ExternalGeometryFacade is not added + // for(i=2;itestFlag(ExternalGeometryExtension::Defining)) + // continue; + // shapes.push_back(getEdge(geo, convertSubName( + // Data::IndexedName::fromConst("ExternalEdge", i-1), false).c_str())); + // } + // if(shapes.empty() && vertices.empty()) + // Shape.setValue(Part::TopoShape()); + // else if (vertices.empty()) { + // // Notice here we supply op code Part::OpCodes::Sketch to makEWires(). + // Shape.setValue(Part::TopoShape().makEWires(shapes,Part::OpCodes::Sketch)); + // } else { + // std::vector results; + // if (!shapes.empty()) { + // // This call of makEWires() does not have the op code, in order to + // // avoid duplication. Because we'll going to make a compound (to + // // include the vertices) below with the same op code. + // // + // // Note, that we HAVE TO add the Part::OpCodes::Sketch op code to all + // // geometry exposed through the Shape property, because + // // SketchObject::getElementName() relies on this op code to + // // differentiate geometries that are exposed with those in edit + // // mode. + // auto wires = Part::TopoShape().makEWires(shapes); + // for (const auto &wire : wires.getSubTopoShapes(TopAbs_WIRE)) + // results.push_back(wire); + // } + // results.insert(results.end(), vertices.begin(), vertices.end()); + // Shape.setValue(Part::TopoShape().makECompound(results, Part::OpCodes::Sketch)); + // } +} + int SketchObject::hasConflicts() const { if (lastDoF < 0)// over-constrained sketch @@ -766,81 +831,81 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP return lastSolverStatus; } -Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const +Base::Vector3d SketchObject::getPoint(const Part::Geometry *geo, PointPos PosId) { - if (!(GeoId == H_Axis || GeoId == V_Axis - || (GeoId <= getHighestCurveIndex() && GeoId >= -getExternalGeometryCount()))) - throw Base::ValueError("SketchObject::getPoint. Invalid GeoId was supplied."); - const Part::Geometry* geo = getGeometry(GeoId); if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) { - const Part::GeomPoint* p = static_cast(geo); + const Part::GeomPoint *p = static_cast(geo); if (PosId == PointPos::start || PosId == PointPos::mid || PosId == PointPos::end) return p->getPoint(); - } - else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { - const Part::GeomLineSegment* lineSeg = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg = static_cast(geo); if (PosId == PointPos::start) return lineSeg->getStartPoint(); else if (PosId == PointPos::end) return lineSeg->getEndPoint(); - } - else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { - const Part::GeomCircle* circle = static_cast(geo); - if (PosId == PointPos::mid) - return circle->getCenter(); - } - else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { - const Part::GeomEllipse* ellipse = static_cast(geo); - if (PosId == PointPos::mid) - return ellipse->getCenter(); - } - else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { - const Part::GeomArcOfCircle* aoc = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = static_cast(geo); + auto pt = circle->getCenter(); + if(PosId != PointPos::mid) + pt.x += circle->getRadius(); + return pt; + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + const Part::GeomEllipse *ellipse = static_cast(geo); + auto pt = ellipse->getCenter(); + if(PosId != PointPos::mid) + pt += ellipse->getMajorAxisDir()*ellipse->getMajorRadius(); + return pt; + } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *aoc = static_cast(geo); if (PosId == PointPos::start) return aoc->getStartPoint(/*emulateCCW=*/true); else if (PosId == PointPos::end) return aoc->getEndPoint(/*emulateCCW=*/true); else if (PosId == PointPos::mid) return aoc->getCenter(); - } - else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { - const Part::GeomArcOfEllipse* aoc = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoc = static_cast(geo); if (PosId == PointPos::start) return aoc->getStartPoint(/*emulateCCW=*/true); else if (PosId == PointPos::end) return aoc->getEndPoint(/*emulateCCW=*/true); else if (PosId == PointPos::mid) return aoc->getCenter(); - } - else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { - const Part::GeomArcOfHyperbola* aoh = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *aoh = static_cast(geo); if (PosId == PointPos::start) return aoh->getStartPoint(); else if (PosId == PointPos::end) return aoh->getEndPoint(); else if (PosId == PointPos::mid) return aoh->getCenter(); - } - else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { - const Part::GeomArcOfParabola* aop = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = static_cast(geo); if (PosId == PointPos::start) return aop->getStartPoint(); else if (PosId == PointPos::end) return aop->getEndPoint(); else if (PosId == PointPos::mid) return aop->getCenter(); - } - else if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { - const Part::GeomBSplineCurve* bsp = static_cast(geo); + } else if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + const Part::GeomBSplineCurve *bsp = static_cast(geo); if (PosId == PointPos::start) return bsp->getStartPoint(); else if (PosId == PointPos::end) return bsp->getEndPoint(); } - return Base::Vector3d(); } +Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const +{ + if (!(GeoId == H_Axis || GeoId == V_Axis + || (GeoId <= getHighestCurveIndex() && GeoId >= -getExternalGeometryCount()))) + throw Base::ValueError("SketchObject::getPoint. Invalid GeoId was supplied."); + const Part::Geometry* geo = getGeometry(GeoId); + return getPoint(geo,PosId); +} + int SketchObject::getAxisCount() const { const std::vector& vals = getInternalGeometry(); @@ -9262,6 +9327,115 @@ void SketchObject::setExpression(const App::ObjectIdentifier& path, } } +Part::TopoShape SketchObject::getEdge(const Part::Geometry *geo, const char *name) const +{ + Part::TopoShape shape(geo->toShape()); + // shape.setElementName(Data::IndexedName::fromConst("Edge", 1), + // Data::MappedName::fromRawData(name)); + TopTools_IndexedMapOfShape vmap; + TopExp::MapShapes(shape.getShape(), TopAbs_VERTEX, vmap); + std::ostringstream ss; + for(int i=1;i<=vmap.Extent();++i) { + auto gpt = BRep_Tool::Pnt(TopoDS::Vertex(vmap(i))); + Base::Vector3d pt(gpt.X(),gpt.Y(),gpt.Z()); + PointPos pos[] = {PointPos::start,PointPos::end}; + for(size_t j=0;j(pos[j]); + // shape.setElementName(Data::IndexedName::fromConst("Vertex", i), + // Data::MappedName::fromRawData(ss.str().c_str())); + break; + } + } + } + return shape; +} + +Data::IndexedName SketchObject::checkSubName(const char *sub) const +{ + // FIXME: trivial implementation needs to be replaced with full logic + (void)sub; + return Data::IndexedName(); +} + +bool SketchObject::geoIdFromShapeType(const Data::IndexedName & indexedName, + int &geoId, + PointPos &posId) const +{ + posId = PointPos::none; + geoId = Sketcher::GeoEnum::GeoUndef; + if (!indexedName) + return false; + const char *shapetype = indexedName.getType(); + if (boost::equals(shapetype,"Edge") || + boost::equals(shapetype,"edge")) { + geoId = indexedName.getIndex() - 1; + } else if (boost::equals(shapetype,"ExternalEdge")) { + geoId = indexedName.getIndex() - 1; + geoId = Sketcher::GeoEnum::RefExt - geoId; + } else if (boost::equals(shapetype,"Vertex") || + boost::equals(shapetype,"vertex")) { + int VtId = indexedName.getIndex() - 1; + getGeoVertexIndex(VtId,geoId,posId); + if (posId==PointPos::none) return false; + } else if (boost::equals(shapetype,"H_Axis")) { + geoId = Sketcher::GeoEnum::HAxis; + } else if (boost::equals(shapetype,"V_Axis")) { + geoId = Sketcher::GeoEnum::VAxis; + } else if (boost::equals(shapetype,"RootPoint")) { + geoId = Sketcher::GeoEnum::RtPnt; + posId = PointPos::start; + } else + return false; + return true; +} + +std::string SketchObject::convertSubName(const Data::IndexedName & indexedName, bool postfix) const +{ + std::ostringstream ss; + int geoId; + PointPos posId; + if(!geoIdFromShapeType(indexedName,geoId,posId)) { + ss << indexedName; + return ss.str(); + } + if(geoId == Sketcher::GeoEnum::HAxis || + geoId == Sketcher::GeoEnum::VAxis || + geoId == Sketcher::GeoEnum::RtPnt) { + if (postfix) + ss << Data::ELEMENT_MAP_PREFIX; + ss << indexedName; + if(postfix) + ss << '.' << indexedName; + return ss.str(); + } + + auto geo = getGeometry(geoId); + if(!geo) { + std::string res = indexedName.toString(); + return res; + } + if (postfix) + ss << Data::ELEMENT_MAP_PREFIX; + ss << (geoId>=0?'g':'e') << GeometryFacade::getFacade(geo)->getId(); + if(posId!=PointPos::none) + ss << 'v' << static_cast(posId); + if(postfix) { + // rename Edge to edge, and Vertex to vertex to avoid ambiguous of + // element mapping of the public shape and internal geometry. + if (indexedName.getIndex() <= 0) + ss << '.' << indexedName; + else if(boost::starts_with(indexedName.getType(),"Edge")) + ss << ".e" << (indexedName.getType()+1) << indexedName.getIndex(); + else if(boost::starts_with(indexedName.getType(),"Vertex")) + ss << ".v" << (indexedName.getType()+1) << indexedName.getIndex(); + else + ss << '.' << indexedName; + } + return ss.str(); +} + int SketchObject::autoConstraint(double precision, double angleprecision, bool includeconstruction) { return analyser->autoconstraint(precision, angleprecision, includeconstruction); diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index e00df5403c..5c48610ff3 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -24,6 +24,7 @@ #define SKETCHER_SKETCHOBJECT_H #include +#include #include #include #include @@ -272,6 +273,7 @@ public: int movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative = false, bool updateGeoBeforeMoving = false); /// retrieves the coordinates of a point + static Base::Vector3d getPoint(const Part::Geometry *geo, PointPos PosId); Base::Vector3d getPoint(int GeoId, PointPos PosId) const; /// toggle geometry to draft line @@ -597,6 +599,35 @@ public: bool isCarbonCopyAllowed(App::Document* pDoc, App::DocumentObject* pObj, bool& xinv, bool& yinv, eReasonList* rsn = nullptr) const; + Part::TopoShape getEdge(const Part::Geometry *geo, const char *name) const; + + Data::IndexedName checkSubName(const char *sub) const; + + bool geoIdFromShapeType(const Data::IndexedName &, int &geoId, PointPos &posId) const; + + bool geoIdFromShapeType(const char *shapetype, int &geoId, PointPos &posId) const + { + return geoIdFromShapeType(checkSubName(shapetype), geoId, posId); + } + + bool geoIdFromShapeType(const char *shapetype, int &geoId) const + { + PointPos posId; + return geoIdFromShapeType(shapetype,geoId,posId); + } + + std::string convertSubName(const char *subname, bool postfix=true) const + { + return convertSubName(checkSubName(subname), postfix); + } + + std::string convertSubName(const std::string & subname, bool postfix=true) const + { + return convertSubName(subname.c_str(), postfix); + } + + std::string convertSubName(const Data::IndexedName &, bool postfix=true) const; + bool isPerformingInternalTransaction() const { return internaltransaction; @@ -654,6 +685,8 @@ protected: void onDocumentRestored() override; void restoreFinished() override; + void buildShape(); + void setExpression(const App::ObjectIdentifier& path, std::shared_ptr expr) override;