181 lines
5.8 KiB
C++
181 lines
5.8 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
#include <cmath>
|
|
#include <numbers>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#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<SystemTest>();
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
_system.reset();
|
|
}
|
|
|
|
SystemTest* System()
|
|
{
|
|
return _system.get();
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<SystemTest> _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<double> bSplineControlPointsX(5);
|
|
std::vector<double> 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<GCS::Point> bSplineControlPoints(5);
|
|
for (size_t i = 0; i < bSplineControlPoints.size(); ++i) {
|
|
bSplineControlPoints[i].x = &bSplineControlPointsX[i];
|
|
bSplineControlPoints[i].y = &bSplineControlPointsY[i];
|
|
}
|
|
std::vector<double> weights(bSplineControlPoints.size(), 1.0);
|
|
std::vector<double*> weightsAsPtr;
|
|
std::vector<double> knots(bSplineControlPoints.size() - 2); // Hardcoded for cubic
|
|
std::vector<double*> knotsAsPtr;
|
|
std::vector<int> 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<double>(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<double*> 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
|
|
);
|
|
}
|