Assembly: Enable dragger when solid is selected. Fixes #12656

This commit is contained in:
PaddleStroke
2024-03-14 10:17:49 +01:00
committed by Yorik van Havre
parent 061aba3476
commit ce72c2d438
2 changed files with 136 additions and 6 deletions

View File

@@ -212,7 +212,7 @@ void ViewProviderAssembly::unsetEdit(int ModNum)
Q_UNUSED(ModNum);
canStartDragging = false;
partMoving = false;
docsToMove = {};
docsToMove.clear();
unsetDragger();
@@ -444,7 +444,7 @@ bool ViewProviderAssembly::mouseButtonPressed(int Button,
// Left Mouse button ****************************************************
if (Button == 1) {
if (pressed) {
if (pressed && !getDraggerVisibility()) {
canStartDragging = true;
}
else { // Button 1 released
@@ -462,7 +462,7 @@ bool ViewProviderAssembly::mouseButtonPressed(int Button,
return false;
}
bool ViewProviderAssembly::getSelectedObjectsWithinAssembly()
bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection, bool onlySolids)
{
// check the current selection, and check if any of the selected objects are within this
// App::Part
@@ -470,6 +470,8 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly()
// Get the document
Gui::Document* doc = Gui::Application::Instance->activeDocument();
docsToMove.clear();
if (!doc) {
return false;
}
@@ -490,6 +492,12 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly()
std::vector<std::string> objsSubNames = selObj.getSubNames();
for (auto& subNamesStr : objsSubNames) {
std::vector<std::string> subNames = parseSubNames(subNamesStr);
if (subNames.empty()) {
continue;
}
if (onlySolids && subNames.back() != "") {
continue;
}
App::DocumentObject* obj = getObjectFromSubNames(subNames);
if (!obj) {
@@ -509,7 +517,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly()
// This function is called before the selection is updated. So if a user click and drag a part
// it is not selected at that point. So we need to get the preselection too.
if (Gui::Selection().hasPreselection()) {
if (addPreselection && Gui::Selection().hasPreselection()) {
// Base::Console().Warning("Gui::Selection().getPreselection().pSubName %s\n",
// Gui::Selection().getPreselection().pSubName);
@@ -549,6 +557,14 @@ std::vector<std::string> ViewProviderAssembly::parseSubNames(std::string& subNam
while (std::getline(subNameStream, subName, '.')) {
subNames.push_back(subName);
}
// Check if the last character of the input string is the delimiter.
// If so, add an empty string to the subNames vector.
// Because the last subname is the element name and can be empty.
if (!subNamesStr.empty() && subNamesStr.back() == '.') {
subNames.push_back(""); // Append empty string for trailing dot.
}
return subNames;
}
@@ -563,6 +579,9 @@ App::DocumentObject* ViewProviderAssembly::getObjectFromSubNames(std::vector<std
else if (subNames.size() == 2) {
// If two subnames then it can't be a body and the object we want is the first one
// For example we want box in "box.face1"
// "assembly.part.box.face1"
// "p.fcstd.assembly.LinkToPart.box.face1"
// "p2.fcstd.Part.box."
return appDoc->getObject(subNames[0].c_str());
}
@@ -764,7 +783,7 @@ void ViewProviderAssembly::initMove(const SbVec2s& cursorPos, Gui::View3DInvento
void ViewProviderAssembly::endMove()
{
docsToMove = {};
docsToMove.clear();
partMoving = false;
canStartDragging = false;
@@ -795,6 +814,50 @@ void ViewProviderAssembly::endMove()
Gui::Command::commitCommand();
}
void ViewProviderAssembly::initMoveDragger()
{
setDraggerVisibility(true);
// find the placement for the dragger.
App::DocumentObject* obj = docsToMove[0].first;
AssemblyObject* assemblyPart = static_cast<AssemblyObject*>(getObject());
draggerInitPlc = AssemblyObject::getGlobalPlacement(obj, obj);
std::vector<App::DocumentObject*> listOfObjs;
for (auto& pair : docsToMove) {
listOfObjs.push_back(pair.first);
}
Base::Vector3d pos = getCenterOfBoundingBox(listOfObjs, listOfObjs);
draggerInitPlc.setPosition(pos);
setDraggerPlacement(draggerInitPlc);
asmDragger->addMotionCallback(draggerMotionCallback, this);
}
void ViewProviderAssembly::endMoveDragger()
{
if (getDraggerVisibility()) {
asmDragger->removeMotionCallback(draggerMotionCallback, this);
setDraggerVisibility(false);
}
}
void ViewProviderAssembly::draggerMotionCallback(void* data, SoDragger* d)
{
auto sudoThis = static_cast<ViewProviderAssembly*>(data);
Base::Placement draggerPlc = sudoThis->getDraggerPlacement();
Base::Placement movePlc = draggerPlc * sudoThis->draggerInitPlc.inverse();
for (auto& pair : sudoThis->docsToMove) {
App::DocumentObject* obj = pair.first;
auto* propPlc = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
if (propPlc) {
propPlc->setValue(movePlc * pair.second);
}
}
}
void ViewProviderAssembly::onSelectionChanged(const Gui::SelectionChanges& msg)
{
if (msg.Type == Gui::SelectionChanges::AddSelection
@@ -802,6 +865,20 @@ void ViewProviderAssembly::onSelectionChanged(const Gui::SelectionChanges& msg)
|| msg.Type == Gui::SelectionChanges::RmvSelection) {
canStartDragging = false;
}
if (msg.Type == Gui::SelectionChanges::AddSelection) {
// If selected object is a single solid show dragger and init dragger move
if (enableMovement && getSelectedObjectsWithinAssembly(false, true)) {
initMoveDragger();
}
}
if (msg.Type == Gui::SelectionChanges::ClrSelection
|| msg.Type == Gui::SelectionChanges::RmvSelection) {
if (enableMovement) {
endMoveDragger();
}
}
}
bool ViewProviderAssembly::onDelete(const std::vector<std::string>& subNames)
@@ -863,3 +940,47 @@ PyObject* ViewProviderAssembly::getPyObject()
pyViewObject->IncRef();
return pyViewObject;
}
// UTILS
Base::Vector3d
ViewProviderAssembly::getCenterOfBoundingBox(const std::vector<App::DocumentObject*>& objs,
const std::vector<App::DocumentObject*>& parts)
{
int count = 0;
Base::Vector3d center;
for (size_t i = 0; i < objs.size(); ++i) {
Gui::ViewProvider* viewProvider = Gui::Application::Instance->getViewProvider(objs[i]);
if (!viewProvider) {
continue;
}
const Base::BoundBox3d& boundingBox = viewProvider->getBoundingBox();
if (!boundingBox.IsValid()) {
continue;
}
Base::Vector3d bboxCenter = boundingBox.GetCenter();
if (parts[i] != objs[i]) {
// bboxCenter does not take into account obj global placement
Base::Placement plc(bboxCenter, Base::Rotation());
// Change plc to be relative to the object placement.
Base::Placement objPlc = AssemblyObject::getPlacementFromProp(objs[i], "Placement");
plc = objPlc.inverse() * plc;
// Change plc to be relative to the origin of the document.
Base::Placement global_plc = AssemblyObject::getGlobalPlacement(objs[i], parts[i]);
plc = global_plc * plc;
bboxCenter = plc.getPosition();
}
center += bboxCenter;
++count;
}
if (count > 0) {
center /= static_cast<double>(count);
}
return center;
}

View File

@@ -114,7 +114,8 @@ public:
return enableMovement;
}
bool getSelectedObjectsWithinAssembly();
bool getSelectedObjectsWithinAssembly(bool addPreselection = true, bool onlySolids = false);
App::DocumentObject* getObjectFromSubNames(std::vector<std::string>& subNames);
std::vector<std::string> parseSubNames(std::string& subNamesStr);
@@ -128,6 +129,10 @@ public:
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
// Dragger controls:
void initMoveDragger();
void endMoveDragger();
static void draggerMotionCallback(void* data, SoDragger* d);
void setDragger();
void unsetDragger();
void setDraggerVisibility(bool val);
@@ -136,6 +141,9 @@ public:
Base::Placement getDraggerPlacement();
Gui::SoFCCSysDragger* getDragger();
static Base::Vector3d getCenterOfBoundingBox(const std::vector<App::DocumentObject*>& objs,
const std::vector<App::DocumentObject*>& parts);
DragMode dragMode;
bool canStartDragging;
bool partMoving;
@@ -147,6 +155,7 @@ public:
Base::Vector3d initialPositionRot;
Base::Placement jcsPlc;
Base::Placement jcsGlobalPlc;
Base::Placement draggerInitPlc;
App::DocumentObject* movingJoint;