diff --git a/src/Gui/Placement.cpp b/src/Gui/Placement.cpp index 372a80f3fa..02d7476843 100644 --- a/src/Gui/Placement.cpp +++ b/src/Gui/Placement.cpp @@ -102,7 +102,7 @@ PlacementHandler::PlacementHandler() : propertyName{"Placement"} , changeProperty{false} { - + setupDocument(); } void PlacementHandler::openTransactionIfNeeded() @@ -120,6 +120,33 @@ void PlacementHandler::setPropertyName(const std::string& name) changeProperty = (propertyName != "Placement"); } +void PlacementHandler::setSelection(const std::vector& selection) +{ + selectionObjects = selection; +} + +void PlacementHandler::reselectObjects() +{ + //we have to clear selection and reselect original object(s) + //else later on the rotation is applied twice because there will + //be 2 (vertex) objects in the selection, and even if both are subobjects + //of the same object the rotation still gets applied twice + Gui::Selection().clearSelection(); + //reselect original object that was selected when placement dlg first opened + for (const auto& it : selectionObjects) { + Gui::Selection().addSelection(it); + } +} + +const App::DocumentObject* PlacementHandler::getFirstOfSelection() const +{ + if (!selectionObjects.empty()) { + return selectionObjects.front().getObject(); + } + + return nullptr; +} + const std::string& PlacementHandler::getPropertyName() const { return propertyName; @@ -186,6 +213,16 @@ void PlacementHandler::revertTransformationOfViewProviders(Gui::Document* docume } } +void PlacementHandler::setRefPlacement(const Base::Placement& plm) +{ + ref = plm; +} + +const Base::Placement& PlacementHandler::getRefPlacement() const +{ + return ref; +} + void PlacementHandler::applyPlacement(const Base::Placement& p, bool incremental) { Gui::Document* document = Application::Instance->activeDocument(); @@ -291,6 +328,52 @@ QString PlacementHandler::getSimplePlacement(App::DocumentObject* obj, const QSt data); } +Base::Vector3d PlacementHandler::computeCenterOfMass() const +{ + Base::Vector3d centerOfMass; + std::vector sel = Gui::Selection().getObjectsOfType + (App::GeoFeature::getClassTypeId()); + if (!sel.empty()) { + for (auto it : sel) { + const App::PropertyComplexGeoData* propgeo = static_cast(it)->getPropertyOfGeometry(); + const Data::ComplexGeoData* geodata = propgeo ? propgeo->getComplexData() : nullptr; + if (geodata && geodata->getCenterOfGravity(centerOfMass)) { + break; + } + } + } + return centerOfMass; +} + +void PlacementHandler::setCenterOfMass(const Base::Vector3d& pnt) +{ + cntOfMass = pnt; +} + +Base::Vector3d PlacementHandler::getCenterOfMass() const +{ + return cntOfMass; +} + +std::tuple> PlacementHandler::getSelectedPoints() const +{ + std::vector selection = Gui::Selection().getSelectionEx(); + std::vector picked; + //combine all pickedpoints into single vector + //even if points are from separate objects + Base::Vector3d firstSelected; //first selected will be central point when 3 points picked + for (auto it = selection.begin(); it != selection.end(); ++it) { + std::vector points = it->getPickedPoints(); + if (it == selection.begin() && !points.empty()) { + firstSelected = points[0]; + } + + picked.insert(picked.begin(), points.begin(), points.end()); + } + + return std::make_tuple(firstSelected, picked); +} + void PlacementHandler::tryRecompute(Gui::Document* document) { try { @@ -300,6 +383,23 @@ void PlacementHandler::tryRecompute(Gui::Document* document) } } +void PlacementHandler::setupDocument() +{ + //NOLINTBEGIN + connectAct = Application::Instance->signalActiveDocument.connect + (std::bind(&PlacementHandler::slotActiveDocument, this, sp::_1)); + //NOLINTEND + App::Document* activeDoc = App::GetApplication().getActiveDocument(); + if (activeDoc) { + appendDocument(activeDoc->getName()); + } +} + +void PlacementHandler::slotActiveDocument(const Gui::Document& doc) +{ + activatedDocument(doc.getDocument()->getName()); +} + // ---------------------------------------------------------------------------- /* TRANSLATOR Gui::Dialog::Placement */ @@ -312,13 +412,11 @@ Placement::Placement(QWidget* parent, Qt::WindowFlags fl) setupConnections(); setupUnits(); setupSignalMapper(); - setupDocument(); setupRotationMethod(); } Placement::~Placement() { - connectAct.disconnect(); delete ui; } @@ -391,18 +489,6 @@ void Placement::setupSignalMapper() #endif } -void Placement::setupDocument() -{ - //NOLINTBEGIN - connectAct = Application::Instance->signalActiveDocument.connect - (std::bind(&Placement::slotActiveDocument, this, sp::_1)); - //NOLINTEND - App::Document* activeDoc = App::GetApplication().getActiveDocument(); - if (activeDoc) { - handler.appendDocument(activeDoc->getName()); - } -} - void Placement::setupRotationMethod() { ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Placement"); @@ -430,11 +516,6 @@ void Placement::open() handler.openTransactionIfNeeded(); } -void Placement::slotActiveDocument(const Gui::Document& doc) -{ - handler.activatedDocument(doc.getDocument()->getName()); -} - QWidget* Placement::getInvalidInput() const { QList sb = this->findChildren(); @@ -466,57 +547,31 @@ void Placement::onCenterOfMassToggled(bool on) ui->zCnt->setDisabled(on); if (on) { - cntOfMass = getCenterOfMass(); - ui->xCnt->setValue(cntOfMass.x); - ui->yCnt->setValue(cntOfMass.y); - ui->zCnt->setValue(cntOfMass.z); + Base::Vector3d pnt = handler.computeCenterOfMass(); + handler.setCenterOfMass(pnt); + ui->xCnt->setValue(pnt.x); + ui->yCnt->setValue(pnt.y); + ui->zCnt->setValue(pnt.z); } } void Placement::onSelectedVertexClicked() { - cntOfMass.Set(0,0,0); ui->centerOfMass->setChecked(false); - bool success=false; - std::vector selection = Gui::Selection().getSelectionEx(); - std::vector picked; - //combine all pickedpoints into single vector - //even if points are from separate objects - Base::Vector3d firstSelected; //first selected will be central point when 3 points picked - for (auto it=selection.begin(); it!=selection.end(); ++it){ - std::vector points = it->getPickedPoints(); - if (it==selection.begin() && !points.empty()){ - firstSelected=points[0]; - } - picked.insert(picked.begin(),points.begin(),points.end()); - } - //we have to clear selection and reselect original object(s) - //else later on the rotation is applied twice because there will - //be 2 (vertex) objects in the selection, and even if both are subobjects - //of the same object the rotation still gets applied twice - Gui::Selection().clearSelection(); - //reselect original object that was selected when placement dlg first opened - for (const auto& it : selectionObjects) - Gui::Selection().addSelection(it); + Base::Vector3d center; + bool success = false; + auto [firstSelected, picked] = handler.getSelectedPoints(); + handler.reselectObjects(); if (picked.size() == 1) { - ui->xCnt->setValue(picked[0].x); - ui->yCnt->setValue(picked[0].y); - ui->zCnt->setValue(picked[0].z); - cntOfMass.x=picked[0].x; - cntOfMass.y=picked[0].y; - cntOfMass.z=picked[0].z; - success=true; + center = picked[0]; + success = true; } else if (picked.size() == 2) { //average the coords to get center of rotation - ui->xCnt->setValue((picked[0].x+picked[1].x)/2.0); - ui->yCnt->setValue((picked[0].y+picked[1].y)/2.0); - ui->zCnt->setValue((picked[0].z+picked[1].z)/2.0); - cntOfMass.x=(picked[0].x+picked[1].x)/2.0; - cntOfMass.y=(picked[0].y+picked[1].y)/2.0; - cntOfMass.z=(picked[0].z+picked[1].z)/2.0; + center = (picked[0] + picked[1]) / 2.0; + //setup a customized axis since the user selected 2 points //keep any existing angle, but setup our own axis Base::Placement plm = getPlacement(); @@ -525,11 +580,11 @@ void Placement::onSelectedVertexClicked() double angle; rot.getRawValue(tmp, angle); Base::Vector3d axis; - if (firstSelected==picked[0]){ - axis = Base::Vector3d(picked[1]-picked[0]); + if (firstSelected == picked[0]){ + axis = Base::Vector3d(picked[1] - picked[0]); } else { - axis = Base::Vector3d(picked[0]-picked[1]); + axis = Base::Vector3d(picked[0] - picked[1]); } double length = axis.Length(); Base::Console().Message("Distance: %.8f\n",length); @@ -546,7 +601,7 @@ void Placement::onSelectedVertexClicked() setPlacementData(plm); //creates custom axis, if needed ui->rotationInput->setCurrentIndex(0); //use rotation with axis instead of euler ui->stackedWidget->setCurrentIndex(0); - success=true; + success = true; } else if (picked.size() == 3){ /* User selected 3 points, so we find the plane defined by those @@ -559,7 +614,7 @@ void Placement::onSelectedVertexClicked() a = picked[1]; c = picked[2]; } - else if (picked[1]==firstSelected){ + else if (picked[1] == firstSelected){ a = picked[0]; c = picked[2]; } @@ -570,12 +625,8 @@ void Placement::onSelectedVertexClicked() Base::Vector3d norm((a-b).Cross(c-b)); norm.Normalize(); - ui->xCnt->setValue(b.x); - ui->yCnt->setValue(b.y); - ui->zCnt->setValue(b.z); - cntOfMass.x=b.x; - cntOfMass.y=b.y; - cntOfMass.z=b.z; + center = b; + //setup a customized axis normal to the plane //keep any existing angle, but setup our own axis Base::Placement plm = getPlacement(); @@ -604,10 +655,15 @@ void Placement::onSelectedVertexClicked() setPlacementData(plm); //creates custom axis, if needed ui->rotationInput->setCurrentIndex(0); //use rotation with axis instead of euler ui->stackedWidget->setCurrentIndex(0); - success=true; + success = true; } - if (!success){ + handler.setCenterOfMass(center); + ui->xCnt->setValue(center.x); + ui->yCnt->setValue(center.y); + ui->zCnt->setValue(center.z); + + if (!success) { Base::Console().Warning("Placement selection error. Select either 1 or 2 points.\n"); QMessageBox msgBox; msgBox.setText(tr("Please select 1, 2, or 3 points before clicking this button. A point may be on a vertex, \ @@ -619,10 +675,6 @@ lies on the vector that is normal to the plane defined by the 3 points. Some di information is provided in the report view, which can be useful when aligning objects. For your \ convenience when Shift + click is used the appropriate distance or angle is copied to the clipboard.")); msgBox.exec(); - ui->xCnt->setValue(0); - ui->yCnt->setValue(0); - ui->zCnt->setValue(0); - return; } } @@ -653,12 +705,12 @@ void Placement::onApplyAxialClicked() void Placement::onApplyIncrementalPlacementToggled(bool on) { if (on) { - this->ref = getPlacementData(); + handler.setRefPlacement(getPlacementData()); onResetButtonClicked(); } else { Base::Placement p = getPlacementData(); - p = p * this->ref; + p = p * handler.getRefPlacement(); setPlacementData(p); onPlacementChanged(0); } @@ -767,7 +819,7 @@ void Placement::onResetButtonClicked() */ void Placement::setSelection(const std::vector& selection) { - selectionObjects = selection; + handler.setSelection(selection); } void Placement::setPropertyName(const std::string& name) @@ -782,9 +834,8 @@ void Placement::setPropertyName(const std::string& name) */ void Placement::bindObject() { - if (!selectionObjects.empty()) { - App::DocumentObject* obj = selectionObjects.front().getObject(); - + // clang-format off + if (const App::DocumentObject* obj = handler.getFirstOfSelection()) { std::string propertyName = handler.getPropertyName(); App::ObjectIdentifier path = App::ObjectIdentifier::parse(obj, propertyName); if (path.getProperty()) { @@ -806,6 +857,7 @@ void Placement::bindObject() ui->rollAngle->evaluateExpression(); } } + // clang-format on } Base::Vector3d Placement::getDirection() const @@ -883,30 +935,14 @@ Base::Vector3d Placement::getAnglesData() const Base::Vector3d Placement::getCenterData() const { - if (ui->centerOfMass->isChecked()) - return this->cntOfMass; + if (ui->centerOfMass->isChecked()) { + return handler.getCenterOfMass(); + } return Base::Vector3d(ui->xCnt->value().getValue(), ui->yCnt->value().getValue(), ui->zCnt->value().getValue()); } -Base::Vector3d Placement::getCenterOfMass() const -{ - Base::Vector3d centerOfMass; - std::vector sel = Gui::Selection().getObjectsOfType - (App::GeoFeature::getClassTypeId()); - if (!sel.empty()) { - for (auto it : sel) { - const App::PropertyComplexGeoData* propgeo = static_cast(it)->getPropertyOfGeometry(); - const Data::ComplexGeoData* geodata = propgeo ? propgeo->getComplexData() : nullptr; - if (geodata && geodata->getCenterOfGravity(centerOfMass)) { - break; - } - } - } - return centerOfMass; -} - Base::Placement Placement::getPlacementData() const { Base::Rotation rot = getRotationData(); diff --git a/src/Gui/Placement.h b/src/Gui/Placement.h index 4306dc61d1..23083c4e7f 100644 --- a/src/Gui/Placement.h +++ b/src/Gui/Placement.h @@ -51,12 +51,21 @@ public: PlacementHandler(); void openTransactionIfNeeded(); void setPropertyName(const std::string&); + void setSelection(const std::vector&); + void reselectObjects(); + const App::DocumentObject* getFirstOfSelection() const; const std::string& getPropertyName() const; void appendDocument(const std::string&); void activatedDocument(const std::string&); void revertTransformation(); + void setRefPlacement(const Base::Placement& plm); + const Base::Placement& getRefPlacement() const; void applyPlacement(const Base::Placement& p, bool incremental); void applyPlacement(const QString& p, bool incremental); + Base::Vector3d computeCenterOfMass() const; + void setCenterOfMass(const Base::Vector3d& pnt); + Base::Vector3d getCenterOfMass() const; + std::tuple> getSelectedPoints() const; private: std::vector getObjects(Gui::Document*) const; @@ -67,17 +76,28 @@ private: void applyPlacement(App::DocumentObject*, const QString& p, bool incremental); QString getIncrementalPlacement(App::DocumentObject*, const QString&) const; QString getSimplePlacement(App::DocumentObject*, const QString&) const; + void setupDocument(); + void slotActiveDocument(const Gui::Document&); private Q_SLOTS: void openTransaction(); private: + using Connection = boost::signals2::scoped_connection; std::string propertyName; // the name of the placement property std::set documents; /** If false apply the placement directly to the transform nodes, * otherwise change the placement property. */ bool changeProperty; + Connection connectAct; + /** + * store these so we can reselect original object + * after user selects points and clicks Selected point(s) + */ + std::vector selectionObjects; + Base::Placement ref; + Base::Vector3d cntOfMass; }; class GuiExport Placement : public QDialog @@ -119,7 +139,6 @@ private: void setupConnections(); void setupUnits(); void setupSignalMapper(); - void setupDocument(); void setupRotationMethod(); bool onApply(); @@ -129,11 +148,9 @@ private: Base::Vector3d getPositionData() const; Base::Vector3d getAnglesData() const; Base::Vector3d getCenterData() const; - Base::Vector3d getCenterOfMass() const; QString getPlacementString() const; QString getPlacementFromEulerAngles() const; QString getPlacementFromAxisWithAngle() const; - void slotActiveDocument(const Gui::Document&); QWidget* getInvalidInput() const; void showErrorMessage(); @@ -141,18 +158,9 @@ Q_SIGNALS: void placementChanged(const QVariant &, bool, bool); private: - using Connection = boost::signals2::connection; Ui_Placement* ui; QSignalMapper* signalMapper; - Connection connectAct; PlacementHandler handler; - Base::Placement ref; - Base::Vector3d cntOfMass; - /** - * store these so we can reselect original object - * after user selects points and clicks Selected point(s) - */ - std::vector selectionObjects; }; class GuiExport DockablePlacement : public Placement