Assembly: Fix lag during dragging of large assemblies. Bundle fix joints together. Show only the movingJoint during dragging. Do not recompute joints during dragging.
This commit is contained in:
committed by
Yorik van Havre
parent
6e2cd4e733
commit
bdfcb6bfb2
@@ -117,6 +117,7 @@ PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part)
|
||||
|
||||
AssemblyObject::AssemblyObject()
|
||||
: mbdAssembly(std::make_shared<ASMTAssembly>())
|
||||
, bundleFixed(false)
|
||||
{}
|
||||
|
||||
AssemblyObject::~AssemblyObject() = default;
|
||||
@@ -182,11 +183,16 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
|
||||
void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
|
||||
{
|
||||
bundleFixed = true;
|
||||
solve();
|
||||
bundleFixed = false;
|
||||
|
||||
dragMbdParts.clear();
|
||||
for (auto part : dragParts) {
|
||||
dragMbdParts.push_back(getMbDPart(part));
|
||||
auto mbdPart = getMbDPart(part);
|
||||
if (std::find(dragMbdParts.begin(), dragMbdParts.end(), mbdPart) == dragMbdParts.end()) {
|
||||
dragMbdParts.push_back(mbdPart);
|
||||
}
|
||||
}
|
||||
|
||||
mbdAssembly->runPreDrag();
|
||||
@@ -197,21 +203,26 @@ void AssemblyObject::doDragStep()
|
||||
try {
|
||||
for (auto& mbdPart : dragMbdParts) {
|
||||
App::DocumentObject* part = nullptr;
|
||||
|
||||
// Find the corresponding DocumentObject for the mbdPart
|
||||
for (auto& pair : objectPartMap) {
|
||||
if (pair.second == mbdPart) {
|
||||
if (pair.second.part == mbdPart) {
|
||||
part = pair.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!part) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Update the MBD part's position
|
||||
Base::Placement plc = getPlacementFromProp(part, "Placement");
|
||||
Base::Vector3d pos = plc.getPosition();
|
||||
mbdPart->updateMbDFromPosition3D(
|
||||
std::make_shared<FullColumn<double>>(ListD {pos.x, pos.y, pos.z}));
|
||||
|
||||
// Update the MBD part's rotation
|
||||
Base::Rotation rot = plc.getRotation();
|
||||
Base::Matrix4D mat;
|
||||
rot.getValue(mat);
|
||||
@@ -222,11 +233,21 @@ void AssemblyObject::doDragStep()
|
||||
->updateMbDFromRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
|
||||
}
|
||||
|
||||
// Timing mbdAssembly->runDragStep()
|
||||
auto dragPartsVec = std::make_shared<std::vector<std::shared_ptr<ASMTPart>>>(dragMbdParts);
|
||||
mbdAssembly->runDragStep(dragPartsVec);
|
||||
|
||||
// Timing the validation and placement setting
|
||||
if (validateNewPlacements()) {
|
||||
setNewPlacements();
|
||||
redrawJointPlacements(getJoints());
|
||||
|
||||
auto joints = getJoints(false);
|
||||
for (auto* joint : joints) {
|
||||
if (joint->Visibility.getValue()) {
|
||||
// redraw only the moving joint as its quite slow as its python code.
|
||||
redrawJointPlacement(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
@@ -258,8 +279,12 @@ bool AssemblyObject::validateNewPlacements()
|
||||
|
||||
auto it = objectPartMap.find(obj);
|
||||
if (it != objectPartMap.end()) {
|
||||
std::shared_ptr<MbD::ASMTPart> mbdPart = it->second;
|
||||
std::shared_ptr<MbD::ASMTPart> mbdPart = it->second.part;
|
||||
Base::Placement newPlacement = getMbdPlacement(mbdPart);
|
||||
if (!it->second.offsetPlc.isIdentity()) {
|
||||
newPlacement = newPlacement * it->second.offsetPlc;
|
||||
}
|
||||
|
||||
if (!oldPlc.isSame(newPlacement)) {
|
||||
Base::Console().Warning(
|
||||
"Assembly : Ignoring bad solve, a grounded object moved.\n");
|
||||
@@ -353,7 +378,7 @@ void AssemblyObject::setNewPlacements()
|
||||
{
|
||||
for (auto& pair : objectPartMap) {
|
||||
App::DocumentObject* obj = pair.first;
|
||||
std::shared_ptr<ASMTPart> mbdPart = pair.second;
|
||||
std::shared_ptr<ASMTPart> mbdPart = pair.second.part;
|
||||
|
||||
if (!obj || !mbdPart) {
|
||||
continue;
|
||||
@@ -366,8 +391,15 @@ void AssemblyObject::setNewPlacements()
|
||||
continue;
|
||||
}
|
||||
|
||||
propPlacement->setValue(getMbdPlacement(mbdPart));
|
||||
obj->purgeTouched();
|
||||
|
||||
Base::Placement newPlacement = getMbdPlacement(mbdPart);
|
||||
if (!pair.second.offsetPlc.isIdentity()) {
|
||||
newPlacement = newPlacement * pair.second.offsetPlc;
|
||||
}
|
||||
if (!propPlacement->getValue().isSame(newPlacement)) {
|
||||
propPlacement->setValue(newPlacement);
|
||||
obj->purgeTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,20 +407,24 @@ void AssemblyObject::redrawJointPlacements(std::vector<App::DocumentObject*> joi
|
||||
{
|
||||
// Notify the joint objects that the transform of the coin object changed.
|
||||
for (auto* joint : joints) {
|
||||
auto* propPlacement =
|
||||
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement1"));
|
||||
if (propPlacement) {
|
||||
propPlacement->setValue(propPlacement->getValue());
|
||||
}
|
||||
propPlacement =
|
||||
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement2"));
|
||||
if (propPlacement) {
|
||||
propPlacement->setValue(propPlacement->getValue());
|
||||
}
|
||||
joint->purgeTouched();
|
||||
redrawJointPlacement(joint);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyObject::redrawJointPlacement(App::DocumentObject* joint)
|
||||
{
|
||||
// Notify the joint object that the transform of the coin object changed.
|
||||
auto* pPlc = dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement1"));
|
||||
if (pPlc) {
|
||||
pPlc->setValue(pPlc->getValue());
|
||||
}
|
||||
pPlc = dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement2"));
|
||||
if (pPlc) {
|
||||
pPlc->setValue(pPlc->getValue());
|
||||
}
|
||||
joint->purgeTouched();
|
||||
}
|
||||
|
||||
void AssemblyObject::recomputeJointPlacements(std::vector<App::DocumentObject*> joints)
|
||||
{
|
||||
// The Placement1 and Placement2 of each joint needs to be updated as the parts moved.
|
||||
@@ -884,6 +920,9 @@ std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointOfType(App::DocumentObjec
|
||||
JointType type)
|
||||
{
|
||||
if (type == JointType::Fixed) {
|
||||
if (bundleFixed) {
|
||||
return nullptr;
|
||||
}
|
||||
return CREATE<ASMTFixedJoint>::With();
|
||||
}
|
||||
else if (type == JointType::Revolute) {
|
||||
@@ -1288,7 +1327,8 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
|
||||
return "";
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart> mbdPart = getMbDPart(part);
|
||||
MbDPartData data = getMbDData(part);
|
||||
std::shared_ptr<ASMTPart> mbdPart = data.part;
|
||||
Base::Placement plc = getPlacementFromProp(joint, propPlcName);
|
||||
// Now we have plc which is the JCS placement, but its relative to the Object, not to the
|
||||
// containing Part.
|
||||
@@ -1308,6 +1348,10 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
|
||||
Base::Placement part_global_plc = getGlobalPlacement(part, ref);
|
||||
plc = part_global_plc.inverse() * plc;
|
||||
}
|
||||
// check if we need to add an offset in case of bundled parts.
|
||||
if (!data.offsetPlc.isIdentity()) {
|
||||
plc = data.offsetPlc * plc;
|
||||
}
|
||||
|
||||
std::string markerName = joint->getFullName();
|
||||
auto mbdMarker = makeMbdMarker(markerName, plc);
|
||||
@@ -1387,17 +1431,21 @@ void AssemblyObject::getRackPinionMarkers(App::DocumentObject* joint,
|
||||
plc1.setRotation(adjustedRotation);
|
||||
|
||||
// Then end of processing similar to handleOneSideOfJoint :
|
||||
|
||||
MbDPartData data1 = getMbDData(part1);
|
||||
std::shared_ptr<ASMTPart> mbdPart = data1.part;
|
||||
if (obj1->getNameInDocument() != part1->getNameInDocument()) {
|
||||
plc1 = rack_global_plc * plc1;
|
||||
|
||||
Base::Placement part_global_plc = getGlobalPlacement(part1, ref1);
|
||||
plc1 = part_global_plc.inverse() * plc1;
|
||||
}
|
||||
// check if we need to add an offset in case of bundled parts.
|
||||
if (!data1.offsetPlc.isIdentity()) {
|
||||
plc1 = data1.offsetPlc * 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;
|
||||
@@ -1449,26 +1497,57 @@ int AssemblyObject::slidingPartIndex(App::DocumentObject* joint)
|
||||
return slidingFound;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart> AssemblyObject::getMbDPart(App::DocumentObject* obj)
|
||||
AssemblyObject::MbDPartData AssemblyObject::getMbDData(App::DocumentObject* part)
|
||||
{
|
||||
std::shared_ptr<ASMTPart> mbdPart;
|
||||
|
||||
Base::Placement plc = getPlacementFromProp(obj, "Placement");
|
||||
|
||||
auto it = objectPartMap.find(obj);
|
||||
auto it = objectPartMap.find(part);
|
||||
if (it != objectPartMap.end()) {
|
||||
// obj has been associated with an ASMTPart before
|
||||
mbdPart = it->second;
|
||||
}
|
||||
else {
|
||||
// obj has not been associated with an ASMTPart before
|
||||
std::string str = obj->getFullName();
|
||||
mbdPart = makeMbdPart(str, plc);
|
||||
mbdAssembly->addPart(mbdPart);
|
||||
objectPartMap[obj] = mbdPart; // Store the association
|
||||
// part has been associated with an ASMTPart before
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return mbdPart;
|
||||
// part has not been associated with an ASMTPart before
|
||||
std::string str = part->getFullName();
|
||||
Base::Placement plc = getPlacementFromProp(part, "Placement");
|
||||
std::shared_ptr<ASMTPart> mbdPart = makeMbdPart(str, plc);
|
||||
mbdAssembly->addPart(mbdPart);
|
||||
MbDPartData data = {mbdPart, Base::Placement()};
|
||||
objectPartMap[part] = data; // Store the association
|
||||
|
||||
// Associate other objects conneted with fixed joints
|
||||
if (bundleFixed) {
|
||||
auto addConnectedFixedParts = [&](App::DocumentObject* currentPart, auto& self) -> void {
|
||||
std::vector<App::DocumentObject*> joints = getJointsOfPart(currentPart);
|
||||
for (auto* joint : joints) {
|
||||
JointType jointType = getJointType(joint);
|
||||
if (jointType == JointType::Fixed) {
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* partToAdd = currentPart == part1 ? part2 : part1;
|
||||
|
||||
if (objectPartMap.find(partToAdd) != objectPartMap.end()) {
|
||||
// already added
|
||||
continue;
|
||||
}
|
||||
|
||||
Base::Placement plci = getPlacementFromProp(partToAdd, "Placement");
|
||||
MbDPartData partData = {mbdPart, plc.inverse() * plci};
|
||||
objectPartMap[partToAdd] = partData; // Store the association
|
||||
|
||||
// Recursively call for partToAdd
|
||||
self(partToAdd, self);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addConnectedFixedParts(part, addConnectedFixedParts);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart> AssemblyObject::getMbDPart(App::DocumentObject* part)
|
||||
{
|
||||
return getMbDData(part).part;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASMTPart>
|
||||
|
||||
@@ -170,6 +170,7 @@ public:
|
||||
void setNewPlacements();
|
||||
static void recomputeJointPlacements(std::vector<App::DocumentObject*> joints);
|
||||
static void redrawJointPlacements(std::vector<App::DocumentObject*> joints);
|
||||
static void redrawJointPlacement(App::DocumentObject* joint);
|
||||
|
||||
// This makes sure that LinkGroups or sub-assemblies have identity placements.
|
||||
void ensureIdentityPlacements();
|
||||
@@ -179,6 +180,16 @@ public:
|
||||
std::shared_ptr<MbD::ASMTPart>
|
||||
makeMbdPart(std::string& name, Base::Placement plc = Base::Placement(), double mass = 1.0);
|
||||
std::shared_ptr<MbD::ASMTPart> getMbDPart(App::DocumentObject* obj);
|
||||
// To help the solver, during dragging, we are bundling parts connected by a fixed joint.
|
||||
// So several assembly components are bundled in a single ASMTPart.
|
||||
// So we need to store the plc of each bundled object relative to the bundle origin (first obj
|
||||
// of objectPartMap).
|
||||
struct MbDPartData
|
||||
{
|
||||
std::shared_ptr<MbD::ASMTPart> part;
|
||||
Base::Placement offsetPlc; // This is the offset within the bundled parts
|
||||
};
|
||||
MbDPartData getMbDData(App::DocumentObject* obj);
|
||||
std::shared_ptr<MbD::ASMTMarker> makeMbdMarker(std::string& name, Base::Placement& plc);
|
||||
std::vector<std::shared_ptr<MbD::ASMTJoint>> makeMbdJoint(App::DocumentObject* joint);
|
||||
std::shared_ptr<MbD::ASMTJoint> makeMbdJointOfType(App::DocumentObject* joint,
|
||||
@@ -236,12 +247,13 @@ public:
|
||||
private:
|
||||
std::shared_ptr<MbD::ASMTAssembly> mbdAssembly;
|
||||
|
||||
std::unordered_map<App::DocumentObject*, std::shared_ptr<MbD::ASMTPart>> objectPartMap;
|
||||
std::unordered_map<App::DocumentObject*, MbDPartData> objectPartMap;
|
||||
std::vector<std::pair<App::DocumentObject*, double>> objMasses;
|
||||
std::vector<std::shared_ptr<MbD::ASMTPart>> dragMbdParts;
|
||||
|
||||
std::vector<std::pair<App::DocumentObject*, Base::Placement>> previousPositions;
|
||||
|
||||
bool bundleFixed;
|
||||
// void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property
|
||||
// *prop) override;
|
||||
|
||||
|
||||
@@ -99,9 +99,9 @@ ViewProviderAssembly::ViewProviderAssembly()
|
||||
, enableMovement(true)
|
||||
, moveOnlyPreselected(false)
|
||||
, moveInCommand(true)
|
||||
, jointVisibilityBackup(false)
|
||||
, ctrlPressed(false)
|
||||
, lastClickTime(0)
|
||||
, jointVisibilitiesBackup({})
|
||||
, docsToMove({})
|
||||
{}
|
||||
|
||||
@@ -783,11 +783,6 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
assemblyPart->getDownstreamParts(docsToMove[0].obj, movingJoint);
|
||||
addPartsToMove(downstreamParts);
|
||||
|
||||
jointVisibilityBackup = movingJoint->Visibility.getValue();
|
||||
if (!jointVisibilityBackup) {
|
||||
movingJoint->Visibility.setValue(true);
|
||||
}
|
||||
|
||||
if (jointType == JointType::Revolute) {
|
||||
return DragMode::RotationOnPlane;
|
||||
}
|
||||
@@ -818,6 +813,26 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento
|
||||
return;
|
||||
}
|
||||
|
||||
auto* assemblyPart = static_cast<AssemblyObject*>(getObject());
|
||||
// When the user drag parts, we switch off all joints visibility and only show the movingjoint
|
||||
jointVisibilitiesBackup.clear();
|
||||
auto joints = assemblyPart->getJoints();
|
||||
for (auto* joint : joints) {
|
||||
if (!joint) {
|
||||
continue;
|
||||
}
|
||||
bool visible = joint->Visibility.getValue();
|
||||
jointVisibilitiesBackup.push_back({joint, visible});
|
||||
if (movingJoint == joint) {
|
||||
if (!visible) {
|
||||
joint->Visibility.setValue(true);
|
||||
}
|
||||
}
|
||||
else if (visible) {
|
||||
joint->Visibility.setValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
SbVec3f vec;
|
||||
if (dragMode == DragMode::RotationOnPlane) {
|
||||
vec = viewer->getPointOnXYPlaneOfPlacement(cursorPos, jcsGlobalPlc);
|
||||
@@ -860,7 +875,6 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento
|
||||
// prevent selection while moving
|
||||
viewer->setSelectionEnabled(false);
|
||||
|
||||
auto* assemblyPart = static_cast<AssemblyObject*>(getObject());
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Assembly");
|
||||
bool solveOnMove = hGrp->GetBool("SolveOnMove", true);
|
||||
@@ -888,8 +902,13 @@ void ViewProviderAssembly::endMove()
|
||||
partMoving = false;
|
||||
canStartDragging = false;
|
||||
|
||||
if (movingJoint && !jointVisibilityBackup) {
|
||||
movingJoint->Visibility.setValue(false);
|
||||
auto* assemblyPart = static_cast<AssemblyObject*>(getObject());
|
||||
auto joints = assemblyPart->getJoints();
|
||||
for (auto pair : jointVisibilitiesBackup) {
|
||||
bool visible = pair.first->Visibility.getValue();
|
||||
if (visible != pair.second) {
|
||||
pair.first->Visibility.setValue(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
movingJoint = nullptr;
|
||||
@@ -904,7 +923,6 @@ void ViewProviderAssembly::endMove()
|
||||
"User parameter:BaseApp/Preferences/Mod/Assembly");
|
||||
bool solveOnMove = hGrp->GetBool("SolveOnMove", true);
|
||||
if (solveOnMove) {
|
||||
auto* assemblyPart = static_cast<AssemblyObject*>(getObject());
|
||||
assemblyPart->postDrag();
|
||||
assemblyPart->setObjMasses({});
|
||||
}
|
||||
|
||||
@@ -203,7 +203,6 @@ public:
|
||||
bool enableMovement;
|
||||
bool moveOnlyPreselected;
|
||||
bool moveInCommand;
|
||||
bool jointVisibilityBackup;
|
||||
bool ctrlPressed;
|
||||
|
||||
long lastClickTime; // Store last click time as milliseconds
|
||||
@@ -218,6 +217,7 @@ public:
|
||||
|
||||
App::DocumentObject* movingJoint;
|
||||
|
||||
std::vector<std::pair<App::DocumentObject*, bool>> jointVisibilitiesBackup;
|
||||
std::vector<std::pair<App::DocumentObject*, double>> objectMasses;
|
||||
std::vector<MovingObject> docsToMove;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user