Use longest edge in face for horizontal/vertical alignment (#20374)

* App: Add second direction to getCameraAlignmentDirection()

* Part: Find longest face edge for horizontal/vertical alignment

* Gui: Use longest face edge for horizontal/vertical alignment

* App: Improve horizontal/vertical alignment for Datums and LCS
This commit is contained in:
Bas Ruigrok
2025-04-14 18:20:49 +02:00
committed by GitHub
parent d91b3e0517
commit 921620ba8a
7 changed files with 62 additions and 20 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
*

View File

@@ -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);

View File

@@ -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<std::tuple<TopoDS_Shape, Standard_Real>> 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 = Geometry::fromShape(get<0>(longestEdge.value()), true)) {
if (const std::unique_ptr<GeomLine> geomLine(static_cast<GeomCurve*>(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 = Geometry::fromShape(topoShape.getSubShape(TopAbs_EDGE, 1), true)) {
const std::unique_ptr<GeomLine> geomLine(static_cast<GeomCurve*>(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) {

View File

@@ -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);