Gui: Rework TaskCSysDragger into new Transform Dialog
This commit refactor ViewProviderDragger and TaskCSysDragger to be more modern and to support selecting TransformOrigin.
This commit is contained in:
@@ -63,6 +63,7 @@
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/BoundBoxPy.h>
|
||||
#include <Base/ConsoleObserver.h>
|
||||
#include <Base/ServiceProvider.h>
|
||||
#include <Base/CoordinateSystemPy.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/ExceptionFactory.h>
|
||||
@@ -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<Base::CADKernelError>;
|
||||
new Base::ExceptionProducer<Base::RestoreError>;
|
||||
new Base::ExceptionProducer<Base::PropertyError>;
|
||||
|
||||
Base::registerServiceImplementation<CenterOfMassProvider>(new NullCenterOfMass);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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<GeoFeatureGroupExtension>();
|
||||
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<App::PropertyPlacement>("Placement");
|
||||
|
||||
if (!placementProperty) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* group = GeoFeatureGroupExtension::getGroupOfObject(obj);
|
||||
if (group) {
|
||||
auto ext = group->getExtensionByType<GeoFeatureGroupExtension>();
|
||||
return ext->globalGroupPlacement() * placementProperty->getValue();
|
||||
}
|
||||
|
||||
return placementProperty->getValue();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
30
src/App/Services.cpp
Normal file
30
src/App/Services.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Kacper Donat <kacper@kadet.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "Services.h"
|
||||
|
||||
std::optional<Base::Vector3d>
|
||||
App::NullCenterOfMass::ofDocumentObject([[maybe_unused]] DocumentObject* object) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
74
src/App/Services.h
Normal file
74
src/App/Services.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Kacper Donat <kacper@kadet.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_SERVICES_H
|
||||
#define APP_SERVICES_H
|
||||
|
||||
#include "DocumentObject.h"
|
||||
|
||||
#include <optional>
|
||||
#include <Base/Placement.h>
|
||||
|
||||
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<Base::Vector3d> 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<Base::Vector3d> ofDocumentObject(DocumentObject* object) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // APP_SERVICES_H
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -402,6 +402,7 @@ SET(Gui_UIC_SRCS
|
||||
SceneInspector.ui
|
||||
InputVector.ui
|
||||
Placement.ui
|
||||
TaskCSysDragger.ui
|
||||
TextureMapping.ui
|
||||
TaskView/TaskAppearance.ui
|
||||
TaskView/TaskOrientation.ui
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; i<num; i++) {
|
||||
@@ -431,7 +436,7 @@ void SoFrameLabel::drawImage()
|
||||
}
|
||||
|
||||
int padding = 5;
|
||||
|
||||
|
||||
bool drawIcon = false;
|
||||
QImage iconImg;
|
||||
int widthIcon = 0;
|
||||
@@ -456,15 +461,15 @@ void SoFrameLabel::drawImage()
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
SbBool drawFrame = frame.getValue();
|
||||
if (drawFrame) {
|
||||
painter.setPen(QPen(QColor(0,0,127), 2, Qt::SolidLine, Qt::RoundCap,
|
||||
Qt::RoundJoin));
|
||||
painter.setBrush(QBrush(brush, Qt::SolidPattern));
|
||||
SbBool drawBorder = border.getValue();
|
||||
if (drawFrame || drawBorder) {
|
||||
painter.setPen(drawBorder ? borderPen : QPen(Qt::transparent));
|
||||
painter.setBrush(QBrush(drawFrame ? backgroundBrush : Qt::transparent));
|
||||
|
||||
QRectF rectangle(0.0, 0.0, widthTotal, heightTotal);
|
||||
painter.drawRoundedRect(rectangle, 5, 5);
|
||||
}
|
||||
|
||||
|
||||
if (drawIcon) {
|
||||
painter.drawImage(QPoint(padding, paddingIconV), iconImg);
|
||||
}
|
||||
@@ -493,10 +498,15 @@ void SoFrameLabel::drawImage()
|
||||
*/
|
||||
void SoFrameLabel::GLRender(SoGLRenderAction *action)
|
||||
{
|
||||
SoState * state = action->getState();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -118,6 +118,8 @@ public:
|
||||
SoSFName name;
|
||||
SoSFInt32 size;
|
||||
SoSFBool frame;
|
||||
SoSFBool border;
|
||||
SoSFBool backgroundUseBaseColor;
|
||||
//SoSFImage image;
|
||||
QPixmap iconPixmap;
|
||||
|
||||
|
||||
@@ -26,11 +26,20 @@
|
||||
#include <limits>
|
||||
#include <QApplication>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
#include <View3DInventorViewer.h>
|
||||
#include <Utilities.h>
|
||||
|
||||
#include <App/Document.h>
|
||||
#include "Document.h" // must be before TaskCSysDragger.h
|
||||
#include "TaskCSysDragger.h"
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/Services.h>
|
||||
#include <Base/Precision.h>
|
||||
#include <Base/ServiceProvider.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#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 <Inventor/nodes/SoPickStyle.h>
|
||||
|
||||
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<QGridLayout*>& layouts, unsigned column = 0)
|
||||
{
|
||||
assert(vpObjectIn);
|
||||
assert(draggerIn);
|
||||
vpObject = vpObjectIn->getObject();
|
||||
dragger->ref();
|
||||
std::vector<int> 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<double>::max());
|
||||
tSpinBox->setUnit(Base::Unit::Length);
|
||||
tSpinBox->setMinimumWidth(spinBoxWidth);
|
||||
gridLayout->addWidget(tSpinBox, 0, 1, Qt::AlignLeft);
|
||||
if (auto geoFeature = vp->getObject<App::GeoFeature>()) {
|
||||
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<double>(&QuantitySpinBox::valueChanged), this, &TaskCSysDragger::onTIncrementSlot);
|
||||
connect(rSpinBox, qOverload<double>(&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<TaskTransform*>(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<double>(&QuantitySpinBox::valueChanged),
|
||||
this,
|
||||
[this](double) {
|
||||
updateIncrements();
|
||||
});
|
||||
connect(ui->rotationIncrementSpinBox,
|
||||
qOverload<double>(&QuantitySpinBox::valueChanged),
|
||||
this,
|
||||
[this](double) {
|
||||
updateIncrements();
|
||||
});
|
||||
connect(ui->positionModeComboBox,
|
||||
qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this,
|
||||
&TaskTransform::onCoordinateSystemChange);
|
||||
connect(ui->placementComboBox,
|
||||
qOverload<int>(&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<double>(&QuantitySpinBox::valueChanged),
|
||||
this,
|
||||
[this](double) {
|
||||
onPositionChange();
|
||||
});
|
||||
}
|
||||
|
||||
for (auto rotationSpinBox :
|
||||
{ui->xRotationSpinBox, ui->yRotationSpinBox, ui->zRotationSpinBox}) {
|
||||
connect(rotationSpinBox,
|
||||
qOverload<double>(&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<PlacementMode>();
|
||||
|
||||
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<PositionMode>();
|
||||
|
||||
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"
|
||||
|
||||
@@ -25,39 +25,138 @@
|
||||
#define TASKCSYSDRAGGER_H
|
||||
|
||||
#include "TaskView/TaskDialog.h"
|
||||
#include <App/DocumentObserver.h>
|
||||
#include "TaskView/TaskView.h"
|
||||
#include "ViewProviderDragger.h"
|
||||
|
||||
#include <Base/ServiceProvider.h>
|
||||
#include <App/Services.h>
|
||||
|
||||
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<std::string, 3> 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::SubObjectPlacementProvider>(),
|
||||
App::CenterOfMassProvider* centerOfMassProvider =
|
||||
Base::provideService<App::CenterOfMassProvider>());
|
||||
~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<SoFCCSysDragger> dragger;
|
||||
|
||||
Ui_TaskCSysDragger *ui;
|
||||
|
||||
SelectionMode selectionMode { SelectionMode::None };
|
||||
PlacementMode placementMode { PlacementMode::ObjectOrigin };
|
||||
PositionMode positionMode { PositionMode::Local };
|
||||
|
||||
std::optional<Base::Placement> 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
|
||||
|
||||
544
src/Gui/TaskCSysDragger.ui
Normal file
544
src/Gui/TaskCSysDragger.ui
Normal file
@@ -0,0 +1,544 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Gui::TaskCSysDragger</class>
|
||||
<widget class="QWidget" name="Gui::TaskCSysDragger">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>1012</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Placement</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="0,1">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Coordinate System</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>positionModeComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="positionModeComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Local Coordinate System</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Global Coordinate System</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="alignRotationCheckBox">
|
||||
<property name="text">
|
||||
<string>align dragger rotation with selected coordinate system</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<spacer name="vSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>41</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="positionGroupBox">
|
||||
<property name="title">
|
||||
<string>Translation</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" columnminimumwidth="100">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QWidget" name="positionStackWidget" native="true">
|
||||
<layout class="QGridLayout" name="absolutePositionLayout" columnstretch="1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="zPositionSpinBox">
|
||||
<property name="unit" stdset="0">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="xPositionSpinBox">
|
||||
<property name="unit" stdset="0">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="xPositionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>xPositionSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="yPositionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>yPositionSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="zPositionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Z</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>zPositionSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="yPositionSpinBox">
|
||||
<property name="unit" stdset="0">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Utilities</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="alignToOtherObjectButton">
|
||||
<property name="text">
|
||||
<string>Move to other object</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="flipPartButton">
|
||||
<property name="text">
|
||||
<string>Flip</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="transformOriginGroupBox">
|
||||
<property name="title">
|
||||
<string>Dragger</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="transformOriginLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="placementComboBox"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="snappingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><b>Snapping</b></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="translationIncrementLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Translation</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>translationIncrementSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="rotationIncrementSpinBox">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QWidget" name="referencePickerWidget" native="true">
|
||||
<layout class="QGridLayout" name="referencePickerLayout" columnstretch="0,1">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="referenceLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>68</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reference</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>referenceLineEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="pickTransformOriginButton">
|
||||
<property name="text">
|
||||
<string>pick reference</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="referenceLineEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="translationIncrementSpinBox">
|
||||
<property name="unit" stdset="0">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2147483647.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Mode</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>placementComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="rotationIncrementLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rotation</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>rotationIncrementSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QGroupBox" name="rotationGroupBox">
|
||||
<property name="title">
|
||||
<string>Rotation</string>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QWidget" name="rotationStackWidget" native="true">
|
||||
<layout class="QGridLayout" name="absoluteRotationLayout" columnstretch="1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="zRotationSpinBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="yRotationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>yRotationSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="zRotationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Z</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>zRotationSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="yRotationSpinBox"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="xRotationSpinBox"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="xRotationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>xRotationSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QAbstractSpinBox</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>placementComboBox</tabstop>
|
||||
<tabstop>referenceLineEdit</tabstop>
|
||||
<tabstop>pickTransformOriginButton</tabstop>
|
||||
<tabstop>translationIncrementSpinBox</tabstop>
|
||||
<tabstop>rotationIncrementSpinBox</tabstop>
|
||||
<tabstop>positionModeComboBox</tabstop>
|
||||
<tabstop>alignRotationCheckBox</tabstop>
|
||||
<tabstop>xPositionSpinBox</tabstop>
|
||||
<tabstop>yPositionSpinBox</tabstop>
|
||||
<tabstop>zPositionSpinBox</tabstop>
|
||||
<tabstop>xRotationSpinBox</tabstop>
|
||||
<tabstop>yRotationSpinBox</tabstop>
|
||||
<tabstop>zRotationSpinBox</tabstop>
|
||||
<tabstop>alignToOtherObjectButton</tabstop>
|
||||
<tabstop>flipPartButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -104,6 +104,28 @@ struct vec_traits<App::Color> {
|
||||
private:
|
||||
const vec_type& v;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline SbMatrix convertTo<SbMatrix, Base::Matrix4D>(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<Base::Matrix4D, SbMatrix>(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; }
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
#include "ViewProviderLink.h"
|
||||
#include "ViewProviderPy.h"
|
||||
|
||||
#include <Utilities.h>
|
||||
|
||||
|
||||
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<SbMatrix>(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<Base::Matrix4D>(smat);
|
||||
}
|
||||
|
||||
void ViewProvider::addDisplayMaskMode(SoNode *node, const char* type)
|
||||
|
||||
@@ -23,16 +23,19 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <string>
|
||||
# include <QAction>
|
||||
# include <QMenu>
|
||||
# include <Inventor/draggers/SoDragger.h>
|
||||
# include <Inventor/nodes/SoPickStyle.h>
|
||||
# include <Inventor/nodes/SoTransform.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <Inventor/draggers/SoDragger.h>
|
||||
#include <Inventor/nodes/SoPickStyle.h>
|
||||
#include <Inventor/nodes/SoTransform.h>
|
||||
#endif
|
||||
|
||||
#include <App/GeoFeature.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/Converter.h>
|
||||
#include "Gui/ViewParams.h"
|
||||
|
||||
#include "Application.h"
|
||||
@@ -44,20 +47,25 @@
|
||||
#include "TaskCSysDragger.h"
|
||||
#include "View3DInventorViewer.h"
|
||||
#include "ViewProviderDragger.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
#include <Base/Tools.h>
|
||||
|
||||
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<App::GeoFeature *>(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<SoGroup*>(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<App::GeoFeature *>(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<App::GeoFeature>()) {
|
||||
mat *= geoFeature->Placement.getValue().inverse().toMatrix();
|
||||
}
|
||||
|
||||
viewer->getDocument()->setEditingTransform(mat);
|
||||
viewer->setupEditingRoot(csysDragger, &mat);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderDragger::unsetEditViewer(Gui::View3DInventorViewer* viewer)
|
||||
{
|
||||
auto selection = static_cast<SoGroup*>(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<ViewProviderDragger*>(data);
|
||||
|
||||
auto sudoThis = static_cast<ViewProviderDragger *>(data);
|
||||
auto dragger = static_cast<SoFCCSysDragger *>(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<App::GeoFeature *>(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<ViewProviderDragger*>(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<ViewProviderDragger*>(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<App::GeoFeature>();
|
||||
|
||||
if (!geoFeature) {
|
||||
return;
|
||||
}
|
||||
|
||||
geoFeature->Placement.setValue(getDraggerPlacement() * getTransformOrigin().inverse());
|
||||
}
|
||||
|
||||
void ViewProviderDragger::updateTransformFromDragger()
|
||||
{
|
||||
const auto placement = getDraggerPlacement() * getTransformOrigin().inverse();
|
||||
|
||||
pcTransform->translation.setValue(Base::convertTo<SbVec3f>(placement.getPosition()));
|
||||
pcTransform->rotation.setValue(Base::convertTo<SbRotation>(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<SbVec3f>(placement.getPosition()));
|
||||
csysDragger->rotation.setValue(Base::convertTo<SbRotation>(placement.getRotation()));
|
||||
|
||||
draggerPlacement = placement;
|
||||
csysDragger->clearIncrementCounts();
|
||||
}
|
||||
|
||||
void ViewProviderDragger::updateDraggerPosition()
|
||||
{
|
||||
if (!csysDragger) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto placement = getObject<App::GeoFeature>()->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<SbRotation>(from.getRotation()));
|
||||
to->translation.setValue(Base::convertTo<SbVec3f>(from.getPosition()));
|
||||
to->center.setValue(0.0f, 0.0f, 0.0f);
|
||||
to->scaleFactor.setValue(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -25,16 +25,20 @@
|
||||
#define GUI_VIEWPROVIDER_DRAGGER_H
|
||||
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "SoFCCSysDragger.h"
|
||||
#include <Base/Placement.h>
|
||||
#include <App/PropertyGeo.h>
|
||||
|
||||
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<SoFCCSysDragger> 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <Base/ExceptionFactory.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <Base/ServiceProvider.h>
|
||||
#include <Base/PrecisionPy.h>
|
||||
|
||||
#include "ArcOfCirclePy.h"
|
||||
@@ -187,8 +188,12 @@
|
||||
|
||||
#include <OCAF/ImportExportSettings.h>
|
||||
#include "MeasureClient.h"
|
||||
|
||||
#include <FuzzyHelper.h>
|
||||
|
||||
#include <App/Services.h>
|
||||
#include <Services.h>
|
||||
|
||||
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<App::SubObjectPlacementProvider>(new AttacherSubObjectPlacement);
|
||||
Base::registerServiceImplementation<App::CenterOfMassProvider>(new PartCenterOfMass);
|
||||
|
||||
PyMOD_Return(partModule);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -553,6 +553,8 @@ SET(Part_SRCS
|
||||
PreCompiled.h
|
||||
ProgressIndicator.cpp
|
||||
ProgressIndicator.h
|
||||
Services.cpp
|
||||
Services.h
|
||||
TopoShape.cpp
|
||||
TopoShape.h
|
||||
TopoShapeCache.cpp
|
||||
|
||||
52
src/Mod/Part/App/Services.cpp
Normal file
52
src/Mod/Part/App/Services.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Kacper Donat <kacper@kadet.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "Services.h"
|
||||
|
||||
AttacherSubObjectPlacement::AttacherSubObjectPlacement()
|
||||
: attacher(std::make_unique<Attacher::AttachEngine3D>())
|
||||
{
|
||||
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<Base::Vector3d> PartCenterOfMass::ofDocumentObject(App::DocumentObject* object) const
|
||||
{
|
||||
if (const auto feature = dynamic_cast<Part::Feature*>(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 {};
|
||||
}
|
||||
47
src/Mod/Part/App/Services.h
Normal file
47
src/Mod/Part/App/Services.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Kacper Donat <kacper@kadet.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PART_SERVICES_H
|
||||
#define PART_SERVICES_H
|
||||
|
||||
#include <Attacher.h>
|
||||
#include <App/Services.h>
|
||||
|
||||
class AttacherSubObjectPlacement final: public App::SubObjectPlacementProvider
|
||||
{
|
||||
public:
|
||||
AttacherSubObjectPlacement();
|
||||
|
||||
Base::Placement calculate(App::SubObjectT object, Base::Placement basePlacement) const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Attacher::AttachEngine3D> attacher;
|
||||
};
|
||||
|
||||
class PartCenterOfMass final: public App::CenterOfMassProvider
|
||||
{
|
||||
public:
|
||||
std::optional<Base::Vector3d> ofDocumentObject(App::DocumentObject* object) const override;
|
||||
};
|
||||
|
||||
#endif // PART_SERVICES_H
|
||||
Reference in New Issue
Block a user