I have got everything to work for me when I use my script (below) to create only one carcass with 2 doors. I can move the carcass anywhere and turn it around the z axis to any angle and the doors will follow, but they are still independent so that I can make them invisible while still seeing the carcass. Exactly what I want.
The problem arises when I use the macro a second time, or more times in the same document. I get new new carcasses as expected (Carcass001, Carcass002, . . .), and I also get new doors packaged in compounds (Compound 001, Compound002, ...). The problem is that all the doors take their size and orientation information only from the original Carcass. So all sets of doors are stacked on top of each other in front of Carcass, and they all change size or orientation only with changes made to Carcass, not Carcass001, or Carcass002 etc.
This is obviously an issue about what is referred to by the door Expression script lines for size and placement. It is always the same object in the Active Document regardless of how many new carcasses are added. Any ideas on how to make the doors refer to the correct carcass? (I tried a direct reference along the lines of leftDoorObj.width = carcassObj.width/2 which works to create doors with proper size and orientation, but which are not parametric and therefore do not change size and orientation with the carcass)
Here is my code.
Code: Select all
# This calls Carcass.py and DoorTest.py
# uses Expressions to set door size and orientation to that of carcass.
import Part,FreeCAD
# Define variables
Thickness = 0.75*25.4
Width = 20*25.4
Height = 30.25*25.4
Depth = 23.75*25.4
DoorThickness = 0.75*25.4
# Carcass Maker
import Carcass # contains Class CarcassShape, produces a solid called Carcass
carcassObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Carcass")
Carcass.CarcassShape(carcassObj,Thickness,Width,Height,Depth)
carcassObj.ViewObject.Proxy = 0 # this is mandatory unless we code the ViewProvider
# Left Door Maker
import DoorTest # contains Class TestDoorShape, produces a solid called TestDoor
leftDoorObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","TestDoor")
# pass cabinet width and height to DoorTest.py
DoorTest.TestDoorShape(leftDoorObj,DoorThickness,Width,Height)
leftDoorObj.setExpression("width", "Carcass.width*0.5") # comment in for 2 doors
# leftDoorObj.setExpression("width", "Carcass.width") #comment in for one door
leftDoorObj.setExpression("height", "Carcass.height")
leftDoorObj.ViewObject.Proxy = 0
# Right Door Maker / BLOCK COMMENT OUT FOR ONE DOOR
import DoorTest
rightDoorObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","TestDoor")
DoorTest.TestDoorShape(rightDoorObj,DoorThickness,Width,Height) # passes cabinet width and height
# to DoorTest.py
rightDoorObj.setExpression('width', 'Carcass.width*0.5') # comment out for one door
rightDoorObj.setExpression("height", "Carcass.height")
rightDoorObj.setExpression('Placement.Base.x', u'Carcass.width/2 ')
rightDoorObj.ViewObject.Proxy = 0
# Make 2 Doors into a Compound
Doors = App.activeDocument().addObject("Part::Compound","Compound")
Doors.Links = (leftDoorObj,rightDoorObj)
App.ActiveDocument.recompute()
# Make Doors follow cabinet when it is moved. Works properly in first use of Macro.
# ***There is still a problem on additional uses of Macro: Applies first Carcass size
# and position to Compound001, Compound002, etc which then all follow size and moves
# of Carcass instead of Carcass001, Carcass002, etc ***
Doors.setExpression('Placement.Base.x', u'Carcass.Placement.Base.x')
Doors.setExpression('Placement.Base.y', u'Carcass.Placement.Base.y')
Doors.setExpression('Placement.Base.z', u'Carcass.Placement.Base.z')
Doors.setExpression('Placement.Rotation.Angle', u'Carcass.Placement.Rotation.Angle')
I will make an effort to try the 'App::PropertyLink' method soon. Could you point out, or annotate, in your example code what is an example of saving a reference to a scripted object, and assigning an object to it. I can't tell by looking at bare code. No amount of doing searches of documentation or forum entries has yielded anything of value. Your explanation of what it is supposed to do, however, makes complete sense to me.
Joel_graff wrote: ↑Sun Mar 17, 2019 2:59 am 1. Add a property to the furniture parts that need to be updated when the carcass changes. The property type needs to be 'App::PropertyLink'
2. After the scripted object is created, save a reference to it and assign the carcass object to the PropertyLink property
That's it.
Whenever the carcass gets recomputed, the execute() method of any furntire part scripted objects that are linked to it will be called.
A sample of code to help get you started: