Assembly: Make RackPinion and Screw easier to setup.

This commit is contained in:
PaddleStroke
2024-04-17 12:45:18 +02:00
committed by Yorik van Havre
parent b44505db39
commit 98c518835c
4 changed files with 180 additions and 24 deletions

View File

@@ -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;

View File

@@ -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();

View File

@@ -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",
}

View File

@@ -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