zalo / CascadeStudio

A Full Live-Scripted CAD Kernel in the Browser
https://zalo.github.io/CascadeStudio/
MIT License
1.03k stars 129 forks source link

Lofting "twists" #57

Closed johnsonm closed 3 years ago

johnsonm commented 3 years ago

For fun, I have tried out using Loft to try to model a rhodonea (rose) curve.

At many places, always aligned with one axis (Y I think, but without an orientation cube / vectors it's hard to tell), the loft is inverted:

image

I don't see a math mistake in my model, though it's possible that one exists. The debugging I've done so far hasn't found one.

I have this modeled well enough for my uses in OpenSCAD, I just thought Loft would be a more natural way to describe this shape than lots of polyhedron segments.

zalo commented 3 years ago

Hooee! That's a crazy loft! The original script double covers the curve, so I rewrote it with a Pipe Operation, but the self-intersections in the top and bottom faces prevent it from working the way you'd expect (so the top and bottom faces are null).

The territory of self-intersecting faces is tricky; I don't have any good advice here, unfortunately.

johnsonm commented 3 years ago

I do weird things, eh?

Of course the approach of using a set of polyhedra as I used in the OpenSCAD model would work here too. (Whether OpenSCAD closes the mesh in that model seems to be a matter of floating point luck; merely changing the radius and leaving the other parameters alone can be the difference between a valid manifold or not.)

Also, I could loft it piecewise. I could make it piecewise by local min and local max distance from origin to control point; then each individual Loft would not be self-intersecting, and with the example parameters with five "petals" would result in 10 lofts. That would be easier to do in CascadeStudio than in OpenSCAD, because of the limitations of the declarative OpenSCAD language, even if OpenSCAD provided Loft() (which as far as I know it doesn't).

Would you expect lofts that are exactly butted to each other because their adjacent ends are defined by the same polygons to properly union into a manifold, since they should intersect but not be self-intersecting?

This could also solve the source of the double-covering problem: Different rhodonea parameters (and also epi/hypo cycloid/trochoids to which this can be reasonably expanded, as in the original from kakaroto) give different periods, and if I used this approach I could check each new face for whether it's within epsilon of the first face and use that to stop the iteration and cover all the reasonable rational versions without explicitly coding the range of the input variable. (Within epsilon to account for floating point inexactly representing pi.)

No matter how this is modeled, handling the self-intersecting nature of the entire curve is the core difficulty. If it weren't for that, it might be easiest to write code to write raw ascii STL! ☺ I could just emit all the outer faces and omit the end faces in STL. But it's not clear to me whether meshlab has a function that could generally and simply resolve those intersections in the "obviously intended" way.

johnsonm commented 3 years ago

Well, that was not a rip-roaring success... It did solve the double-covering problem (confirmed with console.log) but avoiding self-intersection for each Loft didn't make things better:

image

I also tried to Union a list of Loft objects but that gives me Union() encountered ___cxa_is_pointer_type is not defined so I'm still doing something wrong.

zalo commented 3 years ago

Hrm, I just figured a way out. Try this.

By adding a very small epsilon to the Pipe guide, I was able to sort of bypass the self-intersecting face issue... While the Part itself has overlapping faces, I've verified that the Prusa Slicer can automatically resolve these non-manifold ambiguities and print the part without issue.

(Make sure to change the mesh resolution if you'd like a smaller model.)

johnsonm commented 3 years ago

A very short basket-weave! Very sneaky!

As it happens, I'm using Kiri:moto (another all-in-browser tool) to render gcode to cut with my router, and it can't handle non-manifold geometry. He doesn't use your approach of compiling C into js to use in the browser; he's sticking to pure native javascript, which as a discipline doesn't let him use the same libraries prusa-slicer is using to resolve the non-manifold ambiguities.

Again, this exercise is just for fun; I got a manifold out of OpenSCAD with adjacent polyhedra and generated gcode just fine, so I'm just trying out new ideas here. If I can get a consistent manifold it might turn into another nice example.

I wonder if using my piece-wise approach with pipes instead of a loft would help? In any case I should drastically reduce my iterations since I'm not making polyhedra. That default just carried over from making polyhedra smooth enough. Changing that was why I filed #61 ...

johnsonm commented 3 years ago

A Pipe by parts works, renders almost instantly, and produces a manifold object according to meshlab. The code is ugly but there was no point in making it better without first seeing how this approach would work.

image

When I try to Union the parts (see the comments at the end) I get Line 18: Uncaught Encountered Null Face! I was hoping that a Union would refine the shape and get rid of the excess faces, but no such luck.

johnsonm commented 3 years ago

I improved (I think) the code and it creates the same model with what I think is slightly more readable code.