Since PartDesign is open for invasion, I think it's worth publishing a little tutorial on what is needed to integrate into PartDesign workflow.
So far I figured out this:
1. build your python feature on PartDesign::FeaturePython
Code: Select all
new_feature = App.ActiveDocument.addObject('PartDesign::FeaturePython', 'NameOfFeature')
proxy = MyCoolFeature(new_feature)
vp_proxy = ViewProviderMyCoolFeature(new_feature.ViewObject)
* BaseFeature property, which points to the previous object in partdesign sequence. It can be None, if the thing is the first feature in the sequence.
* ViewObject has a method "makeTemporaryVisible", which can be handy in task dialog implementation.
As of now (0.17.10422), it offers no extra overrides compared to Part::FeaturePython
2. Creation and deletion
When creating a new object, you need to add it to active Body. To get active body, use this:
Code: Select all
body = Gui.ActiveDocument.ActiveView.getActiveObject('pdbody')
Code: Select all
body.addObject(new_feature)
Likewise, when your feature is deleted, you should remove the feature from the body, so that it closes the gap in sequence.
Code: Select all
class ViewProviderMyCoolFeature:
...
def onDelete(self, viewprovider, subname):
body = ...
body.removeObject(viewprovider.Object)
return True
As you may have noticed, you need a way to find the body that contains the feature. ActiveBody won't do. In future, there will be a direct way of obtaining that from FreeCAD, but as of now, you have to roll your own.
Code: Select all
def findBodyOf(feature):
bodies = feature.Document.findObjects("PartDesign::Body")
result = [body for body in bodies if feature in body.Group]
assert(len(result)<=1)
return None if len(result)==0 else result[0]
3. executing
Your execute() should write the shape that includes all the previous features and your feature, to its Shape property. It must write out a single solid. Please note that solid.fuse(othersolid) returns a compound, not solid.
Special care should be taken around Placements. Getting Placement to move only the feature but not the rest of the object requires somewhat tricky manipulations with Placement and shape transform, so the easiest way around is to simply block out user from editing Placement, and update it to match the placement of the computed shape, like that:
Code: Select all
def execute(self, selfobj):
....
selfobj.Placement = result_shape.Placement
selfobj.Shape = result_shape