From 04a6f38ec80c805a32d507b77417fb3b7db2b8c1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 Oct 2024 11:59:44 +0200 Subject: [PATCH 1/2] Measure: When measuring the distance between circles then use the center points as reference See forum: https://forum.freecad.org/viewtopic.php?t=91570 --- src/Mod/Measure/App/MeasureDistance.cpp | 101 ++++++++++++++++++++---- src/Mod/Measure/App/MeasureDistance.h | 10 +++ 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/Mod/Measure/App/MeasureDistance.cpp b/src/Mod/Measure/App/MeasureDistance.cpp index e2ac25b126..aa748856df 100644 --- a/src/Mod/Measure/App/MeasureDistance.cpp +++ b/src/Mod/Measure/App/MeasureDistance.cpp @@ -27,7 +27,13 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include #include "MeasureDistance.h" @@ -178,6 +184,44 @@ bool MeasureDistance::getShape(App::PropertyLinkSub* prop, TopoDS_Shape& rShape) return true; } +bool MeasureDistance::distanceCircleCircle(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) +{ + auto circle1 = asCircle(shape1); + auto circle2 = asCircle(shape2); + if (!circle1.IsNull() && !circle2.IsNull()) { + const gp_Pnt p1 = circle1->Location(); + const gp_Pnt p2 = circle2->Location(); + setValues(p1, p2); + return true; + } + + return false; +} + +void MeasureDistance::distanceGeneric(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) +{ + // Calculate the extrema + BRepExtrema_DistShapeShape measure(shape1, shape2); + if (!measure.IsDone() || measure.NbSolution() < 1) { + throw Base::RuntimeError("Could not get extrema"); + } + + const gp_Pnt p1 = measure.PointOnShape1(1); + const gp_Pnt p2 = measure.PointOnShape2(1); + setValues(p1, p2); +} + +void MeasureDistance::setValues(const gp_Pnt& p1, const gp_Pnt& p2) +{ + Position1.setValue(p1.X(), p1.Y(), p1.Z()); + Position2.setValue(p2.X(), p2.Y(), p2.Z()); + + const gp_Pnt delta = p2.XYZ() - p1.XYZ(); + Distance.setValue(p1.Distance(p2)); + DistanceX.setValue(std::fabs(delta.X())); + DistanceY.setValue(std::fabs(delta.Y())); + DistanceZ.setValue(std::fabs(delta.Z())); +} App::DocumentObjectExecReturn* MeasureDistance::execute() { @@ -207,24 +251,11 @@ App::DocumentObjectExecReturn* MeasureDistance::execute() return new App::DocumentObjectExecReturn("Could not get shape"); } - // Calculate the extrema - BRepExtrema_DistShapeShape measure(shape1, shape2); - if (!measure.IsDone() || measure.NbSolution() < 1) { - return new App::DocumentObjectExecReturn("Could not get extrema"); + if (distanceCircleCircle(shape1, shape2)) { + return DocumentObject::StdReturn; } - gp_Pnt p1 = measure.PointOnShape1(1); - Position1.setValue(p1.X(), p1.Y(), p1.Z()); - - gp_Pnt p2 = measure.PointOnShape2(1); - Position2.setValue(p2.X(), p2.Y(), p2.Z()); - - gp_Pnt delta = measure.PointOnShape2(1).XYZ() - measure.PointOnShape1(1).XYZ(); - Distance.setValue(measure.Value()); - DistanceX.setValue(fabs(delta.X())); - DistanceY.setValue(fabs(delta.Y())); - DistanceZ.setValue(fabs(delta.Z())); - + distanceGeneric(shape1, shape2); return DocumentObject::StdReturn; } @@ -240,6 +271,44 @@ void MeasureDistance::onChanged(const App::Property* prop) DocumentObject::onChanged(prop); } +Handle(Geom_Circle) MeasureDistance::asCircle(const TopoDS_Shape& shape) const +{ + if (shape.IsNull()) { + return {}; + } + + if (shape.ShapeType() == TopAbs_EDGE) { + return asCircle(TopoDS::Edge(shape)); + } + + if (shape.ShapeType() == TopAbs_WIRE) { + return asCircle(TopoDS::Wire(shape)); + } + + return {}; +} + +Handle(Geom_Circle) MeasureDistance::asCircle(const TopoDS_Edge& edge) const +{ + Handle(Geom_Circle) circle; + BRepAdaptor_Curve adapt(edge); + if (adapt.GetType() == GeomAbs_Circle) { + circle = new Geom_Circle(adapt.Circle()); + } + + return circle; +} + +Handle(Geom_Circle) MeasureDistance::asCircle(const TopoDS_Wire& wire) const +{ + Handle(Geom_Circle) circle; + BRepAdaptor_CompCurve adapt(wire); + if (adapt.GetType() == GeomAbs_Circle) { + circle = new Geom_Circle(adapt.Circle()); + } + + return circle; +} //! Return the object we are measuring //! used by the viewprovider in determining visibility diff --git a/src/Mod/Measure/App/MeasureDistance.h b/src/Mod/Measure/App/MeasureDistance.h index 299561dd69..732ee7e956 100644 --- a/src/Mod/Measure/App/MeasureDistance.h +++ b/src/Mod/Measure/App/MeasureDistance.h @@ -25,6 +25,7 @@ #include +#include #include #include @@ -35,6 +36,9 @@ #include "MeasureBase.h" +class TopoDS_Edge; +class TopoDS_Wire; + namespace Measure { @@ -99,7 +103,13 @@ public: private: + bool distanceCircleCircle(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); + void distanceGeneric(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); + void setValues(const gp_Pnt& p1, const gp_Pnt& p2); void onChanged(const App::Property* prop) override; + Handle(Geom_Circle) asCircle(const TopoDS_Shape& shape) const; + Handle(Geom_Circle) asCircle(const TopoDS_Edge& edge) const; + Handle(Geom_Circle) asCircle(const TopoDS_Wire& wire) const; }; From 062e11a3c837bef5c6412d93ff8069c5b7ddb301 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 Oct 2024 23:07:49 +0200 Subject: [PATCH 2/2] Test: Add test for MeasureDistance with two circles --- tests/CMakeLists.txt | 3 + tests/src/Mod/CMakeLists.txt | 3 + tests/src/Mod/Measure/App/CMakeLists.txt | 11 +++ tests/src/Mod/Measure/App/MeasureDistance.cpp | 70 +++++++++++++++++++ tests/src/Mod/Measure/CMakeLists.txt | 17 +++++ 5 files changed, 104 insertions(+) create mode 100644 tests/src/Mod/Measure/App/CMakeLists.txt create mode 100644 tests/src/Mod/Measure/App/MeasureDistance.cpp create mode 100644 tests/src/Mod/Measure/CMakeLists.txt diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be8ff26b71..c60c20e7cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -96,6 +96,9 @@ endif(BUILD_ASSEMBLY) if(BUILD_MATERIAL) list (APPEND TestExecutables Material_tests_run) endif(BUILD_MATERIAL) +if(BUILD_MEASURE) + list (APPEND TestExecutables Measure_tests_run) +endif(BUILD_MEASURE) if(BUILD_MESH) list (APPEND TestExecutables Mesh_tests_run) endif(BUILD_MESH) diff --git a/tests/src/Mod/CMakeLists.txt b/tests/src/Mod/CMakeLists.txt index fdef3879bd..faf7feabe1 100644 --- a/tests/src/Mod/CMakeLists.txt +++ b/tests/src/Mod/CMakeLists.txt @@ -4,6 +4,9 @@ endif(BUILD_ASSEMBLY) if(BUILD_MATERIAL) add_subdirectory(Material) endif(BUILD_MATERIAL) +if(BUILD_MEASURE) + add_subdirectory(Measure) +endif(BUILD_MEASURE) if(BUILD_MESH) add_subdirectory(Mesh) endif(BUILD_MESH) diff --git a/tests/src/Mod/Measure/App/CMakeLists.txt b/tests/src/Mod/Measure/App/CMakeLists.txt new file mode 100644 index 0000000000..a66c5b43b3 --- /dev/null +++ b/tests/src/Mod/Measure/App/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources( + Measure_tests_run + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/MeasureDistance.cpp +) + +target_include_directories( + Measure_tests_run + PUBLIC + ${CMAKE_BINARY_DIR} +) diff --git a/tests/src/Mod/Measure/App/MeasureDistance.cpp b/tests/src/Mod/Measure/App/MeasureDistance.cpp new file mode 100644 index 0000000000..86aee30c5a --- /dev/null +++ b/tests/src/Mod/Measure/App/MeasureDistance.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class MeasureDistance: public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + } + + void SetUp() override + { + document = App::GetApplication().newDocument("Measure"); + } + + void TearDown() override + { + App::GetApplication().closeDocument(document->getName()); + } + + App::Document* getDocument() const + { + return document; + } + + TopoDS_Edge makeCircle(const gp_Pnt& pnt) const + { + gp_Circ circle; + circle.SetLocation(pnt); + circle.SetRadius(1.0); + BRepBuilderAPI_MakeEdge mkEdge(circle); + return mkEdge.Edge(); + } + +private: + App::Document* document {}; +}; + +// NOLINTBEGIN +TEST_F(MeasureDistance, testCircleCircle) +{ + App::Document* doc = getDocument(); + auto p1 = dynamic_cast(doc->addObject("Part::Feature", "Shape1")); + p1->Shape.setValue(makeCircle(gp_Pnt(0.0, 0.0, 0.0))); + auto p2 = dynamic_cast(doc->addObject("Part::Feature", "Shape2")); + p2->Shape.setValue(makeCircle(gp_Pnt(3.0, 4.0, 0.0))); + + auto md = dynamic_cast( + doc->addObject("Measure::MeasureDistance", "Distance")); + md->Element1.setValue(p1, {"Edge1"}); + md->Element2.setValue(p2, {"Edge1"}); + + doc->recompute(); + + EXPECT_DOUBLE_EQ(md->Distance.getValue(), 5.0); + EXPECT_DOUBLE_EQ(md->DistanceX.getValue(), 3.0); + EXPECT_DOUBLE_EQ(md->DistanceY.getValue(), 4.0); + EXPECT_DOUBLE_EQ(md->DistanceZ.getValue(), 0.0); + EXPECT_EQ(md->Position1.getValue(), Base::Vector3d(0.0, 0.0, 0.0)); + EXPECT_EQ(md->Position2.getValue(), Base::Vector3d(3.0, 4.0, 0.0)); +} +// NOLINTEND diff --git a/tests/src/Mod/Measure/CMakeLists.txt b/tests/src/Mod/Measure/CMakeLists.txt new file mode 100644 index 0000000000..161ea0c103 --- /dev/null +++ b/tests/src/Mod/Measure/CMakeLists.txt @@ -0,0 +1,17 @@ + +target_include_directories(Measure_tests_run PUBLIC + ${EIGEN3_INCLUDE_DIR} + ${OCC_INCLUDE_DIR} + ${Python3_INCLUDE_DIRS} + ${SMESH_INCLUDE_DIR} + ${VTK_INCLUDE_DIRS} + ${XercesC_INCLUDE_DIRS} +) + +target_link_libraries(Measure_tests_run + gtest_main + ${Google_Tests_LIBS} + Measure +) + +add_subdirectory(App)