diff --git a/src/App/Datums.cpp b/src/App/Datums.cpp index b0279766d9..f4cce14b0f 100644 --- a/src/App/Datums.cpp +++ b/src/App/Datums.cpp @@ -58,10 +58,15 @@ DatumElement::DatumElement(bool hideRole) DatumElement::~DatumElement() = default; -bool DatumElement::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const +bool DatumElement::getCameraAlignmentDirection(Base::Vector3d& directionZ, Base::Vector3d& directionX, const char* subname) const { Q_UNUSED(subname); - Placement.getValue().getRotation().multVec(baseDir, direction); + + Placement.getValue().getRotation().multVec(baseDir, directionZ); + + if (baseDir == Base::Vector3d::UnitZ) { + Placement.getValue().getRotation().multVec(Base::Vector3d::UnitX, directionX); + } return true; } @@ -142,11 +147,14 @@ LocalCoordinateSystem::LocalCoordinateSystem() LocalCoordinateSystem::~LocalCoordinateSystem() = default; -bool LocalCoordinateSystem::getCameraAlignmentDirection(Base::Vector3d& direction, +bool LocalCoordinateSystem::getCameraAlignmentDirection(Base::Vector3d& directionZ, + Base::Vector3d& directionX, const char* subname) const { Q_UNUSED(subname); - Placement.getValue().getRotation().multVec(Base::Vector3d(0., 0., 1.), direction); + + Placement.getValue().getRotation().multVec(Base::Vector3d::UnitZ, directionZ); + Placement.getValue().getRotation().multVec(Base::Vector3d::UnitX, directionX); return true; } diff --git a/src/App/Datums.h b/src/App/Datums.h index e59b854728..3c59a015e5 100644 --- a/src/App/Datums.h +++ b/src/App/Datums.h @@ -55,7 +55,7 @@ public: Base::Vector3d getDirection() const; Base::Vector3d getBaseDirection() const; - bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override; + bool getCameraAlignmentDirection(Base::Vector3d& directionZ, Base::Vector3d& directionX, const char* subname) const override; /// Returns true if this DatumElement is part of a App::Origin. bool isOriginFeature() const; @@ -118,7 +118,7 @@ public: return "Gui::ViewProviderCoordinateSystem"; } - bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override; + bool getCameraAlignmentDirection(Base::Vector3d& directionZ, Base::Vector3d& directionX, const char* subname) const override; /** @name Axis and plane access * This functions returns casted axis and planes objects and asserts they are set correctly diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 298d0cdb96..1c39bd4e70 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -213,10 +213,11 @@ void GeoFeature::setMaterialAppearance(const App::Material& material) Q_UNUSED(material) } -bool GeoFeature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const +bool GeoFeature::getCameraAlignmentDirection(Base::Vector3d& directionZ, Base::Vector3d& directionX, const char* subname) const { Q_UNUSED(subname) - Q_UNUSED(direction) + Q_UNUSED(directionZ) + Q_UNUSED(directionX) return false; } diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index 67f43a3bd6..6636655a69 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -151,11 +151,13 @@ public: /** * @brief Virtual function to get the camera alignment direction * - * Finds a direction to align the camera with. + * Finds a directionZ to align the camera with. + * May also find an optional directionX which could be used for horizontal or vertical alignment. * - * @return bool whether or not a direction is found. + * @return bool whether or not a directionZ is found. */ - virtual bool getCameraAlignmentDirection(Base::Vector3d& direction, + virtual bool getCameraAlignmentDirection(Base::Vector3d& directionZ, + Base::Vector3d& directionX, const char* subname = nullptr) const; /** Search sub element using internal cached geometry * diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 078abfa336..ff7890285f 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -3564,11 +3564,13 @@ void View3DInventorViewer::alignToSelection() const auto geoFeatureSubName = !splitSubName.empty() ? splitSubName.back() : ""; Base::Vector3d alignmentZ; - if (geoFeature->getCameraAlignmentDirection(alignmentZ, geoFeatureSubName.c_str())) { + Base::Vector3d alignmentX (0, 0, 0); + if (geoFeature->getCameraAlignmentDirection(alignmentZ, alignmentX, geoFeatureSubName.c_str())) { - // Find the x alignment - Base::Vector3d alignmentX; - Base::Rotation(Base::Vector3d(0, 0, -1), alignmentZ).multVec(Base::Vector3d(1, 0, 0), alignmentX); + // Find a x alignment if the geoFeature did not suggest any + if (alignmentX == Base::Vector3d (0, 0, 0)) { + Base::Rotation(-Base::Vector3d::UnitZ, alignmentZ).multVec(Base::Vector3d::UnitX, alignmentX); + } // Convert to global coordinates globalRotation.multVec(alignmentZ, alignmentZ); diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 72797760d1..82fa1e94fc 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -1696,7 +1696,7 @@ bool Feature::isElementMappingDisabled(App::PropertyContainer* container) // return false; } -bool Feature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const +bool Feature::getCameraAlignmentDirection(Base::Vector3d& directionZ, Base::Vector3d &directionX, const char* subname) const { const auto topoShape = getTopoShape(this, subname, true); @@ -1711,7 +1711,36 @@ bool Feature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* gp_Pnt point; gp_Vec vector; BRepGProp_Face(face).Normal(0, 0, point, vector); - direction = Base::Vector3d(vector.X(), vector.Y(), vector.Z()).Normalize(); + directionZ = Base::Vector3d(vector.X(), vector.Y(), vector.Z()).Normalize(); + + // Try to find a second alignment direction + // Use the longest straight edge for horizontal or vertical alignment + std::optional> longestEdge; // Tuple of (shape, length of edge) + for (TopExp_Explorer Ex (face, TopAbs_EDGE); Ex.More(); Ex.Next()) { + const auto edge = TopoDS::Edge(Ex.Current()); + const auto edgeTopoShape = TopoShape(edge); + if (!edgeTopoShape.isLinearEdge()) { + continue; + } + + GProp_GProps props; + BRepGProp::LinearProperties(edge, props); + const auto length = props.Mass(); + + // Check if this edge is the longest + if (!longestEdge.has_value() || length > get<1>(longestEdge.value())) { + longestEdge = std::tuple(edge, length); + } + } + + if (longestEdge.has_value()) { + if (const std::unique_ptr geometry = Geometry::fromShape(get<0>(longestEdge.value()), true)) { + if (const std::unique_ptr geomLine(static_cast(geometry.get())->toLine()); geomLine) { + directionX = geomLine->getDir().Normalize(); + } + } + } + return true; } catch (Standard_TypeMismatch&) { @@ -1725,13 +1754,13 @@ bool Feature::getCameraAlignmentDirection(Base::Vector3d& direction, const char* 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(); + directionZ = geomLine->getDir().Normalize(); return true; } } } - return GeoFeature::getCameraAlignmentDirection(direction, subname); + return GeoFeature::getCameraAlignmentDirection(directionZ, directionX, subname); } void Feature::guessNewLink(std::string &replacementName, DocumentObject *base, const char *oldLink) { diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index 6c1a63437b..2496c4032a 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -153,7 +153,7 @@ public: static bool isElementMappingDisabled(App::PropertyContainer *container); - bool getCameraAlignmentDirection(Base::Vector3d &direction, const char *subname) const override; + bool getCameraAlignmentDirection(Base::Vector3d &directionZ, Base::Vector3d &directionX, const char *subname) const override; static void guessNewLink(std::string &replacementName, DocumentObject *base, const char *oldLink);