diff --git a/src/App/Application.cpp b/src/App/Application.cpp
index 56ef0a38b2..9bd89679b8 100644
--- a/src/App/Application.cpp
+++ b/src/App/Application.cpp
@@ -63,6 +63,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -89,6 +90,7 @@
#include "Application.h"
#include "CleanupProcess.h"
#include "ComplexGeoData.h"
+#include "Services.h"
#include "DocumentObjectFileIncluded.h"
#include "DocumentObjectGroup.h"
#include "DocumentObjectGroupPy.h"
@@ -2217,6 +2219,8 @@ void Application::initTypes()
new Base::ExceptionProducer;
new Base::ExceptionProducer;
new Base::ExceptionProducer;
+
+ Base::registerServiceImplementation(new NullCenterOfMass);
}
namespace {
diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt
index 8512c365ea..a4ab592db6 100644
--- a/src/App/CMakeLists.txt
+++ b/src/App/CMakeLists.txt
@@ -289,6 +289,7 @@ SET(FreeCADApp_CPP_SRCS
MetadataPyImp.cpp
ElementNamingUtils.cpp
SafeMode.cpp
+ Services.cpp
StringHasher.cpp
StringHasherPyImp.cpp
StringIDPyImp.cpp
@@ -313,6 +314,7 @@ SET(FreeCADApp_HPP_SRCS
MeasureManager.h
Metadata.h
ElementNamingUtils.h
+ Services.h
StringHasher.h
)
diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp
index d87f405ceb..8d34144c8c 100644
--- a/src/App/GeoFeature.cpp
+++ b/src/App/GeoFeature.cpp
@@ -61,12 +61,7 @@ void GeoFeature::transformPlacement(const Base::Placement& transform)
Base::Placement GeoFeature::globalPlacement() const
{
- auto* group = GeoFeatureGroupExtension::getGroupOfObject(this);
- if (group) {
- auto ext = group->getExtensionByType();
- return ext->globalGroupPlacement() * Placement.getValue();
- }
- return Placement.getValue();
+ return GeoFeature::getGlobalPlacement(this);
}
const PropertyComplexGeoData* GeoFeature::getPropertyOfGeometry() const
@@ -351,3 +346,20 @@ Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj,
return getGlobalPlacement(targetObj, prop->getValue(), subs[0]);
}
+
+Base::Placement GeoFeature::getGlobalPlacement(const DocumentObject* obj)
+{
+ auto placementProperty = obj->getPropertyByName("Placement");
+
+ if (!placementProperty) {
+ return {};
+ }
+
+ auto* group = GeoFeatureGroupExtension::getGroupOfObject(obj);
+ if (group) {
+ auto ext = group->getExtensionByType();
+ return ext->globalGroupPlacement() * placementProperty->getValue();
+ }
+
+ return placementProperty->getValue();
+}
diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h
index cb4dcfbd66..abc36912c5 100644
--- a/src/App/GeoFeature.h
+++ b/src/App/GeoFeature.h
@@ -195,6 +195,7 @@ public:
static Base::Placement
getGlobalPlacement(DocumentObject* targetObj, DocumentObject* rootObj, const std::string& sub);
static Base::Placement getGlobalPlacement(DocumentObject* targetObj, PropertyXLinkSub* prop);
+ static Base::Placement getGlobalPlacement(const DocumentObject* obj);
protected:
void onChanged(const Property* prop) override;
diff --git a/src/App/Services.cpp b/src/App/Services.cpp
new file mode 100644
index 0000000000..ae70735441
--- /dev/null
+++ b/src/App/Services.cpp
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 Kacper Donat *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#include "Services.h"
+
+std::optional
+App::NullCenterOfMass::ofDocumentObject([[maybe_unused]] DocumentObject* object) const
+{
+ return std::nullopt;
+}
\ No newline at end of file
diff --git a/src/App/Services.h b/src/App/Services.h
new file mode 100644
index 0000000000..297819e0c6
--- /dev/null
+++ b/src/App/Services.h
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 Kacper Donat *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#ifndef APP_SERVICES_H
+#define APP_SERVICES_H
+
+#include "DocumentObject.h"
+
+#include
+#include
+
+namespace App
+{
+
+/**
+* This service should provide placement of given sub object (like for example face).
+* This feature is not implemented in the core and so it must be provided by module.
+*/
+class SubObjectPlacementProvider
+{
+public:
+ virtual ~SubObjectPlacementProvider() = default;
+
+ /**
+ * Returns placement of sub object relative to the base placement.
+ */
+ virtual Base::Placement calculate(SubObjectT object, Base::Placement basePlacement) const = 0;
+};
+
+/**
+* This service should provide center of mass calculation;
+*/
+class CenterOfMassProvider
+{
+public:
+ virtual ~CenterOfMassProvider() = default;
+
+ virtual std::optional ofDocumentObject(DocumentObject* object) const = 0;
+};
+
+/**
+* Default implementation for the center of mass contract
+* It always returns empty optional
+*/
+class NullCenterOfMass final : public CenterOfMassProvider
+{
+public:
+ std::optional ofDocumentObject(DocumentObject* object) const override;
+};
+
+}
+
+
+#endif // APP_SERVICES_H
diff --git a/src/Base/Rotation.cpp b/src/Base/Rotation.cpp
index 9947d0cd0b..623b41dd2d 100644
--- a/src/Base/Rotation.cpp
+++ b/src/Base/Rotation.cpp
@@ -87,6 +87,13 @@ Rotation Rotation::fromNormalVector(const Vector3d& normal)
return Rotation(Vector3d(0, 0, 1), normal);
}
+Rotation Rotation::fromEulerAngles(EulerSequence theOrder, double alpha, double beta, double gamma)
+{
+ Rotation rotation;
+ rotation.setEulerAngles(theOrder, alpha, beta, gamma);
+ return rotation;
+}
+
const double* Rotation::getValue() const
{
return &this->quat[0];
diff --git a/src/Base/Rotation.h b/src/Base/Rotation.h
index 03b82d62ad..9f8e6b5c16 100644
--- a/src/Base/Rotation.h
+++ b/src/Base/Rotation.h
@@ -50,29 +50,6 @@ public:
Rotation(Rotation&& rot) = default;
~Rotation() = default;
- /// Utility function to create Rotation based on direction / normal vector
- static Rotation fromNormalVector(const Vector3d& normal);
- //@}
-
- /** Methods to get or set rotations. */
- //@{
- const double* getValue() const;
- void getValue(double& q0, double& q1, double& q2, double& q3) const;
- void setValue(double q0, double q1, double q2, double q3);
- /// If not a null quaternion then \a axis will be normalized
- void getValue(Vector3d& axis, double& rfAngle) const;
- /// Does the same as the method above unless normalizing the axis.
- void getRawValue(Vector3d& axis, double& rfAngle) const;
- void getValue(Matrix4D& matrix) const;
- void setValue(const double q[4]);
- void setValue(const Matrix4D& matrix);
- void setValue(const Vector3d& axis, double fAngle);
- void setValue(const Vector3d& rotateFrom, const Vector3d& rotateTo);
- /// Euler angles in yaw,pitch,roll notation
- void setYawPitchRoll(double y, double p, double r);
- /// Euler angles in yaw,pitch,roll notation
- void getYawPitchRoll(double& y, double& p, double& r) const;
-
enum EulerSequence
{
Invalid,
@@ -115,6 +92,34 @@ public:
EulerSequenceLast,
};
+
+ /// Utility function to create Rotation based on direction / normal vector
+ /// Z base vector is assumed to represent the normal vector
+ static Rotation fromNormalVector(const Vector3d& normal);
+ /// Utility function to create Rotation based on euler angles
+ static Rotation
+ fromEulerAngles(EulerSequence theOrder, double alpha, double beta, double gamma);
+ //@}
+
+ /** Methods to get or set rotations. */
+ //@{
+ const double* getValue() const;
+ void getValue(double& q0, double& q1, double& q2, double& q3) const;
+ void setValue(double q0, double q1, double q2, double q3);
+ /// If not a null quaternion then \a axis will be normalized
+ void getValue(Vector3d& axis, double& rfAngle) const;
+ /// Does the same as the method above unless normalizing the axis.
+ void getRawValue(Vector3d& axis, double& rfAngle) const;
+ void getValue(Matrix4D& matrix) const;
+ void setValue(const double q[4]);
+ void setValue(const Matrix4D& matrix);
+ void setValue(const Vector3d& axis, double fAngle);
+ void setValue(const Vector3d& rotateFrom, const Vector3d& rotateTo);
+ /// Euler angles in yaw,pitch,roll notation
+ void setYawPitchRoll(double y, double p, double r);
+ /// Euler angles in yaw,pitch,roll notation
+ void getYawPitchRoll(double& y, double& p, double& r) const;
+
static const char* eulerSequenceName(EulerSequence seq);
static EulerSequence eulerSequenceFromName(const char* name);
void getEulerAngles(EulerSequence theOrder, double& alpha, double& beta, double& gamma) const;
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index 9e71c9a4f7..ede57f85ba 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -402,6 +402,7 @@ SET(Gui_UIC_SRCS
SceneInspector.ui
InputVector.ui
Placement.ui
+ TaskCSysDragger.ui
TextureMapping.ui
TaskView/TaskAppearance.ui
TaskView/TaskOrientation.ui
diff --git a/src/Gui/SoFCCSysDragger.cpp b/src/Gui/SoFCCSysDragger.cpp
index ed569c44de..a395b968b1 100644
--- a/src/Gui/SoFCCSysDragger.cpp
+++ b/src/Gui/SoFCCSysDragger.cpp
@@ -230,15 +230,17 @@ SoSeparator* TDragger::buildLabelGeometry()
labelSeparator->addChild(labelTranslation);
auto label = new SoFrameLabel();
- label->justification = SoFrameLabel::CENTER;
label->string.connectFrom(&this->label);
label->textColor.setValue(1.0, 1.0, 1.0);
- label->horAlignment.setValue(SoImage::CENTER);
- label->vertAlignment.setValue(SoImage::HALF);
+ label->horAlignment = SoImage::CENTER;
+ label->vertAlignment = SoImage::HALF;
+ label->border = false;
+ label->backgroundUseBaseColor = true;
labelSeparator->addChild(label);
return labelSeparator;
}
+
SoBaseColor* TDragger::buildActiveColor()
{
auto colorActive = new SoBaseColor();
@@ -1170,7 +1172,6 @@ SoFCCSysDragger::SoFCCSysDragger()
SO_KIT_ADD_CATALOG_ENTRY(zRotatorDragger, RDragger, TRUE, zRotatorSeparator, "", TRUE);
// Other
-
SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0));
SO_KIT_ADD_FIELD(translationIncrement, (1.0));
SO_KIT_ADD_FIELD(translationIncrementCountX, (0));
@@ -1186,6 +1187,10 @@ SoFCCSysDragger::SoFCCSysDragger()
SO_KIT_ADD_FIELD(draggerSize, (1.0));
SO_KIT_ADD_FIELD(autoScaleResult, (1.0));
+ SO_KIT_ADD_FIELD(xAxisLabel, ("X"));
+ SO_KIT_ADD_FIELD(yAxisLabel, ("Y"));
+ SO_KIT_ADD_FIELD(zAxisLabel, ("Z"));
+
SO_KIT_INIT_INSTANCE();
// Colors
@@ -1198,17 +1203,17 @@ SoFCCSysDragger::SoFCCSysDragger()
tDragger = SO_GET_ANY_PART(this, "xTranslatorDragger", TDragger);
tDragger->translationIncrement.connectFrom(&this->translationIncrement);
tDragger->autoScaleResult.connectFrom(&this->autoScaleResult);
- tDragger->label.setValue("U");
+ tDragger->label.connectFrom(&xAxisLabel);
translationIncrementCountX.connectFrom(&tDragger->translationIncrementCount);
tDragger = SO_GET_ANY_PART(this, "yTranslatorDragger", TDragger);
tDragger->translationIncrement.connectFrom(&this->translationIncrement);
tDragger->autoScaleResult.connectFrom(&this->autoScaleResult);
- tDragger->label.setValue("V");
+ tDragger->label.connectFrom(&yAxisLabel);
translationIncrementCountY.connectFrom(&tDragger->translationIncrementCount);
tDragger = SO_GET_ANY_PART(this, "zTranslatorDragger", TDragger);
tDragger->translationIncrement.connectFrom(&this->translationIncrement);
tDragger->autoScaleResult.connectFrom(&this->autoScaleResult);
- tDragger->label.setValue("W");
+ tDragger->label.connectFrom(&zAxisLabel);
translationIncrementCountZ.connectFrom(&tDragger->translationIncrementCount);
// Planar Translator
TPlanarDragger* tPlanarDragger;
diff --git a/src/Gui/SoFCCSysDragger.h b/src/Gui/SoFCCSysDragger.h
index bf33ec9a92..b759bcf70a 100644
--- a/src/Gui/SoFCCSysDragger.h
+++ b/src/Gui/SoFCCSysDragger.h
@@ -282,6 +282,10 @@ public:
SoSFInt32 rotationIncrementCountY; //!< used from outside for rotation y steps.
SoSFInt32 rotationIncrementCountZ; //!< used from outside for rotation z steps.
+ SoSFString xAxisLabel; //!< label for X axis
+ SoSFString yAxisLabel; //!< label for Y axis
+ SoSFString zAxisLabel; //!< label for Z axis
+
void clearIncrementCounts(); //!< used to reset after drag update.
/*! @brief Overall scale of dragger node.
diff --git a/src/Gui/SoTextLabel.cpp b/src/Gui/SoTextLabel.cpp
index feed088b84..1a4a29c0aa 100644
--- a/src/Gui/SoTextLabel.cpp
+++ b/src/Gui/SoTextLabel.cpp
@@ -379,6 +379,8 @@ SoFrameLabel::SoFrameLabel()
SO_NODE_ADD_FIELD(name, ("Helvetica"));
SO_NODE_ADD_FIELD(size, (12));
SO_NODE_ADD_FIELD(frame, (true));
+ SO_NODE_ADD_FIELD(border, (true));
+ SO_NODE_ADD_FIELD(backgroundUseBaseColor, (false));
//SO_NODE_ADD_FIELD(image, (SbVec2s(0,0), 0, NULL));
}
@@ -397,9 +399,11 @@ void SoFrameLabel::notify(SoNotList * list)
f == &this->justification ||
f == &this->name ||
f == &this->size ||
- f == &this->frame) {
+ f == &this->frame ||
+ f == &this->border) {
drawImage();
}
+
inherited::notify(list);
}
@@ -417,11 +421,12 @@ void SoFrameLabel::drawImage()
int w = 0;
int h = fm.height() * num;
const SbColor& b = backgroundColor.getValue();
- QColor brush;
- brush.setRgbF(b[0],b[1],b[2]);
+ QColor backgroundBrush;
+ backgroundBrush.setRgbF(b[0],b[1],b[2]);
const SbColor& t = textColor.getValue();
QColor front;
front.setRgbF(t[0],t[1],t[2]);
+ const QPen borderPen(QColor(0,0,127), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
QStringList lines;
for (int i=0; igetState();
- const SbColor& diffuse = SoLazyElement::getDiffuse(state, 0);
- this->backgroundColor.setValue(diffuse);
+ if (backgroundUseBaseColor.getValue()) {
+ SoState* state = action->getState();
+ const SbColor& diffuse = SoLazyElement::getDiffuse(state, 0);
+
+ if (diffuse != this->backgroundColor.getValue()) {
+ this->backgroundColor.setValue(diffuse);
+ }
+ }
inherited::GLRender(action);
}
diff --git a/src/Gui/SoTextLabel.h b/src/Gui/SoTextLabel.h
index b91feb1980..56b9726711 100644
--- a/src/Gui/SoTextLabel.h
+++ b/src/Gui/SoTextLabel.h
@@ -118,6 +118,8 @@ public:
SoSFName name;
SoSFInt32 size;
SoSFBool frame;
+ SoSFBool border;
+ SoSFBool backgroundUseBaseColor;
//SoSFImage image;
QPixmap iconPixmap;
diff --git a/src/Gui/TaskCSysDragger.cpp b/src/Gui/TaskCSysDragger.cpp
index ab23bc533a..a4e38bcce3 100644
--- a/src/Gui/TaskCSysDragger.cpp
+++ b/src/Gui/TaskCSysDragger.cpp
@@ -26,11 +26,20 @@
#include
#include
#include
+#include
#endif
+#include
+#include
+
#include
-#include "Document.h" // must be before TaskCSysDragger.h
-#include "TaskCSysDragger.h"
+#include
+#include
+#include
+#include
+#include
+
+#include "Document.h" // must be before TaskCSysDragger.h
#include "Application.h"
#include "BitmapFactory.h"
#include "Command.h"
@@ -39,139 +48,582 @@
#include "ViewProviderDragger.h"
#include "TaskView/TaskView.h"
+#include "TaskCSysDragger.h"
+#include "ui_TaskCSysDragger.h"
+
+#include
using namespace Gui;
-
-static double degreesToRadians(const double °reesIn)
+namespace
{
- return degreesIn * (M_PI / 180.0);
-}
-
-TaskCSysDragger::TaskCSysDragger(Gui::ViewProviderDocumentObject* vpObjectIn, Gui::SoFCCSysDragger* draggerIn) :
- dragger(draggerIn)
+void alignGridLayoutColumns(const std::list& layouts, unsigned column = 0)
{
- assert(vpObjectIn);
- assert(draggerIn);
- vpObject = vpObjectIn->getObject();
- dragger->ref();
+ std::vector widths;
- setupGui();
-}
+ auto getActualWidth = [&](const QGridLayout* layout) -> int {
+ if (auto const item = layout->itemAtPosition(0, column)) {
+ return item->geometry().width();
+ }
-TaskCSysDragger::~TaskCSysDragger()
-{
- dragger->unref();
- Gui::Application::Instance->commandManager().getCommandByName("Std_OrthographicCamera")->setEnabled(true);
- Gui::Application::Instance->commandManager().getCommandByName("Std_PerspectiveCamera")->setEnabled(true);
-}
+ return 0;
+ };
-void TaskCSysDragger::dragStartCallback(void *, SoDragger *)
-{
- // This is called when a manipulator is about to manipulating
- if(firstDrag)
- {
- Gui::Application::Instance->activeDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Transform"));
- firstDrag=false;
+ for (const auto layout : layouts) {
+ widths.push_back(getActualWidth(layout));
+ }
+
+ const auto maxWidth = *std::max_element(widths.begin(), widths.end());
+ for (const auto layout : layouts) {
+ layout->setColumnMinimumWidth(column, maxWidth);
}
}
-void TaskCSysDragger::setupGui()
+} // namespace
+
+TaskTransform::TaskTransform(Gui::ViewProviderDragger* vp,
+ Gui::SoFCCSysDragger* dragger,
+ QWidget* parent,
+ App::SubObjectPlacementProvider* subObjectPlacemenProvider,
+ App::CenterOfMassProvider* centerOfMassProvider)
+ : TaskBox(Gui::BitmapFactory().pixmap("Std_TransformManip.svg"), tr("Transform"), false, parent)
+ , vp(vp)
+ , subObjectPlacementProvider(subObjectPlacemenProvider)
+ , centerOfMassProvider(centerOfMassProvider)
+ , dragger(dragger)
+ , ui(new Ui_TaskCSysDragger)
{
- auto incrementsBox = new Gui::TaskView::TaskBox(
- Gui::BitmapFactory().pixmap("Std_TransformManip"),
- tr("Transform"), true, nullptr);
+ blockSelection(true);
- auto gridLayout = new QGridLayout();
- gridLayout->setColumnStretch(1, 1);
+ dragger->addStartCallback(dragStartCallback, this);
+ dragger->addMotionCallback(dragMotionCallback, this);
- auto tLabel = new QLabel(tr("Translation Increment:"), incrementsBox);
- gridLayout->addWidget(tLabel, 0, 0, Qt::AlignRight);
+ vp->resetTransformOrigin();
- QFontMetrics metrics(QApplication::font());
- int spinBoxWidth = metrics.averageCharWidth() * 20;
- tSpinBox = new QuantitySpinBox(incrementsBox);
- tSpinBox->setMinimum(0.0);
- tSpinBox->setMaximum(std::numeric_limits::max());
- tSpinBox->setUnit(Base::Unit::Length);
- tSpinBox->setMinimumWidth(spinBoxWidth);
- gridLayout->addWidget(tSpinBox, 0, 1, Qt::AlignLeft);
+ if (auto geoFeature = vp->getObject()) {
+ originalPlacement = geoFeature->Placement.getValue();
+ }
- auto rLabel = new QLabel(tr("Rotation Increment:"), incrementsBox);
- gridLayout->addWidget(rLabel, 1, 0, Qt::AlignRight);
-
- rSpinBox = new QuantitySpinBox(incrementsBox);
- rSpinBox->setMinimum(0.0);
- rSpinBox->setMaximum(180.0);
- rSpinBox->setUnit(Base::Unit::Angle);
- rSpinBox->setMinimumWidth(spinBoxWidth);
- gridLayout->addWidget(rSpinBox, 1, 1, Qt::AlignLeft);
-
- incrementsBox->groupLayout()->addLayout(gridLayout);
- Content.push_back(incrementsBox);
-
- connect(tSpinBox, qOverload(&QuantitySpinBox::valueChanged), this, &TaskCSysDragger::onTIncrementSlot);
- connect(rSpinBox, qOverload(&QuantitySpinBox::valueChanged), this, &TaskCSysDragger::onRIncrementSlot);
+ setupGui();
}
-void TaskCSysDragger::onTIncrementSlot(double freshValue)
+TaskTransform::~TaskTransform()
{
- dragger->translationIncrement.setValue(freshValue);
+ Gui::Application::Instance->commandManager()
+ .getCommandByName("Std_OrthographicCamera")
+ ->setEnabled(true);
+
+ Gui::Application::Instance->commandManager()
+ .getCommandByName("Std_PerspectiveCamera")
+ ->setEnabled(true);
}
-void TaskCSysDragger::onRIncrementSlot(double freshValue)
+void TaskTransform::dragStartCallback(void*, SoDragger*)
{
- dragger->rotationIncrement.setValue(degreesToRadians(freshValue));
+ // This is called when a manipulator is about to manipulating
+ if (firstDrag) {
+ Gui::Application::Instance->activeDocument()->openCommand(
+ QT_TRANSLATE_NOOP("Command", "Transform"));
+ firstDrag = false;
+ }
+}
+
+void TaskTransform::dragMotionCallback(void* data, SoDragger* dragger)
+{
+ auto task = static_cast(data);
+
+ task->updatePositionAndRotationUi();
+}
+
+void TaskTransform::loadPlacementModeItems() const
+{
+ ui->placementComboBox->clear();
+
+ ui->placementComboBox->addItem(tr("Object origin"),
+ QVariant::fromValue(PlacementMode::ObjectOrigin));
+
+ if (centerOfMassProvider->ofDocumentObject(vp->getObject()).has_value()) {
+ ui->placementComboBox->addItem(tr("Center of mass / Centroid"),
+ QVariant::fromValue(PlacementMode::Centroid));
+ }
+
+ if (subObjectPlacementProvider) {
+ ui->placementComboBox->addItem(tr("Custom"), QVariant::fromValue(PlacementMode::Custom));
+ }
+}
+
+void TaskTransform::loadPositionModeItems() const
+{
+ ui->positionModeComboBox->clear();
+ ui->positionModeComboBox->addItem(tr("Local"), QVariant::fromValue(PositionMode::Local));
+ ui->positionModeComboBox->addItem(tr("Absolute"), QVariant::fromValue(PositionMode::Absolute));
+}
+
+void TaskTransform::setupGui()
+{
+ auto proxy = new QWidget(this);
+ ui->setupUi(proxy);
+ this->groupLayout()->addWidget(proxy);
+
+ loadPlacementModeItems();
+ loadPositionModeItems();
+
+ ui->referencePickerWidget->hide();
+ ui->alignRotationCheckBox->hide();
+
+ for (auto positionSpinBox : {ui->translationIncrementSpinBox,
+ ui->xPositionSpinBox,
+ ui->yPositionSpinBox,
+ ui->zPositionSpinBox}) {
+ positionSpinBox->setUnit(Base::Unit::Length);
+ }
+
+ for (auto rotationSpinBox : {ui->rotationIncrementSpinBox,
+ ui->xRotationSpinBox,
+ ui->yRotationSpinBox,
+ ui->zRotationSpinBox}) {
+ rotationSpinBox->setUnit(Base::Unit::Angle);
+ }
+
+ connect(ui->translationIncrementSpinBox,
+ qOverload(&QuantitySpinBox::valueChanged),
+ this,
+ [this](double) {
+ updateIncrements();
+ });
+ connect(ui->rotationIncrementSpinBox,
+ qOverload(&QuantitySpinBox::valueChanged),
+ this,
+ [this](double) {
+ updateIncrements();
+ });
+ connect(ui->positionModeComboBox,
+ qOverload(&QComboBox::currentIndexChanged),
+ this,
+ &TaskTransform::onCoordinateSystemChange);
+ connect(ui->placementComboBox,
+ qOverload(&QComboBox::currentIndexChanged),
+ this,
+ &TaskTransform::onPlacementModeChange);
+ connect(ui->pickTransformOriginButton,
+ &QPushButton::clicked,
+ this,
+ &TaskTransform::onPickTransformOrigin);
+ connect(ui->alignToOtherObjectButton,
+ &QPushButton::clicked,
+ this,
+ &TaskTransform::onAlignToOtherObject);
+ connect(ui->flipPartButton, &QPushButton::clicked, this, &TaskTransform::onFlip);
+
+ connect(ui->alignRotationCheckBox,
+ &QCheckBox::clicked,
+ this,
+ &TaskTransform::onAlignRotationChanged);
+
+ for (auto positionSpinBox :
+ {ui->xPositionSpinBox, ui->yPositionSpinBox, ui->zPositionSpinBox}) {
+ connect(positionSpinBox,
+ qOverload(&QuantitySpinBox::valueChanged),
+ this,
+ [this](double) {
+ onPositionChange();
+ });
+ }
+
+ for (auto rotationSpinBox :
+ {ui->xRotationSpinBox, ui->yRotationSpinBox, ui->zRotationSpinBox}) {
+ connect(rotationSpinBox,
+ qOverload(&QuantitySpinBox::valueChanged),
+ this,
+ [this](double) {
+ onRotationChange();
+ });
+ }
+
+ alignGridLayoutColumns({ui->absolutePositionLayout,
+ ui->absoluteRotationLayout,
+ ui->transformOriginLayout,
+ ui->referencePickerLayout});
+
+ updateInputLabels();
+ updateDraggerLabels();
+ updateIncrements();
+ updatePositionAndRotationUi();
+}
+
+void TaskTransform::updatePositionAndRotationUi() const
+{
+
+ const auto xyzPlacement = vp->getDraggerPlacement();
+ const auto uvwPlacement = currentCoordinateSystem().origin.inverse() * xyzPlacement;
+
+ auto fixNegativeZero = [](const double value) {
+ return std::fabs(value) < Base::Precision::Confusion() ? 0.0 : value;
+ };
+
+ auto setPositionValues = [&](const Base::Vector3d& vec, auto* x, auto* y, auto* z) {
+ [[maybe_unused]]
+ auto blockers = {QSignalBlocker(x), QSignalBlocker(y), QSignalBlocker(z)};
+
+ x->setValue(fixNegativeZero(vec.x));
+ y->setValue(fixNegativeZero(vec.y));
+ z->setValue(fixNegativeZero(vec.z));
+ };
+
+ auto setRotationValues = [&](const Base::Rotation& rot, auto* x, auto* y, auto* z) {
+ [[maybe_unused]]
+ auto blockers = {QSignalBlocker(x), QSignalBlocker(y), QSignalBlocker(z)};
+
+ double alpha, beta, gamma;
+ rot.getEulerAngles(Base::Rotation::Intrinsic_XYZ, alpha, beta, gamma);
+
+ x->setValue(fixNegativeZero(alpha));
+ y->setValue(fixNegativeZero(beta));
+ z->setValue(fixNegativeZero(gamma));
+ };
+
+ auto setValues = [&](const Base::Placement& placement,
+ auto* px,
+ auto* py,
+ auto* pz,
+ auto* rx,
+ auto* ry,
+ auto* rz) {
+ setPositionValues(placement.getPosition(), px, py, pz);
+ setRotationValues(placement.getRotation(), rx, ry, rz);
+ };
+
+ setValues(uvwPlacement,
+ ui->xPositionSpinBox,
+ ui->yPositionSpinBox,
+ ui->zPositionSpinBox,
+ ui->xRotationSpinBox,
+ ui->yRotationSpinBox,
+ ui->zRotationSpinBox);
+}
+
+void TaskTransform::updateInputLabels() const
+{
+ auto [xLabel, yLabel, zLabel] = currentCoordinateSystem().labels;
+
+ ui->xPositionLabel->setText(QString::fromStdString(xLabel));
+ ui->yPositionLabel->setText(QString::fromStdString(yLabel));
+ ui->zPositionLabel->setText(QString::fromStdString(zLabel));
+
+ ui->xRotationLabel->setText(QString::fromStdString(xLabel));
+ ui->yRotationLabel->setText(QString::fromStdString(yLabel));
+ ui->zRotationLabel->setText(QString::fromStdString(zLabel));
+}
+
+void TaskTransform::updateDraggerLabels() const
+{
+ auto coordinateSystem =
+ isDraggerAlignedToCoordinateSystem() ? absoluteCoordinateSystem() : localCoordinateSystem();
+
+ auto [xLabel, yLabel, zLabel] = coordinateSystem.labels;
+
+ dragger->xAxisLabel.setValue(xLabel.c_str());
+ dragger->yAxisLabel.setValue(yLabel.c_str());
+ dragger->zAxisLabel.setValue(zLabel.c_str());
+}
+
+void TaskTransform::updateIncrements() const
+{
+ dragger->translationIncrement.setValue(
+ std::max(ui->translationIncrementSpinBox->rawValue(), 0.001));
+ dragger->rotationIncrement.setValue(
+ Base::toRadians(std::max(ui->rotationIncrementSpinBox->rawValue(), 0.01)));
+}
+
+void TaskTransform::setSelectionMode(SelectionMode mode)
+{
+ Gui::Selection().clearSelection();
+
+ ui->pickTransformOriginButton->setText(tr("Pick reference"));
+ ui->alignToOtherObjectButton->setText(tr("Move to other object"));
+
+ switch (mode) {
+ case SelectionMode::SelectTransformOrigin:
+ blockSelection(false);
+ ui->referenceLineEdit->setText(tr("Select face, edge or vertex..."));
+ ui->pickTransformOriginButton->setText(tr("Cancel"));
+ break;
+
+ case SelectionMode::SelectAlignTarget:
+ ui->alignToOtherObjectButton->setText(tr("Cancel"));
+ blockSelection(false);
+ break;
+
+ case SelectionMode::None:
+ blockSelection(true);
+ break;
+ }
+
+ selectionMode = mode;
+}
+
+TaskTransform::SelectionMode TaskTransform::getSelectionMode() const
+{
+ return selectionMode;
+}
+
+TaskTransform::CoordinateSystem TaskTransform::localCoordinateSystem() const
+{
+ auto origin = originalPlacement * vp->getTransformOrigin();
+ origin.setRotation(vp->getDraggerPlacement().getRotation());
+
+ return {{"U", "V", "W"}, origin};
+}
+
+TaskTransform::CoordinateSystem TaskTransform::absoluteCoordinateSystem() const
+{
+ return {
+ {"X", "Y", "Z"},
+ Base::Placement {},
+ };
+}
+
+TaskTransform::CoordinateSystem TaskTransform::currentCoordinateSystem() const
+{
+ return ui->positionModeComboBox->currentIndex() == 0 ? localCoordinateSystem()
+ : absoluteCoordinateSystem();
+}
+
+void TaskTransform::onSelectionChanged(const SelectionChanges& msg)
+{
+ if (msg.Type != SelectionChanges::AddSelection) {
+ return;
+ }
+
+ if (!subObjectPlacementProvider) {
+ return;
+ }
+
+ auto doc = Application::Instance->getDocument(msg.pDocName);
+ auto obj = doc->getDocument()->getObject(msg.pObjectName);
+
+ auto globalPlacement = App::GeoFeature::getGlobalPlacement(obj);
+ auto localPlacement = App::GeoFeature::getPlacementFromProp(obj, "Placement");
+ auto rootPlacement = App::GeoFeature::getGlobalPlacement(vp->getObject());
+
+ auto selectedObjectPlacement = rootPlacement.inverse() * globalPlacement
+ * subObjectPlacementProvider->calculate(msg.Object, localPlacement);
+
+ switch (selectionMode) {
+ case SelectionMode::SelectTransformOrigin: {auto label = msg.pOriginalMsg
+ ? QStringLiteral("%1#%2.%3")
+ .arg(QLatin1String(msg.pOriginalMsg->pObjectName),
+ QLatin1String(msg.pObjectName),
+ QLatin1String(msg.pSubName))
+ : QStringLiteral("%1.%2").arg(QLatin1String(msg.pObjectName), QLatin1String(msg.pSubName));
+
+
+ ui->referenceLineEdit->setText(label);
+
+ customTransformOrigin = selectedObjectPlacement;
+
+ updateTransformOrigin();
+
+ break;
+ }
+
+ case SelectionMode::SelectAlignTarget: {
+ vp->setDraggerPlacement(vp->getObjectPlacement() * selectedObjectPlacement);
+
+ vp->updateTransformFromDragger();
+ vp->updatePlacementFromDragger();
+
+ break;
+ }
+
+ default:
+ // no-op
+ break;
+ }
+
+
+ setSelectionMode(SelectionMode::None);
+}
+
+void TaskTransform::onAlignRotationChanged()
+{
+ updateDraggerLabels();
+ updateTransformOrigin();
+}
+
+void TaskTransform::onAlignToOtherObject()
+{
+ setSelectionMode(SelectionMode::SelectAlignTarget);
+}
+
+void TaskTransform::onFlip()
+{
+ auto placement = vp->getDraggerPlacement();
+
+ placement.setRotation(placement.getRotation()
+ * Base::Rotation::fromNormalVector(Base::Vector3d(0, 0, -1)));
+
+ vp->setDraggerPlacement(placement);
+
+ vp->updateTransformFromDragger();
+ vp->updatePlacementFromDragger();
+}
+
+void TaskTransform::onPickTransformOrigin()
+{
+ setSelectionMode(selectionMode == SelectionMode::None ? SelectionMode::SelectTransformOrigin
+ : SelectionMode::None);
+}
+
+void TaskTransform::onPlacementModeChange(int index)
+{
+ placementMode = ui->placementComboBox->currentData().value();
+
+ updateTransformOrigin();
+}
+
+void TaskTransform::updateTransformOrigin()
+{
+ auto getTransformOrigin = [this](const PlacementMode& mode) -> Base::Placement {
+ switch (mode) {
+ case PlacementMode::ObjectOrigin:
+ return {};
+ case PlacementMode::Centroid:
+ if (const auto com = centerOfMassProvider->ofDocumentObject(vp->getObject())) {
+ return Base::Placement {*com, {}};
+ }
+ return {};
+ case PlacementMode::Custom:
+ return customTransformOrigin.value_or(Base::Placement {});
+ default:
+ return {};
+ }
+ };
+
+ ui->referencePickerWidget->setVisible(placementMode == PlacementMode::Custom);
+
+ if (placementMode == PlacementMode::Custom && !customTransformOrigin.has_value()) {
+ onPickTransformOrigin();
+ }
+
+ auto transformOrigin = getTransformOrigin(placementMode);
+ if (isDraggerAlignedToCoordinateSystem()) {
+ transformOrigin.setRotation(
+ (vp->getObjectPlacement().inverse() * absoluteCoordinateSystem().origin).getRotation());
+ }
+
+ vp->setTransformOrigin(transformOrigin);
+
+ updatePositionAndRotationUi();
+ updateDraggerLabels();
+}
+
+bool TaskTransform::isDraggerAlignedToCoordinateSystem() const
+{
+ return positionMode == PositionMode::Absolute && ui->alignRotationCheckBox->isChecked();
+}
+
+void TaskTransform::onTransformOriginReset()
+{
+ vp->resetTransformOrigin();
+}
+
+void TaskTransform::onCoordinateSystemChange([[maybe_unused]] int mode)
+{
+ positionMode = ui->positionModeComboBox->currentData().value();
+
+ ui->alignRotationCheckBox->setVisible(positionMode != PositionMode::Local);
+
+ updateInputLabels();
+ updatePositionAndRotationUi();
+ updateTransformOrigin();
+}
+
+void TaskTransform::onPositionChange()
+{
+ const auto uvwPosition = Base::Vector3d(ui->xPositionSpinBox->rawValue(),
+ ui->yPositionSpinBox->rawValue(),
+ ui->zPositionSpinBox->rawValue());
+
+ const auto xyzPosition = currentCoordinateSystem().origin.getPosition()
+ + currentCoordinateSystem().origin.getRotation().multVec(uvwPosition);
+
+ const auto placement = vp->getDraggerPlacement();
+
+ vp->setDraggerPlacement({xyzPosition, placement.getRotation()});
+
+ vp->updateTransformFromDragger();
+ vp->updatePlacementFromDragger();
+}
+
+void TaskTransform::onRotationChange()
+{
+ const auto uvwRotation = Base::Rotation::fromEulerAngles(Base::Rotation::Intrinsic_XYZ,
+ ui->xRotationSpinBox->rawValue(),
+ ui->yRotationSpinBox->rawValue(),
+ ui->zRotationSpinBox->rawValue());
+
+ const auto xyzRotation = currentCoordinateSystem().origin.getRotation() * uvwRotation;
+
+ const auto placement = vp->getDraggerPlacement();
+
+ vp->setDraggerPlacement({placement.getPosition(), xyzRotation});
+
+ vp->updateTransformFromDragger();
+ vp->updatePlacementFromDragger();
+}
+
+TaskCSysDragger::TaskCSysDragger(ViewProviderDragger* vp, SoFCCSysDragger* dragger)
+ : vp(vp)
+{
+ transform = new TaskTransform(vp, dragger);
+ Content.push_back(transform);
}
void TaskCSysDragger::open()
{
- dragger->addStartCallback(dragStartCallback, this);
- //we can't have user switching camera types while dragger is shown.
- Gui::Application::Instance->commandManager().getCommandByName("Std_OrthographicCamera")->setEnabled(false);
- Gui::Application::Instance->commandManager().getCommandByName("Std_PerspectiveCamera")->setEnabled(false);
-// dragger->translationIncrement.setValue(lastTranslationIncrement);
-// dragger->rotationIncrement.setValue(lastRotationIncrement);
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/History/Dragger");
- double lastTranslationIncrement = hGrp->GetFloat("LastTranslationIncrement", 1.0);
- double lastRotationIncrement = hGrp->GetFloat("LastRotationIncrement", 15.0);
- tSpinBox->setValue(lastTranslationIncrement);
- rSpinBox->setValue(lastRotationIncrement);
+ // we can't have user switching camera types while dragger is shown.
+ Gui::Application::Instance->commandManager()
+ .getCommandByName("Std_OrthographicCamera")
+ ->setEnabled(false);
- Gui::TaskView::TaskDialog::open();
+ Gui::Application::Instance->commandManager()
+ .getCommandByName("Std_PerspectiveCamera")
+ ->setEnabled(false);
+
+ Gui::TaskView::TaskDialog::open();
+
+ Gui::Application::Instance->activeDocument()->openCommand(
+ QT_TRANSLATE_NOOP("Command", "Transform"));
}
bool TaskCSysDragger::accept()
{
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/History/Dragger");
- hGrp->SetFloat("LastTranslationIncrement", tSpinBox->rawValue());
- hGrp->SetFloat("LastRotationIncrement", rSpinBox->rawValue());
+ if (auto documentObject = vp->getObject()) {
+ Gui::Document* document =
+ Gui::Application::Instance->getDocument(documentObject->getDocument());
+ assert(document);
+ document->commitCommand();
+ document->resetEdit();
+ document->getDocument()->recompute();
+ }
- App::DocumentObject* dObject = vpObject.getObject();
- if (dObject) {
- Gui::Document* document = Gui::Application::Instance->getDocument(dObject->getDocument());
- assert(document);
- firstDrag = true;
- document->commitCommand();
- document->resetEdit();
- document->getDocument()->recompute();
- }
- return Gui::TaskView::TaskDialog::accept();
+ return Gui::TaskView::TaskDialog::accept();
}
bool TaskCSysDragger::reject()
{
- App::DocumentObject* dObject = vpObject.getObject();
- if (dObject) {
- Gui::Document* document = Gui::Application::Instance->getDocument(dObject->getDocument());
- assert(document);
- firstDrag = true;
- document->abortCommand();
- document->resetEdit();
- document->getDocument()->recompute();
- }
- return Gui::TaskView::TaskDialog::reject();
+ if (auto documentObject = vp->getObject()) {
+ Gui::Document* document =
+ Gui::Application::Instance->getDocument(documentObject->getDocument());
+ assert(document);
+ document->abortCommand();
+ document->resetEdit();
+ document->getDocument()->recompute();
+ }
+
+ return Gui::TaskView::TaskDialog::reject();
}
#include "moc_TaskCSysDragger.cpp"
diff --git a/src/Gui/TaskCSysDragger.h b/src/Gui/TaskCSysDragger.h
index ba223e5d2c..aac80bf0b9 100644
--- a/src/Gui/TaskCSysDragger.h
+++ b/src/Gui/TaskCSysDragger.h
@@ -25,39 +25,138 @@
#define TASKCSYSDRAGGER_H
#include "TaskView/TaskDialog.h"
-#include
+#include "TaskView/TaskView.h"
+#include "ViewProviderDragger.h"
+
+#include
+#include
class SoDragger;
-namespace Gui
+namespace Attacher
{
- class QuantitySpinBox;
- class SoFCCSysDragger;
- class ViewProviderDragger;
-
- class TaskCSysDragger : public Gui::TaskView::TaskDialog
- {
- Q_OBJECT
- public:
- TaskCSysDragger(ViewProviderDocumentObject *vpObjectIn, SoFCCSysDragger *draggerIn);
- ~TaskCSysDragger() override;
- QDialogButtonBox::StandardButtons getStandardButtons() const override
- { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel;}
- void open() override;
- bool accept() override;
- bool reject() override;
- private Q_SLOTS:
- void onTIncrementSlot(double freshValue);
- void onRIncrementSlot(double freshValue);
- private:
- static inline bool firstDrag = true;
- static void dragStartCallback(void * data, SoDragger * d);
- void setupGui();
- App::DocumentObjectT vpObject;
- SoFCCSysDragger *dragger;
- QuantitySpinBox *tSpinBox;
- QuantitySpinBox *rSpinBox;
- };
+ class AttachEngine;
}
-#endif // TASKCSYSDRAGGER_H
+namespace Gui
+{
+class QuantitySpinBox;
+class SoFCCSysDragger;
+class ViewProviderDragger;
+class Ui_TaskCSysDragger;
+
+class TaskTransform : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
+{
+ Q_OBJECT
+
+public:
+ enum class SelectionMode { None, SelectTransformOrigin, SelectAlignTarget };
+ enum class PlacementMode { ObjectOrigin, Centroid, Custom };
+ enum class PositionMode { Local, Absolute };
+
+ struct CoordinateSystem
+ {
+ std::array labels;
+ Base::Placement origin;
+ };
+
+ Q_ENUM(SelectionMode)
+ Q_ENUM(PlacementMode)
+ Q_ENUM(PositionMode)
+
+ TaskTransform(Gui::ViewProviderDragger* vp,
+ Gui::SoFCCSysDragger* dragger,
+ QWidget* parent = nullptr,
+ App::SubObjectPlacementProvider* subObjectPlacementProvider =
+ Base::provideService(),
+ App::CenterOfMassProvider* centerOfMassProvider =
+ Base::provideService());
+ ~TaskTransform() override;
+
+ void setSelectionMode(SelectionMode mode);
+ SelectionMode getSelectionMode() const;
+
+ CoordinateSystem absoluteCoordinateSystem() const;
+ CoordinateSystem localCoordinateSystem() const;
+ CoordinateSystem currentCoordinateSystem() const;
+
+private:
+ void onSelectionChanged(const SelectionChanges& msg) override;
+
+private Q_SLOTS:
+ void onPlacementModeChange(int index);
+
+ void onPickTransformOrigin();
+ void onTransformOriginReset();
+ void onAlignRotationChanged();
+
+ void onAlignToOtherObject();
+ void onFlip();
+
+ void onCoordinateSystemChange(int mode);
+
+ void onPositionChange();
+ void onRotationChange();
+
+private:
+ static inline bool firstDrag = true;
+ static void dragStartCallback(void* data, SoDragger* d);
+ static void dragMotionCallback(void* data, SoDragger* d);
+
+ void setupGui();
+
+ void loadPreferences();
+ void savePreferences();
+
+ void loadPositionModeItems() const;
+ void loadPlacementModeItems() const;
+
+ void updatePositionAndRotationUi() const;
+ void updateDraggerLabels() const;
+ void updateInputLabels() const;
+ void updateIncrements() const;
+ void updateTransformOrigin();
+
+ bool isDraggerAlignedToCoordinateSystem() const;
+
+ ViewProviderDragger* vp;
+
+ const App::SubObjectPlacementProvider* subObjectPlacementProvider;
+ const App::CenterOfMassProvider *centerOfMassProvider;
+
+ CoinPtr dragger;
+
+ Ui_TaskCSysDragger *ui;
+
+ SelectionMode selectionMode { SelectionMode::None };
+ PlacementMode placementMode { PlacementMode::ObjectOrigin };
+ PositionMode positionMode { PositionMode::Local };
+
+ std::optional customTransformOrigin {};
+ Base::Placement originalPlacement {};
+};
+
+class TaskCSysDragger: public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskCSysDragger(ViewProviderDragger* vp, SoFCCSysDragger* dragger);
+ ~TaskCSysDragger() override = default;
+
+ QDialogButtonBox::StandardButtons getStandardButtons() const override
+ {
+ return QDialogButtonBox::Ok | QDialogButtonBox::Cancel;
+ }
+
+ void open() override;
+ bool accept() override;
+ bool reject() override;
+
+private:
+ ViewProviderDragger* vp;
+ TaskTransform* transform;
+};
+} // namespace Gui
+
+#endif // TASKCSYSDRAGGER_H
diff --git a/src/Gui/TaskCSysDragger.ui b/src/Gui/TaskCSysDragger.ui
new file mode 100644
index 0000000000..a86539f01d
--- /dev/null
+++ b/src/Gui/TaskCSysDragger.ui
@@ -0,0 +1,544 @@
+
+
+ Gui::TaskCSysDragger
+
+
+
+ 0
+ 0
+ 450
+ 1012
+
+
+
+ Placement
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ Coordinate System
+
+
+ positionModeComboBox
+
+
+
+ -
+
+
-
+
+ Local Coordinate System
+
+
+ -
+
+ Global Coordinate System
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ align dragger rotation with selected coordinate system
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 41
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+ QSizePolicy::Policy::Fixed
+
+
+
+ 20
+ 16
+
+
+
+
+ -
+
+
+ Translation
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 6
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ mm
+
+
+
+ -
+
+
+ mm
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ X
+
+
+ xPositionSpinBox
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Y
+
+
+ yPositionSpinBox
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Z
+
+
+ zPositionSpinBox
+
+
+
+ -
+
+
+ mm
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Utilities
+
+
+
-
+
+
+ Move to other object
+
+
+
+ -
+
+
+ QFrame::Shape::StyledPanel
+
+
+ QFrame::Shadow::Raised
+
+
+
+ -
+
+
+ Flip
+
+
+
+
+
+
+ -
+
+
+ Dragger
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
-
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::Shape::NoFrame
+
+
+ <b>Snapping</b>
+
+
+ Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Translation
+
+
+ translationIncrementSpinBox
+
+
+
+ -
+
+
+ 0.000000000000000
+
+
+ 360.000000000000000
+
+
+ 5.000000000000000
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+ QSizePolicy::Policy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+
+ QLayout::SizeConstraint::SetDefaultConstraint
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 68
+ 0
+
+
+
+ Reference
+
+
+ referenceLineEdit
+
+
+
+ -
+
+
+ pick reference
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ mm
+
+
+ 0.000000000000000
+
+
+ 2147483647.000000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Mode
+
+
+ placementComboBox
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Rotation
+
+
+ rotationIncrementSpinBox
+
+
+
+
+
+
+ -
+
+
+ Rotation
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 6
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Y
+
+
+ yRotationSpinBox
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Z
+
+
+ zRotationSpinBox
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ X
+
+
+ xRotationSpinBox
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::QuantitySpinBox
+ QAbstractSpinBox
+
+
+
+
+ placementComboBox
+ referenceLineEdit
+ pickTransformOriginButton
+ translationIncrementSpinBox
+ rotationIncrementSpinBox
+ positionModeComboBox
+ alignRotationCheckBox
+ xPositionSpinBox
+ yPositionSpinBox
+ zPositionSpinBox
+ xRotationSpinBox
+ yRotationSpinBox
+ zRotationSpinBox
+ alignToOtherObjectButton
+ flipPartButton
+
+
+
+
diff --git a/src/Gui/Utilities.h b/src/Gui/Utilities.h
index b9e8019464..42079bf1e1 100644
--- a/src/Gui/Utilities.h
+++ b/src/Gui/Utilities.h
@@ -104,6 +104,28 @@ struct vec_traits {
private:
const vec_type& v;
};
+
+template <>
+inline SbMatrix convertTo(const Base::Matrix4D& vec2)
+{
+ double dMtrx[16];
+ vec2.getGLMatrix(dMtrx);
+ return SbMatrix(dMtrx[0], dMtrx[1], dMtrx[2], dMtrx[3], // clazy:exclude=rule-of-two-soft
+ dMtrx[4], dMtrx[5], dMtrx[6], dMtrx[7],
+ dMtrx[8], dMtrx[9], dMtrx[10], dMtrx[11],
+ dMtrx[12],dMtrx[13],dMtrx[14], dMtrx[15]);
+}
+
+template <>
+inline Base::Matrix4D convertTo(const SbMatrix& vec2)
+{
+ Base::Matrix4D mat;
+ for(int i=0;i<4;++i) {
+ for(int j=0;j<4;++j)
+ mat[i][j] = vec2[j][i];
+ }
+ return mat;
+}
}
namespace App{ class DocumentObject; }
diff --git a/src/Gui/ViewProvider.cpp b/src/Gui/ViewProvider.cpp
index 95085b677d..5fbaeb758e 100644
--- a/src/Gui/ViewProvider.cpp
+++ b/src/Gui/ViewProvider.cpp
@@ -56,6 +56,8 @@
#include "ViewProviderLink.h"
#include "ViewProviderPy.h"
+#include
+
FC_LOG_LEVEL_INIT("ViewProvider", true, true)
@@ -345,13 +347,7 @@ QIcon ViewProvider::mergeColorfulOverlayIcons (const QIcon & orig) const
void ViewProvider::setTransformation(const Base::Matrix4D &rcMatrix)
{
- double dMtrx[16];
- rcMatrix.getGLMatrix(dMtrx);
-
- pcTransform->setMatrix(SbMatrix(dMtrx[0], dMtrx[1], dMtrx[2], dMtrx[3],
- dMtrx[4], dMtrx[5], dMtrx[6], dMtrx[7],
- dMtrx[8], dMtrx[9], dMtrx[10], dMtrx[11],
- dMtrx[12],dMtrx[13],dMtrx[14], dMtrx[15]));
+ pcTransform->setMatrix(convert(rcMatrix));
}
void ViewProvider::setTransformation(const SbMatrix &rcMatrix)
@@ -361,24 +357,12 @@ void ViewProvider::setTransformation(const SbMatrix &rcMatrix)
SbMatrix ViewProvider::convert(const Base::Matrix4D &rcMatrix)
{
- //NOLINTBEGIN
- double dMtrx[16];
- rcMatrix.getGLMatrix(dMtrx);
- return SbMatrix(dMtrx[0], dMtrx[1], dMtrx[2], dMtrx[3], // clazy:exclude=rule-of-two-soft
- dMtrx[4], dMtrx[5], dMtrx[6], dMtrx[7],
- dMtrx[8], dMtrx[9], dMtrx[10], dMtrx[11],
- dMtrx[12],dMtrx[13],dMtrx[14], dMtrx[15]);
- //NOLINTEND
+ return Base::convertTo(rcMatrix);
}
Base::Matrix4D ViewProvider::convert(const SbMatrix &smat)
{
- Base::Matrix4D mat;
- for(int i=0;i<4;++i) {
- for(int j=0;j<4;++j)
- mat[i][j] = smat[j][i];
- }
- return mat;
+ return Base::convertTo(smat);
}
void ViewProvider::addDisplayMaskMode(SoNode *node, const char* type)
diff --git a/src/Gui/ViewProviderDragger.cpp b/src/Gui/ViewProviderDragger.cpp
index 2e20b3f52c..4e60eab9c1 100644
--- a/src/Gui/ViewProviderDragger.cpp
+++ b/src/Gui/ViewProviderDragger.cpp
@@ -23,16 +23,19 @@
#include "PreCompiled.h"
#ifndef _PreComp_
-# include
-# include
-# include
-# include
-# include
-# include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#endif
#include
#include
+#include
+#include
#include "Gui/ViewParams.h"
#include "Application.h"
@@ -44,20 +47,25 @@
#include "TaskCSysDragger.h"
#include "View3DInventorViewer.h"
#include "ViewProviderDragger.h"
+#include "Utilities.h"
+#include
using namespace Gui;
PROPERTY_SOURCE(Gui::ViewProviderDragger, Gui::ViewProviderDocumentObject)
-ViewProviderDragger::ViewProviderDragger() = default;
+ViewProviderDragger::ViewProviderDragger()
+{
+ ADD_PROPERTY_TYPE(TransformOrigin, ({}), nullptr, App::Prop_Hidden, nullptr);
+};
ViewProviderDragger::~ViewProviderDragger() = default;
void ViewProviderDragger::updateData(const App::Property* prop)
{
- if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId()) &&
- strcmp(prop->getName(), "Placement") == 0) {
+ if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId())
+ && strcmp(prop->getName(), "Placement") == 0) {
// Note: If R is the rotation, c the rotation center and t the translation
// vector then Inventor applies the following transformation: R*(x-c)+c+t
// In FreeCAD a placement only has a rotation and a translation part but
@@ -73,6 +81,30 @@ void ViewProviderDragger::updateData(const App::Property* prop)
ViewProviderDocumentObject::updateData(prop);
}
+void ViewProviderDragger::setTransformOrigin(const Base::Placement& placement)
+{
+ TransformOrigin.setValue(placement);
+}
+
+void ViewProviderDragger::resetTransformOrigin()
+{
+ setTransformOrigin({});
+}
+
+void ViewProviderDragger::onChanged(const App::Property* property)
+{
+ if (property == &TransformOrigin) {
+ updateDraggerPosition();
+ }
+
+ ViewProviderDocumentObject::onChanged(property);
+}
+
+TaskView::TaskDialog* ViewProviderDragger::getTransformDialog()
+{
+ return new TaskCSysDragger(this, csysDragger);
+}
+
bool ViewProviderDragger::doubleClicked()
{
Gui::Application::Instance->activeDocument()->setEdit(this, (int)ViewProvider::Default);
@@ -81,249 +113,216 @@ bool ViewProviderDragger::doubleClicked()
void ViewProviderDragger::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
- QIcon iconObject = mergeGreyableOverlayIcons(Gui::BitmapFactory().pixmap("Std_TransformManip.svg"));
+ QIcon iconObject =
+ mergeGreyableOverlayIcons(Gui::BitmapFactory().pixmap("Std_TransformManip.svg"));
QAction* act = menu->addAction(iconObject, QObject::tr("Transform"), receiver, member);
act->setData(QVariant((int)ViewProvider::Transform));
ViewProviderDocumentObject::setupContextMenu(menu, receiver, member);
}
-ViewProvider *ViewProviderDragger::startEditing(int mode) {
+ViewProvider* ViewProviderDragger::startEditing(int mode)
+{
_linkDragger = nullptr;
auto ret = ViewProviderDocumentObject::startEditing(mode);
- if(!ret)
+ if (!ret) {
return ret;
- return _linkDragger?_linkDragger:ret;
+ }
+ return _linkDragger ? _linkDragger : ret;
}
-bool ViewProviderDragger::checkLink() {
+bool ViewProviderDragger::checkLink()
+{
// Trying to detect if the editing request is forwarded by a link object,
// usually by doubleClicked(). If so, we route the request back. There shall
// be no risk of infinite recursion, as ViewProviderLink handles
// ViewProvider::Transform request by itself.
- ViewProviderDocumentObject *vpParent = nullptr;
+ ViewProviderDocumentObject* vpParent = nullptr;
std::string subname;
+
auto doc = Application::Instance->editDocument();
- if(!doc)
+ if (!doc) {
return false;
- doc->getInEdit(&vpParent,&subname);
- if(!vpParent)
+ }
+
+ doc->getInEdit(&vpParent, &subname);
+ if (!vpParent) {
return false;
+ }
+
auto sobj = vpParent->getObject()->getSubObject(subname.c_str());
- if(!sobj || sobj==getObject() || sobj->getLinkedObject(true)!=getObject())
+ if (!sobj || sobj == getObject() || sobj->getLinkedObject(true) != getObject()) {
return false;
+ }
+
auto vp = Application::Instance->getViewProvider(sobj);
- if(!vp)
+ if (!vp) {
return false;
+ }
+
_linkDragger = vp->startEditing(ViewProvider::Transform);
- if(_linkDragger)
- return true;
- return false;
+
+ return _linkDragger != nullptr;
}
bool ViewProviderDragger::setEdit(int ModNum)
{
- Q_UNUSED(ModNum);
+ Q_UNUSED(ModNum);
- if (checkLink()) {
- return true;
- }
-
- App::DocumentObject *genericObject = this->getObject();
-
- if (genericObject->isDerivedFrom(App::GeoFeature::getClassTypeId())) {
- auto geoFeature = static_cast(genericObject);
- const Base::Placement &placement = geoFeature->Placement.getValue();
- auto tempTransform = new SoTransform();
- tempTransform->ref();
- updateTransform(placement, tempTransform);
+ if (checkLink()) {
+ return true;
+ }
assert(!csysDragger);
+
csysDragger = new SoFCCSysDragger();
- csysDragger->setAxisColors(
- Gui::ViewParams::instance()->getAxisXColor(),
- Gui::ViewParams::instance()->getAxisYColor(),
- Gui::ViewParams::instance()->getAxisZColor()
- );
+ csysDragger->setAxisColors(Gui::ViewParams::instance()->getAxisXColor(),
+ Gui::ViewParams::instance()->getAxisYColor(),
+ Gui::ViewParams::instance()->getAxisZColor());
csysDragger->draggerSize.setValue(ViewParams::instance()->getDraggerScale());
- csysDragger->translation.setValue(tempTransform->translation.getValue());
- csysDragger->rotation.setValue(tempTransform->rotation.getValue());
-
- tempTransform->unref();
-
- pcTransform->translation.connectFrom(&csysDragger->translation);
- pcTransform->rotation.connectFrom(&csysDragger->rotation);
+ csysDragger->addStartCallback(dragStartCallback, this);
csysDragger->addFinishCallback(dragFinishCallback, this);
+ csysDragger->addMotionCallback(dragMotionCallback, this);
- // dragger node is added to viewer's editing root in setEditViewer
- // pcRoot->insertChild(csysDragger, 0);
- csysDragger->ref();
+ Gui::Control().showDialog(getTransformDialog());
- auto task = new TaskCSysDragger(this, csysDragger);
- Gui::Control().showDialog(task);
- }
+ updateDraggerPosition();
- return true;
+ return true;
}
void ViewProviderDragger::unsetEdit(int ModNum)
{
- Q_UNUSED(ModNum);
+ Q_UNUSED(ModNum);
- if(csysDragger)
- {
- pcTransform->translation.disconnect(&csysDragger->translation);
- pcTransform->rotation.disconnect(&csysDragger->rotation);
+ csysDragger.reset();
- // dragger node is added to viewer's editing root in setEditViewer
- // pcRoot->removeChild(csysDragger); //should delete csysDragger
- csysDragger->unref();
- csysDragger = nullptr;
- }
- Gui::Control().closeDialog();
+ Gui::Control().closeDialog();
}
void ViewProviderDragger::setEditViewer(Gui::View3DInventorViewer* viewer, int ModNum)
{
Q_UNUSED(ModNum);
- if (csysDragger && viewer)
- {
- auto rootPickStyle = new SoPickStyle();
- rootPickStyle->style = SoPickStyle::UNPICKABLE;
- auto selection = static_cast(viewer->getSceneGraph());
- selection->insertChild(rootPickStyle, 0);
- viewer->setSelectionEnabled(false);
- csysDragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera());
+ if (csysDragger && viewer) {
+ csysDragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera());
- auto mat = viewer->getDocument()->getEditingTransform();
- viewer->getDocument()->setEditingTransform(mat);
- auto feat = dynamic_cast(getObject());
- if(feat) {
- auto matInverse = feat->Placement.getValue().toMatrix();
- matInverse.inverse();
- mat *= matInverse;
- }
- viewer->setupEditingRoot(csysDragger,&mat);
+ auto mat = viewer->getDocument()->getEditingTransform();
+ if (auto geoFeature = getObject()) {
+ mat *= geoFeature->Placement.getValue().inverse().toMatrix();
+ }
+
+ viewer->getDocument()->setEditingTransform(mat);
+ viewer->setupEditingRoot(csysDragger, &mat);
}
}
void ViewProviderDragger::unsetEditViewer(Gui::View3DInventorViewer* viewer)
-{
- auto selection = static_cast(viewer->getSceneGraph());
- SoNode *child = selection->getChild(0);
- if (child && child->isOfType(SoPickStyle::getClassTypeId())) {
- selection->removeChild(child);
- viewer->setSelectionEnabled(true);
- }
-}
+{}
-void ViewProviderDragger::dragFinishCallback(void *data, SoDragger *d)
+void ViewProviderDragger::dragStartCallback(void* data, [[maybe_unused]] SoDragger* d)
{
// This is called when a manipulator has done manipulating
+ auto vp = static_cast(data);
- auto sudoThis = static_cast(data);
- auto dragger = static_cast(d);
- updatePlacementFromDragger(sudoThis, dragger);
-
- //Gui::Application::Instance->activeDocument()->commitCommand();
+ vp->draggerPlacement = vp->getDraggerPlacement();
+ vp->csysDragger->clearIncrementCounts();
}
-void ViewProviderDragger::updatePlacementFromDragger(ViewProviderDragger* sudoThis, SoFCCSysDragger* draggerIn)
+void ViewProviderDragger::dragFinishCallback(void* data, SoDragger* d)
{
- App::DocumentObject *genericObject = sudoThis->getObject();
- if (!genericObject->isDerivedFrom(App::GeoFeature::getClassTypeId()))
- return;
- auto geoFeature = static_cast(genericObject);
- Base::Placement originalPlacement = geoFeature->Placement.getValue();
- double pMatrix[16];
- originalPlacement.toMatrix().getMatrix(pMatrix);
- Base::Placement freshPlacement = originalPlacement;
+ // This is called when a manipulator has done manipulating
+ auto vp = static_cast(data);
- //local cache for brevity.
- double translationIncrement = draggerIn->translationIncrement.getValue();
- double rotationIncrement = draggerIn->rotationIncrement.getValue();
- int tCountX = draggerIn->translationIncrementCountX.getValue();
- int tCountY = draggerIn->translationIncrementCountY.getValue();
- int tCountZ = draggerIn->translationIncrementCountZ.getValue();
- int rCountX = draggerIn->rotationIncrementCountX.getValue();
- int rCountY = draggerIn->rotationIncrementCountY.getValue();
- int rCountZ = draggerIn->rotationIncrementCountZ.getValue();
+ vp->draggerPlacement = vp->getDraggerPlacement();
+ vp->csysDragger->clearIncrementCounts();
- //just as a little sanity check make sure only 1 or 2 fields has changed.
- int numberOfFieldChanged = 0;
- if (tCountX) numberOfFieldChanged++;
- if (tCountY) numberOfFieldChanged++;
- if (tCountZ) numberOfFieldChanged++;
- if (rCountX) numberOfFieldChanged++;
- if (rCountY) numberOfFieldChanged++;
- if (rCountZ) numberOfFieldChanged++;
- if (numberOfFieldChanged == 0)
- return;
- assert(numberOfFieldChanged == 1 || numberOfFieldChanged == 2);
+ vp->updatePlacementFromDragger();
+}
- //helper lambdas.
- auto getVectorX = [&pMatrix]() {return Base::Vector3d(pMatrix[0], pMatrix[4], pMatrix[8]);};
- auto getVectorY = [&pMatrix]() {return Base::Vector3d(pMatrix[1], pMatrix[5], pMatrix[9]);};
- auto getVectorZ = [&pMatrix]() {return Base::Vector3d(pMatrix[2], pMatrix[6], pMatrix[10]);};
+void ViewProviderDragger::dragMotionCallback(void* data, SoDragger* d)
+{
+ auto vp = static_cast(data);
- if (tCountX)
- {
- Base::Vector3d movementVector(getVectorX());
- movementVector *= (tCountX * translationIncrement);
- freshPlacement.move(movementVector);
- geoFeature->Placement.setValue(freshPlacement);
- }
- if (tCountY)
- {
- Base::Vector3d movementVector(getVectorY());
- movementVector *= (tCountY * translationIncrement);
- freshPlacement.move(movementVector);
- geoFeature->Placement.setValue(freshPlacement);
- }
- if (tCountZ)
- {
- Base::Vector3d movementVector(getVectorZ());
- movementVector *= (tCountZ * translationIncrement);
- freshPlacement.move(movementVector);
- geoFeature->Placement.setValue(freshPlacement);
- }
- if (rCountX)
- {
- Base::Vector3d rotationVector(getVectorX());
- Base::Rotation rotation(rotationVector, rCountX * rotationIncrement);
- freshPlacement.setRotation(rotation * freshPlacement.getRotation());
- geoFeature->Placement.setValue(freshPlacement);
- }
- if (rCountY)
- {
- Base::Vector3d rotationVector(getVectorY());
- Base::Rotation rotation(rotationVector, rCountY * rotationIncrement);
- freshPlacement.setRotation(rotation * freshPlacement.getRotation());
- geoFeature->Placement.setValue(freshPlacement);
- }
- if (rCountZ)
- {
- Base::Vector3d rotationVector(getVectorZ());
- Base::Rotation rotation(rotationVector, rCountZ * rotationIncrement);
- freshPlacement.setRotation(rotation * freshPlacement.getRotation());
- geoFeature->Placement.setValue(freshPlacement);
- }
+ vp->updateTransformFromDragger();
+}
- draggerIn->clearIncrementCounts();
+void ViewProviderDragger::updatePlacementFromDragger()
+{
+ const auto geoFeature = getObject();
+
+ if (!geoFeature) {
+ return;
+ }
+
+ geoFeature->Placement.setValue(getDraggerPlacement() * getTransformOrigin().inverse());
+}
+
+void ViewProviderDragger::updateTransformFromDragger()
+{
+ const auto placement = getDraggerPlacement() * getTransformOrigin().inverse();
+
+ pcTransform->translation.setValue(Base::convertTo(placement.getPosition()));
+ pcTransform->rotation.setValue(Base::convertTo(placement.getRotation()));
+}
+
+Base::Placement ViewProviderDragger::getDraggerPlacement() const
+{
+ const double translationStep = csysDragger->translationIncrement.getValue();
+ const int xSteps = csysDragger->translationIncrementCountX.getValue();
+ const int ySteps = csysDragger->translationIncrementCountY.getValue();
+ const int zSteps = csysDragger->translationIncrementCountZ.getValue();
+
+ const auto rotation = draggerPlacement.getRotation();
+ const auto xBase = rotation.multVec(Base::Vector3d(1, 0, 0));
+ const auto yBase = rotation.multVec(Base::Vector3d(0, 1, 0));
+ const auto zBase = rotation.multVec(Base::Vector3d(0, 0, 1));
+
+ const auto positionIncrement =
+ xBase * (translationStep * xSteps) +
+ yBase * (translationStep * ySteps) +
+ zBase * (translationStep * zSteps);
+
+ const double rotationStep = csysDragger->rotationIncrement.getValue();
+ const int xRotationSteps = csysDragger->rotationIncrementCountX.getValue();
+ const int yRotationSteps = csysDragger->rotationIncrementCountY.getValue();
+ const int zRotationSteps = csysDragger->rotationIncrementCountZ.getValue();
+
+ auto newRotation = rotation;
+ newRotation = newRotation * Base::Rotation(Base::Vector3d(1, 0, 0), xRotationSteps * rotationStep);
+ newRotation = newRotation * Base::Rotation(Base::Vector3d(0, 1, 0), yRotationSteps * rotationStep);
+ newRotation = newRotation * Base::Rotation(Base::Vector3d(0, 0, 1), zRotationSteps * rotationStep);
+
+ return Base::Placement(
+ draggerPlacement.getPosition() + positionIncrement,
+ newRotation
+ );
+}
+
+void ViewProviderDragger::setDraggerPlacement(const Base::Placement& placement)
+{
+ csysDragger->translation.setValue(Base::convertTo(placement.getPosition()));
+ csysDragger->rotation.setValue(Base::convertTo(placement.getRotation()));
+
+ draggerPlacement = placement;
+ csysDragger->clearIncrementCounts();
+}
+
+void ViewProviderDragger::updateDraggerPosition()
+{
+ if (!csysDragger) {
+ return;
+ }
+
+ auto placement = getObject()->Placement.getValue() * getTransformOrigin();
+
+ setDraggerPlacement(placement);
}
void ViewProviderDragger::updateTransform(const Base::Placement& from, SoTransform* to)
{
- auto q0 = (float)from.getRotation().getValue()[0];
- auto q1 = (float)from.getRotation().getValue()[1];
- auto q2 = (float)from.getRotation().getValue()[2];
- auto q3 = (float)from.getRotation().getValue()[3];
- auto px = (float)from.getPosition().x;
- auto py = (float)from.getPosition().y;
- auto pz = (float)from.getPosition().z;
- to->rotation.setValue(q0,q1,q2,q3);
- to->translation.setValue(px,py,pz);
- to->center.setValue(0.0f,0.0f,0.0f);
- to->scaleFactor.setValue(1.0f,1.0f,1.0f);
+ to->rotation.setValue(Base::convertTo(from.getRotation()));
+ to->translation.setValue(Base::convertTo(from.getPosition()));
+ to->center.setValue(0.0f, 0.0f, 0.0f);
+ to->scaleFactor.setValue(1.0f, 1.0f, 1.0f);
}
diff --git a/src/Gui/ViewProviderDragger.h b/src/Gui/ViewProviderDragger.h
index 40502f016a..ce5a6da50c 100644
--- a/src/Gui/ViewProviderDragger.h
+++ b/src/Gui/ViewProviderDragger.h
@@ -25,16 +25,20 @@
#define GUI_VIEWPROVIDER_DRAGGER_H
#include "ViewProviderDocumentObject.h"
+#include "SoFCCSysDragger.h"
+#include
+#include
class SoDragger;
class SoTransform;
-namespace Base { class Placement;}
-
namespace Gui {
+namespace TaskView {
+ class TaskDialog;
+}
+
class View3DInventorViewer;
-class SoFCCSysDragger;
/**
* The base class for all view providers modifying the placement
@@ -52,6 +56,13 @@ public:
/// destructor.
~ViewProviderDragger() override;
+ App::PropertyPlacement TransformOrigin;
+
+ Base::Placement getTransformOrigin() const { return TransformOrigin.getValue(); }
+ void setTransformOrigin(const Base::Placement& placement);
+ void resetTransformOrigin();
+
+public:
/** @name Edit methods */
//@{
bool doubleClicked() override;
@@ -63,21 +74,40 @@ public:
/*! synchronize From FC placement to Coin placement*/
static void updateTransform(const Base::Placement &from, SoTransform *to);
+ void updatePlacementFromDragger();
+ void updateTransformFromDragger();
+
+ Base::Placement getDraggerPlacement() const;
+ void setDraggerPlacement(const Base::Placement& placement);
+
protected:
bool setEdit(int ModNum) override;
void unsetEdit(int ModNum) override;
void setEditViewer(View3DInventorViewer*, int ModNum) override;
void unsetEditViewer(View3DInventorViewer*) override;
//@}
- SoFCCSysDragger *csysDragger = nullptr;
+
+ void onChanged(const App::Property* prop) override;
+
+ /**
+ * Returns a newly create dialog for the part to be placed in the task view
+ * Must be reimplemented in subclasses.
+ */
+ virtual TaskView::TaskDialog* getTransformDialog();
+
+ CoinPtr csysDragger = nullptr;
private:
- static void dragFinishCallback(void * data, SoDragger * d);
- static void updatePlacementFromDragger(ViewProviderDragger *sudoThis, SoFCCSysDragger *draggerIn);
+ static void dragStartCallback(void *data, SoDragger *d);
+ static void dragFinishCallback(void *data, SoDragger *d);
+ static void dragMotionCallback(void *data, SoDragger *d);
+
+ void updateDraggerPosition();
bool checkLink();
ViewProvider *_linkDragger = nullptr;
+ Base::Placement draggerPlacement { };
};
} // namespace Gui
diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp
index a2cad7a67f..6e2fe24d0b 100644
--- a/src/Gui/ViewProviderLink.cpp
+++ b/src/Gui/ViewProviderLink.cpp
@@ -2893,7 +2893,7 @@ void ViewProviderLink::setEditViewer(Gui::View3DInventorViewer* viewer, int ModN
dragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera());
viewer->setupEditingRoot(pcDragger,&dragCtx->preTransform);
- auto task = new TaskCSysDragger(this, dragger);
+ auto task = new TaskCSysDragger(nullptr, dragger);
Gui::Control().showDialog(task);
}
}
diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp
index c244d033a5..7668f6d9dd 100644
--- a/src/Mod/Part/App/AppPart.cpp
+++ b/src/Mod/Part/App/AppPart.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#include "ArcOfCirclePy.h"
@@ -187,8 +188,12 @@
#include
#include "MeasureClient.h"
+
#include
+#include
+#include
+
namespace Part {
extern PyObject* initModule();
}
@@ -572,7 +577,10 @@ PyMOD_INIT_FUNC(Part)
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean");
Part::FuzzyHelper::setBooleanFuzzy(hGrp->GetFloat("BooleanFuzzy",10.0));
-
+
+ Base::registerServiceImplementation(new AttacherSubObjectPlacement);
+ Base::registerServiceImplementation(new PartCenterOfMass);
+
PyMOD_Return(partModule);
}
// clang-format on
diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt
index 71bedcac65..871d58c2df 100644
--- a/src/Mod/Part/App/CMakeLists.txt
+++ b/src/Mod/Part/App/CMakeLists.txt
@@ -553,6 +553,8 @@ SET(Part_SRCS
PreCompiled.h
ProgressIndicator.cpp
ProgressIndicator.h
+ Services.cpp
+ Services.h
TopoShape.cpp
TopoShape.h
TopoShapeCache.cpp
diff --git a/src/Mod/Part/App/Services.cpp b/src/Mod/Part/App/Services.cpp
new file mode 100644
index 0000000000..53eb46b947
--- /dev/null
+++ b/src/Mod/Part/App/Services.cpp
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 Kacper Donat *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#include "Services.h"
+
+AttacherSubObjectPlacement::AttacherSubObjectPlacement()
+ : attacher(std::make_unique())
+{
+ attacher->setUp({}, Attacher::mmMidpoint);
+}
+
+Base::Placement AttacherSubObjectPlacement::calculate(App::SubObjectT object,
+ Base::Placement basePlacement) const
+{
+ attacher->setReferences({object});
+ return basePlacement.inverse() * attacher->calculateAttachedPlacement(basePlacement);
+}
+
+std::optional PartCenterOfMass::ofDocumentObject(App::DocumentObject* object) const
+{
+ if (const auto feature = dynamic_cast(object)) {
+ const auto shape = feature->Shape.getShape();
+
+ if (const auto cog = shape.centerOfGravity()) {
+ const Base::Placement comPlacement { *cog, Base::Rotation { } };
+
+ return (feature->Placement.getValue().inverse() * comPlacement).getPosition();
+ }
+ }
+
+ return {};
+}
\ No newline at end of file
diff --git a/src/Mod/Part/App/Services.h b/src/Mod/Part/App/Services.h
new file mode 100644
index 0000000000..217ff47e8d
--- /dev/null
+++ b/src/Mod/Part/App/Services.h
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 Kacper Donat *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#ifndef PART_SERVICES_H
+#define PART_SERVICES_H
+
+#include
+#include
+
+class AttacherSubObjectPlacement final: public App::SubObjectPlacementProvider
+{
+public:
+ AttacherSubObjectPlacement();
+
+ Base::Placement calculate(App::SubObjectT object, Base::Placement basePlacement) const override;
+
+private:
+ std::unique_ptr attacher;
+};
+
+class PartCenterOfMass final: public App::CenterOfMassProvider
+{
+public:
+ std::optional ofDocumentObject(App::DocumentObject* object) const override;
+};
+
+#endif // PART_SERVICES_H