Assembly: Fix case of link groups
This commit is contained in:
committed by
Yorik van Havre
parent
5cb2fd5261
commit
7c6dde17fb
@@ -92,7 +92,7 @@ namespace PartApp = Part;
|
||||
using namespace Assembly;
|
||||
using namespace MbD;
|
||||
|
||||
void printPlacement(Base::Placement plc, const char* name)
|
||||
static void printPlacement(Base::Placement plc, const char* name)
|
||||
{
|
||||
Base::Vector3d pos = plc.getPosition();
|
||||
Base::Vector3d axis;
|
||||
@@ -111,6 +111,39 @@ void printPlacement(Base::Placement plc, const char* name)
|
||||
angle);
|
||||
}
|
||||
|
||||
static bool isLink(App::DocumentObject* obj)
|
||||
{
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
if (link) {
|
||||
return link->ElementCount.getValue() == 0;
|
||||
}
|
||||
|
||||
auto* linkEl = dynamic_cast<App::LinkElement*>(obj);
|
||||
if (linkEl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isLinkGroup(App::DocumentObject* obj)
|
||||
{
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
if (link) {
|
||||
return link->ElementCount.getValue() > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ================================ Assembly Object ============================
|
||||
|
||||
PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part)
|
||||
@@ -144,6 +177,8 @@ App::DocumentObjectExecReturn* AssemblyObject::execute()
|
||||
|
||||
int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
{
|
||||
ensureIdentityPlacements();
|
||||
|
||||
mbdAssembly = makeMbdAssembly();
|
||||
objectPartMap.clear();
|
||||
|
||||
@@ -454,7 +489,7 @@ App::DocumentObject* AssemblyObject::getJointOfPartConnectingToGround(App::Docum
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JointGroup* AssemblyObject::getJointGroup(App::Part* part)
|
||||
JointGroup* AssemblyObject::getJointGroup(const App::Part* part)
|
||||
{
|
||||
App::Document* doc = part->getDocument();
|
||||
|
||||
@@ -471,12 +506,12 @@ JointGroup* AssemblyObject::getJointGroup(App::Part* part)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JointGroup* AssemblyObject::getJointGroup()
|
||||
JointGroup* AssemblyObject::getJointGroup() const
|
||||
{
|
||||
return getJointGroup(this);
|
||||
}
|
||||
|
||||
ViewGroup* AssemblyObject::getExplodedViewGroup()
|
||||
ViewGroup* AssemblyObject::getExplodedViewGroup() const
|
||||
{
|
||||
App::Document* doc = getDocument();
|
||||
|
||||
@@ -1693,6 +1728,37 @@ void AssemblyObject::updateGroundedJointsPlacements()
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyObject::ensureIdentityPlacements()
|
||||
{
|
||||
std::vector<App::DocumentObject*> group = Group.getValues();
|
||||
for (auto* obj : group) {
|
||||
// When used in assembly, link groups must have identity placements.
|
||||
if (isLinkGroup(obj)) {
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
auto* pPlc = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
if (!pPlc || !link) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Base::Placement plc = pPlc->getValue();
|
||||
if (plc.isIdentity()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pPlc->setValue(Base::Placement());
|
||||
obj->purgeTouched();
|
||||
|
||||
// To keep the LinkElement positions, we apply plc to their placements
|
||||
std::vector<App::DocumentObject*> elts = link->ElementList.getValues();
|
||||
for (auto* elt : elts) {
|
||||
pPlc = dynamic_cast<App::PropertyPlacement*>(elt->getPropertyByName("Placement"));
|
||||
pPlc->setValue(plc * pPlc->getValue());
|
||||
elt->purgeTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================= Utils ======================================
|
||||
|
||||
void AssemblyObject::swapJCS(App::DocumentObject* joint)
|
||||
@@ -2055,7 +2121,7 @@ Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* targetOb
|
||||
if (obj == targetObj) {
|
||||
return plc;
|
||||
}
|
||||
if (obj->isDerivedFrom<App::Link>()) {
|
||||
if (isLink(obj)) {
|
||||
// Update doc in case its an external link.
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
@@ -2240,7 +2306,7 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::Part>()) {
|
||||
if (obj->isDerivedFrom<App::Part>() || isLinkGroup(obj)) {
|
||||
continue;
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
@@ -2250,7 +2316,7 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std
|
||||
// Primitive, fastener, gear, etc.
|
||||
return obj;
|
||||
}
|
||||
else if (obj->isDerivedFrom<App::Link>()) {
|
||||
else if (isLink(obj)) {
|
||||
App::DocumentObject* linked_obj = obj->getLinkedObject();
|
||||
if (linked_obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
auto* retObj = handlePartDesignBody(linked_obj, it);
|
||||
@@ -2315,7 +2381,7 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::Link>()) { // update the document if necessary for next object
|
||||
if (isLink(obj)) { // update the document if necessary for next object
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
|
||||
@@ -2332,6 +2398,10 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
continue; // we ignore groups.
|
||||
}
|
||||
|
||||
if (isLinkGroup(obj)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,6 +171,8 @@ public:
|
||||
static void recomputeJointPlacements(std::vector<App::DocumentObject*> joints);
|
||||
static void redrawJointPlacements(std::vector<App::DocumentObject*> joints);
|
||||
|
||||
// This makes sure that LinkGroups or sub-assemblies have identity placements.
|
||||
void ensureIdentityPlacements();
|
||||
|
||||
// Ondsel Solver interface
|
||||
std::shared_ptr<MbD::ASMTAssembly> makeMbdAssembly();
|
||||
@@ -191,8 +193,8 @@ public:
|
||||
int slidingPartIndex(App::DocumentObject* joint);
|
||||
|
||||
void jointParts(std::vector<App::DocumentObject*> joints);
|
||||
JointGroup* getJointGroup();
|
||||
ViewGroup* getExplodedViewGroup();
|
||||
JointGroup* getJointGroup() const;
|
||||
ViewGroup* getExplodedViewGroup() const;
|
||||
std::vector<App::DocumentObject*>
|
||||
getJoints(bool updateJCS = true, bool delBadJoints = false, bool subJoints = true);
|
||||
std::vector<App::DocumentObject*> getGroundedJoints();
|
||||
@@ -257,7 +259,7 @@ public:
|
||||
|
||||
static DistanceType getDistanceType(App::DocumentObject* joint);
|
||||
|
||||
static JointGroup* getJointGroup(App::Part* part);
|
||||
static JointGroup* getJointGroup(const App::Part* part);
|
||||
|
||||
// getters to get from properties
|
||||
static void setJointActivated(App::DocumentObject* joint, bool val);
|
||||
|
||||
@@ -49,6 +49,17 @@
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="ensureIdentityPlacements">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Makes sure that LinkGroups or sub-assemblies have identity placements.
|
||||
|
||||
ensureIdentityPlacements()
|
||||
|
||||
Returns: None
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="clearUndo">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
|
||||
@@ -68,6 +68,15 @@ PyObject* AssemblyObjectPy::solve(PyObject* args)
|
||||
return Py_BuildValue("i", ret);
|
||||
}
|
||||
|
||||
PyObject* AssemblyObjectPy::ensureIdentityPlacements(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
this->getAssemblyObjectPtr()->ensureIdentityPlacements();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* AssemblyObjectPy::undoSolve(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
|
||||
@@ -544,6 +544,17 @@ bool ViewProviderAssembly::canDragObjectIn3d(App::DocumentObject* obj) const
|
||||
|
||||
// Check if the selected object is a child of the assembly
|
||||
if (!assemblyPart->hasObject(obj, true)) {
|
||||
// hasObject does not detect LinkElements (see
|
||||
// https://github.com/FreeCAD/FreeCAD/issues/16113) the following block can be removed if
|
||||
// the issue is fixed :
|
||||
auto* linkEl = dynamic_cast<App::LinkElement*>(obj);
|
||||
if (linkEl) {
|
||||
auto* linkGroup = linkEl->getLinkGroup();
|
||||
if (assemblyPart->hasObject(linkGroup, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -499,49 +499,6 @@ class Joint:
|
||||
|
||||
joint.Reference2 = [obj, [elt, vtx]]
|
||||
|
||||
def getSubnameForSelection(self, obj, part, elName):
|
||||
# We need the subname starting from the part.
|
||||
# Example for : Assembly.Part1.LinkToPart2.Part3.Body.Tip.Face1
|
||||
# part is Part1 and obj is Body
|
||||
# we should get : LinkToPart2.Part3.Body.Tip.Face1
|
||||
|
||||
if obj is None or part is None:
|
||||
return elName
|
||||
|
||||
if obj.TypeId == "PartDesign::Body":
|
||||
elName = obj.Tip.Name + "." + elName
|
||||
elif obj.TypeId == "App::Link":
|
||||
linked_obj = obj.getLinkedObject()
|
||||
if linked_obj.TypeId == "PartDesign::Body":
|
||||
elName = linked_obj.Tip.Name + "." + elName
|
||||
|
||||
if obj != part and obj in part.OutListRecursive:
|
||||
bSub = ""
|
||||
currentObj = part
|
||||
|
||||
limit = 0
|
||||
while limit < 1000:
|
||||
limit = limit + 1
|
||||
|
||||
if currentObj != part:
|
||||
if bSub != "":
|
||||
bSub = bSub + "."
|
||||
bSub = bSub + currentObj.Name
|
||||
|
||||
if currentObj == obj:
|
||||
break
|
||||
|
||||
if currentObj.TypeId == "App::Link":
|
||||
currentObj = currentObj.getLinkedObject()
|
||||
|
||||
for obji in currentObj.OutList:
|
||||
if obji == obj or obj in obji.OutListRecursive:
|
||||
currentObj = obji
|
||||
break
|
||||
|
||||
elName = bSub + "." + elName
|
||||
return elName
|
||||
|
||||
def dumps(self):
|
||||
return None
|
||||
|
||||
@@ -716,6 +673,13 @@ class Joint:
|
||||
)
|
||||
if not sameDir:
|
||||
jcsPlc2 = UtilsAssembly.flipPlacement(jcsPlc2)
|
||||
|
||||
# For link groups and sub-assemblies we have to take into account
|
||||
# the parent placement (ie the linkgroup plc) as the linkgroup is not the moving part
|
||||
# But instead of doing as follow, we rather enforce identity placement for linkgroups.
|
||||
# parentPlc = UtilsAssembly.getParentPlacementIfNeeded(part2)
|
||||
# part2.Placement = globalJcsPlc1 * jcsPlc2.inverse() * parentPlc.inverse()
|
||||
|
||||
part2.Placement = globalJcsPlc1 * jcsPlc2.inverse()
|
||||
return True
|
||||
|
||||
@@ -730,6 +694,7 @@ class Joint:
|
||||
)
|
||||
if not sameDir:
|
||||
jcsPlc1 = UtilsAssembly.flipPlacement(jcsPlc1)
|
||||
|
||||
part1.Placement = globalJcsPlc2 * jcsPlc1.inverse()
|
||||
return True
|
||||
return False
|
||||
@@ -1288,7 +1253,7 @@ class MakeJointSelGate:
|
||||
selected_object.isDerivedFrom("Part::Feature")
|
||||
or selected_object.isDerivedFrom("App::Part")
|
||||
):
|
||||
if selected_object.isDerivedFrom("App::Link"):
|
||||
if UtilsAssembly.isLink(selected_object):
|
||||
linked = selected_object.getLinkedObject()
|
||||
|
||||
if not (linked.isDerivedFrom("Part::Feature") or linked.isDerivedFrom("App::Part")):
|
||||
@@ -1315,6 +1280,7 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.activeType = "Part"
|
||||
else:
|
||||
self.activeType = "Assembly"
|
||||
self.assembly.ensureIdentityPlacements()
|
||||
|
||||
self.doc = self.assembly.Document
|
||||
self.gui_doc = Gui.getDocument(self.doc)
|
||||
|
||||
@@ -95,6 +95,16 @@ def assembly_has_at_least_n_parts(n):
|
||||
return False
|
||||
|
||||
|
||||
def isLink(obj):
|
||||
# If element count is not 0, then its a link group in which case the Link
|
||||
# is a container and it's the LinkElement that is linking to external doc.
|
||||
return (obj.TypeId == "App::Link" and obj.ElementCount == 0) or obj.TypeId == "App::LinkElement"
|
||||
|
||||
|
||||
def isLinkGroup(obj):
|
||||
return obj.TypeId == "App::Link" and obj.ElementCount > 0
|
||||
|
||||
|
||||
def getObject(ref):
|
||||
if len(ref) != 2:
|
||||
return None
|
||||
@@ -113,7 +123,6 @@ def getObject(ref):
|
||||
return None
|
||||
|
||||
doc = ref[0].Document
|
||||
|
||||
for i, obj_name in enumerate(names):
|
||||
obj = doc.getObject(obj_name)
|
||||
|
||||
@@ -124,7 +133,7 @@ def getObject(ref):
|
||||
if i == len(names) - 2:
|
||||
return obj
|
||||
|
||||
if obj.TypeId in {"App::Part", "Assembly::AssemblyObject"}:
|
||||
if obj.TypeId in {"App::Part", "Assembly::AssemblyObject"} or isLinkGroup(obj):
|
||||
continue
|
||||
|
||||
elif obj.TypeId == "PartDesign::Body":
|
||||
@@ -142,7 +151,7 @@ def getObject(ref):
|
||||
# primitive, fastener, gear ...
|
||||
return obj
|
||||
|
||||
elif obj.TypeId == "App::Link":
|
||||
elif isLink(obj):
|
||||
linked_obj = obj.getLinkedObject()
|
||||
if linked_obj.TypeId == "PartDesign::Body":
|
||||
if i + 1 < len(names):
|
||||
@@ -173,72 +182,7 @@ def isBodySubObject(typeId):
|
||||
)
|
||||
|
||||
|
||||
# To be deprecated. CommandCreateView needs to stop using it.
|
||||
def getContainingPart(full_name, selected_object, activeAssemblyOrPart=None):
|
||||
# full_name is "Assembly.Assembly1.LinkOrPart1.LinkOrBox.Edge16" -> LinkOrPart1
|
||||
# or "Assembly.Assembly1.LinkOrPart1.LinkOrBody.pad.Edge16" -> LinkOrPart1
|
||||
# or "Assembly.Assembly1.LinkOrPart1.LinkOrBody.Sketch.Edge1" -> LinkOrPart1
|
||||
|
||||
if selected_object is None:
|
||||
App.Console.PrintError("getContainingPart() in UtilsAssembly.py selected_object is None")
|
||||
return None
|
||||
|
||||
names = full_name.split(".")
|
||||
doc = App.ActiveDocument
|
||||
if len(names) < 3:
|
||||
App.Console.PrintError(
|
||||
"getContainingPart() in UtilsAssembly.py the object name is too short, at minimum it should be something like 'Assembly.Box.edge16'. It shouldn't be shorter"
|
||||
)
|
||||
return None
|
||||
|
||||
for objName in names:
|
||||
obj = doc.getObject(objName)
|
||||
|
||||
if not obj:
|
||||
continue
|
||||
|
||||
if obj == selected_object:
|
||||
return selected_object
|
||||
|
||||
if obj.TypeId == "PartDesign::Body" and isBodySubObject(selected_object.TypeId):
|
||||
if selected_object in obj.OutListRecursive:
|
||||
return obj
|
||||
|
||||
# Note here we may want to specify a specific behavior for Assembly::AssemblyObject.
|
||||
if obj.TypeId == "App::Part":
|
||||
if selected_object in obj.OutListRecursive:
|
||||
if not activeAssemblyOrPart:
|
||||
return obj
|
||||
elif activeAssemblyOrPart in obj.OutListRecursive or obj == activeAssemblyOrPart:
|
||||
# If the user put the assembly inside a Part, then we ignore it.
|
||||
continue
|
||||
else:
|
||||
return obj
|
||||
|
||||
elif obj.TypeId == "App::Link":
|
||||
linked_obj = obj.getLinkedObject()
|
||||
if linked_obj.TypeId == "PartDesign::Body" and isBodySubObject(selected_object.TypeId):
|
||||
if selected_object in linked_obj.OutListRecursive:
|
||||
return obj
|
||||
if linked_obj.TypeId in ["App::Part", "Assembly::AssemblyObject"]:
|
||||
# linked_obj_doc = linked_obj.Document
|
||||
# selected_obj_in_doc = doc.getObject(selected_object.Name)
|
||||
if selected_object in linked_obj.OutListRecursive:
|
||||
if not activeAssemblyOrPart:
|
||||
return obj
|
||||
elif (linked_obj.Document == activeAssemblyOrPart.Document) and (
|
||||
activeAssemblyOrPart in linked_obj.OutListRecursive
|
||||
or linked_obj == activeAssemblyOrPart
|
||||
):
|
||||
continue
|
||||
else:
|
||||
return obj
|
||||
|
||||
# no container found so we return the object itself.
|
||||
return selected_object
|
||||
|
||||
|
||||
# To be deprecated. Kept for migrationScript.
|
||||
# Deprecated. Kept for migrationScript.
|
||||
def getObjectInPart(objName, part):
|
||||
if part is None:
|
||||
return None
|
||||
@@ -336,7 +280,7 @@ def getGlobalPlacement(ref, targetObj=None):
|
||||
if obj == targetObj:
|
||||
return plc
|
||||
|
||||
if obj.TypeId == "App::Link":
|
||||
if isLink(obj):
|
||||
linked_obj = obj.getLinkedObject()
|
||||
doc = linked_obj.Document # in case its an external link.
|
||||
|
||||
@@ -437,17 +381,15 @@ def findElementClosestVertex(assembly, ref, mousePos):
|
||||
if element_name == "":
|
||||
return ""
|
||||
|
||||
moving_part = getMovingPart(assembly, ref)
|
||||
obj = getObject(ref)
|
||||
|
||||
# We need mousePos to be relative to the part containing obj global placement
|
||||
if obj != moving_part:
|
||||
plc = App.Placement()
|
||||
plc.Base = mousePos
|
||||
global_plc = getGlobalPlacement(ref)
|
||||
plc = global_plc.inverse() * plc # We make it relative to obj Origin
|
||||
plc = obj.Placement * plc # Make plc in the same lcs as obj
|
||||
mousePos = plc.Base
|
||||
# We need mousePos to be in the same lcs as obj
|
||||
plc = App.Placement()
|
||||
plc.Base = mousePos
|
||||
global_plc = getGlobalPlacement(ref)
|
||||
plc = global_plc.inverse() * plc # We make it relative to obj Origin
|
||||
plc = obj.Placement * plc # Make plc in the same lcs as obj
|
||||
mousePos = plc.Base
|
||||
|
||||
elt_type, elt_index = extract_type_and_number(element_name)
|
||||
|
||||
@@ -693,10 +635,10 @@ def getSubMovingParts(obj, partsAsSolid):
|
||||
objs.append(obj)
|
||||
return objs
|
||||
|
||||
elif obj.TypeId == "App::DocumentObjectGroup":
|
||||
elif isLinkGroup(obj) or obj.TypeId == "App::DocumentObjectGroup":
|
||||
return getMovablePartsWithin(obj)
|
||||
|
||||
if obj.TypeId == "App::Link":
|
||||
if isLink(obj):
|
||||
linked_obj = obj.getLinkedObject()
|
||||
if linked_obj.TypeId == "App::Part" or linked_obj.isDerivedFrom("Part::Feature"):
|
||||
return [obj]
|
||||
@@ -727,7 +669,7 @@ def getCenterOfMass(parts):
|
||||
def getObjMassAndCom(obj, containingPart=None):
|
||||
link_global_plc = None
|
||||
|
||||
if obj.TypeId == "App::Link":
|
||||
if isLink(obj):
|
||||
link_global_plc = getGlobalPlacement(obj, containingPart)
|
||||
obj = obj.getLinkedObject()
|
||||
|
||||
@@ -754,14 +696,23 @@ def getObjMassAndCom(obj, containingPart=None):
|
||||
com = comPlc.Base * mass
|
||||
return mass, com
|
||||
|
||||
elif obj.isDerivedFrom("App::Part") or obj.isDerivedFrom("App::DocumentObjectGroup"):
|
||||
elif (
|
||||
isLinkGroup(obj)
|
||||
or obj.isDerivedFrom("App::Part")
|
||||
or obj.isDerivedFrom("App::DocumentObjectGroup")
|
||||
):
|
||||
if containingPart is None and obj.isDerivedFrom("App::Part"):
|
||||
containingPart = obj
|
||||
|
||||
total_mass = 0
|
||||
total_com = App.Vector(0, 0, 0)
|
||||
|
||||
for subObj in obj.OutList:
|
||||
if isLinkGroup(obj):
|
||||
children = obj.ElementList
|
||||
else:
|
||||
children = obj.Group
|
||||
|
||||
for subObj in children:
|
||||
mass, com = getObjMassAndCom(subObj, containingPart)
|
||||
total_mass += mass
|
||||
total_com += com
|
||||
@@ -1134,6 +1085,10 @@ def getMovingPart(assembly, ref):
|
||||
if obj.TypeId == "App::DocumentObjectGroup":
|
||||
continue # we ignore groups.
|
||||
|
||||
# If it is a LinkGroup then we skip it
|
||||
if isLinkGroup(obj):
|
||||
continue
|
||||
|
||||
return obj
|
||||
|
||||
return None
|
||||
@@ -1195,3 +1150,23 @@ def addVertexToReference(ref, vertex_name):
|
||||
ref = [ref[0], subs]
|
||||
|
||||
return ref
|
||||
|
||||
|
||||
def getLinkGroup(linkElement):
|
||||
if linkElement.TypeId == "App::LinkElement":
|
||||
for obj in linkElement.InList:
|
||||
if obj.TypeId == "App::Link":
|
||||
if linkElement in obj.ElementList:
|
||||
return obj
|
||||
print("Link Group not found.")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def getParentPlacementIfNeeded(part):
|
||||
if part.TypeId == "App::LinkElement":
|
||||
linkGroup = getLinkGroup(part)
|
||||
if linkGroup:
|
||||
return linkGroup.Placement
|
||||
|
||||
return Base.Placement()
|
||||
|
||||
Reference in New Issue
Block a user