NURBS: Improve calculation of tangents on degenerate NURBS patches#736
NURBS: Improve calculation of tangents on degenerate NURBS patches#736ruevs wants to merge 1 commit intosolvespace:masterfrom
Conversation
|
Some thoughts on this issue. First, I don't think the small adjustments to u,v are likely to be a problem but I'm still against doing it unless needed. The criteria here are not optimal, you can create a perfectly good curve that has coincident end points (draw bezier with one left click and one right, constrain the end points together). Having said that, this would probably work fine. I'm leaning toward passing an optional flag "allowZero" defaulting to false (similar to mustConverge). We'd get the tangents and then check if they're within EPS of zero. If so, adjust u or v and call ourself recursively and pass the flag as true so we only try once. This way we can have better control over it. We could also default it to true and try passing it as false in a number of places to see where the bug really is - meaning what part of the boolean code actually fails with a zero tangent vector. Not that I'm excited to do that, but I might just to get a better understanding of the failure. Checking for an actual zero tangent is also the actual condition we're looking for. What do you think? |
|
You are right that I should have done a for loop and checked all control points along the edge not just the end ones (I debugged and at least for the cone and sphere all three are the same). I'll change that. As for the "move inwards only if the tangent is zero" approach I tried it here on lines 423-433: Overall I like the approach in this pull request better (caveat - without understanding all affected users of tangents), because we have a "boolen" decision of whether we are on a singularity/degenerate point instead on some arbitrary numerical tolerance. I debugged the failing case (with the cone) and it fails with As for adding a flag - it is a great idea for debugging, but instinctively I do not like it as a final solution. If we were to add it permanently (defaulted to |
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
|
@phkahler amended, please take a look. |
|
@ruevs Ouch :-) that's a lot of code, but it does look correct for finding these "pole" point/edges. What if we reduced that first condition with something like: if (ctrl[0][0].EqualsExactly(ctrl[0][1]) && ctrl[0][degn].EqualsExactly(ctrl[0][degn-1]) { It seems the answer to the comments question is yes - it makes it easier to find these later. |
|
@ruevs I propose the following change which is less strict but also just less. |
|
Let me think some more... I don't like mine - too verbose, too much copy paste. For loops (but they don't particularly bother me, even though I have not tried to profile it). |
I believe the tangent will go to zero at U,V = (0,0) if only 2 points are coincident. Meaning if you have a 3rd order curve with 4 control points (A,B,C,D) where A and B are coincident but also C and D are coincident, you will get a line but the tangent will go to zero at both ends but not in the middle. All of the fixes proposed for tangents so far will work with the degenerate curves SolveSpace can create today via revolve and lathe. I'm still not happy with the verbosity of mine either. I still think checking the result and doing a retry might be the most visually appealing way to go but I haven't written it to verify. It would make explicit in the code what the condition being tested is and probably less ugly too. Performance of a retry should not be a problem, as it is rare. |
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 `tu` or `tv` is shorter than a threshold value. Fixes: solvespace#652 Alternative to: solvespace#736 solvespace#734
I agree, but in that case if we are at U,V = (0, 0.2) with A = B != C = D we should not have to increase U. It should be necessary only at (0,0) and (0,1). It probably does not matter if we do it anyway but I do not like "imprecise" solutions when there is an efficient precise/discrete one. What I mean is that there is a truth table of what we should do:
Is this correct? If it is then I will try to find a better looking implementation of it. (B=C? can it cause a zero length tangent?)
Visually appealing - yes - I absolutely agree.
It is rare if there are no such points in a model. If there are... I just implemented the "numerical" approach here: https://github.com/ruevs/solvespace/commits/NURBSTangentsNumerical Another thing that I do not like (in both solutions) is that the UV space is 0-1 by nudging Also depending on the curvature of the patch close to the "singularity" moving u/v by 1e-6 may or may not make the tangent > TANGENT_ZERO_TOLERANCE (1e-9) in five iterations. Therefore how to choose the values of I think we should not choose the good looking (compact and simple source) solution when there is an efficient one in this case. |
|
Closing, since #746 is merged in master and achieves the same. |
This avoids zero length normals.
Sometimes NURBS patches have a "degenerate" (zero length/to a point)
edge/side. In this case the tangent(s) on points "along" that "edge"
become zero length.
A normal
nat a point (u.v) on a NURBS surface is calculated by calculatingthe tangents
tuandtvat that point and taking the cross product.However when an edge is "degenerate" (for example a cone created by lathing
a triangle) then
tv(and possiblytu) becomes zero andnbecomes zero.This causes a problems with NURBS booleans.
To solve this problem the tangent calculation is changed to shift
uorvinwardsif they are on a degenerate/pinched point on the surface.
Fixes: #652
Alternative to: #734