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.
This commit is contained in:
@@ -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
|
||||
|
||||
287
src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp
Normal file
287
src/Gui/Inventor/SoFCPlacementIndicatorKit.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// 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 "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <sstream>
|
||||
|
||||
#include <Inventor/nodes/SoBaseColor.h>
|
||||
#include <Inventor/nodes/SoComplexity.h>
|
||||
#include <Inventor/nodes/SoCone.h>
|
||||
#include <Inventor/nodes/SoCylinder.h>
|
||||
#include <Inventor/nodes/SoDrawStyle.h>
|
||||
#include <Inventor/nodes/SoLightModel.h>
|
||||
#include <Inventor/nodes/SoMaterial.h>
|
||||
#include <Inventor/nodes/SoRotation.h>
|
||||
#include <Inventor/nodes/SoSeparator.h>
|
||||
#include <Inventor/nodes/SoTransform.h>
|
||||
#include <Inventor/nodes/SoTranslation.h>
|
||||
#include <Inventor/nodes/SoFontStyle.h>
|
||||
#endif
|
||||
|
||||
#include "SoFCPlacementIndicatorKit.h"
|
||||
|
||||
#include "So3DAnnotation.h"
|
||||
#include "SoAxisCrossKit.h"
|
||||
|
||||
#include <SoTextLabel.h>
|
||||
#include <Utilities.h>
|
||||
#include <ViewParams.h>
|
||||
#include <ViewProvider.h>
|
||||
#include <App/Color.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
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<SbVec3f>((cylinderOffset + offset) * axis));
|
||||
pcTranslate->rotation.setValue(Base::convertTo<SbRotation>(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<SbColor>(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<SbRotation>(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<SbColor>(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
|
||||
103
src/Gui/Inventor/SoFCPlacementIndicatorKit.h
Normal file
103
src/Gui/Inventor/SoFCPlacementIndicatorKit.h
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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 SOFCPLACEMENTINDICATORKIT_H
|
||||
#define SOFCPLACEMENTINDICATORKIT_H
|
||||
|
||||
#include <Inventor/nodekits/SoBaseKit.h>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
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
|
||||
@@ -79,6 +79,8 @@
|
||||
#include "propertyeditor/PropertyItem.h"
|
||||
#include "ArcEngine.h"
|
||||
|
||||
#include <Inventor/SoFCPlacementIndicatorKit.h>
|
||||
|
||||
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user