From cc93d99f49df722aa9de5e603ebca105008225e7 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Thu, 27 Jun 2024 14:05:27 -0400 Subject: [PATCH 1/5] Toponaming: Add tests for subshaoebinder, attachment problems. --- .../TestTopologicalNamingProblem.py | 325 ++++++++++++------ 1 file changed, 222 insertions(+), 103 deletions(-) diff --git a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py index f32be160a2..e69eedf596 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py +++ b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py @@ -806,59 +806,56 @@ class TestTopologicalNamingProblem(unittest.TestCase): def testChangeSketch(self): # Arrange - self.Body = self.Doc.addObject('PartDesign::Body', 'Body') + doc = self.Doc + + body = doc.addObject('PartDesign::Body', 'Body') # Make first offset cube Pad - self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch') - self.Body.addObject(self.PadSketch) - TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2)) - self.Doc.recompute() - self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad") - self.Body.addObject(self.Pad) - self.Pad.Profile = self.PadSketch - self.Pad.Length = 10 - self.Doc.recompute() + padSketch = doc.addObject('Sketcher::SketchObject', 'Sketch') + body.addObject(padSketch) + TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (31.37, 25.2)) + doc.recompute() + pad = doc.addObject("PartDesign::Pad", "Pad") + body.addObject(pad) + pad.Profile = padSketch + pad.Length = 10 + doc.recompute() - self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001') - self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',]) - self.Sketch001.MapMode = 'FlatFace' + sketch001 = body.newObject('Sketcher::SketchObject','Sketch001') + sketch001 = doc.Sketch001 + sketch001.AttachmentSupport = (doc.getObject('Pad'),['Face6',]) + sketch001.MapMode = 'FlatFace' App.ActiveDocument.recompute() - self.Sketch001.addExternal("Pad","Edge10") - self.Sketch001.addExternal("Pad","Edge7") - geoList = [] geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 5.000000)) - self.Sketch001.addGeometry(geoList,False) + sketch001.addGeometry(geoList,False) del geoList - self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000)) - self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3)) - App.ActiveDocument.recompute() - self.Doc.recompute() + sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000)) + doc.recompute() - self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001') - self.Pad001.Profile = self.Doc.getObject('Sketch001') - self.Pad001.Length = 10 + pad001 = body.newObject('PartDesign::Pad','Pad001') + pad001.Profile = doc.getObject('Sketch001') + pad001.Length = 10 App.ActiveDocument.recompute() - self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis']) - self.Sketch001.Visibility = False + pad001.ReferenceAxis = (doc.getObject('Sketch001'),['N_Axis']) + sketch001.Visibility = False App.ActiveDocument.recompute() + pad001.Length = 10.000000 + pad001.TaperAngle = 0.000000 + pad001.UseCustomVector = 0 + pad001.Direction = (0, 0, 1) + pad001.ReferenceAxis = (doc.getObject('Sketch001'), ['N_Axis']) + pad001.AlongSketchNormal = 1 + pad001.Type = 0 + pad001.UpToFace = None + pad001.Reversed = 0 + pad001.Midplane = 0 + pad001.Offset = 0 + doc.recompute() + doc.getObject('Pad').Visibility = False - self.Pad001.Length = 10.000000 - self.Pad001.TaperAngle = 0.000000 - self.Pad001.UseCustomVector = 0 - self.Pad001.Direction = (0, 0, 1) - self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis']) - self.Pad001.AlongSketchNormal = 1 - self.Pad001.Type = 0 - self.Pad001.UpToFace = None - self.Pad001.Reversed = 0 - self.Pad001.Midplane = 0 - self.Pad001.Offset = 0 - self.Doc.recompute() - self.Doc.getObject('Pad').Visibility = False - - self.Doc.getObject('Sketch001').Visibility = False + doc.getObject('Sketch001').Visibility = False # Modify the original sketch to generate TNP issue geoList = [] @@ -870,7 +867,7 @@ class TestTopologicalNamingProblem(unittest.TestCase): App.Vector(4.869811, 22.837425, 0.000000))) geoList.append(Part.LineSegment(App.Vector(4.869811, 22.837425, 0.000000), App.Vector(2.510468, 22.837425, 0.000000))) - self.PadSketch.addGeometry(geoList,False) + padSketch.addGeometry(geoList,False) del geoList constraintList = [] @@ -882,93 +879,88 @@ class TestTopologicalNamingProblem(unittest.TestCase): constraintList.append(Sketcher.Constraint('Vertical', 6)) constraintList.append(Sketcher.Constraint('Horizontal', 5)) constraintList.append(Sketcher.Constraint('Horizontal', 7)) - self.PadSketch.addConstraint(constraintList) + padSketch.addConstraint(constraintList) del constraintList - self.Doc.recompute() + doc.recompute() # Assert - if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. + if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return - self.assertEqual(self.Body.Shape.BoundBox.XMin,0) - self.assertEqual(self.Body.Shape.BoundBox.YMin,0) - self.assertEqual(self.Body.Shape.BoundBox.ZMin,0) - self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37) - self.assertEqual(self.Body.Shape.BoundBox.YMax,25.2) - self.assertEqual(self.Body.Shape.BoundBox.ZMax,20) + self.assertEqual(body.Shape.BoundBox.XMin,0) + self.assertEqual(body.Shape.BoundBox.YMin,0) + self.assertEqual(body.Shape.BoundBox.ZMin,0) + self.assertEqual(body.Shape.BoundBox.XMax,31.37) + self.assertEqual(body.Shape.BoundBox.YMax,25.2) + self.assertEqual(body.Shape.BoundBox.ZMax,20) def testApplyFillet(self): # Arrange - self.Body = self.Doc.addObject('PartDesign::Body', 'Body') + doc = self.Doc + body = doc.addObject('PartDesign::Body', 'Body') # Make first offset cube Pad - self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch') - self.Body.addObject(self.PadSketch) - TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2)) - self.Doc.recompute() - self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad") - self.Body.addObject(self.Pad) - self.Pad.Profile = self.PadSketch - self.Pad.Length = 10 - self.Doc.recompute() + padSketch = doc.addObject('Sketcher::SketchObject', 'Sketch') + body.addObject(padSketch) + TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (31.37, 25.2)) + doc.recompute() + pad = doc.addObject("PartDesign::Pad", "Pad") + body.addObject(pad) + pad.Profile = padSketch + pad.Length = 10 + doc.recompute() - self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001') - self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',]) - self.Sketch001.MapMode = 'FlatFace' - App.ActiveDocument.recompute() - - self.Sketch001.addExternal("Pad","Edge10") - self.Sketch001.addExternal("Pad","Edge7") + sketch001 = body.newObject('Sketcher::SketchObject','Sketch001') + sketch001.AttachmentSupport = (doc.getObject('Pad'),['Face6',]) + sketch001.MapMode = 'FlatFace' geoList = [] geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 5.000000)) - self.Sketch001.addGeometry(geoList,False) + sketch001.addGeometry(geoList,False) del geoList - self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000)) - self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3)) - App.ActiveDocument.recompute() - self.Doc.recompute() + sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000)) + doc.recompute() - self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001') - self.Pad001.Profile = self.Doc.getObject('Sketch001') - self.Pad001.Length = 10 + pad001 = body.newObject('PartDesign::Pad','Pad001') + pad001.Profile = doc.getObject('Sketch001') + pad001.Length = 10 App.ActiveDocument.recompute() - self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis']) - self.Sketch001.Visibility = False + pad001.ReferenceAxis = (doc.getObject('Sketch001'),['N_Axis']) + sketch001.Visibility = False App.ActiveDocument.recompute() - self.Pad001.Length = 10.000000 - self.Pad001.TaperAngle = 0.000000 - self.Pad001.UseCustomVector = 0 - self.Pad001.Direction = (0, 0, 1) - self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis']) - self.Pad001.AlongSketchNormal = 1 - self.Pad001.Type = 0 - self.Pad001.UpToFace = None - self.Pad001.Reversed = 0 - self.Pad001.Midplane = 0 - self.Pad001.Offset = 0 - self.Doc.recompute() - self.Doc.getObject('Pad').Visibility = False + pad001.Length = 10.000000 + pad001.TaperAngle = 0.000000 + pad001.UseCustomVector = 0 + pad001.Direction = (0, 0, 1) + pad001.ReferenceAxis = (doc.getObject('Sketch001'), ['N_Axis']) + pad001.AlongSketchNormal = 1 + pad001.Type = 0 + pad001.UpToFace = None + pad001.Reversed = 0 + pad001.Midplane = 0 + pad001.Offset = 0 + doc.recompute() + doc.getObject('Pad').Visibility = False - self.Doc.getObject('Sketch001').Visibility = False + doc.getObject('Sketch001').Visibility = False - area1 = self.Pad.Shape.Area + area1 = pad.Shape.Area # Act - self.Doc.getObject('Sketch').fillet(2,3, + doc.getObject('Sketch').fillet(2,3, App.Vector(6.673934,25.000000,0), App.Vector(0.000000,21.980343,0), 4.740471,True,True,False) - self.Doc.recompute() - area2 = self.Pad.Shape.Area + doc.recompute() + area2 = pad.Shape.Area # Assert - if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. + if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return - self.assertEqual(self.Body.Shape.BoundBox.XMin,0) - self.assertEqual(self.Body.Shape.BoundBox.YMin,0) - self.assertEqual(self.Body.Shape.BoundBox.ZMin,0) - self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37) - self.assertAlmostEqual(self.Body.Shape.BoundBox.YMax,25.2) - self.assertEqual(self.Body.Shape.BoundBox.ZMax,20) + self.assertEqual(body.Shape.BoundBox.XMin,0) + self.assertEqual(body.Shape.BoundBox.YMin,0) + self.assertEqual(body.Shape.BoundBox.ZMin,0) + self.assertEqual(body.Shape.BoundBox.XMax,31.37) + self.assertAlmostEqual(body.Shape.BoundBox.YMax,25.2) + self.assertEqual(body.Shape.BoundBox.ZMax,20) self.assertNotEqual(area1, area2) def testShapeBinder(self): @@ -1464,16 +1456,142 @@ class TestTopologicalNamingProblem(unittest.TestCase): self.assertEqual(App.Gui.Selection.getSelectionEx("", 0)[0].SubElementNames[0][-8:],",F.Face2") def testFileSaveRestore(self): + # Arrange self.Body = self.Doc.addObject('PartDesign::Body', 'Body') self.create_t_sketch() self.assertEqual(self.Doc.Sketch.Shape.ElementMapSize, 18) filename = self.Doc.Name + # Act self.Doc.saveAs(filename) App.closeDocument(filename) self.Doc = App.openDocument(filename+".FCStd") self.Doc.recompute() + # Assert self.assertEqual(self.Doc.Sketch.Shape.ElementMapSize, 18) + def testBodySubShapeBinderElementMap(self): + # Arrange + doc = App.ActiveDocument + doc.addObject("Part::Box","Box") + doc.ActiveObject.Label = "Cube" + doc.addObject("Part::Box","Box") + doc.ActiveObject.Label = "Cube" + doc.addObject("Part::MultiFuse","Fusion") + doc.Fusion.Shapes = [doc.Box, doc.Box001,] + doc.recompute() + self.assertEqual(doc.Fusion.Shape.ElementMapSize, 26) + + doc.addObject('PartDesign::Body','Body') + doc.Body.Label = 'Body' + + doc.addObject('PartDesign::Body','Body001') + doc.Body001.Label = 'Body001' + + # act + # Set up the subshapebinder version + binder = doc.Body.newObject('PartDesign::SubShapeBinder','Binder') + binder.Support = [(doc.Fusion, (""))] + doc.recompute() + + # Set up the base feature version + doc.Body001.BaseFeature = App.activeDocument().Fusion + doc.recompute() + + # assert + self.assertEqual(doc.Body.OutList[1].Shape.ElementMapSize, 26) # subobjects ( subshapebinder here ) should have elementmap + self.assertEqual(doc.Body.Shape.ElementMapSize, 0) # TODO: This is Sus, although LS3 passes. Might be because + # SubShapeBinder is different in LS3. + self.assertEqual(doc.Body001.BaseFeature.Shape.ElementMapSize, 26) # base feature lookup should have element map + self.assertEqual(doc.Body001.Shape.ElementMapSize, 26) # Body Shape should have element map + + + def testBaseFeatureAttachmentSupport(self): + # Arrange + doc = App.ActiveDocument + doc.addObject("Part::Box","Box") + doc.ActiveObject.Label = "Cube" + doc.recompute() + doc.addObject("Part::Box","Box") + doc.ActiveObject.Label = "Cube" + doc.Box001.Placement=App.Placement(App.Vector(5.00,5.00,5.00),App.Rotation(App.Vector(0.00,0.00,1.00),0.00)) + doc.recompute() + + doc.addObject("Part::MultiFuse","Fusion") + doc.Fusion.Shapes = [doc.Box, doc.Box001,] + + doc.recompute() + # doc.Box.Visibility = False + # doc.Box001.Visibility = False + # doc.recompute() + + doc.addObject('PartDesign::Body','Body') + doc.Body.Label = 'Body' + doc.Body.BaseFeature = App.activeDocument().Fusion + doc.recompute() + + doc.Body.newObject('Sketcher::SketchObject','Sketch') + doc.Sketch.AttachmentSupport = (doc.getObject('BaseFeature'), ('Face8')) + doc.Sketch.MapMode = 'FlatFace' + doc.recompute() + geoList = [] + geoList.append(Part.LineSegment(App.Vector(12.0, 13.0, 0.000000),App.Vector(12.0, 11.0, 0.000000))) + geoList.append(Part.LineSegment(App.Vector(12.0, 11, 0.000000),App.Vector(14.0, 11.0, 0.000000))) + geoList.append(Part.LineSegment(App.Vector(14.0, 11, 0.000000),App.Vector(14.0, 13.0, 0.000000))) + geoList.append(Part.LineSegment(App.Vector(14.0, 13.0, 0.000000),App.Vector(12, 13.0, 0.000000))) + doc.Sketch.addGeometry(geoList,False) + del geoList + constraintList = [] + constraintList.append(Sketcher.Constraint('Coincident', 0, 2, 1, 1)) + constraintList.append(Sketcher.Constraint('Coincident', 1, 2, 2, 1)) + constraintList.append(Sketcher.Constraint('Coincident', 2, 2, 3, 1)) + constraintList.append(Sketcher.Constraint('Coincident', 3, 2, 0, 1)) + constraintList.append(Sketcher.Constraint('Vertical', 0)) + constraintList.append(Sketcher.Constraint('Vertical', 2)) + constraintList.append(Sketcher.Constraint('Horizontal', 1)) + constraintList.append(Sketcher.Constraint('Horizontal', 3)) + doc.Sketch.addConstraint(constraintList) + del constraintList + constraintList = [] + doc.recompute() + + # Assert that we have a sketch element map before proceeding + self.assertEqual(doc.Sketch.Shape.ElementMapSize,12) + + # Arrange + doc.Body.newObject('PartDesign::Pad','Pad') + doc.Pad.Profile = (doc.Sketch, ['',]) + doc.Pad.Length = 10 + doc.recompute() + doc.Pad.ReferenceAxis = (doc.Sketch,['N_Axis']) + doc.Sketch.Visibility = False + doc.Pad.Length = 10.000000 + doc.Pad.TaperAngle = 0.000000 + doc.Pad.UseCustomVector = 0 + doc.Pad.Direction = (0, -1, 0) + doc.Pad.ReferenceAxis = (doc.Sketch, ['N_Axis']) + doc.Pad.AlongSketchNormal = 1 + doc.Pad.Type = 0 + doc.Pad.UpToFace = None + doc.Pad.Reversed = 0 + doc.Pad.Midplane = 0 + doc.Pad.Offset = 0 + doc.BaseFeature.Visibility = False + doc.Sketch.Visibility = False + doc.recompute() + + # Act + doc.Box001.Width='3.00 mm' + doc.Box001.Placement=App.Placement(App.Vector(5.00,5.00,5.00),App.Rotation(App.Vector(0.00,0.00,1.00),0.00)) + doc.recompute() + # Assert + self.assertEqual(len(doc.Body.Shape.Faces),17) # Check that the object seems right. + self.assertEqual(len(doc.Body.Shape.Edges),42) + self.assertEqual(len(doc.Body.Shape.Vertexes),28) + self.assertEqual(len(doc.Body.Shape.Shells),1) + self.assertEqual(len(doc.Body.Shape.Solids),1) + self.assertEqual(doc.Sketch.AttachmentSupport[0][1][0], 'Face9') # Attachment autochanged from Face8. + # potentially check the .BoundBox ( calc seems off on this, Not applying sketch position to Pad object ) + def create_t_sketch(self): self.Doc.getObject('Body').newObject('Sketcher::SketchObject', 'Sketch') geo_list = [ @@ -1931,3 +2049,4 @@ class TestTopologicalNamingProblem(unittest.TestCase): def tearDown(self): """ Close our test document """ App.closeDocument(self.Doc.Name) + From 3dbc1d7393fd25c7cca3725d5b0583bacffda044 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 27 Jun 2024 16:56:16 -0400 Subject: [PATCH 2/5] Toponaming: Transfer in missing Code for BaseFeatures and Sketches --- src/Mod/Part/App/BodyBase.cpp | 6 ++ src/Mod/Part/App/PartFeature.cpp | 31 +++--- src/Mod/PartDesign/App/Body.cpp | 62 ++++++++++- src/Mod/PartDesign/App/FeatureBase.cpp | 31 ++++-- src/Mod/Sketcher/App/SketchObject.cpp | 144 +++++++++++++++++++++++-- src/Mod/Sketcher/App/SketchObject.h | 3 + 6 files changed, 240 insertions(+), 37 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 8b26c78e14..7bef103057 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -52,6 +52,12 @@ BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) if (body->hasObject(f)) return body; } + // for(;;) { + // auto group = App::GeoFeatureGroupExtension::getGroupOfObject(f); + // if(!group || group->isDerivedFrom(BodyBase::getClassTypeId())) + // return static_cast(group); + // f = group; + // } } return nullptr; diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 50795b6b08..f64183646a 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -387,10 +387,11 @@ App::DocumentObject* Feature::getSubObject(const char* subname, TopoShape ts(Shape.getShape()); bool doTransform = mat != ts.getTransform(); if (doTransform) { - ts.setShape(ts.getShape().Located(TopLoc_Location())); + ts.setShape(ts.getShape().Located(TopLoc_Location()), false); } if (subname && *subname && !ts.isNull()) { - ts = ts.getSubShape(subname); + // ts = ts.getSubShape(subname); // TODO WAS THIS WRONG? + ts = ts.getSubTopoShape(subname,true); } if (doTransform && !ts.isNull()) { static int sCopy = -1; @@ -483,13 +484,12 @@ static std::vector> getElementSource(App::Docu break; } } - // TODO: 02/24 Toponaming project: It appears that getElementOwner is always nullptr. - // if (owner->isDerivedFrom(App::GeoFeature::getClassTypeId())) { - // auto o = - // static_cast(owner)->getElementOwner(ret.back().second); - // if (o) - // doc = o->getDocument(); - // } + if (owner->isDerivedFrom(App::GeoFeature::getClassTypeId())) { + auto o = + static_cast(owner)->getElementOwner(ret.back().second); + if (o) + doc = o->getDocument(); + } obj = doc->getObjectByID(tag < 0 ? -tag : tag); if (type) { for (auto& hist : history) { @@ -586,13 +586,12 @@ std::list Feature::getElementHistory(App::DocumentObject* fea break; } } - // TODO: 02/24 Toponaming project: It appears that getElementOwner is always nullptr. - // if(feature->isDerivedFrom(App::GeoFeature::getClassTypeId())) { - // auto owner = - // static_cast(feature)->getElementOwner(element); - // if(owner) - // doc = owner->getDocument(); - // } + if(feature->isDerivedFrom(App::GeoFeature::getClassTypeId())) { + auto owner = + static_cast(feature)->getElementOwner(element); + if(owner) + doc = owner->getDocument(); + } obj = doc->getObjectByID(std::abs(tag)); } if (!recursive) { diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 930b160ba0..0ca740c239 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -32,6 +32,7 @@ #include "BodyPy.h" #include "FeatureBase.h" #include "FeatureSketchBased.h" +#include "FeatureSolid.h" #include "FeatureTransformed.h" #include "ShapeBinder.h" @@ -118,6 +119,22 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) start = Tip.getValue(); } +// +// #ifdef FC_USE_TNP_FIX +// int index; +// if (!start || !start->getNameInDocument() +// // || start->isDerivedFrom(PartDesign::Extrusion::getClassTypeId()) +// || start->isDerivedFrom(PartDesign::Solid::getClassTypeId()) +// || !this->Group.find(start->getNameInDocument(), &index)) { // No Tip +// return nullptr; +// } +// const auto & objs = this->Group.getValues(); +// for (--index; index>=0; --index) { +// if (isSolidFeature(objs[index])) +// return objs[index]; +// } +// +// #else if (!start) { // No Tip return nullptr; } @@ -136,7 +153,7 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) if (rvIt != features.rend()) { // the solid found in model list return *rvIt; } - +// #endif return nullptr; } @@ -146,6 +163,20 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start) start = Tip.getValue(); } +// #ifdef FC_USE_TNP_FIX +// int index; +// if (!start || !start->getNameInDocument() +// || !this->Group.find(start->getNameInDocument(), &index)) { // No Tip +// return nullptr; +// } +// +// const auto & objs = this->Group.getValues(); +// int count = this->Group.getSize(); +// for (++index; indexisDerivedFrom()) { if (PartDesign::Feature::isDatum(obj)) { // Datum objects are not solid @@ -375,6 +409,7 @@ std::vector Body::removeObject(App::DocumentObject* featur App::DocumentObjectExecReturn *Body::execute() { + Part::BodyBase::execute(); /* Base::Console().Error("Body '%s':\n", getNameInDocument()); App::DocumentObject* tip = Tip.getValue(); @@ -502,6 +537,29 @@ std::vector Body::getSubObjects(int reason) const { App::DocumentObject *Body::getSubObject(const char *subname, PyObject **pyObj, Base::Matrix4D *pmat, bool transform, int depth) const { + // while(subname && *subname=='.') ++subname; // skip leading . + // + // // PartDesign::Feature now support grouping sibling features, and the user + // // is free to expand/collapse at any time. To not disrupt subname path + // // because of this, the body will peek the next two sub-objects reference, + // // and skip the first sub-object if possible. + // if(subname) { + // const char * firstDot = strchr(subname,'.'); + // if (firstDot) { + // const char * secondDot = strchr(firstDot+1, '.'); + // if (secondDot) { + // auto firstObj = Group.find(std::string(subname, firstDot).c_str()); + // if (!firstObj || firstObj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // auto secondObj = Group.find(std::string(firstDot+1, secondDot).c_str()); + // if (secondObj) { + // // we support only one level of sibling grouping, so no + // // recursive call to our own getSubObject() + // return Part::BodyBase::getSubObject(firstDot+1,pyObj,pmat,transform,depth+1); + // } + // } + // } + // } + // } #if 1 return Part::BodyBase::getSubObject(subname,pyObj,pmat,transform,depth); #else diff --git a/src/Mod/PartDesign/App/FeatureBase.cpp b/src/Mod/PartDesign/App/FeatureBase.cpp index d7fc21cb66..add16252a6 100644 --- a/src/Mod/PartDesign/App/FeatureBase.cpp +++ b/src/Mod/PartDesign/App/FeatureBase.cpp @@ -52,21 +52,31 @@ short int FeatureBase::mustExecute() const { if(BaseFeature.isTouched()) return 1; - return Part::Feature::mustExecute(); + return PartDesign::Feature::mustExecute(); } -App::DocumentObjectExecReturn* FeatureBase::execute() { +App::DocumentObjectExecReturn* FeatureBase::execute() +{ - if(!BaseFeature.getValue()) - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "BaseFeature link is not set")); + if (!BaseFeature.getValue()) { + return new App::DocumentObjectExecReturn( + QT_TRANSLATE_NOOP("Exception", "BaseFeature link is not set")); + } - if(!BaseFeature.getValue()->isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "BaseFeature must be a Part::Feature")); + if (!BaseFeature.getValue()->isDerivedFrom(Part::Feature::getClassTypeId())) { + return new App::DocumentObjectExecReturn( + QT_TRANSLATE_NOOP("Exception", "BaseFeature must be a Part::Feature")); + } - auto shape = static_cast(BaseFeature.getValue())->Shape.getValue(); - if (shape.IsNull()) - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "BaseFeature has an empty shape")); + auto shape = Part::Feature::getTopoShape(BaseFeature.getValue()); + if (!shape.countSubShapes(TopAbs_SOLID)) { + shape = shape.makeElementSolid(); + } + if (shape.isNull()) { + return new App::DocumentObjectExecReturn( + QT_TRANSLATE_NOOP("Exception", "BaseFeature has an empty shape")); + } Shape.setValue(shape); @@ -91,7 +101,7 @@ void FeatureBase::onChanged(const App::Property* prop) { trySetBaseFeatureOfBody(); } - Part::Feature::onChanged(prop); + PartDesign::Feature::onChanged(prop); } void FeatureBase::onDocumentRestored() @@ -100,6 +110,7 @@ void FeatureBase::onDocumentRestored() auto body = getFeatureBody(); if (!body) Placement.setStatus(App::Property::Hidden, false); + PartDesign::Feature::onDocumentRestored(); } }//namespace PartDesign diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index c595c57d8b..f45284e5ff 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -85,6 +85,10 @@ #include "SketchObjectPy.h" #include "SolverGeometryExtension.h" +#include +#include +#include + #undef DEBUG // #define DEBUG @@ -265,7 +269,8 @@ void SketchObject::buildShape() Part::TopoShape vertex(TopoDS::Vertex(geo->toShape())); int idx = getVertexIndexGeoPos(i-1, Sketcher::PointPos::start); std::string name = convertSubName(Data::IndexedName::fromConst("Vertex", idx+1), false); - + vertex.setElementName(Data::IndexedName::fromConst("Vertex", 1), + Data::MappedName::fromRawData(name.c_str()), 0L); vertices.push_back(vertex); vertices.back().copyElementMap(vertex, Part::OpCodes::Sketch); } else { @@ -285,14 +290,14 @@ void SketchObject::buildShape() } // 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())); - // } + 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()); return; @@ -9420,6 +9425,127 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint* cstr, bool bForce, bool return true; } +App::DocumentObject *SketchObject::getSubObject( + const char *subname, PyObject **pyObj, + Base::Matrix4D *pmat, bool transform, int depth) const +{ + while(subname && *subname=='.') ++subname; // skip leading . + std::string sub; + const char *mapped = Data::isMappedElement(subname); + if(!subname || !subname[0]) + return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); + const char *element = Data::findElementName(subname); + // if(element != subname) { + // const char *dot = strchr(subname,'.'); + // if(!dot) + // return 0; + // std::string name(subname,dot-subname); + // auto child = Exports.find(name.c_str()); + // if(!child) + // return 0; + // return child->getSubObject(dot+1,pyObj,pmat,true,depth+1); + // } + + Data::IndexedName indexedName = checkSubName(subname); + int index = indexedName.getIndex(); + const char * shapetype = indexedName.getType(); + const Part::Geometry *geo = 0; + Part::TopoShape subshape; + Base::Vector3d point; + + if (auto realType = convertInternalName(indexedName.getType())) { + if (realType[0] == '\0') + // subshape = InternalShape.getShape(); + subshape = Shape.getShape(); + else { + auto shapeType = Part::TopoShape::shapeType(realType, true); + if (shapeType != TopAbs_SHAPE) + // subshape = InternalShape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); + subshape = Shape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); + } + if (subshape.isNull()) + return nullptr; + } + else if (!pyObj || !mapped) { + if (!pyObj + || (index > 0 + && !boost::algorithm::contains(subname, "edge") + && !boost::algorithm::contains(subname, "vertex"))) + return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); + } else { + subshape = Shape.getShape().getSubTopoShape(subname, true); + if (!subshape.isNull()) + return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); + } + + if (subshape.isNull()) { + if (boost::equals(shapetype,"Edge") || + boost::equals(shapetype,"edge")) { + geo = getGeometry(index - 1); + if (!geo) + return nullptr; + } else if (boost::equals(shapetype,"ExternalEdge")) { + int GeoId = index - 1; + GeoId = -GeoId - 3; + geo = getGeometry(GeoId); + if(!geo) + return nullptr; + } else if (boost::equals(shapetype,"Vertex") || + boost::equals(shapetype,"vertex")) { + int VtId = index- 1; + int GeoId; + PointPos PosId; + getGeoVertexIndex(VtId,GeoId,PosId); + if (PosId==PointPos::none) + return nullptr; + point = getPoint(GeoId,PosId); + } + else if (boost::equals(shapetype,"RootPoint")) + point = getPoint(Sketcher::GeoEnum::RtPnt,PointPos::start); + else if (boost::equals(shapetype,"H_Axis")) + geo = getGeometry(Sketcher::GeoEnum::HAxis); + else if (boost::equals(shapetype,"V_Axis")) + geo = getGeometry(Sketcher::GeoEnum::VAxis); + else if (boost::equals(shapetype,"Constraint")) { + int ConstrId = PropertyConstraintList::getIndexFromConstraintName(shapetype); + const std::vector< Constraint * > &vals = this->Constraints.getValues(); + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return nullptr; + if(pyObj) + *pyObj = vals[ConstrId]->getPyObject(); + return const_cast(this); + } else + return nullptr; + } + + if (pmat && transform) + *pmat *= Placement.getValue().toMatrix(); + + if (pyObj) { + Part::TopoShape shape; + std::string name = convertSubName(indexedName,false); + if (geo) { + shape = getEdge(geo,name.c_str()); + if(pmat && !shape.isNull()) + shape.transformShape(*pmat,false,true); + } else if (!subshape.isNull()) { + shape = subshape; + if (pmat) + shape.transformShape(*pmat,false,true); + } else { + if(pmat) + point = (*pmat)*point; + shape = BRepBuilderAPI_MakeVertex(gp_Pnt(point.x,point.y,point.z)).Vertex(); + shape.setElementName(Data::IndexedName::fromConst("Vertex", 1), + Data::MappedName::fromRawData(name.c_str()), 0); + } + shape.Tag = getID(); + *pyObj = Py::new_reference_to(Part::shape2pyshape(shape)); + } + + return const_cast(this); +} + void SketchObject::setExpression(const App::ObjectIdentifier& path, std::shared_ptr expr) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 2a5ab1b713..41875a8dd5 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -672,6 +672,9 @@ public: bool& yinv, eReasonList* rsn = nullptr) const; + DocumentObject *getSubObject(const char *subname, PyObject **pyObj=0, + Base::Matrix4D *mat=0, bool transform=true, int depth=0) const override; + Part::TopoShape getEdge(const Part::Geometry* geo, const char* name) const; Data::IndexedName checkSubName(const char* sub) const; From 08859462ea64f90483ca5bd18010d7f4ea77eb3f Mon Sep 17 00:00:00 2001 From: bgbsww Date: Thu, 27 Jun 2024 18:21:00 -0400 Subject: [PATCH 3/5] Toponaming: Cleanups --- src/Mod/Part/App/BodyBase.cpp | 6 --- src/Mod/Part/App/PartFeature.cpp | 1 - src/Mod/PartDesign/App/Body.cpp | 55 --------------------------- src/Mod/Sketcher/App/SketchObject.cpp | 12 ------ 4 files changed, 74 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 7bef103057..8b26c78e14 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -52,12 +52,6 @@ BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) if (body->hasObject(f)) return body; } - // for(;;) { - // auto group = App::GeoFeatureGroupExtension::getGroupOfObject(f); - // if(!group || group->isDerivedFrom(BodyBase::getClassTypeId())) - // return static_cast(group); - // f = group; - // } } return nullptr; diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index f64183646a..e6be3036ef 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -390,7 +390,6 @@ App::DocumentObject* Feature::getSubObject(const char* subname, ts.setShape(ts.getShape().Located(TopLoc_Location()), false); } if (subname && *subname && !ts.isNull()) { - // ts = ts.getSubShape(subname); // TODO WAS THIS WRONG? ts = ts.getSubTopoShape(subname,true); } if (doTransform && !ts.isNull()) { diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 0ca740c239..4caf52d176 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -119,22 +119,6 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) start = Tip.getValue(); } -// -// #ifdef FC_USE_TNP_FIX -// int index; -// if (!start || !start->getNameInDocument() -// // || start->isDerivedFrom(PartDesign::Extrusion::getClassTypeId()) -// || start->isDerivedFrom(PartDesign::Solid::getClassTypeId()) -// || !this->Group.find(start->getNameInDocument(), &index)) { // No Tip -// return nullptr; -// } -// const auto & objs = this->Group.getValues(); -// for (--index; index>=0; --index) { -// if (isSolidFeature(objs[index])) -// return objs[index]; -// } -// -// #else if (!start) { // No Tip return nullptr; } @@ -153,7 +137,6 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) if (rvIt != features.rend()) { // the solid found in model list return *rvIt; } -// #endif return nullptr; } @@ -163,20 +146,6 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start) start = Tip.getValue(); } -// #ifdef FC_USE_TNP_FIX -// int index; -// if (!start || !start->getNameInDocument() -// || !this->Group.find(start->getNameInDocument(), &index)) { // No Tip -// return nullptr; -// } -// -// const auto & objs = this->Group.getValues(); -// int count = this->Group.getSize(); -// for (++index; index Body::getSubObjects(int reason) const { App::DocumentObject *Body::getSubObject(const char *subname, PyObject **pyObj, Base::Matrix4D *pmat, bool transform, int depth) const { - // while(subname && *subname=='.') ++subname; // skip leading . - // - // // PartDesign::Feature now support grouping sibling features, and the user - // // is free to expand/collapse at any time. To not disrupt subname path - // // because of this, the body will peek the next two sub-objects reference, - // // and skip the first sub-object if possible. - // if(subname) { - // const char * firstDot = strchr(subname,'.'); - // if (firstDot) { - // const char * secondDot = strchr(firstDot+1, '.'); - // if (secondDot) { - // auto firstObj = Group.find(std::string(subname, firstDot).c_str()); - // if (!firstObj || firstObj->isDerivedFrom(PartDesign::Feature::getClassTypeId())) { - // auto secondObj = Group.find(std::string(firstDot+1, secondDot).c_str()); - // if (secondObj) { - // // we support only one level of sibling grouping, so no - // // recursive call to our own getSubObject() - // return Part::BodyBase::getSubObject(firstDot+1,pyObj,pmat,transform,depth+1); - // } - // } - // } - // } - // } #if 1 return Part::BodyBase::getSubObject(subname,pyObj,pmat,transform,depth); #else diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index f45284e5ff..a60e8d8576 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -9435,16 +9435,6 @@ App::DocumentObject *SketchObject::getSubObject( if(!subname || !subname[0]) return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); const char *element = Data::findElementName(subname); - // if(element != subname) { - // const char *dot = strchr(subname,'.'); - // if(!dot) - // return 0; - // std::string name(subname,dot-subname); - // auto child = Exports.find(name.c_str()); - // if(!child) - // return 0; - // return child->getSubObject(dot+1,pyObj,pmat,true,depth+1); - // } Data::IndexedName indexedName = checkSubName(subname); int index = indexedName.getIndex(); @@ -9455,12 +9445,10 @@ App::DocumentObject *SketchObject::getSubObject( if (auto realType = convertInternalName(indexedName.getType())) { if (realType[0] == '\0') - // subshape = InternalShape.getShape(); subshape = Shape.getShape(); else { auto shapeType = Part::TopoShape::shapeType(realType, true); if (shapeType != TopAbs_SHAPE) - // subshape = InternalShape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); subshape = Shape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); } if (subshape.isNull()) From 3d6a4900038feab12d75f6bc0d6dfc271f209336 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 22:25:06 +0000 Subject: [PATCH 4/5] Review cleanups --- src/Mod/Part/App/PartFeature.cpp | 20 +++++++++++--------- src/Mod/PartDesign/App/Body.cpp | 3 --- src/Mod/Sketcher/App/SketchObject.h | 7 +++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index e6be3036ef..60fad39631 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -484,10 +484,11 @@ static std::vector> getElementSource(App::Docu } } if (owner->isDerivedFrom(App::GeoFeature::getClassTypeId())) { - auto o = - static_cast(owner)->getElementOwner(ret.back().second); - if (o) - doc = o->getDocument(); + auto ownerGeoFeature = + static_cast(owner)->getElementOwner(ret.back().second); + if (ownerGeoFeature) { + doc = ownerGeoFeature->getDocument(); + } } obj = doc->getObjectByID(tag < 0 ? -tag : tag); if (type) { @@ -585,11 +586,12 @@ std::list Feature::getElementHistory(App::DocumentObject* fea break; } } - if(feature->isDerivedFrom(App::GeoFeature::getClassTypeId())) { - auto owner = - static_cast(feature)->getElementOwner(element); - if(owner) - doc = owner->getDocument(); + if (feature->isDerivedFrom(App::GeoFeature::getClassTypeId())) { + auto ownerGeoFeature = + static_cast(feature)->getElementOwner(element); + if (ownerGeoFeature) { + doc = ownerGeoFeature->getDocument(); + } } obj = doc->getObjectByID(std::abs(tag)); } diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 4caf52d176..b9fd563da4 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -189,9 +189,6 @@ bool Body::isSolidFeature(const App::DocumentObject *obj) return false; } - // if (obj == BaseFeature.getValue()) - // return true; - if (obj->isDerivedFrom()) { if (PartDesign::Feature::isDatum(obj)) { // Datum objects are not solid diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 41875a8dd5..b6a10acbc4 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -672,8 +672,11 @@ public: bool& yinv, eReasonList* rsn = nullptr) const; - DocumentObject *getSubObject(const char *subname, PyObject **pyObj=0, - Base::Matrix4D *mat=0, bool transform=true, int depth=0) const override; + DocumentObject* getSubObject(const char* subname, + PyObject** pyObj = 0, + Base::Matrix4D* mat = 0, + bool transform = true, + int depth = 0) const override; Part::TopoShape getEdge(const Part::Geometry* geo, const char* name) const; From bdcdb630c0b258dd56c20145e83b831ac6a2ba48 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Fri, 28 Jun 2024 22:21:03 -0400 Subject: [PATCH 5/5] Cleanup --- src/Mod/Sketcher/App/SketchObject.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index a60e8d8576..36e2c579c5 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -259,7 +259,7 @@ void SketchObject::buildShape() std::vector shapes; std::vector vertices; - int i=0; + unsigned i=0; for(auto geo : getInternalGeometry()) { ++i; if(GeometryFacade::getConstruction(geo)) @@ -9434,7 +9434,6 @@ App::DocumentObject *SketchObject::getSubObject( const char *mapped = Data::isMappedElement(subname); if(!subname || !subname[0]) return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); - const char *element = Data::findElementName(subname); Data::IndexedName indexedName = checkSubName(subname); int index = indexedName.getIndex();