Skip to content

Commit d900578

Browse files
committed
NURBS: Improve calculation of tangents on degenerate NURBS patches
This avoids zero length normals. Sometimes NURBS patches have a "degenerate" (zero length/to a point) edge/side. For example lathed surfaces with a point on the lathe axis. In this case the tangent(s) on points "along" that "edge" become zero length. A normal `n` at a point (u.v) on a NURBS surface is calculated by calculating the tangents `tu` and `tv` at that point and taking the cross product. However when an edge is "degenerate" then `tv` (or possibly `tu`) becomes zero and `n` becomes zero. This causes a problems with NURBS booleans when the seams are in-plane with another surface. To solve this problem the tangent calculation is changed to shift `u` or `v` inwards if they are on a degenerate/pinched point on the surface. Fixes: solvespace#652 Alternative to: solvespace#734
1 parent d72eba8 commit d900578

1 file changed

Lines changed: 58 additions & 3 deletions

File tree

src/srf/ratpoly.cpp

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,64 @@ void SSurface::TangentsAt(double u, double v, Vector *tu, Vector *tv) const {
340340
den_u = 0,
341341
den_v = 0;
342342

343-
int i, j;
344-
for(i = 0; i <= degm; i++) {
345-
for(j = 0; j <= degn; j++) {
343+
// Check if we are trying to calculate a tengent "along" a degenerate (zero length)
344+
// edge of a NURBS patch. In this case move the `u` or `v` parameter "inward" a bit.
345+
if(EXACT(0.0 == u)) {
346+
bool shift_inward = true;
347+
// For the edge to be degenerate all control points along it have to be the same.
348+
for(int i = 0; i < degn; i++) { // not <= we use i+1 in the body of the lopp
349+
if (!(ctrl[0][i].EqualsExactly(ctrl[0][i + 1]))) {
350+
shift_inward = false;
351+
break;
352+
}
353+
}
354+
if(true == shift_inward) {
355+
u += LENGTH_EPS;
356+
}
357+
} else if(EXACT(1.0 == u)) {
358+
bool shift_inward = true;
359+
// For the edge to be degenerate all control points along it have to be the same.
360+
for(int i = 0; i < degn; i++) { // not <= we use i+1 in the body of the lopp
361+
if(!(ctrl[degm][i].EqualsExactly(ctrl[degm][i + 1]))) {
362+
shift_inward = false;
363+
break;
364+
}
365+
}
366+
if(true == shift_inward) {
367+
u -= LENGTH_EPS;
368+
}
369+
}
370+
371+
if(EXACT(0.0 == v)) {
372+
bool shift_inward = true;
373+
// For the edge to be degenerate all control points along it have to be the same.
374+
for(int i = 0; i < degm; i++) { // not <= we use i+1 in the body of the lopp
375+
if(!(ctrl[i][0].EqualsExactly(ctrl[i + 1][0]))) {
376+
shift_inward = false;
377+
break;
378+
}
379+
}
380+
if(true == shift_inward) {
381+
v += LENGTH_EPS;
382+
dbp("NURBS patch pinched along 'u' at v=0 how did you do this?");
383+
}
384+
} else if(EXACT(1.0 == v)) {
385+
bool shift_inward = true;
386+
// For the edge to be degenerate all control points along it have to be the same.
387+
for(int i = 0; i < degm; i++) { // not <= we use i+1 in the body of the lopp
388+
if(!(ctrl[i][degn].EqualsExactly(ctrl[i + 1][degn]))) {
389+
shift_inward = false;
390+
break;
391+
}
392+
}
393+
if(true == shift_inward) {
394+
v -= LENGTH_EPS;
395+
dbp("NURBS patch pinched along 'u' at v=1 how did you do this?");
396+
}
397+
}
398+
399+
for(int i = 0; i <= degm; i++) {
400+
for(int j = 0; j <= degn; j++) {
346401
double Bi = Bernstein(i, degm, u),
347402
Bj = Bernstein(j, degn, v),
348403
Bip = BernsteinDerivative(i, degm, u),

0 commit comments

Comments
 (0)