From 130d5618c23fc428d00dad2cb8dd72e11c30795d Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 15 May 2025 14:09:49 +0200 Subject: [PATCH] Measure: Extend angle measurements Support to measure the angle using a planar B-spline surface --- src/Mod/Part/App/MeasureClient.cpp | 18 ++- src/Mod/Part/App/VectorAdapter.cpp | 191 ++++++++++++++++++----------- src/Mod/Part/App/VectorAdapter.h | 69 ++++++----- 3 files changed, 169 insertions(+), 109 deletions(-) diff --git a/src/Mod/Part/App/MeasureClient.cpp b/src/Mod/Part/App/MeasureClient.cpp index 08c14315fc..52d6ace3fe 100644 --- a/src/Mod/Part/App/MeasureClient.cpp +++ b/src/Mod/Part/App/MeasureClient.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -56,12 +57,14 @@ #include #include +#include "Attacher.h" #include "VectorAdapter.h" #include "PartFeature.h" #include "MeasureClient.h" using namespace Part; +using Attacher::AttachEnginePlane; // From: https://github.com/Celemation/FreeCAD/blob/joel_selection_summary_demo/src/Gui/Selection/SelectionSummary.cpp @@ -183,10 +186,19 @@ App::MeasureElementType PartMeasureTypeCb(App::DocumentObject* ob, const char* s BRepAdaptor_Surface surface(face); switch (surface.GetType()) { - case GeomAbs_Cylinder: { return App::MeasureElementType::CYLINDER; } - case GeomAbs_Plane: { return App::MeasureElementType::PLANE; } + case GeomAbs_Cylinder: { + return App::MeasureElementType::CYLINDER; + } + case GeomAbs_Plane: { + return App::MeasureElementType::PLANE; + } default: { - return App::MeasureElementType::SURFACE; } + TopLoc_Location loc; + Handle(Geom_Surface) surf = BRep_Tool::Surface(face, loc); + GeomLib_IsPlanarSurface check(surf, AttachEnginePlane::planarPrecision()); + return check.IsPlanar() ? App::MeasureElementType::PLANE + : App::MeasureElementType::SURFACE; + } } } case TopAbs_SHELL: { diff --git a/src/Mod/Part/App/VectorAdapter.cpp b/src/Mod/Part/App/VectorAdapter.cpp index a2f9cdec58..7801edac71 100644 --- a/src/Mod/Part/App/VectorAdapter.cpp +++ b/src/Mod/Part/App/VectorAdapter.cpp @@ -31,6 +31,7 @@ #include "PrimitiveFeature.h" #include "PartFeature.h" +#include "Attacher.h" #include #include @@ -40,117 +41,163 @@ #include #include #include +#include +#include +using Attacher::AttachEnginePlane; namespace Part { -VectorAdapter::VectorAdapter() : status(false), vector() +VectorAdapter::VectorAdapter() + : status(false) { } -VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) : - status(false), vector(), origin(pickedPointIn) +VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) + : status(false) + , origin(pickedPointIn) { - Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn); - if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) - { - Handle(Geom_ElementarySurface) eSurface = Handle(Geom_ElementarySurface)::DownCast(surface); - gp_Dir direction = eSurface->Axis().Direction(); - vector = direction; + std::vector> funcs = { + [this](const TopoDS_Face& face, const gp_Vec& vec) { + return this->handleElementarySurface(face, vec); + }, + [this](const TopoDS_Face& face, const gp_Vec& vec) { + return this->handlePlanarSurface(face, vec); + } + }; + for (const auto& it : funcs) { + if (it(faceIn, pickedPointIn)) { + break; + } + } +} + +VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn) + : status(false) + , origin(pickedPointIn) +{ + TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True); + TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True); + vector = convert(lastVertex) - convert(firstVertex); + if (vector.Magnitude() < Precision::Confusion()) { + return; + } vector.Normalize(); - if (faceIn.Orientation() == TopAbs_REVERSED) { - vector.Reverse(); - } - if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) || - surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) - ) - { - origin = eSurface->Axis().Location().XYZ(); - projectOriginOntoVector(pickedPointIn); - } - else { - origin = pickedPointIn + vector; - } + status = true; - } + projectOriginOntoVector(pickedPointIn); } -VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn) : - status(false), vector(), origin(pickedPointIn) +VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In) + : status(false) { - TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True); - TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True); - vector = convert(lastVertex) - convert(firstVertex); - if (vector.Magnitude() < Precision::Confusion()) { - return; - } - vector.Normalize(); + vector = convert(vertex2In) - convert(vertex1In); + vector.Normalize(); - status = true; - projectOriginOntoVector(pickedPointIn); + //build origin half way. + gp_Vec tempVector = (convert(vertex2In) - convert(vertex1In)); + double mag = tempVector.Magnitude(); + tempVector.Normalize(); + tempVector *= (mag / 2.0); + origin = tempVector + convert(vertex1In); + + status = true; } -VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In) : - status(false), vector(), origin() +VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2) + : status(false) { - vector = convert(vertex2In) - convert(vertex1In); - vector.Normalize(); + vector = vector2- vector1; + vector.Normalize(); - //build origin half way. - gp_Vec tempVector = (convert(vertex2In) - convert(vertex1In)); - double mag = tempVector.Magnitude(); - tempVector.Normalize(); - tempVector *= (mag / 2.0); - origin = tempVector + convert(vertex1In); + //build origin half way. + gp_Vec tempVector = vector2 - vector1; + double mag = tempVector.Magnitude(); + tempVector.Normalize(); + tempVector *= (mag / 2.0); + origin = tempVector + vector1; - status = true; + status = true; } -VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2) : - status(false), vector(), origin() +bool VectorAdapter::handleElementarySurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) { - vector = vector2- vector1; - vector.Normalize(); + Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn); + if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) { + Handle(Geom_ElementarySurface) eSurface = Handle(Geom_ElementarySurface)::DownCast(surface); + gp_Dir direction = eSurface->Axis().Direction(); + vector = direction; + vector.Normalize(); + if (faceIn.Orientation() == TopAbs_REVERSED) { + vector.Reverse(); + } + if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) || + surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) + ) { + origin = eSurface->Axis().Location().XYZ(); + projectOriginOntoVector(pickedPointIn); + } + else { + origin = pickedPointIn + vector; + } + status = true; + return true; + } - //build origin half way. - gp_Vec tempVector = vector2 - vector1; - double mag = tempVector.Magnitude(); - tempVector.Normalize(); - tempVector *= (mag / 2.0); - origin = tempVector + vector1; + return false; +} - status = true; +bool VectorAdapter::handlePlanarSurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) +{ + Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn); + GeomLib_IsPlanarSurface check(surface, AttachEnginePlane::planarPrecision()); + if (check.IsPlanar()) { + double u1 {}; + double u2 {}; + double v1 {}; + double v2 {}; + surface->Bounds(u1, u2, v1, v2); + GeomLProp_SLProps prop(surface, u1, v1, 1, Precision::Confusion()); + if (prop.IsNormalDefined()) { + vector = prop.Normal(); + vector.Normalize(); + if (faceIn.Orientation() == TopAbs_REVERSED) { + vector.Reverse(); + } + origin = pickedPointIn + vector; + status = true; + return true; + } + } + + return false; } void VectorAdapter::projectOriginOntoVector(const gp_Vec &pickedPointIn) { - Handle(Geom_Curve) heapLine = new Geom_Line(origin.XYZ(), vector.XYZ()); - gp_Pnt tempPoint(pickedPointIn.XYZ()); - GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine); - if (projection.NbPoints() < 1) { - return; - } - origin.SetXYZ(projection.Point(1).XYZ()); + Handle(Geom_Curve) heapLine = new Geom_Line(origin.XYZ(), vector.XYZ()); + gp_Pnt tempPoint(pickedPointIn.XYZ()); + GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine); + if (projection.NbPoints() >= 1) { + origin.SetXYZ(projection.Point(1).XYZ()); + } } VectorAdapter::operator gp_Lin() const { - gp_Pnt tempOrigin; - tempOrigin.SetXYZ(origin.XYZ()); - return gp_Lin(tempOrigin, gp_Dir(vector)); + gp_Pnt tempOrigin; + tempOrigin.SetXYZ(origin.XYZ()); + return gp_Lin(tempOrigin, gp_Dir(vector)); } /*convert a vertex to vector*/ gp_Vec VectorAdapter::convert(const TopoDS_Vertex &vertex) { - gp_Pnt point = BRep_Tool::Pnt(vertex); - gp_Vec out(point.X(), point.Y(), point.Z()); - return out; + gp_Pnt point = BRep_Tool::Pnt(vertex); + gp_Vec out(point.X(), point.Y(), point.Z()); + return out; } - - } - diff --git a/src/Mod/Part/App/VectorAdapter.h b/src/Mod/Part/App/VectorAdapter.h index 2196401305..5b6b8a2401 100644 --- a/src/Mod/Part/App/VectorAdapter.h +++ b/src/Mod/Part/App/VectorAdapter.h @@ -43,45 +43,46 @@ namespace Part class VectorAdapter { public: - /*!default construction isValid is set to false*/ - VectorAdapter(); - /*!Build a vector from a faceIn - * @param faceIn vector will be normal to plane and equal to cylindrical axis. - * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ - VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn); - /*!Build a vector from an edgeIn - * @param edgeIn vector will be lastPoint - firstPoint. - * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ - VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn); - /*!Build a vector From 2 vertices. - *vector will be equal to @param vertex2In - @param vertex1In.*/ - VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In); - /*!Build a vector From 2 vectors. - *vector will be equal to @param vector2 - @param vector1.*/ - VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2); + /*!default construction isValid is set to false*/ + VectorAdapter(); + /*!Build a vector from a faceIn + * @param faceIn vector will be normal to plane and equal to cylindrical axis. + * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ + VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn); + /*!Build a vector from an edgeIn + * @param edgeIn vector will be lastPoint - firstPoint. + * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ + VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn); + /*!Build a vector From 2 vertices. + *vector will be equal to @param vertex2In - @param vertex1In.*/ + VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In); + /*!Build a vector From 2 vectors. + *vector will be equal to @param vector2 - @param vector1.*/ + VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2); - /*!make sure no errors in vector construction. - * @return true = vector is good. false = vector is NOT good.*/ - bool isValid() const {return status;} - /*!get the calculated vector. - * @return the vector. use isValid to ensure correct results.*/ - operator gp_Vec() const {return vector;}//explicit bombs - /*!build occ line used for extrema calculation*/ - operator gp_Lin() const;//explicit bombs - gp_Vec getPickPoint() const {return origin;} - - operator Base::Vector3d() const { - return Base::Vector3d(vector.X(), vector.Y(), vector.Z()); - } + /*!make sure no errors in vector construction. + * @return true = vector is good. false = vector is NOT good.*/ + bool isValid() const {return status;} + /*!get the calculated vector. + * @return the vector. use isValid to ensure correct results.*/ + explicit operator gp_Vec() const {return vector;} + /*!build occ line used for extrema calculation*/ + explicit operator gp_Lin() const; + gp_Vec getPickPoint() const {return origin;} + explicit operator Base::Vector3d() const { + return Base::Vector3d(vector.X(), vector.Y(), vector.Z()); + } static gp_Vec convert(const TopoDS_Vertex& vertex); - private: - void projectOriginOntoVector(const gp_Vec &pickedPointIn); - bool status; - gp_Vec vector; - gp_Vec origin; +private: + void projectOriginOntoVector(const gp_Vec &pickedPointIn); + bool handleElementarySurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn); + bool handlePlanarSurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn); + bool status; + gp_Vec vector; + gp_Vec origin; };