diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index 426ed43610..d1819cb551 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -4783,12 +4783,10 @@ TopoShape& TopoShape::makeElementRefine(const TopoShape& shape, const char* op, return {}; std::vector res; - int type = shape.shapeType(); - for(;;) { - if(--type < 0) - break; - const char *shapetype = shapeName((TopAbs_ShapeEnum)type).c_str(); - for(int idx : findAncestors(shape.getShape(), (TopAbs_ShapeEnum)type)) + + for (int type = shape.shapeType() - 1; type >= 0; type--) { + const char* shapetype = shapeName((TopAbs_ShapeEnum)type).c_str(); + for (int idx : findAncestors(shape.getShape(), (TopAbs_ShapeEnum)type)) res.emplace_back(shapetype, idx); } return res; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index ff8705c54b..3991507434 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -161,16 +161,6 @@ SketchObject::SketchObject() "Sketch", (App::PropertyType)(App::Prop_None), "Tolerance for fitting arcs of projected external geometry"); - // ADD_PROPERTY_TYPE(ExternalBSplineMaxDegree, - // (0), - // "Sketch", - // (App::Prop_None), - // "Maximum degree of imported external BSpline. Zero to disable simplification"); - // ADD_PROPERTY_TYPE(ExternalBSplineTolerance, - // (0.0), - // "Sketch", - // (App::Prop_None), - // "Tolerance for simplifying imported external BSpline"); geoLastId = 0; ADD_PROPERTY(InternalShape, @@ -186,22 +176,6 @@ SketchObject::SketchObject() allowOtherBody = true; allowUnaligned = true; -// for (std::vector::iterator it = ExternalGeo.begin(); it != ExternalGeo.end(); -// ++it) -// if (*it) -// delete *it; -// ExternalGeo.clear(); -// auto HLine = GeometryTypedFacade::getTypedFacade(); -// auto VLine = GeometryTypedFacade::getTypedFacade(); -// HLine->getTypedGeometry()->setPoints(Base::Vector3d(0, 0, 0), Base::Vector3d(1, 0, 0)); -// VLine->getTypedGeometry()->setPoints(Base::Vector3d(0, 0, 0), Base::Vector3d(0, 1, 0)); -// HLine->setConstruction(true); -// VLine->setConstruction(true); -// ExternalGeo.push_back(HLine->getGeometry()); -// ExternalGeo.push_back(VLine->getGeometry()); -// HLine->setOwner(false);// we have transferred the ownership to ExternalGeo -// VLine->setOwner(false);// we have transferred the ownership to ExternalGeo - initExternalGeo(); rebuildVertexIndex(); @@ -236,14 +210,7 @@ SketchObject::SketchObject() registerElementCache(internalPrefix(), &InternalShape); } -SketchObject::~SketchObject() -{ -// for (std::vector::iterator it = ExternalGeo.begin(); it != ExternalGeo.end(); -// ++it) -// if (*it) -// delete *it; -// ExternalGeo.clear(); - +SketchObject::~SketchObject() { delete analyser; } @@ -252,8 +219,6 @@ void SketchObject::setupObject() ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Sketcher"); ArcFitTolerance.setValue(hGrpp->GetFloat("ArcFitTolerance", Precision::Confusion()*10.0)); -// ExternalBSplineMaxDegree.setValue(hGrpp->GetInt("ExternalBSplineMaxDegree", 5)); -// ExternalBSplineTolerance.setValue(hGrpp->GetFloat("ExternalBSplineTolerance", 1e-4)); MakeInternals.setValue(hGrpp->GetBool("MakeInternals", false)); inherited::setupObject(); } @@ -346,8 +311,7 @@ App::DocumentObjectExecReturn* SketchObject::execute() return App::DocumentObject::StdReturn; } -static bool inline checkSmallEdge(const Part::TopoShape &s) -{ +static bool inline checkSmallEdge(const Part::TopoShape &s) { if (s.shapeType() != TopAbs_EDGE) return false; BRepAdaptor_Curve adapt(TopoDS::Edge(s.getShape())); @@ -401,7 +365,6 @@ void SketchObject::buildShape() { #endif } - // FIXME: Commented since ExternalGeometryFacade is not added for(size_t i=2;i geomlist = solvedSketch.extractGeometry(); -// Geometry.setValues(geomlist); -// for (std::vector::iterator it = geomlist.begin(); it != geomlist.end(); -// ++it) -// if (*it) -// delete *it; Part::PropertyGeometryList tmp; tmp.setValues(std::move(geomlist)); // Only set values if there is actual changes @@ -1349,6 +1307,10 @@ int SketchObject::toggleVirtualSpace(int ConstrId) this->Constraints.setValues(std::move(newVals)); + // Solver didn't actually update, but we need this to inform view provider + // to redraw + signalSolverUpdate(); + return 0; } @@ -1925,26 +1887,109 @@ int SketchObject::setConstruction(int GeoId, bool on) // no need to check input data validity as this is an sketchobject managed operation. Base::StateLocker lock(managedoperation, true); +#ifdef FC_USE_TNP_FIX + Part::PropertyGeometryList *prop; + int idx; + if (GeoId >= 0) { + prop = &Geometry; + if (GeoId < Geometry.getSize()) + idx = GeoId; + else + return -1; + }else if (GeoId <= GeoEnum::RefExt && -GeoId-1 < ExternalGeo.getSize()) { + prop = &ExternalGeo; + idx = -GeoId-1; + }else + return -1; +#else const std::vector& vals = getInternalGeometry(); if (GeoId < 0 || GeoId >= int(vals.size())) return -1; if (getGeometryFacade(GeoId)->isInternalAligned()) return -1; +#endif // While it may seem that there is not a need to trigger an update at this time, because the // solver has its own copy of the geometry, and updateColors of the viewprovider may be // triggered by the clearselection of the UI command, this won't update the elements widget, in // the accumulative of actions it is judged that it is worth to trigger an update here. +#ifdef FC_USE_TNP_FIX + std::unique_ptr geo(prop->getValues()[idx]->clone()); + if(prop == &Geometry) + GeometryFacade::setConstruction(geo.get(), on); + else { + auto egf = ExternalGeometryFacade::getFacade(geo.get()); + egf->setFlag(ExternalGeometryExtension::Defining, on); + } + + prop->set1Value(idx,std::move(geo)); + +#else std::unique_ptr geo(vals[GeoId]->clone()); GeometryFacade::setConstruction(geo.get(), on); this->Geometry.set1Value(GeoId, std::move(geo)); - +#endif solverNeedsUpdate = true; return 0; } +int SketchObject::toggleExternalGeometryFlag(const std::vector &geoIds, + const std::vector &flags) +{ + if (flags.empty()) + return 0; + auto flag = flags.front(); + + Base::StateLocker lock(managedoperation, true); // no need to check input data validity as this is an sketchobject managed operation. + + bool update = false; + bool touched = false; + auto geos = ExternalGeo.getValues(); + std::set idSet(geoIds.begin(),geoIds.end()); + for(auto geoId : geoIds) { + if(geoId > GeoEnum::RefExt || -geoId-1>=ExternalGeo.getSize()) + continue; + if(!idSet.count(geoId)) + continue; + idSet.erase(geoId); + int idx = -geoId-1; + auto &geo = geos[idx]; + auto egf = ExternalGeometryFacade::getFacade(geo); + bool value = !egf->testFlag(flag); + if(egf->getRef().size()) { + for(auto gid : getRelatedGeometry(geoId)) { + if(gid == geoId) + continue; + int idx = -gid-1; + auto &g = geos[idx]; + g = g->clone(); + auto egf = ExternalGeometryFacade::getFacade(g); + egf->setFlag(flag, value); + for (size_t i=1; isetFlag(flags[i], value); + idSet.erase(gid); + } + } + geo = geo->clone(); + egf->setGeometry(geo); + egf->setFlag(flag, value); + for (size_t i=1; isetFlag(flags[i], value); + if (value || flag != ExternalGeometryExtension::Frozen) + update = true; + touched = true; + } + + if(!touched) + return -1; + ExternalGeo.setValues(geos); + if (update) + rebuildExternalGeometry(); + return 0; +} + void SketchObject::addGeometryState(const Constraint* cstr) const { const std::vector& vals = getInternalGeometry(); @@ -4780,9 +4825,6 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId, } // add the geometry -// std::map geoIdMap; -// std::map isStartEndInverted; -// std::vector newgeoVals(getInternalGeometry()); std::vector symmetricVals = getSymmetric(geoIdList, geoIdMap, isStartEndInverted, refGeoId, refPosId); newgeoVals.insert(newgeoVals.end(), symmetricVals.begin(), symmetricVals.end()); @@ -5147,7 +5189,6 @@ std::vector SketchObject::getSymmetric(const std::vector& auto* geosymaoe = static_cast(geosym); Base::Vector3d cp = geosymaoe->getCenter(); - // double df= geosymaoe->getFocal(); Base::Vector3d f1 = geosymaoe->getFocus(); Base::Vector3d sf1 = @@ -5342,7 +5383,6 @@ std::vector SketchObject::getSymmetric(const std::vector& geosymbsp->setPoles(poles); - // isStartEndInverted.insert(std::make_pair(geoId, false)); } else if (geosym->is()) { auto* geosympoint = static_cast(geosym); @@ -6878,7 +6918,6 @@ bool SketchObject::convertToNURBS(int GeoId) Base::StateLocker lock(managedoperation, true); if (GeoId > getHighestCurveIndex() -// || (GeoId < 0 && -GeoId > static_cast(ExternalGeo.size())) || GeoId == -1 || (GeoId < 0 && -GeoId > static_cast(ExternalGeo.getSize())) || GeoId == -1 || GeoId == -2) return false; @@ -7715,7 +7754,6 @@ int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName, boo // set the Link list. ExternalGeometry.setValues(Objects, SubElements); try { -// rebuildExternalGeometry(); rebuildExternalGeometry(defining, intersection); } catch (const Base::Exception& e) { @@ -8014,7 +8052,6 @@ int SketchObject::attachExternal( } auto geos = ExternalGeo.getValues(); -// auto geos = ExternalGeo; std::vector Objects = ExternalGeometry.getValues(); auto itObj = Objects.begin(); @@ -8026,7 +8063,7 @@ int SketchObject::attachExternal( for(auto &key : externalGeoRef) { if (*itObj == Obj && *itSub == SubName){ - FC_ERR("Duplicdate external element reference in " << getFullName() << ": " << key); + FC_ERR("Duplicate external element reference in " << getFullName() << ": " << key); return -1; } // detach old reference @@ -8062,7 +8099,6 @@ int SketchObject::attachExternal( std::vector SketchObject::getRelatedGeometry(int GeoId) const { std::vector res; if(GeoId>GeoEnum::RefExt || -GeoId-1>=ExternalGeo.getSize()) -// if(GeoId>GeoEnum::RefExt || -GeoId-1>=ExternalGeo.size()) return res; auto geo = getGeometry(GeoId); if(!geo) @@ -8084,7 +8120,6 @@ std::vector SketchObject::getRelatedGeometry(int GeoId) const { int SketchObject::syncGeometry(const std::vector &geoIds) { bool touched = false; auto geos = ExternalGeo.getValues(); -// auto geos = ExternalGeo; std::set idSet; for(int geoId : geoIds) { auto geo = getGeometry(geoId); @@ -8095,7 +8130,6 @@ int SketchObject::syncGeometry(const std::vector &geoIds) { } for(int geoId : idSet) { if(geoId <= GeoEnum::RefExt && -geoId-1 < ExternalGeo.getSize()) { -// if(geoId <= GeoEnum::RefExt && -geoId-1 < ExternalGeo.size()) { auto &geo = geos[-geoId-1]; geo = geo->clone(); ExternalGeometryFacade::getFacade(geo)->setFlag(ExternalGeometryExtension::Sync); @@ -8115,7 +8149,6 @@ const Part::Geometry* SketchObject::_getGeometry(int GeoId) const return geomlist[GeoId]; } else if (GeoId < 0 && -GeoId-1 < ExternalGeo.getSize()) -// else if (GeoId < 0 && -GeoId-1 < ExternalGeo.size()) return ExternalGeo[-GeoId-1]; return nullptr; @@ -8127,7 +8160,6 @@ int SketchObject::getCompleteGeometryIndex(int GeoId) const if (GeoId < int(Geometry.getSize())) return GeoId; } -// else if (-GeoId <= int(ExternalGeo.size())) else if (-GeoId <= int(ExternalGeo.getSize())) return -GeoId - 1; @@ -8136,7 +8168,6 @@ int SketchObject::getCompleteGeometryIndex(int GeoId) const int SketchObject::getGeoIdFromCompleteGeometryIndex(int completeGeometryIndex) const { -// int completeGeometryCount = int(Geometry.getSize() + ExternalGeo.size()); int completeGeometryCount = int(Geometry.getSize() + ExternalGeo.getSize()); if (completeGeometryIndex < 0 || completeGeometryIndex >= completeGeometryCount) @@ -8258,14 +8289,14 @@ Part::Geometry* projectLine(const BRepAdaptor_Curve& curve, const Handle(Geom_Pl // Project an edge to a line. Only works if the edge is planar and its plane is // perpendicular to the projection plane. This function is to work around OCC -// normal projection bug which seems to only repsect the start and ending points +// normal projection bug which seems to only respect the start and ending points // of an arc but disregarding any extreme points. OCC also has trouble handling // BSpline projection to a straight line. Although it does correctly projects // the line including extreme bounds, it will produce a BSpline with degree // more than one. // // The work around here is to use an aligned bounding box of the edge to get -// the projection of the extremem points to construct the projected line. +// the projection of the extreme points to construct the projected line. Part::Geometry* projectEdgeToLine(const TopoDS_Edge &edge, const Base::Placement& invPlm) { @@ -8342,7 +8373,7 @@ void getParameterRange(Handle(Geom_Curve) curve, // The reason of this function is because the first/last parameter reported // from some curve does not really corresponds to the first/last vertex of // the edge. I can only guess this is because the curve (in some cases) is - // actually computed on demaond from surface (in BRepAdaptor_Curve maybe). + // actually computed on demand from surface (in BRepAdaptor_Curve maybe). // And in the process, there is something off in tolerance causing the // derived parameter not matching the value corresponding to the position of // the actual vertex. @@ -8364,7 +8395,7 @@ void adjustParameterRange(const TopoDS_Edge &edge, // lower arc. Because projection orientation may swap the first and last // parameter of the original curve. // - // We project the middel point of the original curve to the projected curve + // We project the middle point of the original curve to the projected curve // to decide whether to flip the parameters. Handle(Geom_Curve) origCurve = BRepAdaptor_Curve(edge).Curve().Curve(); @@ -8589,13 +8620,13 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) auto obj = getDocument()->getObject(objName.c_str()); if(!obj) continue; - std::pair elementName; + App::ElementNamePair elementName; App::GeoFeature::resolveElement(obj,ref.c_str()+pos+1,elementName); - if(elementName.second.size() - && !App::GeoFeature::hasMissingElement(elementName.second.c_str())) + if(elementName.oldName.size() + && !App::GeoFeature::hasMissingElement(elementName.oldName.c_str())) { Objects.push_back(obj); - SubElements.push_back(elementName.second); + SubElements.push_back(elementName.oldName); keys.push_back(ref); } } @@ -8656,8 +8687,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) frozen = true; if(egf->testFlag(ExternalGeometryExtension::Sync)) sync = true; -// if (egf->testFlag(ExternalGeometryExtension::Intersection)) -// intersection = true; } } if(frozen && !sync) { @@ -8745,7 +8774,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) BRepAdaptor_Curve curve(edge); if (curve.GetType() == GeomAbs_Line) { geos.emplace_back(projectLine(curve, gPlane, invPlm)); -// ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); } } } @@ -8763,7 +8791,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) const TopoDS_Edge& edge = TopoDS::Edge(refSubShape); BRepAdaptor_Curve curve(edge); if (curve.GetType() == GeomAbs_Line) { -// ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); geos.emplace_back(projectLine(curve, gPlane, invPlm)); } else if (curve.GetType() == GeomAbs_Circle) { @@ -8787,7 +8814,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) gCircle->setCenter(Base::Vector3d(cnt.X(), cnt.Y(), cnt.Z())); GeometryFacade::setConstruction(gCircle, true); -// ExternalGeo.push_back(gCircle); geos.emplace_back(gCircle); } else { @@ -8797,7 +8823,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) hCircle, curve.FirstParameter(), curve.LastParameter()); gArc->setHandle(tCurve); GeometryFacade::setConstruction(gArc, true); -// ExternalGeo.push_back(gArc); geos.emplace_back(gArc); } } @@ -8917,7 +8942,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) projectedSegment->setPoints(p1, p2); GeometryFacade::setConstruction(projectedSegment, true); -// ExternalGeo.push_back(projectedSegment); geos.emplace_back(projectedSegment); } else {// general case, full circle @@ -8957,9 +8981,7 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Part::GeomEllipse* ellipse = new Part::GeomEllipse(); ellipse->setHandle(curve); GeometryFacade::setConstruction(ellipse, true); - -// ExternalGeo.push_back(ellipse); - geos.emplace_back(ellipse); + geos.emplace_back(ellipse); } } } @@ -9031,8 +9053,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Part::GeomCircle* circle = new Part::GeomCircle(); circle->setHandle(curve); GeometryFacade::setConstruction(circle, true); - -// ExternalGeo.push_back(circle); geos.emplace_back(circle); } else { @@ -9046,7 +9066,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Base::Vector3d(start.X(), start.Y(), start.Z()), Base::Vector3d(end.X(), end.Y(), end.Z())); GeometryFacade::setConstruction(projectedSegment, true); -// ExternalGeo.push_back(projectedSegment); geos.emplace_back(projectedSegment); } else { @@ -9060,8 +9079,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Part::GeomEllipse* ellipse = new Part::GeomEllipse(); ellipse->setHandle(curve); GeometryFacade::setConstruction(ellipse, true); - -// ExternalGeo.push_back(ellipse); geos.emplace_back(ellipse); } } @@ -9089,14 +9106,12 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Base::Vector3d p = (p1 + p2) / 2; Part::GeomPoint* point = new Part::GeomPoint(p); GeometryFacade::setConstruction(point, true); -// ExternalGeo.push_back(point); geos.emplace_back(point); } else { Part::GeomLineSegment* line = new Part::GeomLineSegment(); line->setPoints(p1, p2); GeometryFacade::setConstruction(line, true); -// ExternalGeo.push_back(line); geos.emplace_back(line); } } @@ -9112,7 +9127,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) circle->setCenter(Base::Vector3d(p.X(), p.Y(), p.Z())); GeometryFacade::setConstruction(circle, true); -// ExternalGeo.push_back(circle); geos.emplace_back(circle); } else { @@ -9124,7 +9138,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) projCurve.LastParameter()); arc->setHandle(tCurve); GeometryFacade::setConstruction(arc, true); -// ExternalGeo.push_back(arc); geos.emplace_back(arc); } } @@ -9151,14 +9164,12 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Base::Vector3d(center.X(), center.Y(), center.Z())); GeometryFacade::setConstruction(circle, true); -// ExternalGeo.push_back(circle); geos.emplace_back(circle); } else { Part::GeomBSplineCurve* bspline = new Part::GeomBSplineCurve(projCurve.BSpline()); GeometryFacade::setConstruction(bspline, true); -// ExternalGeo.push_back(bspline); geos.emplace_back(bspline); } } @@ -9180,7 +9191,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) hyperbola->setAngleXU( -xdir.AngleWithRef(xdirref.XDirection(), normal)); GeometryFacade::setConstruction(hyperbola, true); -// ExternalGeo.push_back(hyperbola); geos.emplace_back(hyperbola); } else { @@ -9193,7 +9203,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) projCurve.LastParameter()); aoh->setHandle(tCurve); GeometryFacade::setConstruction(aoh, true); -// ExternalGeo.push_back(aoh); geos.emplace_back(aoh); } } @@ -9214,7 +9223,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) parabola->setAngleXU( -xdir.AngleWithRef(xdirref.XDirection(), normal)); GeometryFacade::setConstruction(parabola, true); -// ExternalGeo.push_back(parabola); geos.emplace_back(parabola); } else { @@ -9227,7 +9235,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) projCurve.LastParameter()); aop->setHandle(tCurve); GeometryFacade::setConstruction(aop, true); -// ExternalGeo.push_back(aop); geos.emplace_back(aop); } } @@ -9246,7 +9253,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Handle(Geom_Ellipse) curve = new Geom_Ellipse(e); ellipse->setHandle(curve); GeometryFacade::setConstruction(ellipse, true); -// ExternalGeo.push_back(ellipse); geos.emplace_back(ellipse); } else { @@ -9258,7 +9264,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) projCurve.LastParameter()); aoe->setHandle(tCurve); GeometryFacade::setConstruction(aoe, true); -// ExternalGeo.push_back(aoe); geos.emplace_back(aoe); } } @@ -9283,7 +9288,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) Part::GeomPoint* point = new Part::GeomPoint(p); GeometryFacade::setConstruction(point, true); -// ExternalGeo.push_back(point); geos.emplace_back(point); } break; default: @@ -9300,8 +9304,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) FC_THROWM(Base::CADKernelError,"Failed to get intersection"); Part::TopoShape intersectionShape(maker.Shape()); auto edges = intersectionShape.getSubTopoShapes(TopAbs_EDGE); -// for (const auto &s : edges) -// importEdge(s.getShape()); // Section of some face (e.g. sphere) produce more than one arcs // from the same circle. So we try to fit the arcs with a single // circle/arc. @@ -9322,8 +9324,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) } } } -// for (const auto &s : intersectionShape.getSubShapes(TopAbs_VERTEX, TopAbs_EDGE)) -// importVertex(s); } } catch (Base::Exception &e) { @@ -9353,7 +9353,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) if (intersection) { for(auto &geo : geos) { auto egf = ExternalGeometryFacade::getFacade(geo.get()); -// egf->setFlag(ExternalGeometryExtension::Intersection); egf->setFlag(ExternalGeometryExtension::Defining, defining); } } else if (defining && i+1==(int)Objects.size()) { @@ -9450,7 +9449,6 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) void SketchObject::fixExternalGeometry(const std::vector &geoIds) { std::set idSet(geoIds.begin(),geoIds.end()); auto geos = ExternalGeo.getValues(); -// auto geos = ExternalGeo; auto objs = ExternalGeometry.getValues(); auto subs = ExternalGeometry.getSubValues(); bool touched = false; @@ -9503,7 +9501,6 @@ void SketchObject::fixExternalGeometry(const std::vector &geoIds) { std::vector SketchObject::getCompleteGeometry() const { std::vector vals = getInternalGeometry(); -// vals.insert(vals.end(), ExternalGeo.rbegin(), ExternalGeo.rend());// in reverse order const auto &geos = getExternalGeometry(); vals.insert(vals.end(), geos.rbegin(), geos.rend()); // in reverse order return vals; @@ -9512,13 +9509,11 @@ std::vector SketchObject::getCompleteGeometry() const GeoListFacade SketchObject::getGeoListFacade() const { std::vector facade; -// facade.reserve(Geometry.getSize() + ExternalGeo.size()); facade.reserve(Geometry.getSize() + ExternalGeo.getSize()); for (auto geo : Geometry.getValues()) facade.push_back(GeometryFacade::getFacade(geo)); -// for (auto rit = ExternalGeo.rbegin(); rit != ExternalGeo.rend(); rit++) const auto &externalGeos = ExternalGeo.getValues(); for(auto rit = externalGeos.rbegin(); rit != externalGeos.rend(); rit++) facade.push_back(GeometryFacade::getFacade(*rit)); @@ -10279,14 +10274,7 @@ static inline bool checkMigration(Part::PropertyGeometryList &prop) void SketchObject::onChanged(const App::Property* prop) { -// if (isRestoring() && prop == &Geometry) { -// std::vector geom = Geometry.getValues(); -// std::vector supportedGeom = supportedGeometry(geom); -// // To keep upward compatibility ignore unsupported geometry types -// if (supportedGeom.size() != geom.size()) { -// Geometry.setValues(supportedGeom); -// return; -// } + if (prop == &Geometry) { if (isRestoring() && checkMigration(Geometry)) { // Construction migration to extension @@ -10308,6 +10296,21 @@ void SketchObject::onChanged(const App::Property* prop) } } } + geoMap.clear(); + const auto &vals = getInternalGeometry(); + for(long i=0;i<(long)vals.size();++i) { + auto geo = vals[i]; + auto gf = GeometryFacade::getFacade(geo); + if(!gf->getId()) + gf->setId(++geoLastId); + else if(gf->getId() > geoLastId) + geoLastId = gf->getId(); + while(!geoMap.insert(std::make_pair(gf->getId(),i)).second) { + FC_WARN("duplicate geometry id " << gf->getId() << " -> " << geoLastId+1); + gf->setId(++geoLastId); + } + } + updateGeoHistory(); } auto doc = getDocument(); @@ -10546,7 +10549,7 @@ void SketchObject::updateGeometryRefs() { std::unordered_map legacyMap; for(int i=0;i<(int)objs.size();++i) { auto obj = objs[i]; - const std::string &sub=shadows[i].first.size()?shadows[i].first:subs[i]; + const std::string &sub=shadows[i].newName.size()?shadows[i].newName:subs[i]; externalGeoRef.emplace_back(obj->getNameInDocument()); auto &key = externalGeoRef.back(); key += '.'; @@ -11806,10 +11809,10 @@ std::string SketchObject::getGeometryReference(int GeoId) const { if(!obj) return ref; - std::pair elementName; + App::ElementNamePair elementName; App::GeoFeature::resolveElement(obj,ref.c_str()+pos+1,elementName); - if(elementName.second.size()) - return objName + "." + elementName.second; + if(elementName.oldName.size()) + return objName + "." + elementName.oldName; return ref; } diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index cc1a781fc4..83f2aabeae 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -38,6 +38,8 @@ #include "GeometryFacade.h" #include "Sketch.h" +#include "SketchGeometryExtension.h" +#include "ExternalGeometryExtension.h" namespace Sketcher { @@ -70,8 +72,6 @@ public: Part ::PropertyGeometryList ExternalGeo; App ::PropertyBool FullyConstrained; App ::PropertyPrecision ArcFitTolerance; - // App ::PropertyInteger ExternalBSplineMaxDegree; - // App ::PropertyPrecision ExternalBSplineTolerance; Part ::PropertyPartShape InternalShape; App ::PropertyPrecision InternalTolerance; App ::PropertyBool MakeInternals; @@ -213,7 +213,6 @@ public: typename GeometryT = Part::Geometry, typename = typename std::enable_if< std::is_base_of::type>::value>::type> - // const GeometryT* getGeometry(int GeoId) const; const GeometryT* getGeometry(int GeoId) const { return static_cast(_getGeometry(GeoId)); @@ -229,7 +228,6 @@ public: /// returns a list of projected external geometries const std::vector& getExternalGeometry() const { - // return ExternalGeo; return ExternalGeo.getValues(); } /// rebuilds external geometry (projection onto the sketch plane) @@ -237,7 +235,6 @@ public: /// returns the number of external Geometry entities int getExternalGeometryCount() const { - // return ExternalGeo.size(); return ExternalGeo.getSize(); } /// auto fix external geometry references @@ -751,6 +748,8 @@ public: std::string convertSubName(const Data::IndexedName&, bool postfix = true) const; + Data::IndexedName shapeTypeFromGeoId(int GeoId, PointPos pos = Sketcher::PointPos::none) const; + App::ElementNamePair getElementName(const char* name, ElementNameType type) const override; bool isPerformingInternalTransaction() const @@ -824,13 +823,17 @@ public: // geometry extension functionalities for single element sketch object int getGeometryId(int GeoId, long& id) const; protected: + // Only the first flag is toggled, the rest of the flags is set or cleared following the first + // flag. + int toggleExternalGeometryFlag(const std::vector& geoIds, + const std::vector& flags); + + void buildShape(); /// get called by the container when a property has changed void onChanged(const App::Property* /*prop*/) override; void onDocumentRestored() override; void restoreFinished() override; - void buildShape(); - std::string validateExpression(const App::ObjectIdentifier& path, std::shared_ptr expr); @@ -924,8 +927,6 @@ private: /// Flag to allow carbon copy from misaligned geometry bool allowUnaligned; - // std::vector ExternalGeo; - std::vector VertexId2GeoId; std::vector VertexId2PosId; @@ -1039,22 +1040,6 @@ inline int SketchObject::moveTemporaryPoint(int geoId, return solvedSketch.movePoint(geoId, pos, toPoint, relative); } -// template -// const GeometryT* SketchObject::getGeometry(int GeoId) const -//{ -// if (GeoId >= 0) { -// const std::vector& geomlist = getInternalGeometry(); -// if (GeoId < int(geomlist.size())) { -// return static_cast(geomlist[GeoId]); -// } -// } -//// else if (-GeoId <= int(ExternalGeo.size())) { -// else if (-GeoId <= int(ExternalGeo.getSize())) { -// return static_cast(ExternalGeo[-GeoId - 1]); -// } -// -// return nullptr; -//} using SketchObjectPython = App::FeaturePythonT; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index d5d1583887..a3f2d71701 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2884,41 +2884,38 @@ void ViewProviderSketch::drawEditMarkers(const std::vector& Edit editCoinManager->drawEditMarkers(EditMarkers, augmentationlevel); } -void ViewProviderSketch::updateData(const App::Property* prop) -{ +void ViewProviderSketch::updateData(const App::Property* prop) { ViewProvider2DObject::updateData(prop); - // In the case of an undo/redo transaction, updateData is triggered by - // SketchObject::onUndoRedoFinished() in the solve() In the case of an internal transaction, - // touching the geometry results in a call to updateData. - if (isInEditMode() && !getSketchObject()->getDocument()->isPerformingTransaction() - && !getSketchObject()->isPerformingInternalTransaction() - && (prop == &(getSketchObject()->Geometry) || prop == &(getSketchObject()->Constraints))) { + if (prop != &getSketchObject()->Constraints) + signalElementsChanged(); +} - // At this point, we do not need to solve the Sketch - // If we are adding geometry an update can be triggered before the sketch is actually - // solved. Because a solve is mandatory to any addition (at least to update the DoF of the - // solver), only when the solver geometry is the same in number than the sketch geometry an - // update should trigger a redraw. This reduces even more the number of redraws per - // insertion of geometry +void ViewProviderSketch::slotSolverUpdate() +{ + if (!isInEditMode() ) + return; - // solver information is also updated when no matching geometry, so that if a solving fails - // this failed solving info is presented to the user - UpdateSolverInformation();// just update the solver window with the last SketchObject - // solving information + // At this point, we do not need to solve the Sketch + // If we are adding geometry an update can be triggered before the sketch is actually + // solved. Because a solve is mandatory to any addition (at least to update the DoF of the + // solver), only when the solver geometry is the same in number than the sketch geometry an + // update should trigger a redraw. This reduces even more the number of redraws per + // insertion of geometry - if (getSketchObject()->getExternalGeometryCount() - + getSketchObject()->getHighestCurveIndex() + 1 - == getSolvedSketch().getGeometrySize()) { - Gui::MDIView* mdi = Gui::Application::Instance->editDocument()->getActiveView(); - if (mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) - draw(false, true); + // solver information is also updated when no matching geometry, so that if a solving fails + // this failed solving info is presented to the user + UpdateSolverInformation();// just update the solver window with the last SketchObject + // solving information - signalConstraintsChanged(); - } + if (getSketchObject()->getExternalGeometryCount() + + getSketchObject()->getHighestCurveIndex() + 1 + == getSolvedSketch().getGeometrySize()) { + Gui::MDIView* mdi = Gui::Application::Instance->editDocument()->getActiveView(); + if (mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) + draw(false, true); - if (prop != &getSketchObject()->Constraints) - signalElementsChanged(); + signalConstraintsChanged(); } } @@ -3124,6 +3121,15 @@ bool ViewProviderSketch::setEdit(int ModNum) getSketchObject()->validateExternalLinks(); } + //NOLINTBEGIN + connectUndoDocument = getDocument()->signalUndoDocument.connect( + std::bind(&ViewProviderSketch::slotUndoDocument, this, sp::_1)); + connectRedoDocument = getDocument()->signalRedoDocument.connect( + std::bind(&ViewProviderSketch::slotRedoDocument, this, sp::_1)); + connectSolverUpdate = getSketchObject() + ->signalSolverUpdate.connect(boost::bind(&ViewProviderSketch::slotSolverUpdate, this)); + //NOLINTEND + // There are geometry extensions introduced by the solver and geometry extensions introduced by // the viewprovider. // 1. It is important that the solver has geometry with updated extensions. @@ -3139,13 +3145,6 @@ bool ViewProviderSketch::setEdit(int ModNum) // a draw(true) via ViewProvider::UpdateData. getSketchObject()->solve(true); - //NOLINTBEGIN - connectUndoDocument = getDocument()->signalUndoDocument.connect( - std::bind(&ViewProviderSketch::slotUndoDocument, this, sp::_1)); - connectRedoDocument = getDocument()->signalRedoDocument.connect( - std::bind(&ViewProviderSketch::slotRedoDocument, this, sp::_1)); - //NOLINTEND - // Enable solver initial solution update while dragging. getSketchObject()->setRecalculateInitialSolutionWhileMovingPoint( viewProviderParameters.recalculateInitialSolutionWhileDragging); @@ -3355,6 +3354,7 @@ void ViewProviderSketch::unsetEdit(int ModNum) connectUndoDocument.disconnect(); connectRedoDocument.disconnect(); + connectSolverUpdate.disconnect(); // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 90d8372cd2..61837ec680 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -745,6 +745,7 @@ protected: //@{ void slotUndoDocument(const Gui::Document&); void slotRedoDocument(const Gui::Document&); + void slotSolverUpdate(); void forceUpdateData(); //@} @@ -924,6 +925,7 @@ private: private: boost::signals2::connection connectUndoDocument; boost::signals2::connection connectRedoDocument; + boost::signals2::connection connectSolverUpdate; // modes while sketching SketchMode Mode; diff --git a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py index e83e9093e4..b2733ad31c 100644 --- a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py +++ b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py @@ -537,6 +537,113 @@ class TestSketcherSolver(unittest.TestCase): self.assertEqual(len(hole.Shape.Edges), 32) self.assertEqual(len(sketch2.ExternalGeometry), 1) + def testSaveLoadWithExternalGeometryReference(self): + body = self.Doc.addObject("PartDesign::Body", "Body") + sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") + CreateRectangleSketch(sketch, (0, 0), (30, 30)) + pad = self.Doc.addObject("PartDesign::Pad", "Pad") + pad.Profile = sketch + sketch1 = self.Doc.addObject("Sketcher::SketchObject", "Sketch1") + body.addObject(sketch) + body.addObject(pad) + body.addObject(sketch1) + self.Doc.recompute() + sketch1.addExternal("Pad", "Edge12") + self.Doc.recompute() + + # Try changing it before the save + sketch = self.Doc.getObject("Sketch") + g1 = sketch.Constraints[11].First + d1 = sketch.Constraints[11].Value + sketch.delConstraint(11) + sketch.addConstraint(Sketcher.Constraint("Distance", g1, d1 - 1.0)) + self.Doc.recompute() + + filename = self.Doc.Name + ".FCStd" + self.Doc.saveAs(filename) + FreeCAD.closeDocument(self.Doc.Name) + self.Doc = FreeCAD.openDocument(filename) + pad = self.Doc.getObject("Pad") + self.Doc.recompute() + pad = self.Doc.getObject("Pad") + + sketch = self.Doc.getObject("Sketch") + g1 = sketch.Constraints[11].First + d1 = sketch.Constraints[11].Value + sketch.delConstraint(11) + sketch.addConstraint(Sketcher.Constraint("Distance", g1, d1 - 1.0)) + self.Doc.recompute() + + pad = self.Doc.getObject("Pad") + # TODO: Assert some stuff when the bug is fixed + # self.assertEqual(pad.Shape.ElementMapSize,0) + # self.assertNotNull(pad.Shape.ElementReverseMap["Edge12"]) + + def testTNPExternalGeometryStored(self): + # Arrange + import xml.etree.ElementTree as ET + + sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") + CreateRectangleSketch(sketch, (0, 0), (30, 30)) + sketch1 = self.Doc.addObject("Sketcher::SketchObject", "Sketch1") + pad = self.Doc.addObject("PartDesign::Pad", "Pad") + pad.Profile = sketch + self.Doc.recompute() + # sketch1.addExternal("Sketch", "Edge3") + sketch1.addExternal("Pad", "Edge12") + self.Doc.recompute() + # Act + root = ET.fromstring("" + sketch1.Content + "") + # Can't use != in an xpath because it wasn't added until python 3.10. + # "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref!='']" + extRefs = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref='']" + ) + extRefsAll = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref]" + ) + # Assert + self.assertEqual(len(extRefs), 2) + self.assertEqual(len(extRefsAll), 3) + self.assertEqual(root.tag, "all") + # Act + filename = self.Doc.Name + ".FCStd" + self.Doc.saveAs(filename) + FreeCAD.closeDocument(self.Doc.Name) + self.Doc = FreeCAD.openDocument(filename) + # Assert + root = ET.fromstring("" + self.Doc.getObject("Sketch1").Content + "") + extRefs = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref='']" + ) + extRefsAll = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref]" + ) + self.assertEqual(len(extRefs), 2) + self.assertEqual(len(extRefsAll), 3) + self.assertEqual(root.tag, "all") + # Act + sketch = self.Doc.getObject("Sketch") + g1 = sketch.Constraints[11].First + d1 = sketch.Constraints[11].Value + sketch.delConstraint(11) + sketch.addConstraint(Sketcher.Constraint("Distance", g1, d1 - 1.0)) + self.Doc.recompute() + # Assert + root = ET.fromstring("" + self.Doc.getObject("Sketch1").Content + "") + extRefs = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref='']" + ) + extRefsAll = root.findall( + "*/*[@name='ExternalGeo']//*/[@type='Sketcher::ExternalGeometryExtension']/[@Ref]" + ) + self.assertEqual(len(extRefs), 2) + self.assertEqual(len(extRefsAll), 3) + self.assertEqual(root.tag, "all") + + # TODO other tests: + # getHigherElement + def assertSuccessfulSolve(self, sketch, msg=None): status = sketch.solve() # TODO: can we get the solver's messages somehow to improve the message? diff --git a/tests/src/Mod/Sketcher/App/SketchObject.cpp b/tests/src/Mod/Sketcher/App/SketchObject.cpp index 761ebf97ff..989a03f7c6 100644 --- a/tests/src/Mod/Sketcher/App/SketchObject.cpp +++ b/tests/src/Mod/Sketcher/App/SketchObject.cpp @@ -266,29 +266,29 @@ TEST_F(SketchObjectTest, testGetElementName) // unless it's Export, we are really just testing the superclass App::GeoFeature::getElementName // call. auto forward_normal_name = - getObject()->getElementName("g39;SKT", App::GeoFeature::ElementNameType::Normal); + getObject()->getElementName("g1;SKT", App::GeoFeature::ElementNameType::Normal); auto reverse_normal_name = getObject()->getElementName("Vertex2", App::GeoFeature::ElementNameType::Normal); auto reverse_export_name = getObject()->getElementName("Vertex1", App::GeoFeature::ElementNameType::Export); auto map = getObject()->Shape.getShape().getElementMap(); ASSERT_EQ(map.size(), 3); - EXPECT_STREQ(map[0].name.toString().c_str(), "g39;SKT"); + EXPECT_STREQ(map[0].name.toString().c_str(), "g1;SKT"); EXPECT_EQ(map[0].index.toString(), "Edge1"); // Assert #ifndef FC_USE_TNP_FIX EXPECT_STREQ(forward_normal_name.newName.c_str(), ""); - EXPECT_STREQ(forward_normal_name.oldName.c_str(), "g39;SKT"); + EXPECT_STREQ(forward_normal_name.oldName.c_str(), "g1;SKT"); EXPECT_STREQ(reverse_normal_name.newName.c_str(), ""); EXPECT_STREQ(reverse_normal_name.oldName.c_str(), "Vertex2"); - EXPECT_STREQ(reverse_export_name.newName.c_str(), ";g39v1;SKT.Vertex1"); + EXPECT_STREQ(reverse_export_name.newName.c_str(), ";g1v1;SKT.Vertex1"); EXPECT_STREQ(reverse_export_name.oldName.c_str(), "Vertex1"); #else - EXPECT_STREQ(forward_normal_name.newName.c_str(), ";g39;SKT.Edge1"); + EXPECT_STREQ(forward_normal_name.newName.c_str(), ";g1;SKT.Edge1"); EXPECT_STREQ(forward_normal_name.oldName.c_str(), "Edge1"); - EXPECT_STREQ(reverse_normal_name.newName.c_str(), ";g39v2;SKT.Vertex2"); + EXPECT_STREQ(reverse_normal_name.newName.c_str(), ";g1v2;SKT.Vertex2"); EXPECT_STREQ(reverse_normal_name.oldName.c_str(), "Vertex2"); - EXPECT_STREQ(reverse_export_name.newName.c_str(), ";g39v1;SKT.Vertex1"); + EXPECT_STREQ(reverse_export_name.newName.c_str(), ";g1v1;SKT.Vertex1"); EXPECT_STREQ(reverse_export_name.oldName.c_str(), "Vertex1"); #endif }