Core: Refactor placement dialog

This commit is contained in:
wmayer
2024-09-05 17:08:43 +02:00
parent aa44c2a5d3
commit f8648b475a
2 changed files with 157 additions and 113 deletions

View File

@@ -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<Gui::SelectionObject>& 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<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
(App::GeoFeature::getClassTypeId());
if (!sel.empty()) {
for (auto it : sel) {
const App::PropertyComplexGeoData* propgeo = static_cast<App::GeoFeature*>(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<Base::Vector3d, std::vector<Base::Vector3d>> PlacementHandler::getSelectedPoints() const
{
std::vector<Gui::SelectionObject> selection = Gui::Selection().getSelectionEx();
std::vector<Base::Vector3d> 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<Base::Vector3d> 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<Gui::QuantitySpinBox*> sb = this->findChildren<Gui::QuantitySpinBox*>();
@@ -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<Gui::SelectionObject> selection = Gui::Selection().getSelectionEx();
std::vector<Base::Vector3d> 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<Base::Vector3d> 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<Gui::SelectionObject>& 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<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
(App::GeoFeature::getClassTypeId());
if (!sel.empty()) {
for (auto it : sel) {
const App::PropertyComplexGeoData* propgeo = static_cast<App::GeoFeature*>(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();

View File

@@ -51,12 +51,21 @@ public:
PlacementHandler();
void openTransactionIfNeeded();
void setPropertyName(const std::string&);
void setSelection(const std::vector<SelectionObject>&);
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<Base::Vector3d, std::vector<Base::Vector3d>> getSelectedPoints() const;
private:
std::vector<App::DocumentObject*> 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<std::string> 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<SelectionObject> 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<SelectionObject> selectionObjects;
};
class GuiExport DockablePlacement : public Placement