Assembly: Property change from Object/Part to Reference
This commit is contained in:
committed by
Yorik van Havre
parent
828e85963e
commit
8d3e3acd11
@@ -171,15 +171,11 @@ def get_active_view(gui_doc):
|
||||
|
||||
|
||||
# The joint object consists of 2 JCS (joint coordinate systems) and a Joint Type.
|
||||
# A JCS is a placement that is computed (unless it is detached) from :
|
||||
# - An Object: this can be any Part::Feature solid. Or a PartDesign Body. Or a App::Link to those.
|
||||
# - A Part DocumentObject : This is the lowest level containing part. It can be either the Object itself if it
|
||||
# stands alone. Or a App::Part. Or a App::Link to a App::Part.
|
||||
# For example :
|
||||
# Assembly.Assembly1.Part1.Part2.Box : Object is Box, part is 'Part1'
|
||||
# Assembly.Assembly1.LinkToPart1.Part2.Box : Object is Box, part is 'LinkToPart1'
|
||||
# A JCS is a placement that is computed (unless it is detached) from references (PropertyXLinkSubHidden) that links to :
|
||||
# - An object: this can be any Part::Feature solid. Or a PartDesign Body. Or a App::Link to those.
|
||||
# - An element name: This can be either a face, an edge, a vertex or empty. Empty means that the Object placement will be used
|
||||
# - A vertex name: For faces and edges, we need to specify which vertex of said face/edge to use
|
||||
# Both element names hold the full path to the object.
|
||||
# From these a placement is computed. It is relative to the Object.
|
||||
class Joint:
|
||||
def __init__(self, joint, type_index):
|
||||
@@ -203,22 +199,15 @@ class Joint:
|
||||
|
||||
def createProperties(self, joint):
|
||||
self.migrationScript(joint)
|
||||
self.migrationScript2(joint)
|
||||
|
||||
# First Joint Connector
|
||||
if not hasattr(joint, "Object1"):
|
||||
if not hasattr(joint, "Reference1"):
|
||||
joint.addProperty(
|
||||
"App::PropertyXLinkSub",
|
||||
"Object1",
|
||||
"App::PropertyXLinkSubHidden",
|
||||
"Reference1",
|
||||
"Joint Connector 1",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The first object of the joint"),
|
||||
)
|
||||
|
||||
if not hasattr(joint, "Part1"):
|
||||
joint.addProperty(
|
||||
"App::PropertyLink",
|
||||
"Part1",
|
||||
"Joint Connector 1",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The first part of the joint"),
|
||||
QT_TRANSLATE_NOOP("App::Property", "The first reference of the joint"),
|
||||
)
|
||||
|
||||
if not hasattr(joint, "Placement1"):
|
||||
@@ -228,7 +217,7 @@ class Joint:
|
||||
"Joint Connector 1",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"This is the local coordinate system within object1 that will be used for the joint.",
|
||||
"This is the local coordinate system within Reference1's object that will be used for the joint.",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -244,20 +233,12 @@ class Joint:
|
||||
)
|
||||
|
||||
# Second Joint Connector
|
||||
if not hasattr(joint, "Object2"):
|
||||
if not hasattr(joint, "Reference2"):
|
||||
joint.addProperty(
|
||||
"App::PropertyXLinkSub",
|
||||
"Object2",
|
||||
"App::PropertyXLinkSubHidden",
|
||||
"Reference2",
|
||||
"Joint Connector 2",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The second object of the joint"),
|
||||
)
|
||||
|
||||
if not hasattr(joint, "Part2"):
|
||||
joint.addProperty(
|
||||
"App::PropertyLink",
|
||||
"Part2",
|
||||
"Joint Connector 2",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The second part of the joint"),
|
||||
QT_TRANSLATE_NOOP("App::Property", "The second reference of the joint"),
|
||||
)
|
||||
|
||||
if not hasattr(joint, "Placement2"):
|
||||
@@ -267,7 +248,7 @@ class Joint:
|
||||
"Joint Connector 2",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"This is the local coordinate system within object2 that will be used for the joint.",
|
||||
"This is the local coordinate system within Reference2's object that will be used for the joint.",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -470,6 +451,97 @@ class Joint:
|
||||
|
||||
joint.Object2 = [obj2, [el2, vtx2]]
|
||||
|
||||
def migrationScript2(self, joint):
|
||||
if hasattr(joint, "Object1"):
|
||||
obj = joint.Object1[0]
|
||||
part = joint.Part1
|
||||
elt = joint.Object1[1][0]
|
||||
vtx = joint.Object1[1][1]
|
||||
|
||||
joint.removeProperty("Object1")
|
||||
joint.removeProperty("Part1")
|
||||
|
||||
# now we need to get the 'selection-root-obj' and the global path
|
||||
rootObj, path = UtilsAssembly.getRootPath(obj, part)
|
||||
obj = rootObj
|
||||
elt = path + elt
|
||||
vtx = path + vtx
|
||||
|
||||
joint.addProperty(
|
||||
"App::PropertyXLinkSubHidden",
|
||||
"Reference1",
|
||||
"Joint Connector 1",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The first reference of the joint"),
|
||||
)
|
||||
|
||||
joint.Reference1 = [obj, [elt, vtx]]
|
||||
|
||||
if hasattr(joint, "Object2"):
|
||||
obj = joint.Object2[0]
|
||||
part = joint.Part2
|
||||
elt = joint.Object2[1][0]
|
||||
vtx = joint.Object2[1][1]
|
||||
|
||||
joint.removeProperty("Object2")
|
||||
joint.removeProperty("Part2")
|
||||
|
||||
rootObj, path = UtilsAssembly.getRootPath(obj, part)
|
||||
obj = rootObj
|
||||
elt = path + elt
|
||||
vtx = path + vtx
|
||||
|
||||
joint.addProperty(
|
||||
"App::PropertyXLinkSubHidden",
|
||||
"Reference2",
|
||||
"Joint Connector 2",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The second reference of the 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
|
||||
|
||||
@@ -495,10 +567,11 @@ class Joint:
|
||||
return
|
||||
|
||||
if prop == "Rotation" or prop == "Offset":
|
||||
self.updateJCSPlacements(joint)
|
||||
if joint.Object1 is None or joint.Object2 is None:
|
||||
if joint.Reference1 is None or joint.Reference2 is None:
|
||||
return
|
||||
|
||||
self.updateJCSPlacements(joint)
|
||||
|
||||
presolved = self.preSolve(joint, False)
|
||||
|
||||
isAssembly = self.getAssembly(joint).Type == "Assembly"
|
||||
@@ -508,45 +581,34 @@ class Joint:
|
||||
self.updateJCSPlacements(joint)
|
||||
|
||||
if prop == "Distance" and (joint.JointType == "Distance" or joint.JointType == "Angle"):
|
||||
if joint.Part1 and joint.Part2:
|
||||
if joint.JointType == "Angle" and joint.Distance != 0.0:
|
||||
self.preventParallel(joint)
|
||||
solveIfAllowed(self.getAssembly(joint))
|
||||
if joint.Reference1 is None or joint.Reference2 is None:
|
||||
return
|
||||
|
||||
if joint.JointType == "Angle" and joint.Distance != 0.0:
|
||||
self.preventParallel(joint)
|
||||
solveIfAllowed(self.getAssembly(joint))
|
||||
|
||||
def execute(self, fp):
|
||||
"""Do something when doing a recomputation, this method is mandatory"""
|
||||
# App.Console.PrintMessage("Recompute Python Box feature\n")
|
||||
pass
|
||||
|
||||
def setJointConnectors(self, joint, current_selection):
|
||||
def setJointConnectors(self, joint, refs):
|
||||
# current selection is a vector of strings like "Assembly.Assembly1.Assembly2.Body.Pad.Edge16" including both what selection return as obj_name and obj_sub
|
||||
assembly = self.getAssembly(joint)
|
||||
isAssembly = assembly.Type == "Assembly"
|
||||
|
||||
if len(current_selection) >= 1:
|
||||
joint.Object1 = [
|
||||
current_selection[0]["object"],
|
||||
[current_selection[0]["element_name"], current_selection[0]["vertex_name"]],
|
||||
]
|
||||
joint.Part1 = current_selection[0]["part"]
|
||||
joint.Placement1 = self.findPlacement(
|
||||
joint, joint.Object1[0], joint.Part1, joint.Object1[1][0], joint.Object1[1][1]
|
||||
)
|
||||
if len(refs) >= 1:
|
||||
joint.Reference1 = refs[0]
|
||||
joint.Placement1 = self.findPlacement(joint, joint.Reference1, 0)
|
||||
else:
|
||||
joint.Object1 = None
|
||||
joint.Part1 = None
|
||||
joint.Reference1 = None
|
||||
joint.Placement1 = App.Placement()
|
||||
self.partMovedByPresolved = None
|
||||
|
||||
if len(current_selection) >= 2:
|
||||
joint.Object2 = [
|
||||
current_selection[1]["object"],
|
||||
[current_selection[1]["element_name"], current_selection[1]["vertex_name"]],
|
||||
]
|
||||
joint.Part2 = current_selection[1]["part"]
|
||||
joint.Placement2 = self.findPlacement(
|
||||
joint, joint.Object2[0], joint.Part2, joint.Object2[1][0], joint.Object2[1][1], True
|
||||
)
|
||||
if len(refs) >= 2:
|
||||
joint.Reference2 = refs[1]
|
||||
joint.Placement2 = self.findPlacement(joint, joint.Reference2, 1)
|
||||
if joint.JointType in JointUsingPreSolve:
|
||||
self.preSolve(joint)
|
||||
elif joint.JointType in JointParallelForbidden:
|
||||
@@ -558,8 +620,7 @@ class Joint:
|
||||
self.updateJCSPlacements(joint)
|
||||
|
||||
else:
|
||||
joint.Object2 = None
|
||||
joint.Part2 = None
|
||||
joint.Reference2 = None
|
||||
joint.Placement2 = App.Placement()
|
||||
if isAssembly:
|
||||
assembly.undoSolve()
|
||||
@@ -567,14 +628,10 @@ class Joint:
|
||||
|
||||
def updateJCSPlacements(self, joint):
|
||||
if not joint.Detach1:
|
||||
joint.Placement1 = self.findPlacement(
|
||||
joint, joint.Object1[0], joint.Part1, joint.Object1[1][0], joint.Object1[1][1]
|
||||
)
|
||||
joint.Placement1 = self.findPlacement(joint, joint.Reference1, 0)
|
||||
|
||||
if not joint.Detach2:
|
||||
joint.Placement2 = self.findPlacement(
|
||||
joint, joint.Object2[0], joint.Part2, joint.Object2[1][0], joint.Object2[1][1], True
|
||||
)
|
||||
joint.Placement2 = self.findPlacement(joint, joint.Reference2, 1)
|
||||
|
||||
"""
|
||||
So here we want to find a placement that corresponds to a local coordinate system that would be placed at the selected vertex.
|
||||
@@ -586,15 +643,12 @@ class Joint:
|
||||
- if elt is a cylindrical face, vtx can also be the center of the arcs of the cylindrical face.
|
||||
"""
|
||||
|
||||
def findPlacement(self, joint, obj, part, elt, vtx, isSecond=False):
|
||||
if not obj or not part:
|
||||
return App.Placement()
|
||||
|
||||
def findPlacement(self, joint, ref, index=0):
|
||||
ignoreVertex = joint.JointType == "Distance"
|
||||
plc = UtilsAssembly.findPlacement(obj, part, elt, vtx, ignoreVertex)
|
||||
plc = UtilsAssembly.findPlacement(ref, ignoreVertex)
|
||||
|
||||
# We apply rotation / reverse / offset it necessary, but only to the second JCS.
|
||||
if isSecond:
|
||||
if index == 1:
|
||||
if joint.Offset.Length != 0.0:
|
||||
plc = UtilsAssembly.applyOffsetToPlacement(plc, joint.Offset)
|
||||
if joint.Rotation != 0.0:
|
||||
@@ -604,28 +658,28 @@ class Joint:
|
||||
|
||||
def flipOnePart(self, joint):
|
||||
assembly = self.getAssembly(joint)
|
||||
part2ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Part2")
|
||||
part1Grounded = assembly.isPartGrounded(joint.Part1)
|
||||
part2Grounded = assembly.isPartGrounded(joint.Part2)
|
||||
part2ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Reference2")
|
||||
|
||||
part1 = UtilsAssembly.getMovingPart(assembly, joint.Reference1)
|
||||
part2 = UtilsAssembly.getMovingPart(assembly, joint.Reference2)
|
||||
|
||||
part1Grounded = assembly.isPartGrounded(part1)
|
||||
part2Grounded = assembly.isPartGrounded(part2)
|
||||
if part2ConnectedByJoint and not part2Grounded:
|
||||
jcsPlc = UtilsAssembly.getJcsPlcRelativeToPart(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
)
|
||||
globalJcsPlc = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
assembly, joint.Placement2, joint.Reference2
|
||||
)
|
||||
globalJcsPlc = UtilsAssembly.getJcsGlobalPlc(joint.Placement2, joint.Reference2)
|
||||
jcsPlc = UtilsAssembly.flipPlacement(jcsPlc)
|
||||
joint.Part2.Placement = globalJcsPlc * jcsPlc.inverse()
|
||||
part2.Placement = globalJcsPlc * jcsPlc.inverse()
|
||||
|
||||
elif not part1Grounded:
|
||||
jcsPlc = UtilsAssembly.getJcsPlcRelativeToPart(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
)
|
||||
globalJcsPlc = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
assembly, joint.Placement1, joint.Reference1
|
||||
)
|
||||
globalJcsPlc = UtilsAssembly.getJcsGlobalPlc(joint.Placement1, joint.Reference1)
|
||||
jcsPlc = UtilsAssembly.flipPlacement(jcsPlc)
|
||||
joint.Part1.Placement = globalJcsPlc * jcsPlc.inverse()
|
||||
part1.Placement = globalJcsPlc * jcsPlc.inverse()
|
||||
|
||||
solveIfAllowed(self.getAssembly(joint))
|
||||
|
||||
@@ -634,13 +688,18 @@ class Joint:
|
||||
|
||||
# we actually don't want to match perfectly the JCS, it is best to match them
|
||||
# in the current closest direction, ie either matched or flipped.
|
||||
|
||||
sameDir = self.areJcsSameDir(joint)
|
||||
assembly = self.getAssembly(joint)
|
||||
|
||||
part1 = UtilsAssembly.getMovingPart(assembly, joint.Reference1)
|
||||
part2 = UtilsAssembly.getMovingPart(assembly, joint.Reference2)
|
||||
|
||||
isAssembly = assembly.Type == "Assembly"
|
||||
if isAssembly:
|
||||
joint.Activated = False
|
||||
part1Connected = assembly.isPartConnected(joint.Part1)
|
||||
part2Connected = assembly.isPartConnected(joint.Part2)
|
||||
part1Connected = assembly.isPartConnected(part1)
|
||||
part2Connected = assembly.isPartConnected(part2)
|
||||
joint.Activated = True
|
||||
else:
|
||||
part1Connected = False
|
||||
@@ -648,34 +707,30 @@ class Joint:
|
||||
|
||||
if not part2Connected:
|
||||
if savePlc:
|
||||
self.partMovedByPresolved = joint.Part2
|
||||
self.presolveBackupPlc = joint.Part2.Placement
|
||||
self.partMovedByPresolved = part2
|
||||
self.presolveBackupPlc = part2.Placement
|
||||
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
)
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(joint.Placement1, joint.Reference1)
|
||||
jcsPlc2 = UtilsAssembly.getJcsPlcRelativeToPart(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
assembly, joint.Placement2, joint.Reference2
|
||||
)
|
||||
if not sameDir:
|
||||
jcsPlc2 = UtilsAssembly.flipPlacement(jcsPlc2)
|
||||
joint.Part2.Placement = globalJcsPlc1 * jcsPlc2.inverse()
|
||||
part2.Placement = globalJcsPlc1 * jcsPlc2.inverse()
|
||||
return True
|
||||
|
||||
elif not part1Connected:
|
||||
if savePlc:
|
||||
self.partMovedByPresolved = joint.Part1
|
||||
self.presolveBackupPlc = joint.Part1.Placement
|
||||
self.partMovedByPresolved = part1
|
||||
self.presolveBackupPlc = part1.Placement
|
||||
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
)
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(joint.Placement2, joint.Reference2)
|
||||
jcsPlc1 = UtilsAssembly.getJcsPlcRelativeToPart(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
assembly, joint.Placement1, joint.Reference1
|
||||
)
|
||||
if not sameDir:
|
||||
jcsPlc1 = UtilsAssembly.flipPlacement(jcsPlc1)
|
||||
joint.Part1.Placement = globalJcsPlc2 * jcsPlc1.inverse()
|
||||
part1.Placement = globalJcsPlc2 * jcsPlc1.inverse()
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -693,47 +748,43 @@ class Joint:
|
||||
return
|
||||
|
||||
assembly = self.getAssembly(joint)
|
||||
|
||||
part1 = UtilsAssembly.getMovingPart(assembly, joint.Reference1)
|
||||
part2 = UtilsAssembly.getMovingPart(assembly, joint.Reference2)
|
||||
|
||||
isAssembly = assembly.Type == "Assembly"
|
||||
if isAssembly:
|
||||
part1ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Part1")
|
||||
part2ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Part2")
|
||||
part1ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Reference1")
|
||||
part2ConnectedByJoint = assembly.isJointConnectingPartToGround(joint, "Reference2")
|
||||
else:
|
||||
part1ConnectedByJoint = False
|
||||
part2ConnectedByJoint = True
|
||||
|
||||
if part2ConnectedByJoint:
|
||||
self.partMovedByPresolved = joint.Part2
|
||||
self.presolveBackupPlc = joint.Part2.Placement
|
||||
self.partMovedByPresolved = part2
|
||||
self.presolveBackupPlc = part2.Placement
|
||||
|
||||
joint.Part2.Placement = UtilsAssembly.applyRotationToPlacementAlongAxis(
|
||||
joint.Part2.Placement, 10, App.Vector(1, 0, 0)
|
||||
part2.Placement = UtilsAssembly.applyRotationToPlacementAlongAxis(
|
||||
part2.Placement, 10, App.Vector(1, 0, 0)
|
||||
)
|
||||
|
||||
elif part1ConnectedByJoint:
|
||||
self.partMovedByPresolved = joint.Part1
|
||||
self.presolveBackupPlc = joint.Part1.Placement
|
||||
self.partMovedByPresolved = part1
|
||||
self.presolveBackupPlc = part1.Placement
|
||||
|
||||
joint.Part1.Placement = UtilsAssembly.applyRotationToPlacementAlongAxis(
|
||||
joint.Part1.Placement, 10, App.Vector(1, 0, 0)
|
||||
part1.Placement = UtilsAssembly.applyRotationToPlacementAlongAxis(
|
||||
part1.Placement, 10, App.Vector(1, 0, 0)
|
||||
)
|
||||
|
||||
def areJcsSameDir(self, joint):
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
)
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
)
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(joint.Placement1, joint.Reference1)
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(joint.Placement2, joint.Reference2)
|
||||
|
||||
return UtilsAssembly.arePlacementSameDir(globalJcsPlc1, globalJcsPlc2)
|
||||
|
||||
def areJcsZParallel(self, joint):
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement1, joint.Object1[0], joint.Part1
|
||||
)
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(
|
||||
joint.Placement2, joint.Object2[0], joint.Part2
|
||||
)
|
||||
globalJcsPlc1 = UtilsAssembly.getJcsGlobalPlc(joint.Placement1, joint.Reference1)
|
||||
globalJcsPlc2 = UtilsAssembly.getJcsGlobalPlc(joint.Placement2, joint.Reference2)
|
||||
|
||||
return UtilsAssembly.arePlacementZParallel(globalJcsPlc1, globalJcsPlc2)
|
||||
|
||||
@@ -872,9 +923,9 @@ class ViewProviderJoint:
|
||||
def get_JCS_size(self):
|
||||
return get_camera_height(self.gui_doc) / 20
|
||||
|
||||
def set_JCS_placement(self, soTransform, placement, obj, part):
|
||||
def set_JCS_placement(self, soTransform, placement, ref):
|
||||
# change plc to be relative to the origin of the document.
|
||||
global_plc = UtilsAssembly.getGlobalPlacement(obj, part)
|
||||
global_plc = UtilsAssembly.getGlobalPlacement(ref)
|
||||
placement = global_plc * placement
|
||||
|
||||
t = placement.Base
|
||||
@@ -887,29 +938,27 @@ class ViewProviderJoint:
|
||||
"""If a property of the handled feature has changed we have the chance to handle this here"""
|
||||
# joint is the handled feature, prop is the name of the property that has changed
|
||||
if prop == "Placement1":
|
||||
if joint.Object1:
|
||||
if hasattr(joint, "Reference1") and joint.Reference1:
|
||||
plc = joint.Placement1
|
||||
self.switch_JCS1.whichChild = coin.SO_SWITCH_ALL
|
||||
|
||||
if joint.Part1:
|
||||
self.set_JCS_placement(self.transform1, plc, joint.Object1[0], joint.Part1)
|
||||
self.set_JCS_placement(self.transform1, plc, joint.Reference1)
|
||||
else:
|
||||
self.switch_JCS1.whichChild = coin.SO_SWITCH_NONE
|
||||
|
||||
if prop == "Placement2":
|
||||
if joint.Object2:
|
||||
if hasattr(joint, "Reference2") and joint.Reference2:
|
||||
plc = joint.Placement2
|
||||
self.switch_JCS2.whichChild = coin.SO_SWITCH_ALL
|
||||
|
||||
if joint.Part2:
|
||||
self.set_JCS_placement(self.transform2, plc, joint.Object2[0], joint.Part2)
|
||||
self.set_JCS_placement(self.transform2, plc, joint.Reference2)
|
||||
else:
|
||||
self.switch_JCS2.whichChild = coin.SO_SWITCH_NONE
|
||||
|
||||
def showPreviewJCS(self, visible, placement=None, obj=None, part=None):
|
||||
def showPreviewJCS(self, visible, placement=None, ref=None):
|
||||
if visible:
|
||||
self.switch_JCS_preview.whichChild = coin.SO_SWITCH_ALL
|
||||
self.set_JCS_placement(self.transform3, placement, obj, part)
|
||||
self.set_JCS_placement(self.transform3, placement, ref)
|
||||
else:
|
||||
self.switch_JCS_preview.whichChild = coin.SO_SWITCH_NONE
|
||||
|
||||
@@ -1232,9 +1281,8 @@ class MakeJointSelGate:
|
||||
# Only objects within the assembly.
|
||||
return False
|
||||
|
||||
full_obj_name = ".".join(objs_names)
|
||||
full_element_name = full_obj_name + "." + element_name
|
||||
selected_object = UtilsAssembly.getObject(full_element_name)
|
||||
ref = [obj, [sub]]
|
||||
selected_object = UtilsAssembly.getObject(ref)
|
||||
|
||||
if not (
|
||||
selected_object.isDerivedFrom("Part::Feature")
|
||||
@@ -1329,8 +1377,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
else:
|
||||
App.setActiveTransaction("Create " + self.jointName + " Joint")
|
||||
|
||||
self.current_selection = []
|
||||
self.preselection_dict = None
|
||||
self.refs = []
|
||||
self.presel_ref = None
|
||||
|
||||
self.createJointObject()
|
||||
self.visibilityBackup = False
|
||||
@@ -1359,7 +1407,7 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.addition_rejected = False
|
||||
|
||||
def accept(self):
|
||||
if len(self.current_selection) != 2:
|
||||
if len(self.refs) != 2:
|
||||
App.Console.PrintWarning(
|
||||
translate("Assembly", "You need to select 2 elements from 2 separate parts.")
|
||||
)
|
||||
@@ -1419,52 +1467,27 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
continue
|
||||
|
||||
for sub_name in sel.SubElementNames:
|
||||
# We add sub_name twice because the joints references have element name + vertex name
|
||||
# and in the case of initial selection, both are the same.
|
||||
ref = [sel.Object, [sub_name, sub_name]]
|
||||
moving_part = self.getMovingPart(ref)
|
||||
|
||||
# Only objects within the assembly.
|
||||
objs_names, element_name = UtilsAssembly.getObjsNamesAndElement(
|
||||
sel.ObjectName, sub_name
|
||||
)
|
||||
if self.assembly.Name not in objs_names:
|
||||
if moving_part is None:
|
||||
Gui.Selection.removeSelection(sel.Object, sub_name)
|
||||
continue
|
||||
|
||||
obj_name = sel.ObjectName
|
||||
|
||||
full_obj_name = UtilsAssembly.getFullObjName(obj_name, sub_name)
|
||||
full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name)
|
||||
selected_object = UtilsAssembly.getObject(full_element_name)
|
||||
element_name = UtilsAssembly.getElementName(full_element_name)
|
||||
part_containing_selected_object = self.getContainingPart(
|
||||
full_element_name, selected_object
|
||||
)
|
||||
|
||||
if selected_object == self.assembly:
|
||||
# do not accept selection of assembly itself
|
||||
Gui.Selection.removeSelection(sel.Object, sub_name)
|
||||
continue
|
||||
|
||||
if (
|
||||
len(self.current_selection) == 1
|
||||
and selected_object == self.current_selection[0]["object"]
|
||||
):
|
||||
if len(self.refs) == 1 and moving_part == self.getMovingPart(self.refs[0]):
|
||||
# do not select several feature of the same object.
|
||||
self.current_selection.clear()
|
||||
self.refs.clear()
|
||||
Gui.Selection.clearSelection()
|
||||
return
|
||||
|
||||
selection_dict = {
|
||||
"object": selected_object,
|
||||
"part": part_containing_selected_object,
|
||||
"element_name": element_name,
|
||||
"full_element_name": full_element_name,
|
||||
"full_obj_name": full_obj_name,
|
||||
"vertex_name": element_name,
|
||||
}
|
||||
|
||||
self.current_selection.append(selection_dict)
|
||||
self.refs.append(ref)
|
||||
|
||||
# do not accept initial selection if we don't have 2 selected features
|
||||
if len(self.current_selection) != 2:
|
||||
self.current_selection.clear()
|
||||
if len(self.refs) != 2:
|
||||
self.refs.clear()
|
||||
Gui.Selection.clearSelection()
|
||||
else:
|
||||
self.updateJoint()
|
||||
@@ -1635,46 +1658,17 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.form.groupBox_limits.hide()
|
||||
|
||||
def updateTaskboxFromJoint(self):
|
||||
self.current_selection = []
|
||||
self.preselection_dict = None
|
||||
self.refs = []
|
||||
self.presel_ref = None
|
||||
|
||||
obj1 = self.joint.Object1[0]
|
||||
part1 = self.joint.Part1
|
||||
el1 = self.joint.Object1[1][0]
|
||||
vtx1 = self.joint.Object1[1][1]
|
||||
ref1 = self.joint.Reference1
|
||||
ref2 = self.joint.Reference2
|
||||
|
||||
obj2 = self.joint.Object2[0]
|
||||
part2 = self.joint.Part2
|
||||
el2 = self.joint.Object2[1][0]
|
||||
vtx2 = self.joint.Object2[1][1]
|
||||
self.refs.append(ref1)
|
||||
self.refs.append(ref2)
|
||||
|
||||
selection_dict1 = {
|
||||
"object": obj1,
|
||||
"part": part1,
|
||||
"element_name": el1,
|
||||
"vertex_name": vtx1,
|
||||
}
|
||||
|
||||
selection_dict2 = {
|
||||
"object": obj2,
|
||||
"part": part2,
|
||||
"element_name": el2,
|
||||
"vertex_name": vtx2,
|
||||
}
|
||||
|
||||
self.current_selection.append(selection_dict1)
|
||||
self.current_selection.append(selection_dict2)
|
||||
|
||||
# Add the elements to the selection. Note we cannot do :
|
||||
# Gui.Selection.addSelection(self.doc.Name, obj1.Name, elName)
|
||||
# Because obj1 can be external in which case addSelection will fail. And
|
||||
# Gui.Selection.addSelection(obj1.Document.Name, obj1.Name, elName)
|
||||
# will not select in the assembly doc.
|
||||
elName = self.getSubnameForSelection(obj1, part1, el1)
|
||||
Gui.Selection.addSelection(self.doc.Name, part1.Name, elName)
|
||||
|
||||
elName = self.getSubnameForSelection(obj2, part2, el2)
|
||||
Gui.Selection.addSelection(self.doc.Name, part2.Name, elName)
|
||||
Gui.Selection.addSelection(ref1[0].Document.Name, ref1[0].Name, ref1[1][0])
|
||||
Gui.Selection.addSelection(ref2[0].Document.Name, ref2[0].Name, ref2[1][0])
|
||||
|
||||
self.form.distanceSpinbox.setProperty("rawValue", self.joint.Distance)
|
||||
self.form.distanceSpinbox2.setProperty("rawValue", self.joint.Distance2)
|
||||
@@ -1693,63 +1687,23 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.form.jointType.setCurrentIndex(JointTypes.index(self.joint.JointType))
|
||||
self.updateJointList()
|
||||
|
||||
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 updateJoint(self):
|
||||
# First we build the listwidget
|
||||
self.updateJointList()
|
||||
|
||||
# Then we pass the new list to the joint object
|
||||
self.joint.Proxy.setJointConnectors(self.joint, self.current_selection)
|
||||
self.joint.Proxy.setJointConnectors(self.joint, self.refs)
|
||||
|
||||
def updateJointList(self):
|
||||
self.form.featureList.clear()
|
||||
simplified_names = []
|
||||
for sel in self.current_selection:
|
||||
sname = sel["object"].Label
|
||||
if sel["element_name"] != "":
|
||||
sname = sname + "." + sel["element_name"]
|
||||
for ref in self.refs:
|
||||
|
||||
sname = UtilsAssembly.getObject(ref).Label
|
||||
|
||||
element_name = UtilsAssembly.getElementName(ref[1][0])
|
||||
if element_name != "":
|
||||
sname = sname + "." + element_name
|
||||
simplified_names.append(sname)
|
||||
self.form.featureList.addItems(simplified_names)
|
||||
|
||||
@@ -1771,15 +1725,15 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.form.limitRotMaxSpinbox.setProperty("rawValue", angle)
|
||||
|
||||
def moveMouse(self, info):
|
||||
if len(self.current_selection) >= 2 or (
|
||||
len(self.current_selection) == 1
|
||||
if len(self.refs) >= 2 or (
|
||||
len(self.refs) == 1
|
||||
and (
|
||||
not self.preselection_dict
|
||||
or self.current_selection[0]["part"] == self.preselection_dict["part"]
|
||||
not self.presel_ref
|
||||
or self.getMovingPart(self.refs[0]) == self.getMovingPart(self.presel_ref)
|
||||
)
|
||||
):
|
||||
self.joint.ViewObject.Proxy.showPreviewJCS(False)
|
||||
if len(self.current_selection) >= 2:
|
||||
if len(self.refs) >= 2:
|
||||
self.updateLimits()
|
||||
return
|
||||
|
||||
@@ -1789,38 +1743,24 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
|
||||
if (
|
||||
not cursor_info
|
||||
or not self.preselection_dict
|
||||
# or cursor_info["SubName"] != self.preselection_dict["sub_name"]
|
||||
or not self.presel_ref
|
||||
# or cursor_info["SubName"] != self.presel_ref["sub_name"]
|
||||
# Removed because they are not equal when hovering a line endpoints.
|
||||
# But we don't actually need to test because if there's no preselection then not cursor is None
|
||||
):
|
||||
self.joint.ViewObject.Proxy.showPreviewJCS(False)
|
||||
return
|
||||
|
||||
# newPos = self.view.getPoint(*info["Position"]) # This is not what we want, it's not pos on the object but on the focal plane
|
||||
ref = self.presel_ref
|
||||
|
||||
# newPos = self.view.getPoint(*info["Position"]) is not OK: it's not pos on the object but on the focal plane
|
||||
newPos = App.Vector(cursor_info["x"], cursor_info["y"], cursor_info["z"])
|
||||
self.preselection_dict["mouse_pos"] = newPos
|
||||
vertex_name = UtilsAssembly.findElementClosestVertex(self.assembly, ref, newPos)
|
||||
|
||||
if self.preselection_dict["element_name"] == "":
|
||||
self.preselection_dict["vertex_name"] = ""
|
||||
else:
|
||||
self.preselection_dict["vertex_name"] = UtilsAssembly.findElementClosestVertex(
|
||||
self.preselection_dict
|
||||
)
|
||||
ref = UtilsAssembly.addVertexToReference(ref, vertex_name)
|
||||
|
||||
isSecond = len(self.current_selection) == 1
|
||||
obj = self.preselection_dict["object"]
|
||||
part = self.preselection_dict["part"]
|
||||
placement = self.joint.Proxy.findPlacement(
|
||||
self.joint,
|
||||
obj,
|
||||
part,
|
||||
self.preselection_dict["element_name"],
|
||||
self.preselection_dict["vertex_name"],
|
||||
isSecond,
|
||||
)
|
||||
self.joint.ViewObject.Proxy.showPreviewJCS(True, placement, obj, part)
|
||||
placement = self.joint.Proxy.findPlacement(self.joint, ref, 0)
|
||||
self.joint.ViewObject.Proxy.showPreviewJCS(True, placement, ref)
|
||||
self.previewJCSVisible = True
|
||||
|
||||
# 3D view keyboard handler
|
||||
@@ -1845,38 +1785,46 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
|
||||
for index in selected_indexes:
|
||||
row = index.row()
|
||||
if row < len(self.current_selection):
|
||||
selection_dict = self.current_selection[row]
|
||||
elName = self.getSubnameForSelection(
|
||||
selection_dict["object"],
|
||||
selection_dict["part"],
|
||||
selection_dict["element_name"],
|
||||
)
|
||||
Gui.Selection.removeSelection(selection_dict["object"], elName)
|
||||
if row < len(self.refs):
|
||||
ref = self.refs[row]
|
||||
|
||||
Gui.Selection.removeSelection(ref[0], ref[1][0])
|
||||
|
||||
return True # Consume the event
|
||||
|
||||
return super().eventFilter(watched, event)
|
||||
|
||||
def getContainingPart(self, full_element_name, obj):
|
||||
return UtilsAssembly.getContainingPart(full_element_name, obj, self.assembly)
|
||||
def getMovingPart(self, ref):
|
||||
return UtilsAssembly.getMovingPart(self.assembly, ref)
|
||||
|
||||
# selectionObserver stuff
|
||||
def addSelection(self, doc_name, obj_name, sub_name, mousePos):
|
||||
full_obj_name = UtilsAssembly.getFullObjName(obj_name, sub_name)
|
||||
full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name)
|
||||
selected_object = UtilsAssembly.getObject(full_element_name)
|
||||
element_name = UtilsAssembly.getElementName(full_element_name)
|
||||
part_containing_selected_object = self.getContainingPart(full_element_name, selected_object)
|
||||
rootObj = App.getDocument(doc_name).getObject(obj_name)
|
||||
resolved = rootObj.resolveSubElement(sub_name)
|
||||
element_name_TNP = resolved[1]
|
||||
element_name = resolved[2]
|
||||
|
||||
# Preprocess the sub_name to remove the TNP string
|
||||
# We do this because after we need to add the vertex_name as well.
|
||||
# And the names will be resolved anyway after.
|
||||
if len(element_name_TNP.split(".")) == 2:
|
||||
names = sub_name.split(".")
|
||||
names.pop(-2) # remove the TNP string
|
||||
sub_name = ".".join(names)
|
||||
|
||||
ref = [rootObj, [sub_name]]
|
||||
|
||||
moving_part = self.getMovingPart(ref)
|
||||
|
||||
# Check if the addition is acceptable (we are not doing this in selection gate to let user move objects)
|
||||
acceptable = True
|
||||
if len(self.current_selection) >= 2:
|
||||
if len(self.refs) >= 2:
|
||||
# No more than 2 elements can be selected for basic joints.
|
||||
acceptable = False
|
||||
|
||||
for selection_dict in self.current_selection:
|
||||
if selection_dict["part"] == part_containing_selected_object:
|
||||
for reference in self.refs:
|
||||
sel_moving_part = self.getMovingPart(reference)
|
||||
if sel_moving_part == moving_part:
|
||||
# Can't join a solid to itself. So the user need to select 2 different parts.
|
||||
acceptable = False
|
||||
|
||||
@@ -1886,20 +1834,14 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
return
|
||||
|
||||
# Selection is acceptable so add it
|
||||
selection_dict = {
|
||||
"object": selected_object,
|
||||
"part": part_containing_selected_object,
|
||||
"element_name": element_name,
|
||||
"full_element_name": full_element_name,
|
||||
"full_obj_name": full_obj_name,
|
||||
"mouse_pos": App.Vector(mousePos[0], mousePos[1], mousePos[2]),
|
||||
}
|
||||
if element_name == "":
|
||||
selection_dict["vertex_name"] = ""
|
||||
else:
|
||||
selection_dict["vertex_name"] = UtilsAssembly.findElementClosestVertex(selection_dict)
|
||||
|
||||
self.current_selection.append(selection_dict)
|
||||
mousePos = App.Vector(mousePos[0], mousePos[1], mousePos[2])
|
||||
vertex_name = UtilsAssembly.findElementClosestVertex(self.assembly, ref, mousePos)
|
||||
|
||||
# add the vertex name to the reference
|
||||
ref = UtilsAssembly.addVertexToReference(ref, vertex_name)
|
||||
|
||||
self.refs.append(ref)
|
||||
self.updateJoint()
|
||||
|
||||
# We hide the preview JCS if we just added to the selection
|
||||
@@ -1910,41 +1852,27 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
self.addition_rejected = False
|
||||
return
|
||||
|
||||
full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name)
|
||||
selected_object = UtilsAssembly.getObject(full_element_name)
|
||||
element_name = UtilsAssembly.getElementName(full_element_name)
|
||||
part_containing_selected_object = self.getContainingPart(full_element_name, selected_object)
|
||||
ref = [App.getDocument(doc_name).getObject(obj_name), [sub_name]]
|
||||
moving_part = self.getMovingPart(ref)
|
||||
|
||||
# Find and remove the corresponding dictionary from the combined list
|
||||
for selection_dict in self.current_selection:
|
||||
if selection_dict["part"] == part_containing_selected_object:
|
||||
self.current_selection.remove(selection_dict)
|
||||
for reference in self.refs:
|
||||
sel_moving_part = self.getMovingPart(reference)
|
||||
if sel_moving_part == moving_part:
|
||||
self.refs.remove(reference)
|
||||
break
|
||||
|
||||
self.updateJoint()
|
||||
|
||||
def setPreselection(self, doc_name, obj_name, sub_name):
|
||||
if not sub_name:
|
||||
self.preselection_dict = None
|
||||
self.presel_ref = None
|
||||
return
|
||||
|
||||
full_obj_name = UtilsAssembly.getFullObjName(obj_name, sub_name)
|
||||
full_element_name = UtilsAssembly.getFullElementName(obj_name, sub_name)
|
||||
selected_object = UtilsAssembly.getObject(full_element_name)
|
||||
element_name = UtilsAssembly.getElementName(full_element_name)
|
||||
part_containing_selected_object = self.getContainingPart(full_element_name, selected_object)
|
||||
|
||||
self.preselection_dict = {
|
||||
"object": selected_object,
|
||||
"part": part_containing_selected_object,
|
||||
"sub_name": sub_name,
|
||||
"element_name": element_name,
|
||||
"full_element_name": full_element_name,
|
||||
"full_obj_name": full_obj_name,
|
||||
}
|
||||
self.presel_ref = [App.getDocument(doc_name).getObject(obj_name), [sub_name]]
|
||||
|
||||
def clearSelection(self, doc_name):
|
||||
self.current_selection.clear()
|
||||
self.refs.clear()
|
||||
self.updateJoint()
|
||||
|
||||
def setJointsPickableState(self, state: bool):
|
||||
|
||||
Reference in New Issue
Block a user