Repository navigation
Use cubic NURBS surfaces for helical sweeps - #1813
Conversation
|
@alken1t15 Good job. I wasn't sure if you were going to do this one or not, so I did #1814 myself. The only thing I don't like with yours is the tests. While it does need some testing, I don't think we need to commit a unit test to the repository. I also see you found the incomplete copying in MakeFromHelicalRevolutionOf(). That was a surprise for me too. Every thing went red and I was confused. Claude found the problem in couple minutes. I'm guessing you used some AI for this, or that bug probably would have taken a long time to find - even I would have had trouble finding it and I wrote the helix code ;-) Yours is more compact. Mine adds a new function in ratpoly. @ruevs which do you prefer? EDIT: Your test of distf and dists to determine degree 2 or 3 may need a tolerance, but also for revolve they are both zero so that should be OK. |
|
@phkahler Thanks for looking! I've removed the tests from the PR and kept them locally. The diff now only touches The two approaches use the same degree-elevated arc and endpoint slope condition. Here the cubic control points are computed directly in I left the distance comparison exact for now: ordinary revolutions have equal offsets, while a nonzero axial displacement takes the cubic path. The formula also has a finite zero-angle limit ( |
Bot(h) fail the Turing test ;-) Give the "I" (without "A") a bit of time :-) |
| if(ps.Equals(pf)) { | ||
| // Keep the existing handling of degenerate ordinary revolutions. | ||
| // A small helical sweep can have nearby ends without lying on the axis. | ||
| if(ret.degn == 2 && ps.Equals(pf)) { |
There was a problem hiding this comment.
This is important and therefore this PR wins.
This fixes an existing problem with helixes rotated by a very small angle - they will be "mistreated undeservedly" :-).
| SSurface ret = {}; | ||
| ret.degm = sb->deg; | ||
| ret.degn = 2; | ||
| ret.degn = (dists == distf) ? 2 : 3; |
There was a problem hiding this comment.
I don't like this - even though dists and distf will probably be bit identical doubles.
But just in case - steal the code from here:
https://github.com/solvespace/solvespace/pull/1814/changes#diff-deec245a10911b7fc46369d2f1d19541c6ba4616ea90aeff8cf3b24749f01005R83
|
Just out of curiosity I (this "I") ran it's "AI" on the battle of #1813 vs. #1814. Thinking: I prefer #1813 as currently submitted. The two PRs produce essentially the same approximation for ordinary helices, but #1813 is more narrowly scoped and handles small/zero-angle sweeps better. I compared heads The deciding difference: endpoint collapse#1814 retains this existing code: if(ps.Equals(pf)) {
ps = c;
ct = c;
pf = c;
}Nearby rotational endpoints do not imply that the point lies on the axis. They can simply mean the sweep angle is small. For example, take a control point at
The same collapse occurs for sufficiently small nonzero angles. It is a potentially large positional error, not merely an error within tolerance. This is inherited from master, not introduced by #1814, but #1813 explicitly fixes it for sweeps with axial displacement. Its axial formula also handles the zero-angle limit correctly. The principal mathematics is equivalentBoth implementations:
With #1813 computes that directly. #1814 obtains it through degree elevation followed by an axial correction. Independent numerical sampling reproduced the advertised improvement:
Errors are relative to patch height. The two implementations agreed to floating-point roundoff in the nondegenerate cases I sampled, including reverse sweeps and an arbitrary axis. Accuracy on normal helices is not a reason to choose between them. Implementation tradeoffs#1813’s exact distance comparison is defensible. I would not add a tolerance merely because these are doubles. This selects quadratic versus cubic representation; it does not divide by the displacement or require it to be appreciably nonzero. The ordinary-revolution callers explicitly supply equal offsets, and the cubic formula remains well-behaved for tiny displacement and angle. #1814’s helper is legitimate, but optional. Both make the necessary trim fix. Copying the surface boundary’s actual degree, control points, and all weights in RecommendationMerge #1813, perhaps borrowing #1814’s explanatory derivation comment. If you prefer the reusable-helper architecture, #1814 is a reasonable alternative after adopting the small/zero-angle handling from #1813. Neither current diff includes regression tests—#1813’s were removed following the discussion—so I would not use committed test coverage as a differentiator. Validation here was source review and independent numerical reproduction, not builds of both PRs or GUI/STEP round-trip testing. |
I missed that in 1814. I asked it to declare the curve object outside the loop and wanted it to simply assign the points to it rather than call a constructor for each one. I do need to slow down... |
Who's going to read all that generated code? - as I keep asking - not specifically in SolveSpace - for the whole planet :-) And I'm generating more as I write this :-/ |
|
@ruevs Thanks for reviewing both versions. What specific changes, if any, would you like in this PR before it can be merged? In particular:
Please let me know if anything else is missing or needs correcting, and I'll update the PR. |
|
@alken1t15 Can you use the comment explanation from the other PR in this one. Then we can merge this one and drop the other completely. |
|
@alken1t15 thank you for the contribution! |
|
@phkahler You're welcome, and thanks for the review and guidance! Are there any open, unclaimed issues of moderate to high difficulty that you'd particularly like help with at the moment? Geometry, NURBS or solver work would interest me. Ideally something reported within the last six months, with a reasonably clear scope. I've also asked about #1723 and #1774; if either would be useful to take on, I'd be happy to start there. |
|
@alken1t15 I'm not sure if this PR caused it, but the CI tests on Ununtu are failing on master. All the regression tests pass but it's failing with a memory leak when built with sanitizers on. Could you have a look? |
|
@phkahler @ruevs I reproduced the leak and opened #1817 with a one-line cleanup fix. Running With the cleanup call added, the isolated test and all 300 tests (1,246 checks) pass with sanitizers, leak detection and OpenMP enabled, using the failing CI seed |
Helical sweeps currently vary in pitch within each rational quadratic patch. This uses degree-elevated rational cubic arcs with axial controls chosen to match the analytic helix tangent at both endpoints. Ordinary revolutions keep their quadratic surfaces. Longitudinal shell trim curves now use the surface boundary's actual degree and weights.
For a 90° patch, a 10,001-sample comparison against the analytic helix reduces maximum axial error from about 2.11% to 0.0493% of patch height, while preserving the circular projection. The resulting helix is still an approximation.
For comparison, two quadratic half-patches have about 0.2512% maximum axial error relative to the original patch height. These are sampled errors, not formal bounds or a runtime benchmark.
Validation: Release build with GCC 11.4; 306 test cases and 12,375 checks passed locally, including additional checks for pitch/radius, reverse and small sweeps, endpoint tangents, adjacent patches, a rational profile with an arbitrary axis, ordinary revolutions, watertight shell triangulation, STEP serialization and a Boolean cut. The additional tests are kept locally and are not included in this PR, as requested. Interactive GUI validation and external STEP re-import have not been performed.
Fixes #1448.