From 62432046bf52546efbc4f4b716350c82c5ca6e13 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sat, 15 Feb 2025 16:42:43 +0100 Subject: [PATCH 1/5] Gui: Fix empty sketch plane rendering --- src/Base/Tools2D.h | 6 ++++++ src/Mod/Part/Gui/ViewProvider2DObject.cpp | 6 ++++++ src/Mod/Part/Gui/ViewProvider2DObject.h | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Base/Tools2D.h b/src/Base/Tools2D.h index 251c8139bb..9bc10d19c3 100644 --- a/src/Base/Tools2D.h +++ b/src/Base/Tools2D.h @@ -119,6 +119,7 @@ public: inline BoundBox2d(double fX1, double fY1, double fX2, double fY2); ~BoundBox2d() = default; inline bool IsValid() const; + inline bool IsInfinite() const; inline bool IsEqual(const BoundBox2d& bbox, double tolerance) const; // operators @@ -477,6 +478,11 @@ inline bool BoundBox2d::IsValid() const return (MaxX >= MinX) && (MaxY >= MinY); } +inline bool BoundBox2d::IsInfinite() const +{ + return MaxX >= DOUBLE_MAX && MaxY >= DOUBLE_MAX && MinX <= -DOUBLE_MAX && MinY <= -DOUBLE_MAX; +} + inline bool BoundBox2d::IsEqual(const BoundBox2d& bbox, double tolerance) const { return Vector2d(MinX, MinY).IsEqual(Vector2d(bbox.MinX, bbox.MinY), tolerance) diff --git a/src/Mod/Part/Gui/ViewProvider2DObject.cpp b/src/Mod/Part/Gui/ViewProvider2DObject.cpp index e9b62513bf..50f8a20502 100644 --- a/src/Mod/Part/Gui/ViewProvider2DObject.cpp +++ b/src/Mod/Part/Gui/ViewProvider2DObject.cpp @@ -396,6 +396,12 @@ void ViewProvider2DObject::updatePlane() Base::ViewOrthoProjMatrix proj(place.inverse().toMatrix()); Base::BoundBox2d bb = bbox.ProjectBox(&proj); + // when projection of invalid it often results in infinite shapes + // if that happens we simply use some small bounding box to mark plane + if (bb.IsInfinite() || !bb.IsValid()) { + bb = Base::BoundBox2d(-1, -1, 1, 1); + } + SbVec3f verts[4] = { SbVec3f(bb.MinX - horizontalPlanePadding, bb.MinY - verticalPlanePadding, 0), SbVec3f(bb.MinX - horizontalPlanePadding, bb.MaxY + verticalPlanePadding, 0), diff --git a/src/Mod/Part/Gui/ViewProvider2DObject.h b/src/Mod/Part/Gui/ViewProvider2DObject.h index 47280be184..19d34b4f72 100644 --- a/src/Mod/Part/Gui/ViewProvider2DObject.h +++ b/src/Mod/Part/Gui/ViewProvider2DObject.h @@ -42,7 +42,7 @@ class PartGuiExport ViewProvider2DObject : public PartGui::ViewProviderPart PROPERTY_HEADER_WITH_OVERRIDE(PartGui::ViewProvider2DObject); static constexpr float horizontalPlanePadding = 8; - static constexpr float verticalPlanePadding = 5; + static constexpr float verticalPlanePadding = 6; public: /// constructor From 70789826607a89a9ae4601fd6c66d5412248dee4 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 23 Feb 2025 15:01:42 +0100 Subject: [PATCH 2/5] Base: Add Vector3*::Unit* axis constants This is simple helper that can be used to replace hardcoded values of base axis with properly labeled ones. --- src/Base/Vector3D.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Base/Vector3D.h b/src/Base/Vector3D.h index ff931c0d1f..62ad1fb5f1 100644 --- a/src/Base/Vector3D.h +++ b/src/Base/Vector3D.h @@ -101,6 +101,10 @@ template class Vector3 { public: + static const Vector3 UnitX; + static const Vector3 UnitY; + static const Vector3 UnitZ; + using num_type = float_type; using traits_type = float_traits; [[nodiscard]] static constexpr num_type epsilon() @@ -256,7 +260,12 @@ public: //@} }; -// global functions +template +Vector3 const Vector3::UnitX(1.0, 0.0, 0.0); +template +Vector3 const Vector3::UnitY(0.0, 1.0, 0.0); +template +Vector3 const Vector3::UnitZ(0.0, 0.0, 1.0); /// Returns the distance between two points template From 9e2865a8d4d206193157093269421aaf5fed5675 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 23 Feb 2025 15:02:47 +0100 Subject: [PATCH 3/5] Gui: Add SoFCPlacementIndicatorKit node This adds SoFCPlacementIndicatorKit - a node that can be used to show position of object to the user. It can be configured in various ways so it should be a good base for future unification of features like this across the application. --- src/Gui/CMakeLists.txt | 2 + .../Inventor/SoFCPlacementIndicatorKit.cpp | 287 ++++++++++++++++++ src/Gui/Inventor/SoFCPlacementIndicatorKit.h | 103 +++++++ src/Gui/SoFCDB.cpp | 3 + 4 files changed, 395 insertions(+) create mode 100644 src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp create mode 100644 src/Gui/Inventor/SoFCPlacementIndicatorKit.h diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index d264fd83dc..2726ea0752 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1067,6 +1067,7 @@ SET(Inventor_CPP_SRCS Inventor/So3DAnnotation.cpp Inventor/SoAutoZoomTranslation.cpp Inventor/SoAxisCrossKit.cpp + Inventor/SoFCPlacementIndicatorKit.cpp Inventor/SoDrawingGrid.cpp Inventor/SoFCBackgroundGradient.cpp Inventor/SoFCBoundingBox.cpp @@ -1099,6 +1100,7 @@ SET(Inventor_SRCS Inventor/SmSwitchboard.h Inventor/SoAutoZoomTranslation.h Inventor/SoAxisCrossKit.h + Inventor/SoFCPlacementIndicatorKit.h Inventor/SoDrawingGrid.h Inventor/SoFCBackgroundGradient.h Inventor/SoFCBoundingBox.h diff --git a/src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp b/src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp new file mode 100644 index 0000000000..d794b4d4e5 --- /dev/null +++ b/src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 Kacper Donat * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "SoFCPlacementIndicatorKit.h" + +#include "So3DAnnotation.h" +#include "SoAxisCrossKit.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace Gui +{ + +SO_KIT_SOURCE(SoFCPlacementIndicatorKit); + +SoFCPlacementIndicatorKit::SoFCPlacementIndicatorKit() +{ + SO_KIT_CONSTRUCTOR(SoFCPlacementIndicatorKit); + + SO_KIT_ADD_CATALOG_ENTRY(root, SoShapeScale, false, this, "", true); + + SO_KIT_INIT_INSTANCE(); + + SO_NODE_ADD_FIELD(coloredAxis, (true)); + SO_NODE_ADD_FIELD(scaleFactor, (scaleFactorDefault)); + SO_NODE_ADD_FIELD(axisLength, (axisLengthDefault)); + + SO_NODE_ADD_FIELD(parts, (AxisCross)); + SO_NODE_DEFINE_ENUM_VALUE(Part, Axes); + SO_NODE_DEFINE_ENUM_VALUE(Part, PlaneIndicator); + SO_NODE_DEFINE_ENUM_VALUE(Part, Labels); + SO_NODE_DEFINE_ENUM_VALUE(Part, ArrowHeads); + SO_NODE_DEFINE_ENUM_VALUE(Part, AxisCross); + SO_NODE_DEFINE_ENUM_VALUE(Part, AllParts); + SO_NODE_SET_SF_ENUM_TYPE(parts, Part); + + SO_NODE_ADD_FIELD(axes, (AllAxes)); + SO_NODE_DEFINE_ENUM_VALUE(Axes, X); + SO_NODE_DEFINE_ENUM_VALUE(Axes, Y); + SO_NODE_DEFINE_ENUM_VALUE(Axes, Z); + SO_NODE_DEFINE_ENUM_VALUE(Axes, AllAxes); + SO_NODE_SET_SF_ENUM_TYPE(axes, Axes); + + auto root = SO_GET_ANY_PART(this, "root", SoShapeScale); + root->scaleFactor.connectFrom(&scaleFactor); + + recomputeGeometry(); +} + +void SoFCPlacementIndicatorKit::initClass() +{ + SO_KIT_INIT_CLASS(SoFCPlacementIndicatorKit, SoBaseKit, "BaseKit"); +} + +void SoFCPlacementIndicatorKit::notify(SoNotList* l) +{ + SoField* field = l->getLastField(); + + if (field == &parts || field == &axes || field == &axisLength) { + // certainly this is not the fastest way to recompute the geometry as it does recreate + // everything from the scratch. It is however very easy to implement and this node should + // not really change too often so the performance penalty is better than making code that + // is harder to maintain. + recomputeGeometry(); + return; + } + + SoBaseKit::notify(l); +} + +void SoFCPlacementIndicatorKit::recomputeGeometry() +{ + auto root = SO_GET_ANY_PART(this, "root", SoShapeScale); + root->setPart("shape", createGeometry()); +} + +SoSeparator* SoFCPlacementIndicatorKit::createGeometry() +{ + auto sep = new SoSeparator(); + + auto pcBaseColor = new SoBaseColor(); + pcBaseColor->rgb.setValue(0.7f, 0.7f, 0.5f); + + auto pcLightModel = new SoLightModel(); + pcLightModel->model = SoLightModel::BASE_COLOR; + + sep->addChild(pcBaseColor); + sep->addChild(pcLightModel); + + if (parts.getValue() & PlaneIndicator) { + sep->addChild(createPlaneIndicator()); + } + + if (parts.getValue() & Axes) { + sep->addChild(createAxes()); + } + + return sep; +} + +SoSeparator* SoFCPlacementIndicatorKit::createAxes() +{ + const auto cylinderOffset = axisLength.getValue() / 2.f; + + const auto createAxis = [&](const char* label, + Base::Vector3d axis, + uint32_t packedColor, + const double offset) { + App::Color axisColor(packedColor); + + auto sep = new SoSeparator; + + auto rotation = Base::Rotation(Base::Vector3d::UnitY, axis); + auto pcTranslate = new SoTransform(); + pcTranslate->translation.setValue( + Base::convertTo((cylinderOffset + offset) * axis)); + pcTranslate->rotation.setValue(Base::convertTo(rotation)); + + auto pcArrowShaft = new SoCylinder(); + pcArrowShaft->radius = axisThickness / 2.0f; + pcArrowShaft->height = axisLength; + + if (coloredAxis.getValue()) { + auto pcBaseColor = new SoBaseColor(); + pcBaseColor->rgb.setValue(Base::convertTo(axisColor)); + + sep->addChild(pcBaseColor); + } + + sep->addChild(pcTranslate); + sep->addChild(pcArrowShaft); + + if (parts.getValue() & ArrowHeads) { + auto pcArrowHeadTranslation = new SoTranslation(); + pcArrowHeadTranslation->translation.setValue(0.0, cylinderOffset, 0.0); + + auto pcArrowHead = new SoCone(); + pcArrowHead->bottomRadius = arrowHeadRadius; + pcArrowHead->height = arrowHeadHeight; + + auto pcArrowHeadSeparator = new SoSeparator(); + pcArrowHeadSeparator->addChild(pcArrowHeadTranslation); + pcArrowHeadSeparator->addChild(pcArrowHead); + + sep->addChild(pcArrowHeadSeparator); + } + + if (parts.getValue() & Labels) { + auto pcLabelSeparator = new SoSeparator(); + + auto pcLabelTranslation = new SoTranslation(); + pcLabelTranslation->translation.setValue(0.0, cylinderOffset + labelOffset, 0.0); + pcLabelSeparator->addChild(pcLabelTranslation); + + auto pcAxisLabel = new SoFrameLabel(); + pcAxisLabel->string.setValue(label); + pcAxisLabel->textColor.setValue(1.0, 1.0, 1.0); + pcAxisLabel->horAlignment = SoImage::CENTER; + pcAxisLabel->vertAlignment = SoImage::HALF; + pcAxisLabel->border = false; + pcAxisLabel->frame = false; + pcAxisLabel->textUseBaseColor = true; + pcAxisLabel->size = labelFontSize; + + pcLabelSeparator->addChild(pcAxisLabel); + + sep->addChild(pcLabelSeparator); + } + + return sep; + }; + + auto sep = new SoSeparator; + + auto xyOffset = (parts.getValue() & PlaneIndicator) + ? planeIndicatorRadius + planeIndicatorMargin + : axisMargin; + + if (axes.getValue() & X) { + sep->addChild(createAxis("X", + Base::Vector3d::UnitX, + ViewParams::instance()->getAxisXColor(), + xyOffset)); + } + + if (axes.getValue() & Y) { + sep->addChild(createAxis("Y", + Base::Vector3d::UnitY, + ViewParams::instance()->getAxisYColor(), + xyOffset)); + } + + if (axes.getValue() & Z) { + auto zOffset = (parts.getValue() & PlaneIndicator) + ? planeIndicatorMargin + : axisMargin; + sep->addChild(createAxis("Z", + Base::Vector3d::UnitZ, + ViewParams::instance()->getAxisZColor(), + zOffset)); + } + + return sep; +} + +SoSeparator* SoFCPlacementIndicatorKit::createPlaneIndicator() +{ + // cylinders are aligned with Y axis for some reason + auto rotation = Base::Rotation(Base::Vector3d::UnitY, Base::Vector3d::UnitZ); + + auto pcRotation = new SoRotation(); + pcRotation->rotation = Base::convertTo(rotation); + + auto pcComplexity = new SoComplexity(); + pcComplexity->value = 1.0f; + + auto pcCylinder = new SoCylinder(); + pcCylinder->height = 0.f; + pcCylinder->radius = planeIndicatorRadius; + pcCylinder->parts = SoCylinder::TOP; + + const auto gray = App::Color(0.75f, 0.75f, 0.75f); + + auto pcMaterial = new SoMaterial(); + pcMaterial->diffuseColor.setValue(Base::convertTo(gray)); + pcMaterial->ambientColor.connectFrom(&pcMaterial->diffuseColor); + pcMaterial->transparency = planeIndicatorTransparency; + + auto sep = new SoSeparator; + + sep->addChild(pcRotation); + sep->addChild(pcMaterial); + sep->addChild(pcComplexity); + sep->addChild(pcCylinder); + + return sep; +} + +SoFCPlacementIndicatorKit::~SoFCPlacementIndicatorKit() = default; + +} // namespace Gui \ No newline at end of file diff --git a/src/Gui/Inventor/SoFCPlacementIndicatorKit.h b/src/Gui/Inventor/SoFCPlacementIndicatorKit.h new file mode 100644 index 0000000000..2346c8d5fe --- /dev/null +++ b/src/Gui/Inventor/SoFCPlacementIndicatorKit.h @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 Kacper Donat * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef SOFCPLACEMENTINDICATORKIT_H +#define SOFCPLACEMENTINDICATORKIT_H + +#include + +#include + +namespace Gui { + +class GuiExport SoFCPlacementIndicatorKit : public SoBaseKit { + using inherited = SoBaseKit; + + static constexpr double planeIndicatorRadius = 0.4f; + static constexpr double planeIndicatorMargin = 0.2f; + static constexpr double planeIndicatorTransparency = 0.3f; + + static constexpr double axisMargin = 0.0f; + static constexpr double axisLengthDefault = 0.6f; + static constexpr double axisThickness = 0.065f; + + static constexpr double arrowHeadRadius = axisThickness * 1.25f; + static constexpr double arrowHeadHeight = arrowHeadRadius * 3.f; + + static constexpr double labelOffset = 0.4f; + static constexpr int labelFontSize = 9; + + static constexpr double scaleFactorDefault = 40.f; + + SO_KIT_HEADER(SoFCPlacementIndicatorKit); + + SO_KIT_CATALOG_ENTRY_HEADER(root); + +public: + SoFCPlacementIndicatorKit(); + static void initClass(); + + void notify(SoNotList* l) override; + + // clang-format off + enum Part + { + Axes = 1 << 0, + PlaneIndicator = 1 << 1, + Labels = 1 << 2, + ArrowHeads = 1 << 3, + + // common configurations + AllParts = Axes | PlaneIndicator | Labels | ArrowHeads, + AxisCross = Axes | Labels | ArrowHeads + }; + + enum Axis + { + X = 1 << 0, + Y = 1 << 1, + Z = 1 << 2, + AllAxes = X | Y | Z + }; + // clang-format on + + SoSFEnum parts; + SoSFEnum axes; + SoSFBool coloredAxis; + SoSFFloat scaleFactor; + SoSFFloat axisLength; + +private: + void recomputeGeometry(); + + SoSeparator* createOriginIndicator(); + SoSeparator* createGeometry(); + SoSeparator* createAxes(); + SoSeparator* createPlaneIndicator(); + + ~SoFCPlacementIndicatorKit() override; +}; + +} // Gui + +#endif //SOFCPLACEMENTINDICATORKIT_H diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 960270f208..76cb08f20c 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -79,6 +79,8 @@ #include "propertyeditor/PropertyItem.h" #include "ArcEngine.h" +#include + using namespace Gui; using namespace Gui::Inventor; @@ -148,6 +150,7 @@ void Gui::SoFCDB::init() SoMouseWheelEvent ::initClass(); So3DAnnotation ::initClass(); SoDelayedAnnotationsElement ::initClass(); + SoFCPlacementIndicatorKit ::initClass(); PropertyItem ::init(); PropertySeparatorItem ::init(); From cc7d06747850353d65969b2b05051b695b282b7e Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 23 Feb 2025 15:04:34 +0100 Subject: [PATCH 4/5] Gui: SoFrameLabel text color from base color support This adds support for obtaining text color from the state of the graph (base color) to SoFrameLabel nodes. --- src/Gui/SoTextLabel.cpp | 10 ++++++++++ src/Gui/SoTextLabel.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/Gui/SoTextLabel.cpp b/src/Gui/SoTextLabel.cpp index 1a4a29c0aa..a08cc645d3 100644 --- a/src/Gui/SoTextLabel.cpp +++ b/src/Gui/SoTextLabel.cpp @@ -381,6 +381,7 @@ SoFrameLabel::SoFrameLabel() SO_NODE_ADD_FIELD(frame, (true)); SO_NODE_ADD_FIELD(border, (true)); SO_NODE_ADD_FIELD(backgroundUseBaseColor, (false)); + SO_NODE_ADD_FIELD(textUseBaseColor, (false)); //SO_NODE_ADD_FIELD(image, (SbVec2s(0,0), 0, NULL)); } @@ -508,6 +509,15 @@ void SoFrameLabel::GLRender(SoGLRenderAction *action) } } + if (textUseBaseColor.getValue()) { + SoState* state = action->getState(); + const SbColor& diffuse = SoLazyElement::getDiffuse(state, 0); + + if (diffuse != this->textColor.getValue()) { + this->textColor.setValue(diffuse); + } + } + inherited::GLRender(action); } diff --git a/src/Gui/SoTextLabel.h b/src/Gui/SoTextLabel.h index 56b9726711..d2dcf43b91 100644 --- a/src/Gui/SoTextLabel.h +++ b/src/Gui/SoTextLabel.h @@ -120,6 +120,7 @@ public: SoSFBool frame; SoSFBool border; SoSFBool backgroundUseBaseColor; + SoSFBool textUseBaseColor; //SoSFImage image; QPixmap iconPixmap; From 2ee47b4f1db6a3882223e72f7001c0f798a2db13 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 23 Feb 2025 15:05:46 +0100 Subject: [PATCH 5/5] Gui: Add Show Placement utility --- src/Gui/ViewProviderDragger.cpp | 22 ++++++++++++++++++++++ src/Gui/ViewProviderDragger.h | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/src/Gui/ViewProviderDragger.cpp b/src/Gui/ViewProviderDragger.cpp index 70caa50b6b..00b653e709 100644 --- a/src/Gui/ViewProviderDragger.cpp +++ b/src/Gui/ViewProviderDragger.cpp @@ -43,6 +43,7 @@ #include "Control.h" #include "Document.h" #include "SoFCCSysDragger.h" +#include "Inventor/SoFCPlacementIndicatorKit.h" #include "SoFCUnifiedSelection.h" #include "TaskCSysDragger.h" #include "View3DInventorViewer.h" @@ -60,6 +61,14 @@ PROPERTY_SOURCE(Gui::ViewProviderDragger, Gui::ViewProviderDocumentObject) ViewProviderDragger::ViewProviderDragger() { ADD_PROPERTY_TYPE(TransformOrigin, ({}), nullptr, App::Prop_Hidden, nullptr); + ADD_PROPERTY_TYPE(ShowPlacement, + (false), + "Display Options", + App::Prop_None, + "If true, placement of object is additionally rendered."); + + pcPlacement = new SoSwitch; + pcPlacement->whichChild = SO_SWITCH_NONE; }; ViewProviderDragger::~ViewProviderDragger() = default; @@ -98,6 +107,9 @@ void ViewProviderDragger::onChanged(const App::Property* property) if (property == &TransformOrigin) { updateDraggerPosition(); } + else if (property == &ShowPlacement) { + pcPlacement->whichChild = ShowPlacement.getValue() ? SO_SWITCH_ALL : SO_SWITCH_NONE; + } ViewProviderDocumentObject::onChanged(property); } @@ -322,6 +334,16 @@ void ViewProviderDragger::setDraggerPlacement(const Base::Placement& placement) csysDragger->clearIncrementCounts(); } +void ViewProviderDragger::attach(App::DocumentObject* pcObject) +{ + ViewProviderDocumentObject::attach(pcObject); + + getAnnotation()->addChild(pcPlacement); + + auto* pcAxisCrossKit = new Gui::SoFCPlacementIndicatorKit(); + pcPlacement->addChild(pcAxisCrossKit); +} + void ViewProviderDragger::updateDraggerPosition() { if (!csysDragger) { diff --git a/src/Gui/ViewProviderDragger.h b/src/Gui/ViewProviderDragger.h index 21808413a7..a0635ef2c6 100644 --- a/src/Gui/ViewProviderDragger.h +++ b/src/Gui/ViewProviderDragger.h @@ -56,11 +56,17 @@ public: /// destructor. ~ViewProviderDragger() override; + /// Property controlling visibility of the placement indicator, useful for displaying origin + /// position of attached Document Object. + App::PropertyBool ShowPlacement; + /// Origin used when object is transformed. It temporarily changes the origin of object. /// Dragger is normally placed at the transform origin, unless explicitly overridden via /// ViewProviderDragger#setDraggerPlacement() method. App::PropertyPlacement TransformOrigin; + void attach(App::DocumentObject* pcObject) override; + /// Convenience method to obtain the transform origin Base::Placement getTransformOrigin() const { return TransformOrigin.getValue(); } /// Convenience method to set the transform origin @@ -114,6 +120,7 @@ protected: CoinPtr csysDragger = nullptr; ViewProvider *forwardedViewProvider = nullptr; + CoinPtr pcPlacement; private: static void dragStartCallback(void *data, SoDragger *d); static void dragFinishCallback(void *data, SoDragger *d);