// SPDX-License-Identifier: LGPL-2.1-or-later #include #include #include #include "Mod/Sketcher/App/planegcs/GCS.h" #include "Mod/Sketcher/App/planegcs/Geo.h" #include "Mod/Sketcher/App/planegcs/Constraints.h" class SystemTest: public GCS::System { public: size_t getNumberOfConstraints(int tagID = -1) { return _getNumberOfConstraints(tagID); } }; class ConstraintsTest: public ::testing::Test { protected: void SetUp() override { _system = std::make_unique(); } void TearDown() override { _system.reset(); } SystemTest* System() { return _system.get(); } private: std::unique_ptr _system; }; TEST_F(ConstraintsTest, tangentBSplineAndArc) // NOLINT { // Arrange // TODO: Add arc, B-spline, and point double pointX = 3.5, arcStartX = 5.0, arcEndX = 0.0, arcCenterX = 0.0; double pointY = 3.5, arcStartY = 0.0, arcEndY = 5.0, arcCenterY = 0.0; GCS::Point point, arcStart, arcEnd, arcCenter; point.x = &pointX; point.y = &pointY; arcStart.x = &arcStartX; arcStart.y = &arcStartY; arcEnd.x = &arcEndX; arcEnd.y = &arcEndY; arcCenter.x = &arcCenterX; arcCenter.y = &arcCenterY; double arcRadius = 5.0, arcStartAngle = 0.0, arcEndAngle = std::numbers::pi / 2; double desiredAngle = std::numbers::pi; double bSplineStartX = 0.0, bSplineEndX = 16.0; double bSplineStartY = 10.0, bSplineEndY = -10.0; GCS::Point bSplineStart, bSplineEnd; bSplineStart.x = &bSplineStartX; bSplineStart.y = &bSplineStartY; bSplineEnd.x = &bSplineEndX; bSplineEnd.y = &bSplineEndY; std::vector bSplineControlPointsX(5); std::vector bSplineControlPointsY(5); bSplineControlPointsX[0] = 0.0; bSplineControlPointsY[0] = 10.0; bSplineControlPointsX[1] = 0.0; bSplineControlPointsY[1] = 6.0; bSplineControlPointsX[2] = 6.0; bSplineControlPointsY[2] = 0.5; bSplineControlPointsX[3] = 16.0; bSplineControlPointsY[3] = 0.5; bSplineControlPointsX[4] = 16.0; bSplineControlPointsY[4] = -10.0; std::vector bSplineControlPoints(5); for (size_t i = 0; i < bSplineControlPoints.size(); ++i) { bSplineControlPoints[i].x = &bSplineControlPointsX[i]; bSplineControlPoints[i].y = &bSplineControlPointsY[i]; } std::vector weights(bSplineControlPoints.size(), 1.0); std::vector weightsAsPtr; std::vector knots(bSplineControlPoints.size() - 2); // Hardcoded for cubic std::vector knotsAsPtr; std::vector mult(bSplineControlPoints.size() - 2, 1); // Hardcoded for cubic mult.front() = 4; // Hardcoded for cubic mult.back() = 4; // Hardcoded for cubic for (size_t i = 0; i < bSplineControlPoints.size(); ++i) { weightsAsPtr.push_back(&weights[i]); } for (size_t i = 0; i < knots.size(); ++i) { knots[i] = static_cast(i); knotsAsPtr.push_back(&knots[i]); } GCS::Arc arc; arc.start = arcStart; arc.end = arcEnd; arc.center = arcCenter; arc.rad = &arcRadius; arc.startAngle = &arcStartAngle; arc.endAngle = &arcEndAngle; GCS::BSpline bspline; bspline.start = bSplineStart; bspline.end = bSplineEnd; bspline.poles = bSplineControlPoints; bspline.weights = weightsAsPtr; bspline.knots = knotsAsPtr; bspline.mult = mult; bspline.degree = 3; bspline.periodic = false; double bsplineParam = 0.35; std::vector params = { point.x, point.y, arcStart.x, arcStart.y, arcEnd.x, arcEnd.y, arcCenter.x, arcCenter.y, &arcRadius, bSplineStart.x, bSplineStart.y, bSplineEnd.x, bSplineEnd.y, &bSplineControlPointsX[0], &bSplineControlPointsY[0], &bSplineControlPointsX[1], &bSplineControlPointsY[1], &bSplineControlPointsX[2], &bSplineControlPointsY[2], &bSplineControlPointsX[3], &bSplineControlPointsY[3], &bSplineControlPointsX[4], &bSplineControlPointsY[4], &desiredAngle, &bsplineParam }; params.insert(params.end(), weightsAsPtr.begin(), weightsAsPtr.end()); params.insert(params.end(), knotsAsPtr.begin(), knotsAsPtr.end()); // Act // TODO: Apply constraint and solve System()->addConstraintArcRules(arc); System()->addConstraintPointOnArc(point, arc, 0, true); System()->addConstraintPointOnBSpline(point, bspline, &bsplineParam, 0, true); System()->addConstraintAngleViaPointAndParam(bspline, arc, point, &bsplineParam, &desiredAngle, 0, true); int solveResult = System()->solve(params); if (solveResult == GCS::Success) { System()->applySolution(); } // Assert EXPECT_EQ(solveResult, GCS::Success); // is point on arc? EXPECT_DOUBLE_EQ( (arcRadius) * (arcRadius), (pointX - arcCenterX) * (pointX - arcCenterX) + (pointY - arcCenterY) * (pointY - arcCenterY) ); // is point on B-spline? GCS::DeriVector2 pointAtBSplineParam = bspline.Value(bsplineParam, 1.0); EXPECT_DOUBLE_EQ(pointAtBSplineParam.x, pointX); EXPECT_DOUBLE_EQ(pointAtBSplineParam.y, pointY); // TODO: are tangents at relevant parameter equal? GCS::DeriVector2 centerToPoint((pointX - arcCenterX), (pointY - arcCenterY)); GCS::DeriVector2 tangentBSplineAtPoint(pointAtBSplineParam.dx, pointAtBSplineParam.dy); double dprd; // FIXME: This error is probably too high. Fixing this may require improving the solver, // however. EXPECT_NEAR( std::fabs(centerToPoint.crossProdZ(tangentBSplineAtPoint, dprd)) / (centerToPoint.length() * tangentBSplineAtPoint.length()), 1.0, 0.005 ); }