From 4c45f385741a2463cb060779b21b8db3d23cc5c3 Mon Sep 17 00:00:00 2001 From: Bas Ruigrok Date: Sun, 12 May 2024 14:31:09 +0200 Subject: [PATCH 1/4] App: Add getCameraAlignmentDirection() to GeoFeature --- src/App/GeoFeature.cpp | 7 +++++++ src/App/GeoFeature.h | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 1d9e6d763c..b09323d4d7 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -209,6 +209,13 @@ void GeoFeature::setMaterialAppearance(const App::Material& material) Q_UNUSED(material) } +bool GeoFeature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const +{ + Q_UNUSED(subname) + Q_UNUSED(direction) + return false; +} + #ifdef FC_USE_TNP_FIX bool GeoFeature::hasMissingElement(const char* subname) { diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index 025d5f969e..d483a45243 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -141,6 +141,15 @@ public: * appearance from an App::Material object. */ virtual void setMaterialAppearance(const App::Material& material); + + /** + * @brief Virtual function to get the camera alignment direction + * + * Finds a direction to align the camera with. + * + * @return bool whether or not a direction is found. + */ + virtual bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname = nullptr) const; #ifdef FC_USE_TNP_FIX /** Search sub element using internal cached geometry * From f7078d13d4393bd6b8434c4e638dd8388a63b7ed Mon Sep 17 00:00:00 2001 From: Bas Ruigrok Date: Sun, 12 May 2024 14:37:19 +0200 Subject: [PATCH 2/4] Part: Implement getCameraAlignmentDirection() for PartFeature Returns normal of a face or direction of an edge --- src/Mod/Part/App/PartFeature.cpp | 40 ++++++++++++++++++++++++++++++++ src/Mod/Part/App/PartFeature.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index aae5563c10..32df8cc8e0 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -35,6 +35,7 @@ # include # include # include +# include # include # include # include @@ -68,6 +69,7 @@ #include #include +#include "Geometry.h" #include "PartFeature.h" #include "PartFeaturePy.h" #include "PartPyCXX.h" @@ -1410,6 +1412,44 @@ bool Feature::isElementMappingDisabled(App::PropertyContainer* container) // return false; } +bool Feature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const +{ + const auto topoShape = getTopoShape(this, subname, true); + + if (topoShape.isNull()) { + return false; + } + + // Face normal + if (topoShape.isPlanar()) { + try { + const auto face = TopoDS::Face(topoShape.getShape()); + gp_Pnt point; + gp_Vec vector; + BRepGProp_Face(face).Normal(0, 0, point, vector); + direction = Base::Vector3d(vector.X(), vector.Y(), vector.Z()).Normalize(); + return true; + } + catch (Standard_TypeMismatch&) { + // Shape is not a face, do nothing + } + } + + // Edge direction + const size_t edgeCount = topoShape.countSubShapes(TopAbs_EDGE); + if (edgeCount == 1 && topoShape.isLinearEdge()) { + if (const std::unique_ptr geometry = Geometry::fromShape(topoShape.getSubShape(TopAbs_EDGE, 1), true)) { + const std::unique_ptr geomLine(static_cast(geometry.get())->toLine()); + if (geomLine) { + direction = geomLine->getDir().Normalize(); + return true; + } + } + } + + return GeoFeature::getCameraAlignmentDirection(direction, subname); +} + // --------------------------------------------------------- PROPERTY_SOURCE(Part::FilletBase, Part::Feature) diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index 6a1af4d48a..4387ccdd74 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -152,6 +152,8 @@ public: create(const TopoShape& shape, const char* name = nullptr, App::Document* document = nullptr); static bool isElementMappingDisabled(App::PropertyContainer *container); + + bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override; #ifdef FC_USE_TNP_FIX const std::vector& searchElementCache(const std::string &element, From 52b6f4f5ad088b4f07d7830e390b533fa5b09ff6 Mon Sep 17 00:00:00 2001 From: Bas Ruigrok Date: Sun, 12 May 2024 14:45:16 +0200 Subject: [PATCH 3/4] Gui: Add alignToSelection() method and command --- src/Gui/CommandView.cpp | 28 +++++++++++++++++++++++++++ src/Gui/View3DInventor.cpp | 7 +++++++ src/Gui/View3DInventorViewer.cpp | 33 ++++++++++++++++++++++++++++++++ src/Gui/View3DInventorViewer.h | 2 ++ 4 files changed, 70 insertions(+) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index f4cb50cd8c..6e77adfb17 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -4076,6 +4076,33 @@ bool StdRecallWorkingView::isActive() return view && view->getViewer()->hasHomePosition(); } +//=========================================================================== +// Std_AlignToSelection +//=========================================================================== + +DEF_STD_CMD_A(StdCmdAlignToSelection) + +StdCmdAlignToSelection::StdCmdAlignToSelection() + : Command("Std_AlignToSelection") +{ + sGroup = "Standard-View"; + sMenuText = QT_TR_NOOP("Align to selection"); + sToolTipText = QT_TR_NOOP("Align the view with the selection"); + sWhatsThis = "Std_AlignToSelection"; + eType = Alter3DView; +} + +void StdCmdAlignToSelection::activated(int iMsg) +{ + Q_UNUSED(iMsg); + doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"AlignToSelection\")"); +} + +bool StdCmdAlignToSelection::isActive() +{ + return getGuiApplication()->sendHasMsgToActiveView("AlignToSelection"); +} + //=========================================================================== // Instantiation //=========================================================================== @@ -4107,6 +4134,7 @@ void CreateViewStdCommands() rcCmdMgr.addCommand(new StdStoreWorkingView()); rcCmdMgr.addCommand(new StdRecallWorkingView()); rcCmdMgr.addCommand(new StdCmdViewGroup()); + rcCmdMgr.addCommand(new StdCmdAlignToSelection()); rcCmdMgr.addCommand(new StdCmdViewExample1()); rcCmdMgr.addCommand(new StdCmdViewExample2()); diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 937128baf1..7770a71f2e 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -408,6 +408,10 @@ bool View3DInventor::onMsg(const char* pMsg, const char** ppReturn) getGuiDocument()->saveCopy(); return true; } + else if (strcmp("AlignToSelection", pMsg) == 0) { + _viewer->alignToSelection(); + return true; + } else if (strcmp("ZoomIn", pMsg) == 0) { View3DInventorViewer* viewer = getViewer(); viewer->navigationStyle()->zoomIn(); @@ -511,6 +515,9 @@ bool View3DInventor::onHasMsg(const char* pMsg) const else if(strncmp("Dump",pMsg,4) == 0) { return true; } + else if (strcmp("AlignToSelection", pMsg) == 0) { + return true; + } if (strcmp("ZoomIn", pMsg) == 0) { return true; } diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index ee5313b081..c792191e0c 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -3341,6 +3341,39 @@ void View3DInventorViewer::viewSelection() } } +void View3DInventorViewer::alignToSelection() +{ + if (!getCamera()) { + return; + } + + const auto selection = Selection().getSelection(); + + // Empty selection + if (selection.empty()) { + return; + } + + // Too much selections + if (selection.size() > 1) { + return; + } + + // Get the geo feature + App::GeoFeature* geoFeature = nullptr; + std::pair elementName; + App::GeoFeature::resolveElement(selection[0].pObject, selection[0].SubName, elementName, false, App::GeoFeature::ElementNameType::Normal, nullptr, nullptr, &geoFeature); + if (!geoFeature) { + return; + } + + Base::Vector3d direction; + if (geoFeature->getCameraAlignmentDirection(direction, selection[0].SubName)) { + const auto orientation = SbRotation(SbVec3f(0, 0, 1), Base::convertTo(direction)); + setCameraOrientation(orientation); + } +} + /** * @brief Decide if it should be possible to start any animation * diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index eca7f186b0..cdcdc5c853 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -414,6 +414,8 @@ public: */ void viewSelection(); + void alignToSelection(); + void setGradientBackground(Background); Background getGradientBackground() const; void setGradientBackgroundColor(const SbColor& fromColor, From c985c3ddee4cd9b0e7f805e5aa90f0d7ec689df3 Mon Sep 17 00:00:00 2001 From: Bas Ruigrok Date: Thu, 9 May 2024 18:01:18 +0200 Subject: [PATCH 4/4] Gui: Add alignToSelection() icon and add to toolbar Co-authored-by: Max Wilfinger <6246609+maxwxyz@users.noreply.github.com> --- src/Gui/CommandView.cpp | 4 +- src/Gui/Icons/align-to-selection.svg | 148 +++++++++++++++++++++++++++ src/Gui/Icons/resource.qrc | 1 + src/Gui/Workbench.cpp | 2 +- 4 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 src/Gui/Icons/align-to-selection.svg diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 6e77adfb17..bf9427538c 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -4079,16 +4079,16 @@ bool StdRecallWorkingView::isActive() //=========================================================================== // Std_AlignToSelection //=========================================================================== - DEF_STD_CMD_A(StdCmdAlignToSelection) StdCmdAlignToSelection::StdCmdAlignToSelection() : Command("Std_AlignToSelection") { - sGroup = "Standard-View"; + sGroup = "View"; sMenuText = QT_TR_NOOP("Align to selection"); sToolTipText = QT_TR_NOOP("Align the view with the selection"); sWhatsThis = "Std_AlignToSelection"; + sPixmap = "align-to-selection"; eType = Alter3DView; } diff --git a/src/Gui/Icons/align-to-selection.svg b/src/Gui/Icons/align-to-selection.svg new file mode 100644 index 0000000000..0d4e894525 --- /dev/null +++ b/src/Gui/Icons/align-to-selection.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [maxwxyz] + + + https://www.freecad.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/ + + + FreeCAD LGPL2+ + + + 2024 + + + + + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index 614a660e4b..7a1decff26 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -235,6 +235,7 @@ colors.svg px.svg AddonManager.svg + align-to-selection.svg Group.svg Geofeaturegroup.svg Geoassembly.svg diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index dcc97d9561..e2cdb337da 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -810,7 +810,7 @@ ToolBarItem* StdWorkbench::setupToolBars() const // View auto view = new ToolBarItem( root ); view->setCommand("View"); - *view << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewGroup" + *view << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewGroup" << "Std_AlignToSelection" << "Separator" << "Std_DrawStyle" << "Std_TreeViewActions" << "Separator" << "Std_MeasureDistance" << "Std_Measure";