diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 2ea0610fc9..43d2e81e5c 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -833,70 +833,85 @@ void AttachEngine::readLinks(const std::vector &objs, #ifdef FC_USE_TNP_FIX for (std::size_t i = 0; i < objs.size(); i++) { if (!objs[i]->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) { - FC_THROWM(AttachEngineException, "AttachEngine3D: attached to a non App::GeoFeature '" - << objs[i]->getNameInDocument() << "'"); + FC_THROWM(AttachEngineException, + "AttachEngine3D: attached to a non App::GeoFeature '" + << objs[i]->getNameInDocument() << "'"); } - App::GeoFeature *geof = static_cast(objs[i]); + auto* geof = dynamic_cast(objs[i]); geofs[i] = geof; Part::TopoShape shape; if (geof->isDerivedFrom(App::Plane::getClassTypeId())) { - //obtain Z axis and origin of placement + // obtain Z axis and origin of placement Base::Vector3d norm; geof->Placement.getValue().getRotation().multVec(Base::Vector3d(0.0, 0.0, 1.0), norm); Base::Vector3d org; geof->Placement.getValue().multVec(Base::Vector3d(), org); - //make shape - an local-XY plane infinite face - gp_Pln pl = gp_Pln(gp_Pnt(org.x, org.y, org.z), gp_Dir(norm.x, norm.y, norm.z)); - TopoDS_Shape myShape = BRepBuilderAPI_MakeFace(pl).Shape(); + // make shape - an local-XY plane infinite face + gp_Pln plane = gp_Pln(gp_Pnt(org.x, org.y, org.z), gp_Dir(norm.x, norm.y, norm.z)); + TopoDS_Shape myShape = BRepBuilderAPI_MakeFace(plane).Shape(); myShape.Infinite(true); - storage.push_back(myShape); + storage.emplace_back(myShape); shapes[i] = &(storage[storage.size() - 1]); - } else if (geof->isDerivedFrom(App::Line::getClassTypeId())) { - //obtain X axis and origin of placement - //note an inconsistency: App::Line is along local X, PartDesign::DatumLine is along local Z. + } + else if (geof->isDerivedFrom(App::Line::getClassTypeId())) { + // obtain X axis and origin of placement + // note an inconsistency: App::Line is along local X, PartDesign::DatumLine is along + // local Z. Base::Vector3d dir; geof->Placement.getValue().getRotation().multVec(Base::Vector3d(1.0, 0.0, 0.0), dir); Base::Vector3d org; geof->Placement.getValue().multVec(Base::Vector3d(), org); - //make shape - an infinite line along local X axis - gp_Lin l = gp_Lin(gp_Pnt(org.x, org.y, org.z), gp_Dir(dir.x, dir.y, dir.z)); - TopoDS_Shape myShape = BRepBuilderAPI_MakeEdge(l).Shape(); + // make shape - an infinite line along local X axis + gp_Lin line = gp_Lin(gp_Pnt(org.x, org.y, org.z), gp_Dir(dir.x, dir.y, dir.z)); + TopoDS_Shape myShape = BRepBuilderAPI_MakeEdge(line).Shape(); myShape.Infinite(true); - storage.push_back(myShape); + storage.emplace_back(myShape); shapes[i] = &(storage[storage.size() - 1]); - } else { + } + else { try { shape = Part::Feature::getTopoShape(geof, sub[i].c_str(), true); for (;;) { - if (shape.isNull()) - FC_THROWM(AttachEngineException, "AttachEngine3D: subshape not found " - << objs[i]->getNameInDocument() << '.' << sub[i]); + if (shape.isNull()) { + FC_THROWM(AttachEngineException, + "AttachEngine3D: subshape not found " + << objs[i]->getNameInDocument() << '.' << sub[i]); + } if (shape.shapeType() != TopAbs_COMPOUND - || shape.countSubShapes(TopAbs_SHAPE) != 1) + || shape.countSubShapes(TopAbs_SHAPE) != 1) { break; + } // auto extract the single sub-shape from a compound shape = shape.getSubTopoShape(TopAbs_SHAPE, 1); } - storage.push_back(shape.getShape()); - } catch (Standard_Failure &e) { - FC_THROWM(AttachEngineException, "AttachEngine3D: subshape not found " - << objs[i]->getNameInDocument() << '.' << sub[i] - << std::endl << e.GetMessageString()); - } catch (Base::CADKernelError &e) { - FC_THROWM(AttachEngineException, "AttachEngine3D: subshape not found " - << objs[i]->getNameInDocument() << '.' << sub[i] - << std::endl << e.what()); + storage.emplace_back(shape.getShape()); + } + catch (Standard_Failure& e) { + FC_THROWM(AttachEngineException, + "AttachEngine3D: subshape not found " << objs[i]->getNameInDocument() + << '.' << sub[i] << std::endl + << e.GetMessageString()); + } + catch (Base::CADKernelError& e) { + FC_THROWM(AttachEngineException, + "AttachEngine3D: subshape not found " << objs[i]->getNameInDocument() + << '.' << sub[i] << std::endl + << e.what()); + } + if (storage.back().IsNull()) { + FC_THROWM(AttachEngineException, + "AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.' + << sub[i]); } - if (storage.back().IsNull()) - FC_THROWM(AttachEngineException, "AttachEngine3D: null subshape " - << objs[i]->getNameInDocument() << '.' << sub[i]); shapes[i] = &(storage.back()); } - //FIXME: unpack single-child compounds here? Compounds are not used so far, so it should be considered later, when the need arises. + // FIXME: unpack single-child compounds here? Compounds are not used so far, so it should be + // considered later, when the need arises. types[i] = getShapeType(*(shapes[i])); - if (sub[i].length() == 0) + if (sub[i].length() == 0) { types[i] = eRefType(types[i] | rtFlagHasPlacement); + } } #else diff --git a/src/Mod/Sketcher/App/SketchGeometryExtension.cpp b/src/Mod/Sketcher/App/SketchGeometryExtension.cpp index 4c2f224c72..fa27e85d7a 100644 --- a/src/Mod/Sketcher/App/SketchGeometryExtension.cpp +++ b/src/Mod/Sketcher/App/SketchGeometryExtension.cpp @@ -37,7 +37,7 @@ constexpr std::array constexpr std::array SketchGeometryExtension::geometrymode2str; -TYPESYSTEM_SOURCE(Sketcher::SketchGeometryExtension, Part::GeometryPersistenceExtension) +TYPESYSTEM_SOURCE(Sketcher::SketchGeometryExtension, Part::GeometryMigrationPersistenceExtension) // scoped within the class, multithread ready std::atomic SketchGeometryExtension::_GeometryID; @@ -86,11 +86,9 @@ void SketchGeometryExtension::saveAttributes(Base::Writer& writer) const { Part::GeometryPersistenceExtension::saveAttributes(writer); - // This is removed as the stored Id is not used and it may interfere with RT's future - // implementation - writer.Stream() // << "\" id=\"" << Id - << "\" internalGeometryType=\"" << (int)InternalGeometryType << "\" geometryModeFlags=\"" - << GeometryModeFlags.to_string() << "\" geometryLayer=\"" << GeometryLayer; + writer.Stream() << "\" id=\"" << Id << "\" internalGeometryType=\"" << (int)InternalGeometryType + << "\" geometryModeFlags=\"" << GeometryModeFlags.to_string() + << "\" geometryLayer=\"" << GeometryLayer; } void SketchGeometryExtension::preSave(Base::Writer& writer) const diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index c4407221f4..c27b96b39c 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -31,19 +31,15 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -138,7 +134,7 @@ SketchObject::SketchObject() ADD_PROPERTY_TYPE(ExternalGeometry, (nullptr, nullptr), "Sketch", - (App::PropertyType)(App::Prop_None), + (App::PropertyType)(App::Prop_None | App::Prop_ReadOnly), "Sketch external geometry"); ADD_PROPERTY_TYPE(FullyConstrained, (false), @@ -615,12 +611,13 @@ namespace bg = boost::geometry; namespace bgi = boost::geometry::index; // NOLINTNEXTLINE -BOOST_GEOMETRY_REGISTER_POINT_3D( - Base::Vector3d,double,bg::cs::cartesian,x,y,z) +BOOST_GEOMETRY_REGISTER_POINT_3D(Base::Vector3d, double, bg::cs::cartesian, x, y, z) -class SketchObject::GeoHistory { +class SketchObject::GeoHistory +{ private: static constexpr int bgiMaxElements = 16; + public: using Parameters = bgi::linear; @@ -628,7 +625,7 @@ public: using IdSets = std::pair; using AdjList = std::list; - //associate a geo with connected ones on both points + // associate a geo with connected ones on both points using AdjMap = std::map; // maps start/end points to all existing geo to query and update adjacencies @@ -640,8 +637,8 @@ public: AdjList::iterator find(const Base::Vector3d &pt,bool strict=true){ std::vector ret; - rtree.query(bgi::nearest(pt,1),std::back_inserter(ret)); - if(!ret.empty()) { + rtree.query(bgi::nearest(pt, 1), std::back_inserter(ret)); + if (!ret.empty()) { // NOTE: we are using square distance here, the 1e-6 threshold is // very forgiving. We should have used Precision::SquareConfisuion(), // which is 1e-14. However, there is a problem with current @@ -722,15 +719,16 @@ public: void SketchObject::updateGeoHistory() { if(!geoHistoryLevel) return; - if(!geoHistory) + if (!geoHistory) { geoHistory = std::make_unique(); + } FC_TIME_INIT(t); const auto &geos = getInternalGeometry(); geoHistory->clear(); - for(auto geo : geos) { - auto pstart = getPoint(geo,PointPos::start); - auto pend = getPoint(geo,PointPos::end); + for (auto geo : geos) { + auto pstart = getPoint(geo, PointPos::start); + auto pend = getPoint(geo, PointPos::end); int id = GeometryFacade::getId(geo); geoHistory->update(pstart,id); if(pstart!=pend) @@ -1872,6 +1870,8 @@ int SketchObject::toggleConstruction(int GeoId) this->Geometry.set1Value(GeoId, std::move(geo)); solverNeedsUpdate = true; + signalSolverUpdate(); // FIXME: In theory this is totally redundant, but now seems required + // for UI to update. return 0; } @@ -7094,9 +7094,11 @@ bool SketchObject::modifyBSplineKnotMultiplicity(int GeoId, int knotIndex, int m // no need to check input data validity as this is an sketchobject managed operation. Base::StateLocker lock(managedoperation, true); - if (GeoId < 0 || GeoId > getHighestCurveIndex()) - THROWMT(Base::ValueError, - QT_TRANSLATE_NOOP("Exceptions", "B-spline Geometry Index (GeoID) is out of bounds.")) + if (GeoId < 0 || GeoId > getHighestCurveIndex()) { + THROWMT( + Base::ValueError, + QT_TRANSLATE_NOOP("Exceptions", "B-spline Geometry Index (GeoID) is out of bounds.")) + } if (multiplicityincr == 0)// no change in multiplicity THROWMT( @@ -8265,7 +8267,7 @@ Part::Geometry* projectLine(const BRepAdaptor_Curve& curve, const Handle(Geom_Pl invPlm.multVec(p1, p1); invPlm.multVec(p2, p2); - if (Base::DistanceP2(p1, p2) < Precision::SquareConfusion()) { + if (Base::Distance(p1, p2) < Precision::Confusion()) { Base::Vector3d p = (p1 + p2) / 2; Part::GeomPoint* point = new Part::GeomPoint(p); GeometryFacade::setConstruction(point, true); @@ -8279,7 +8281,7 @@ Part::Geometry* projectLine(const BRepAdaptor_Curve& curve, const Handle(Geom_Pl } } -} // anonymous namespace +} // anonymous namespace bool SketchObject::evaluateSupport() { @@ -10092,21 +10094,26 @@ void SketchObject::onChanged(const App::Property* prop) if (prop == &Geometry) { if (isRestoring() && checkMigration(Geometry)) { // Construction migration to extension - for( auto geometryValue : Geometry.getValues()) { - if(geometryValue->hasExtension(Part::GeometryMigrationExtension::getClassTypeId())) { + for (auto geometryValue : Geometry.getValues()) { + if (geometryValue->hasExtension( + Part::GeometryMigrationExtension::getClassTypeId())) { auto ext = std::static_pointer_cast( - geometryValue->getExtension(Part::GeometryMigrationExtension::getClassTypeId()).lock()); + geometryValue + ->getExtension(Part::GeometryMigrationExtension::getClassTypeId()) + .lock()); - auto gf = GeometryFacade::getFacade(geometryValue); // at this point IA geometry is already migrated + auto gf = GeometryFacade::getFacade( + geometryValue); // at this point IA geometry is already migrated - if(ext->testMigrationType(Part::GeometryMigrationExtension::Construction)) { - bool oldconstr = ext->getConstruction(); - if( geometryValue->getTypeId() == Part::GeomPoint::getClassTypeId() && !gf->isInternalAligned()){ + if (ext->testMigrationType(Part::GeometryMigrationExtension::Construction)) { + bool oldconstr = ext->getConstruction(); + if (geometryValue->getTypeId() == Part::GeomPoint::getClassTypeId() + && !gf->isInternalAligned()) { oldconstr = true; } gf->setConstruction(oldconstr); } - if(ext->testMigrationType(Part::GeometryMigrationExtension::GeometryId)) { + if (ext->testMigrationType(Part::GeometryMigrationExtension::GeometryId)) { gf->setId(ext->getId()); } } @@ -10117,13 +10124,15 @@ void SketchObject::onChanged(const App::Property* prop) for(long i=0;i<(long)vals.size();++i) { auto geo = vals[i]; auto gf = GeometryFacade::getFacade(geo); - if(gf->getId() == 0) { + if (gf->getId() == 0) { gf->setId(++geoLastId); - } else if(gf->getId() > 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); // NOLINT + while (!geoMap.insert(std::make_pair(gf->getId(), i)).second) { + FC_WARN("duplicate geometry id " << gf->getId() << " -> " + << geoLastId + 1); // NOLINT gf->setId(++geoLastId); } } @@ -10198,23 +10207,28 @@ void SketchObject::onChanged(const App::Property* prop) } } } - } else if ( prop == &ExternalGeo && !prop->testStatus(App::Property::User3) ) { - if(doc && doc->isPerformingTransaction()) { + } + else if (prop == &ExternalGeo && !prop->testStatus(App::Property::User3)) { + if (doc && doc->isPerformingTransaction()) { setStatus(App::PendingTransactionUpdate, true); -} + } if (isRestoring() && checkMigration(ExternalGeo)) { - for( auto geometryValue : ExternalGeo.getValues()) { - if(geometryValue->hasExtension(Part::GeometryMigrationExtension::getClassTypeId())) { + for (auto geometryValue : ExternalGeo.getValues()) { + if (geometryValue->hasExtension( + Part::GeometryMigrationExtension::getClassTypeId())) { auto ext = std::static_pointer_cast( - geometryValue->getExtension(Part::GeometryMigrationExtension::getClassTypeId()).lock()); + geometryValue + ->getExtension(Part::GeometryMigrationExtension::getClassTypeId()) + .lock()); std::unique_ptr egf; - if(ext->testMigrationType(Part::GeometryMigrationExtension::GeometryId)) { + if (ext->testMigrationType(Part::GeometryMigrationExtension::GeometryId)) { egf = ExternalGeometryFacade::getFacade(geometryValue); egf->setId(ext->getId()); } - if(ext->testMigrationType(Part::GeometryMigrationExtension::ExternalReference)) { + if (ext->testMigrationType( + Part::GeometryMigrationExtension::ExternalReference)) { if (!egf) { egf = ExternalGeometryFacade::getFacade(geometryValue); } @@ -10231,38 +10245,39 @@ void SketchObject::onChanged(const App::Property* prop) for(int i=0;itestFlag(ExternalGeometryExtension::Detached)) { - if(!egf->getRef().empty()) { + if (egf->testFlag(ExternalGeometryExtension::Detached)) { + if (!egf->getRef().empty()) { detached.insert(egf->getRef()); egf->setRef(std::string()); } egf->setFlag(ExternalGeometryExtension::Detached,false); egf->setFlag(ExternalGeometryExtension::Missing,false); } - if(egf->getId() > geoLastId) { + if (egf->getId() > geoLastId) { geoLastId = egf->getId(); } - if(!externalGeoMap.emplace(egf->getId(),i).second) { - FC_WARN("duplicate geometry id " << egf->getId() << " -> " << geoLastId+1); // NOLINT + if (!externalGeoMap.emplace(egf->getId(), i).second) { + FC_WARN("duplicate geometry id " << egf->getId() << " -> " + << geoLastId + 1); // NOLINT egf->setId(++geoLastId); externalGeoMap[egf->getId()] = i; } - if(!egf->getRef().empty()) { + if (!egf->getRef().empty()) { externalGeoRefMap[egf->getRef()].push_back(egf->getId()); } } - if(!detached.empty()) { + if (!detached.empty()) { auto objs = ExternalGeometry.getValues(); assert(externalGeoRef.size() == objs.size()); auto itObj = objs.begin(); auto subs = ExternalGeometry.getSubValues(); auto itSub = subs.begin(); - for(const auto & i : externalGeoRef) { - if(detached.count(i) != 0U) { + for (const auto& i : externalGeoRef) { + if (detached.count(i) != 0U) { itObj = objs.erase(itObj); itSub = subs.erase(itSub); - auto &refs = externalGeoRefMap[i]; - for(long id : refs) { + auto& refs = externalGeoRefMap[i]; + for (long id : refs) { auto it = externalGeoMap.find(id); if(it!=externalGeoMap.end()) { auto geo = ExternalGeo[it->second]; @@ -10275,7 +10290,7 @@ void SketchObject::onChanged(const App::Property* prop) ++itSub; } } - ExternalGeometry.setValues(objs,subs); + ExternalGeometry.setValues(objs, subs); } else { signalElementsChanged(); @@ -10283,7 +10298,7 @@ void SketchObject::onChanged(const App::Property* prop) } else if (prop == &ExternalGeometry) { #ifdef FC_USE_TNP_FIX - if(doc && doc->isPerformingTransaction()) { + if (doc && doc->isPerformingTransaction()) { setStatus(App::PendingTransactionUpdate, true); } @@ -10293,27 +10308,28 @@ void SketchObject::onChanged(const App::Property* prop) updateGeometryRefs(); signalElementsChanged(); } - } else if (prop == &Placement) { + } + else if (prop == &Placement) { if (ExternalGeometry.getSize() > 0) { touch(); } - } else if (prop == &ExpressionEngine) { - if(!isRestoring() - && doc && !doc->isPerformingTransaction() - && noRecomputes - && !managedoperation) - { + } + else if (prop == &ExpressionEngine) { + if (!isRestoring() && doc && !doc->isPerformingTransaction() && noRecomputes + && !managedoperation) { // if we do not have a recompute, the sketch must be solved to // update the DoF of the solver, constraints and UI try { auto res = ExpressionEngine.execute(); - if(res) { - FC_ERR("Failed to recompute " << ExpressionEngine.getFullName() << ": " << res->Why); // NOLINT + if (res) { + FC_ERR("Failed to recompute " << ExpressionEngine.getFullName() << ": " + << res->Why); // NOLINT delete res; } } catch (Base::Exception &e) { e.ReportException(); - FC_ERR("Failed to recompute " << ExpressionEngine.getFullName() << ": " << e.what()); // NOLINT + FC_ERR("Failed to recompute " << ExpressionEngine.getFullName() << ": " + << e.what()); // NOLINT } solve(); } @@ -10373,7 +10389,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].newName.empty() ? subs[i] : shadows[i].newName; + const std::string& sub = shadows[i].newName.empty() ? subs[i] : shadows[i].newName; externalGeoRef.emplace_back(obj->getNameInDocument()); auto &key = externalGeoRef.back(); key += '.'; @@ -10392,7 +10408,7 @@ void SketchObject::updateGeometryRefs() { if(refMap.empty()) { for(auto geo : geos) { auto egf = ExternalGeometryFacade::getFacade(geo); - if(egf->getRefIndex()<0) { + if (egf->getRefIndex() < 0) { if (egf->getId() < 0 && !egf->getRef().empty()) { // NOLINTNEXTLINE FC_ERR("External geometry reference corrupted in " << getFullName() @@ -10416,21 +10432,23 @@ void SketchObject::updateGeometryRefs() { // if not undo/redo. // // NOLINTNEXTLINE - FC_WARN("Update legacy external reference " << egf->getRef() << " -> " - << externalGeoRef[it->second] << " in " << getFullName()); - } else { + FC_WARN("Update legacy external reference " + << egf->getRef() << " -> " << externalGeoRef[it->second] << " in " + << getFullName()); + } + else { // NOLINTNEXTLINE - FC_LOG("Update undo/redo external reference " << egf->getRef() << " -> " - << externalGeoRef[it->second] << " in " << getFullName()); + FC_LOG("Update undo/redo external reference " + << egf->getRef() << " -> " << externalGeoRef[it->second] << " in " + << getFullName()); } touched = true; egf->setRef(externalGeoRef[it->second]); } continue; } - if(egf->getRefIndex() < (int)externalGeoRef.size() - && egf->getRef() != externalGeoRef[egf->getRefIndex()]) - { + if (egf->getRefIndex() < (int)externalGeoRef.size() + && egf->getRef() != externalGeoRef[egf->getRefIndex()]) { touched = true; egf->setRef(externalGeoRef[egf->getRefIndex()]); } @@ -10442,22 +10460,22 @@ void SketchObject::updateGeometryRefs() { if (it == externalGeoRefMap.end()) { continue; } - for(long id : it->second) { + for (long id : it->second) { auto iter = externalGeoMap.find(id); if(iter!=externalGeoMap.end()) { auto &geo = geos[iter->second]; geo = geo->clone(); auto egf = ExternalGeometryFacade::getFacade(geo); // NOLINTNEXTLINE - FC_LOG(getFullName() << " ref change on ExternalEdge" - << iter->second-1 << ' ' << egf->getRef() << " -> " << v.second); + FC_LOG(getFullName() << " ref change on ExternalEdge" << iter->second - 1 << ' ' + << egf->getRef() << " -> " << v.second); egf->setRef(v.second); touched = true; } } } } - if(touched) { + if (touched) { ExternalGeo.setValues(std::move(geos)); } } @@ -11474,14 +11492,15 @@ Data::IndexedName SketchObject::checkSubName(const char *subname) const{ return Data::IndexedName(); } -Data::IndexedName SketchObject::shapeTypeFromGeoId(int geoId, PointPos posId) const { - if(geoId == GeoEnum::HAxis) { - if(posId == PointPos::start) { +Data::IndexedName SketchObject::shapeTypeFromGeoId(int geoId, PointPos posId) const +{ + if (geoId == GeoEnum::HAxis) { + if (posId == PointPos::start) { return Data::IndexedName::fromConst("RootPoint", 0); } return Data::IndexedName::fromConst("H_Axis", 0); } - if(geoId == GeoEnum::VAxis) { + if (geoId == GeoEnum::VAxis) { return Data::IndexedName::fromConst("V_Axis", 0); } @@ -11493,15 +11512,15 @@ Data::IndexedName SketchObject::shapeTypeFromGeoId(int geoId, PointPos posId) co } if(posId != PointPos::none) { int idx = getVertexIndexGeoPos(geoId, posId); - if(idx < 0){ + if (idx < 0) { return Data::IndexedName(); } - return Data::IndexedName::fromConst("Vertex", idx+1); + return Data::IndexedName::fromConst("Vertex", idx + 1); } if (geoId >= 0) { - return Data::IndexedName::fromConst("Edge", geoId+1); + return Data::IndexedName::fromConst("Edge", geoId + 1); } - return Data::IndexedName::fromConst("ExternalEdge", -geoId-2); + return Data::IndexedName::fromConst("ExternalEdge", -geoId - 2); } bool SketchObject::geoIdFromShapeType(const Data::IndexedName & indexedName, @@ -11608,22 +11627,22 @@ std::string SketchObject::getGeometryReference(int GeoId) const { const std::string &ref = egf->getRef(); - if(egf->testFlag(ExternalGeometryExtension::Missing)) { + if (egf->testFlag(ExternalGeometryExtension::Missing)) { return std::string("? ") + ref; } auto pos = ref.find('.'); - if(pos == std::string::npos) { + if (pos == std::string::npos) { return ref; } - std::string objName = ref.substr(0,pos); + std::string objName = ref.substr(0, pos); auto obj = getDocument()->getObject(objName.c_str()); - if(!obj) { + if (!obj) { return ref; } App::ElementNamePair elementName; - App::GeoFeature::resolveElement(obj,ref.c_str()+pos+1,elementName); + App::GeoFeature::resolveElement(obj, ref.c_str() + pos + 1, elementName); if (!elementName.oldName.empty()) { return objName + "." + elementName.oldName; } diff --git a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py index b2733ad31c..fdf02d6477 100644 --- a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py +++ b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py @@ -538,6 +538,7 @@ class TestSketcherSolver(unittest.TestCase): self.assertEqual(len(sketch2.ExternalGeometry), 1) def testSaveLoadWithExternalGeometryReference(self): + # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") CreateRectangleSketch(sketch, (0, 0), (30, 30)) @@ -551,7 +552,7 @@ class TestSketcherSolver(unittest.TestCase): sketch1.addExternal("Pad", "Edge12") self.Doc.recompute() - # Try changing it before the save + # Act: Try changing sketch before the save sketch = self.Doc.getObject("Sketch") g1 = sketch.Constraints[11].First d1 = sketch.Constraints[11].Value @@ -559,14 +560,16 @@ class TestSketcherSolver(unittest.TestCase): sketch.addConstraint(Sketcher.Constraint("Distance", g1, d1 - 1.0)) self.Doc.recompute() + # Act: Save and reload the file filename = self.Doc.Name + ".FCStd" self.Doc.saveAs(filename) FreeCAD.closeDocument(self.Doc.Name) self.Doc = FreeCAD.openDocument(filename) pad = self.Doc.getObject("Pad") + sketch1 = self.Doc.getObject("Sketch1") self.Doc.recompute() - pad = self.Doc.getObject("Pad") + # Act: change sketch after restore ( trigger missing references if there is a bug ) sketch = self.Doc.getObject("Sketch") g1 = sketch.Constraints[11].First d1 = sketch.Constraints[11].Value @@ -574,10 +577,10 @@ class TestSketcherSolver(unittest.TestCase): 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"]) + # Assert + self.assertEqual(pad.Shape.ElementMapSize, 30) + self.assertIn("Edge12", pad.Shape.ElementReverseMap) + self.assertIn((pad, ("Edge12",)), sketch1.ExternalGeometry) # Not "?Edge12" def testTNPExternalGeometryStored(self): # Arrange @@ -589,7 +592,6 @@ class TestSketcherSolver(unittest.TestCase): 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 @@ -622,7 +624,7 @@ class TestSketcherSolver(unittest.TestCase): self.assertEqual(len(extRefs), 2) self.assertEqual(len(extRefsAll), 3) self.assertEqual(root.tag, "all") - # Act + # Act to change the constraint sketch = self.Doc.getObject("Sketch") g1 = sketch.Constraints[11].First d1 = sketch.Constraints[11].Value @@ -641,6 +643,62 @@ class TestSketcherSolver(unittest.TestCase): self.assertEqual(len(extRefsAll), 3) self.assertEqual(root.tag, "all") + def testConstructionToggleTNP(self): + """Bug 15484""" + # Arrange + import xml.etree.ElementTree as ET + + body = self.Doc.addObject("PartDesign::Body", "Body") + sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") + CreateRectangleSketch(sketch, (0, 0), (30, 30)) + # Add zigsag geo as construction lines + i = sketch.GeometryCount + sketch.addGeometry( + Part.LineSegment(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(-10, 10, 0)), True + ) + sketch.addGeometry( + Part.LineSegment(FreeCAD.Vector(-10, 10, 0), FreeCAD.Vector(-5, 20, 0)), True + ) + sketch.addGeometry( + Part.LineSegment(FreeCAD.Vector(-5, 20, 0), FreeCAD.Vector(-10, 25, 0)), True + ) + sketch.addGeometry( + Part.LineSegment(FreeCAD.Vector(-10, 25, 0), FreeCAD.Vector(0, 30, 0)), True + ) + sketch.addConstraint(Sketcher.Constraint("Coincident", i + 0, 2, i + 1, 1)) + sketch.addConstraint(Sketcher.Constraint("Coincident", i + 1, 2, i + 2, 1)) + sketch.addConstraint(Sketcher.Constraint("Coincident", i + 2, 2, i + 3, 1)) + sketch.addConstraint(Sketcher.Constraint("Coincident", i + 3, 2, 0, 1)) + sketch.addConstraint(Sketcher.Constraint("Coincident", i + 0, 1, 2, 2)) + + pad = self.Doc.addObject("PartDesign::Pad", "Pad") + pad.Profile = sketch + body.addObject(sketch) + body.addObject(pad) + self.Doc.recompute() + sketch1 = self.Doc.addObject("Sketcher::SketchObject", "Sketch1") + sketch1.AttachmentSupport = (pad, ("Face6")) + sketch1.MapMode = "FlatFace" + self.Doc.recompute() + + CreateCircleSketch(sketch1, (2, 2, 0), 1) + CreateCircleSketch(sketch1, (6, 2, 0), 1) + body.addObject(sketch1) + self.Doc.recompute() + # Act toggle construction lines on in sketch; pad now has 9 instead of 6 faces. + sketch.setConstruction(4, False) + sketch.setConstruction(5, False) + sketch.setConstruction(6, False) + sketch.setConstruction(7, False) + sketch.setConstruction(3, True) + self.Doc.recompute() + # Assert + # AttachmentSupport is a list of (object,(subobject list)) with 1 entry. Get the + # first and only subobject name in second part of that first tuple and see that it moved + # from the Face6 we set above. + self.assertEqual(sketch1.AttachmentSupport[0][1][0], "Face9") + self.assertIn("Face6", pad.Shape.ElementReverseMap) # different Face6 exists + # TODO other tests: # getHigherElement