Skip to content

Commit 53b9a55

Browse files
committed
improve: provide fast algorithm for projection.
1 parent 425346f commit 53b9a55

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

src/LNLib/Geometry/Surface/NurbsSurface.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,91 @@ LNLib::UV LNLib::NurbsSurface::GetParamOnSurface(const LN_NurbsSurface& surface,
12671267
return param;
12681268
}
12691269

1270+
LNLib::UV LNLib::NurbsSurface::GetParamOnSurfaceByGSA(const LN_NurbsSurface& surface, const XYZ& givenPoint)
1271+
{
1272+
std::vector<double> knotVectorU = surface.KnotVectorU;
1273+
std::vector<double> knotVectorV = surface.KnotVectorV;
1274+
1275+
double minU = knotVectorU[0];
1276+
double maxU = knotVectorU[knotVectorU.size() - 1];
1277+
double minV = knotVectorV[0];
1278+
double maxV = knotVectorV[knotVectorV.size() - 1];
1279+
1280+
double u0 = (maxU - minU) * 0.5;
1281+
double v0 = (maxV - minV) * 0.5;
1282+
1283+
int counter = 0;
1284+
1285+
while(counter < 1000)
1286+
{
1287+
LNLib::UV initialUV = UV(u0, v0);
1288+
XYZ p0 = GetPointOnSurface(surface, initialUV);
1289+
XYZ normal = Normal(surface, initialUV);
1290+
1291+
std::vector<std::vector<XYZ>> ders = ComputeRationalSurfaceDerivatives(surface, 2, initialUV);
1292+
XYZ Suu = ders[2][0];
1293+
XYZ Svv = ders[0][2];
1294+
XYZ Suv = ders[1][1];
1295+
1296+
XYZ Su = ders[1][0];
1297+
XYZ Sv = ders[0][1];
1298+
1299+
double L = Suu.DotProduct(normal);
1300+
double M = Suv.DotProduct(normal);
1301+
double N = Svv.DotProduct(normal);
1302+
double E = Su.DotProduct(Su);
1303+
double F = Su.DotProduct(Sv);
1304+
double G = Sv.DotProduct(Sv);
1305+
double denominator = E * G - F * F;
1306+
1307+
if (MathUtils::IsAlmostEqualTo(denominator, 0.0))
1308+
{
1309+
return UV(Constants::DoubleEpsilon, Constants::DoubleEpsilon);
1310+
}
1311+
1312+
double c1 = Su.DotProduct(normal);
1313+
double c2 = Sv.DotProduct(normal);
1314+
double c3 = 1;
1315+
double s1 = (givenPoint - p0).DotProduct(Su);
1316+
double s2 = (givenPoint - p0).DotProduct(Sv);
1317+
double s3 = (givenPoint - p0).DotProduct(normal);
1318+
1319+
double a1 = - (c1 * c2 * s2 - c1 * G * s3 - c2 * c2 * s1 + c2 * F * s3 - F * s2 + G * s1 )/(c1 * c1 * G - 2 * c1 * c2 * F + c2 * c2 * E - E * G + F * F);
1320+
double a2 = (c1 * c1 * s2 - c1 * c2 * s1 - c1 * F * s3 + c2 * E * s3 - E * s2 + F * s1)/(c1 * c1 * G - 2 * c1 * c2 * F + c2 * c2 * E - E * G + F * F);
1321+
1322+
double curvature = (L * a1 * a1 + 2 * M * a1* a2 + N * a2 * a2)/(E * a1 * a1 + 2 * F * a1 * a2 + G * a2 * a2);
1323+
double radius = 1 / abs(curvature);
1324+
1325+
XYZ m = p0 + radius * normal;
1326+
XYZ q = givenPoint + (m - givenPoint) * (1 - radius / (m.Distance(givenPoint)));
1327+
1328+
double c4 = (q - p0).DotProduct(Su);
1329+
double c5 = (q - p0).DotProduct(Sv);
1330+
1331+
double deltaU = (c4 * G - c5 * F) / denominator;
1332+
double deltaV = -(c4 * F - c5 * E) / denominator;
1333+
1334+
double ut = u0 + deltaU;
1335+
double vt = v0 + deltaV;
1336+
1337+
u0 = ut;
1338+
v0 = vt;
1339+
1340+
if (MathUtils::IsLessThanOrEqual(abs(deltaU), Constants::DoubleEpsilon) &&
1341+
MathUtils::IsLessThanOrEqual(abs(deltaV), Constants::DoubleEpsilon))
1342+
{
1343+
LNLib::UV newUV = UV(ut, vt);
1344+
XYZ newNormal = Normal(surface, newUV);
1345+
if (normal.IsAlmostEqualTo(newNormal))
1346+
{
1347+
break;
1348+
}
1349+
}
1350+
counter++;
1351+
}
1352+
return UV(u0, v0);
1353+
}
1354+
12701355
void LNLib::NurbsSurface::Reparametrize(const LN_NurbsSurface& surface, double minU, double maxU, double minV, double maxV, LN_NurbsSurface& result)
12711356
{
12721357
std::vector<double> knotVectorU = surface.KnotVectorU;

src/LNLib/include/NurbsSurface.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ namespace LNLib
118118
/// </summary>
119119
static UV GetParamOnSurface(const LN_NurbsSurface& surface, const XYZ& givenPoint);
120120

121+
/// <summary>
122+
/// Experimental:
123+
/// According to https://jcst.ict.ac.cn/fileup/1000-9000/PDF/2019-6-9-9388.pdf
124+
/// A Geometric Strategy Algorithm for Orthogonal Projection onto a Parametric Surface
125+
/// </summary>
126+
static UV GetParamOnSurfaceByGSA(const LN_NurbsSurface& surface, const XYZ& givenPoint);
127+
121128
static void Reparametrize(const LN_NurbsSurface& surface, double minU, double maxU, double minV, double maxV, LN_NurbsSurface& result);
122129

123130
/// <summary>

tests/T_AdvancedGeometric.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ TEST(Test_AdvancedGeometric, Surface_GetParamOrGetPoint)
101101
surface.ControlPoints = cps;
102102
XYZ result = NurbsSurface::GetPointOnSurface(surface, uv);
103103
UV param = NurbsSurface::GetParamOnSurface(surface, result);
104+
UV param1 = NurbsSurface::GetParamOnSurfaceByGSA(surface, result);
104105
EXPECT_TRUE(param.IsAlmostEqualTo(uv));
106+
EXPECT_TRUE(param1.IsAlmostEqualTo(uv));
105107
}
106108

107109
TEST(Test_AdvancedGeometric, Reparametrize)

0 commit comments

Comments
 (0)