Merge pull request #14994 from bgbsww/bgbsww-toponamingBaseFeatureTNP
Toponaming: support base feature in body correctly.
This commit is contained in:
@@ -387,10 +387,10 @@ 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.getSubTopoShape(subname,true);
|
||||
}
|
||||
if (doTransform && !ts.isNull()) {
|
||||
static int sCopy = -1;
|
||||
@@ -483,13 +483,13 @@ static std::vector<std::pair<long, Data::MappedName>> 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<App::GeoFeature*>(owner)->getElementOwner(ret.back().second);
|
||||
// if (o)
|
||||
// doc = o->getDocument();
|
||||
// }
|
||||
if (owner->isDerivedFrom(App::GeoFeature::getClassTypeId())) {
|
||||
auto ownerGeoFeature =
|
||||
static_cast<App::GeoFeature*>(owner)->getElementOwner(ret.back().second);
|
||||
if (ownerGeoFeature) {
|
||||
doc = ownerGeoFeature->getDocument();
|
||||
}
|
||||
}
|
||||
obj = doc->getObjectByID(tag < 0 ? -tag : tag);
|
||||
if (type) {
|
||||
for (auto& hist : history) {
|
||||
@@ -586,13 +586,13 @@ std::list<Data::HistoryItem> 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<App::GeoFeature*>(feature)->getElementOwner(element);
|
||||
// if(owner)
|
||||
// doc = owner->getDocument();
|
||||
// }
|
||||
if (feature->isDerivedFrom(App::GeoFeature::getClassTypeId())) {
|
||||
auto ownerGeoFeature =
|
||||
static_cast<App::GeoFeature*>(feature)->getElementOwner(element);
|
||||
if (ownerGeoFeature) {
|
||||
doc = ownerGeoFeature->getDocument();
|
||||
}
|
||||
}
|
||||
obj = doc->getObjectByID(std::abs(tag));
|
||||
}
|
||||
if (!recursive) {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "BodyPy.h"
|
||||
#include "FeatureBase.h"
|
||||
#include "FeatureSketchBased.h"
|
||||
#include "FeatureSolid.h"
|
||||
#include "FeatureTransformed.h"
|
||||
#include "ShapeBinder.h"
|
||||
|
||||
@@ -136,7 +137,6 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start)
|
||||
if (rvIt != features.rend()) { // the solid found in model list
|
||||
return *rvIt;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,6 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start)
|
||||
if (rvIt != features.end()) { // the solid found in model list
|
||||
return *rvIt;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -375,6 +374,7 @@ std::vector<App::DocumentObject*> Body::removeObject(App::DocumentObject* featur
|
||||
|
||||
App::DocumentObjectExecReturn *Body::execute()
|
||||
{
|
||||
Part::BodyBase::execute();
|
||||
/*
|
||||
Base::Console().Error("Body '%s':\n", getNameInDocument());
|
||||
App::DocumentObject* tip = Tip.getValue();
|
||||
|
||||
@@ -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<Part::Feature*>(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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
#include "SketchObjectPy.h"
|
||||
#include "SolverGeometryExtension.h"
|
||||
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <ExternalGeometryFacade.h>
|
||||
#include <Mod/Part/App/PartPyCXX.h>
|
||||
|
||||
|
||||
#undef DEBUG
|
||||
// #define DEBUG
|
||||
@@ -255,7 +259,7 @@ void SketchObject::buildShape()
|
||||
|
||||
std::vector<Part::TopoShape> shapes;
|
||||
std::vector<Part::TopoShape> vertices;
|
||||
int i=0;
|
||||
unsigned i=0;
|
||||
for(auto geo : getInternalGeometry()) {
|
||||
++i;
|
||||
if(GeometryFacade::getConstruction(geo))
|
||||
@@ -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;i<ExternalGeo.getSize();++i) {
|
||||
// auto geo = ExternalGeo[i];
|
||||
// auto egf = ExternalGeometryFacade::getFacade(geo);
|
||||
// if(!egf->testFlag(ExternalGeometryExtension::Defining))
|
||||
// continue;
|
||||
// shapes.push_back(getEdge(geo, convertSubName(
|
||||
// Data::IndexedName::fromConst("ExternalEdge", i-1), false).c_str()));
|
||||
// }
|
||||
for(i=2;i<ExternalGeo.size();++i) {
|
||||
auto geo = ExternalGeo[i];
|
||||
auto egf = ExternalGeometryFacade::getFacade(geo);
|
||||
if(!egf->testFlag(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,114 @@ 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);
|
||||
|
||||
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 = Shape.getShape();
|
||||
else {
|
||||
auto shapeType = Part::TopoShape::shapeType(realType, true);
|
||||
if (shapeType != TopAbs_SHAPE)
|
||||
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<SketchObject*>(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<SketchObject*>(this);
|
||||
}
|
||||
|
||||
void SketchObject::setExpression(const App::ObjectIdentifier& path,
|
||||
std::shared_ptr<App::Expression> expr)
|
||||
{
|
||||
|
||||
@@ -672,6 +672,12 @@ 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;
|
||||
|
||||
Reference in New Issue
Block a user