Assembly: Make RackPinion and Screw easier to setup.
This commit is contained in:
committed by
Yorik van Havre
parent
b44505db39
commit
98c518835c
@@ -845,6 +845,15 @@ std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointOfType(App::DocumentObjec
|
||||
return mbdJoint;
|
||||
}
|
||||
else if (type == JointType::Screw) {
|
||||
int slidingIndex = slidingPartIndex(joint);
|
||||
if (slidingIndex == 0) { // invalid this joint needs a slider
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (slidingIndex != 1) {
|
||||
swapJCS(joint); // make sure that sliding is first.
|
||||
}
|
||||
|
||||
auto mbdJoint = CREATE<ASMTScrewJoint>::With();
|
||||
mbdJoint->pitch = getJointDistance(joint);
|
||||
return mbdJoint;
|
||||
@@ -1066,13 +1075,21 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string fullMarkerName1 = handleOneSideOfJoint(joint, "Object1", "Part1", "Placement1");
|
||||
std::string fullMarkerName2 = handleOneSideOfJoint(joint, "Object2", "Part2", "Placement2");
|
||||
std::string jointName = joint->getFullName();
|
||||
std::string fullMarkerNameI, fullMarkerNameJ;
|
||||
if (jointType == JointType::RackPinion) {
|
||||
getRackPinionMarkers(joint, fullMarkerNameI, fullMarkerNameJ);
|
||||
}
|
||||
else {
|
||||
fullMarkerNameI = handleOneSideOfJoint(joint, "Object1", "Part1", "Placement1");
|
||||
fullMarkerNameJ = handleOneSideOfJoint(joint, "Object2", "Part2", "Placement2");
|
||||
}
|
||||
if (fullMarkerNameI == "" || fullMarkerNameJ == "") {
|
||||
return {};
|
||||
}
|
||||
|
||||
mbdJoint->setName(joint->getFullName());
|
||||
mbdJoint->setMarkerI(fullMarkerName1);
|
||||
mbdJoint->setMarkerJ(fullMarkerName2);
|
||||
mbdJoint->setMarkerI(fullMarkerNameI);
|
||||
mbdJoint->setMarkerJ(fullMarkerNameJ);
|
||||
|
||||
// Add limits if needed.
|
||||
auto* prop = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("EnableLimits"));
|
||||
@@ -1083,9 +1100,8 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
|
||||
if (propLenMin) {
|
||||
auto limit = ASMTTranslationLimit::With();
|
||||
limit->setName(joint->getFullName() + "-LimitLenMin");
|
||||
limit->setMarkerI(fullMarkerName1);
|
||||
limit->setMarkerJ(fullMarkerName2);
|
||||
// limit->setmotionJoint(jointName);
|
||||
limit->setMarkerI(fullMarkerNameI);
|
||||
limit->setMarkerJ(fullMarkerNameJ);
|
||||
limit->settype("=>");
|
||||
limit->setlimit(std::to_string(propLenMin->getValue()));
|
||||
limit->settol("1.0e-9");
|
||||
@@ -1096,8 +1112,8 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
|
||||
if (propLenMax) {
|
||||
auto limit = ASMTTranslationLimit::With();
|
||||
limit->setName(joint->getFullName() + "-LimitLenMax");
|
||||
limit->setMarkerI(fullMarkerName1);
|
||||
limit->setMarkerJ(fullMarkerName2);
|
||||
limit->setMarkerI(fullMarkerNameI);
|
||||
limit->setMarkerJ(fullMarkerNameJ);
|
||||
limit->settype("=<");
|
||||
limit->setlimit(std::to_string(propLenMax->getValue()));
|
||||
limit->settol("1.0e-9");
|
||||
@@ -1110,8 +1126,8 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
|
||||
if (propRotMin) {
|
||||
auto limit = ASMTRotationLimit::With();
|
||||
limit->setName(joint->getFullName() + "-LimitRotMin");
|
||||
limit->setMarkerI(fullMarkerName1);
|
||||
limit->setMarkerJ(fullMarkerName2);
|
||||
limit->setMarkerI(fullMarkerNameI);
|
||||
limit->setMarkerJ(fullMarkerNameJ);
|
||||
limit->settype("=>");
|
||||
limit->setlimit(std::to_string(propRotMin->getValue()) + "*pi/180.0");
|
||||
limit->settol("1.0e-9");
|
||||
@@ -1122,8 +1138,8 @@ AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
|
||||
if (propRotMax) {
|
||||
auto limit = ASMTRotationLimit::With();
|
||||
limit->setName(joint->getFullName() + "-LimiRotMax");
|
||||
limit->setMarkerI(fullMarkerName1);
|
||||
limit->setMarkerJ(fullMarkerName2);
|
||||
limit->setMarkerI(fullMarkerNameI);
|
||||
limit->setMarkerJ(fullMarkerNameJ);
|
||||
limit->settype("=<");
|
||||
limit->setlimit(std::to_string(propRotMax->getValue()) + "*pi/180.0");
|
||||
limit->settol("1.0e-9");
|
||||
@@ -1144,9 +1160,10 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
|
||||
App::DocumentObject* obj = getObjFromNameProp(joint, propObjName, propPartName);
|
||||
|
||||
if (!part) {
|
||||
std::string msg = std::string("The property ") + propPartName + " of Joint "
|
||||
+ joint->getFullName() + " is empty.\n";
|
||||
THROWM(Base::ValueError, msg);
|
||||
Base::Console().Warning("The property %s or Joint %s is empty.",
|
||||
propPartName,
|
||||
joint->getFullName());
|
||||
return "";
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart> mbdPart = getMbDPart(part);
|
||||
@@ -1172,6 +1189,128 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
|
||||
return "/OndselAssembly/" + mbdPart->name + "/" + markerName;
|
||||
}
|
||||
|
||||
void AssemblyObject::getRackPinionMarkers(App::DocumentObject* joint,
|
||||
std::string& markerNameI,
|
||||
std::string& markerNameJ)
|
||||
{
|
||||
// ASMT rack pinion joint must get the rack as I and pinion as J.
|
||||
// - rack marker has to have Z axis parallel to pinion Z axis.
|
||||
// - rack marker has to have X axis parallel to the sliding axis.
|
||||
// The user will have selected the sliding marker so we need to transform it.
|
||||
// And we need to detect which marker is the rack.
|
||||
|
||||
int slidingIndex = slidingPartIndex(joint);
|
||||
if (slidingIndex == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (slidingIndex != 1) {
|
||||
swapJCS(joint); // make sure that rack is first.
|
||||
}
|
||||
|
||||
App::DocumentObject* part1 = getLinkObjFromProp(joint, "Part1");
|
||||
App::DocumentObject* obj1 = getObjFromNameProp(joint, "Object1", "Part1");
|
||||
Base::Placement plc1 = getPlacementFromProp(joint, "Placement1");
|
||||
|
||||
App::DocumentObject* part2 = getLinkObjFromProp(joint, "Part2");
|
||||
App::DocumentObject* obj2 = getObjFromNameProp(joint, "Object2", "Part2");
|
||||
Base::Placement plc2 = getPlacementFromProp(joint, "Placement2");
|
||||
|
||||
// For the pinion nothing special needed :
|
||||
markerNameJ = handleOneSideOfJoint(joint, "Object2", "Part2", "Placement2");
|
||||
|
||||
// For the rack we need to change the placement :
|
||||
// make the pinion plc relative to the rack placement.
|
||||
Base::Placement pinion_global_plc = getGlobalPlacement(obj2, part2);
|
||||
plc2 = pinion_global_plc * plc2;
|
||||
Base::Placement rack_global_plc = getGlobalPlacement(obj1, part1);
|
||||
plc2 = rack_global_plc.inverse() * plc2;
|
||||
|
||||
// The rot of the rack placement should be the same as the pinion, but with X axis along the
|
||||
// slider axis.
|
||||
Base::Rotation rot = plc2.getRotation();
|
||||
// the yaw of rot has to be the same as plc1
|
||||
Base::Vector3d currentZAxis = rot.multVec(Base::Vector3d(0, 0, 1));
|
||||
Base::Vector3d currentXAxis = rot.multVec(Base::Vector3d(1, 0, 0));
|
||||
Base::Vector3d targetXAxis = plc1.getRotation().multVec(Base::Vector3d(0, 0, 1));
|
||||
|
||||
// Calculate the angle between the current X axis and the target X axis
|
||||
double yawAdjustment = currentXAxis.GetAngle(targetXAxis);
|
||||
|
||||
// Determine the direction of the yaw adjustment using cross product
|
||||
Base::Vector3d crossProd = currentXAxis.Cross(targetXAxis);
|
||||
if (currentZAxis * crossProd < 0) { // If cross product is in opposite direction to Z axis
|
||||
yawAdjustment = -yawAdjustment;
|
||||
}
|
||||
|
||||
// Create a yaw rotation around the Z axis
|
||||
Base::Rotation yawRotation(currentZAxis, yawAdjustment);
|
||||
|
||||
// Combine the initial rotation with the yaw adjustment
|
||||
Base::Rotation adjustedRotation = rot * yawRotation;
|
||||
plc1.setRotation(adjustedRotation);
|
||||
|
||||
// Then end of processing similar to handleOneSideOfJoint :
|
||||
|
||||
if (obj1->getNameInDocument() != part1->getNameInDocument()) {
|
||||
plc1 = rack_global_plc * plc1;
|
||||
|
||||
Base::Placement part_global_plc = getGlobalPlacement(part1);
|
||||
plc1 = part_global_plc.inverse() * plc1;
|
||||
}
|
||||
|
||||
std::string markerName = joint->getFullName();
|
||||
auto mbdMarker = makeMbdMarker(markerName, plc1);
|
||||
std::shared_ptr<ASMTPart> mbdPart = getMbDPart(part1);
|
||||
mbdPart->addMarker(mbdMarker);
|
||||
|
||||
markerNameI = "/OndselAssembly/" + mbdPart->name + "/" + markerName;
|
||||
}
|
||||
|
||||
int AssemblyObject::slidingPartIndex(App::DocumentObject* joint)
|
||||
{
|
||||
App::DocumentObject* part1 = getLinkObjFromProp(joint, "Part1");
|
||||
App::DocumentObject* obj1 = getObjFromNameProp(joint, "Object1", "Part1");
|
||||
Base::Placement plc1 = getPlacementFromProp(joint, "Placement1");
|
||||
|
||||
App::DocumentObject* part2 = getLinkObjFromProp(joint, "Part2");
|
||||
App::DocumentObject* obj2 = getObjFromNameProp(joint, "Object2", "Part2");
|
||||
Base::Placement plc2 = getPlacementFromProp(joint, "Placement2");
|
||||
|
||||
int slidingFound = 0;
|
||||
for (auto* jt : getJoints(false, false)) {
|
||||
if (getJointType(jt) == JointType::Slider) {
|
||||
App::DocumentObject* jpart1 = getLinkObjFromProp(jt, "Part1");
|
||||
App::DocumentObject* jpart2 = getLinkObjFromProp(jt, "Part2");
|
||||
int found = 0;
|
||||
Base::Placement plcjt, plci;
|
||||
if (jpart1 == part1 || jpart1 == part2) {
|
||||
found = (jpart1 == part1) ? 1 : 2;
|
||||
plci = (jpart1 == part1) ? plc1 : plc2;
|
||||
plcjt = getPlacementFromProp(jt, "Placement1");
|
||||
}
|
||||
else if (jpart2 == part1 || jpart2 == part2) {
|
||||
found = (jpart2 == part1) ? 1 : 2;
|
||||
plci = (jpart2 == part1) ? plc1 : plc2;
|
||||
plcjt = getPlacementFromProp(jt, "Placement2");
|
||||
}
|
||||
|
||||
if (found != 0) {
|
||||
// check the placements plcjt and (jcs1 or jcs2 depending on found value) Z axis are
|
||||
// colinear ie if their pitch and roll are the same.
|
||||
double y1, p1, r1, y2, p2, r2;
|
||||
plcjt.getRotation().getYawPitchRoll(y1, p1, r1);
|
||||
plci.getRotation().getYawPitchRoll(y2, p2, r2);
|
||||
if (fabs(p1 - p2) < Precision::Confusion()
|
||||
&& fabs(r1 - r2) < Precision::Confusion()) {
|
||||
slidingFound = found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return slidingFound;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart> AssemblyObject::getMbDPart(App::DocumentObject* obj)
|
||||
{
|
||||
std::shared_ptr<ASMTPart> mbdPart;
|
||||
|
||||
@@ -171,6 +171,10 @@ public:
|
||||
const char* propObjLinkName,
|
||||
const char* propPartName,
|
||||
const char* propPlcName);
|
||||
void getRackPinionMarkers(App::DocumentObject* joint,
|
||||
std::string& markerNameI,
|
||||
std::string& markerNameJ);
|
||||
int slidingPartIndex(App::DocumentObject* joint);
|
||||
|
||||
void jointParts(std::vector<App::DocumentObject*> joints);
|
||||
JointGroup* getJointGroup();
|
||||
|
||||
@@ -258,7 +258,7 @@ class CommandCreateJointRackPinion:
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointRackPinion",
|
||||
"The pitch radius defines the movement ratio between the rack and the pinion.",
|
||||
"Select the same coordinate systems as the revolute and sliding joints. The pitch radius defines the movement ratio between the rack and the pinion.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
@@ -289,7 +289,7 @@ class CommandCreateJointScrew:
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointScrew",
|
||||
"The pitch radius defines the movement ratio between the rotating screw and the sliding part.",
|
||||
"Select the same coordinate systems as the revolute and sliding joints. The pitch radius defines the movement ratio between the rotating screw and the sliding part.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
@@ -317,6 +317,11 @@ class CommandCreateJointGears:
|
||||
"Assembly_CreateJointGears",
|
||||
"Create a Gears Joint: Links two rotating gears together. They will have inverse rotation direction.",
|
||||
)
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointScrew",
|
||||
"Select the same coordinate systems as the revolute joints.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
}
|
||||
@@ -343,6 +348,11 @@ class CommandCreateJointBelt:
|
||||
"Assembly_CreateJointBelt",
|
||||
"Create a Belt Joint: Links two rotating objects together. They will have the same rotation direction.",
|
||||
)
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointScrew",
|
||||
"Select the same coordinate systems as the revolute joints.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
}
|
||||
@@ -363,12 +373,17 @@ class CommandGroupGearBelt:
|
||||
|
||||
return {
|
||||
"Pixmap": "Assembly_CreateJointGears",
|
||||
"MenuText": QT_TRANSLATE_NOOP("Assembly_CreateJointGears", "Create Gear/Belt Joint"),
|
||||
"MenuText": QT_TRANSLATE_NOOP("Assembly_CreateJointGearBelt", "Create Gear/Belt Joint"),
|
||||
"ToolTip": "<p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointGears",
|
||||
"Assembly_CreateJointGearBelt",
|
||||
"Create a Gears/Belt Joint: Links two rotating gears together.",
|
||||
)
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateJointGearBelt",
|
||||
"Select the same coordinate systems as the revolute joints.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
}
|
||||
|
||||
@@ -949,10 +949,8 @@ def findPlacement(obj, part, elt, vtx, ignoreVertex=False):
|
||||
plc.Base = (vertex.X, vertex.Y, vertex.Z)
|
||||
|
||||
# Then we find the Rotation
|
||||
if surface.TypeId == "Part::GeomPlane":
|
||||
if hasattr(surface, "Rotation") and surface.Rotation is not None:
|
||||
plc.Rotation = App.Rotation(surface.Rotation)
|
||||
else:
|
||||
plc.Rotation = surface.Rotation
|
||||
|
||||
# Now plc is the placement relative to the origin determined by the object placement.
|
||||
# But it does not take into account Part placements. So if the solid is in a part and
|
||||
|
||||
Reference in New Issue
Block a user