Open briansturgill opened 2 years ago
I'll probably do more of this discussion to Manifold's board, but felt this thread needs an update. @elalish where would you want this done, Discussions?
Using union script by @platypii (translated to python and adding subtract and intersect) I managed to get a first round of timing tests comparing the C# version of the BSP algorithm with Manifold's algorithm, both using their Python bindings.
I then spent the rest of the day trying to figure out if it was actually true. I've been through it thoroughly and it appears that Manifold's booleans are 3 ORDERS OF MAGNITUDE (1000x) faster than the BSP-based booleans in JSCAD/CSharpCAD.
There are some caveats.
First, the sphere code between the two was different, but I changed the segment values (100 for JSCAD/CSharpCAD and 150 for Manifold) so that the resulting sphere had approximately the same number of vertices and faces.
The Python interface to C# is probably less efficient than the one to Manifold, however the overhead is probably not substantial realtive to the operations being tested.
The test by @platypii is edge case oriented... I don't know if that is having an effect or not.
Finally, JSCAD/CSharpCAD is faster handling the "disjoint" case as we have special handling for that. I'm assuming Manifold doesn't bother checking (it's still very fast for that case).
Here is my code for Manifold:
from pymanifold import Manifold
from time import time_ns
segments = 150
def test(x, radius, name):
s1 = Manifold.sphere(radius=1, circular_segments=segments)
s2 = Manifold.sphere(radius=radius, circular_segments=segments).translate(x, 0, 0)
start = time_ns()
ret = s1+s2
finish = time_ns()
if name == "ignore":
return
print("union", name, (finish-start)/1000000.0)
start = time_ns()
ret = s1^s2
finish = time_ns()
print("intersect", name, (finish-start)/1000000.0)
start = time_ns()
ret = s1-s2
finish = time_ns()
print("subtract", name, (finish-start)/1000000.0)
test(4, 1, "ignore");
test(4, 1, "disjoint");
test(2, 1, "touching");
test(1, 1, "overlap");
test(0, 1, "same");
test(0, 0.5, "inside");
Using separate programs, I checked the output from Manifold and it appears correct. Indeed, in the case "union overlap", CSharpCAD was producing output that was not manifold. Manifold handled it correctly.
I'm hoping someone on the JSCAD team will attempt timing tests with the WASM version. I will be working on the WASM version (under C#'s new wasmtime package) soon.
@briansturgill, @elalish that is great news, looking forward to trying out manifold wasm
Thank you @briansturgill! You really made my day with your analysis.
Manifold does in fact have a fast path for disjoint inputs, but it could probably use further optimization; I'd guess we're not skipping as much as we could.
Oh, forgot to answer the question: Yes, please start a Discussion thread in Manifold.
I've also got issues with a subtract
call (slicer mentions "open edges"), would this be the same issue? and if so, are there any workarounds currently available?
Here's a screenshot from Blender, the selected vertex can be moved freely away from the vertical face. Is that what is considered an "open edge"?
Code below, without the final subtract
code the slicer doesn't complain about any open edges
Let me know how I can help, I'm keen to get this resolved!
edit:
The changes only occur when you output an STL file.
I might just try another export format then!
edit 2: nope, same thing with OBJ, 3MF, etc
manifold library has come a long way from when this thread was started. I am following it closely, and finally have some basinc examples working in jscad.app. My guess with manifold you would not have those errors @nmattia.
I firmly believe future of jscad is in adopting manifold (if not completely, at least as an optional CSG backend)
@hrgdavor thanks! I'm actually giving it a try. The API reference seems to have moved so it's a slow but promising start (the part that failed in JSCAD is exporting without issues in Manifold).
I did have a look at the JSCAD sources and I'm actually not sure it's a boolean issue afterall (in my case); looks like it might be an issue with the way JSCAD triangulates. The STL export does have some triangulation code but AFAICT it shouldn't actually run because the model goes through triangulatePolygons
& friends first. Once I got there I decided to give Manifold a go 😬
Will report on how that goes!
@udif JSCAD internally does care if polygons are triangulated or not. That's the biggest difference with modern CSG engines.
let us know if you find anything suspicious, and can reproduce with a fairly simple test.
I've also got issues with a
subtract
call (slicer mentions "open edges"), would this be the same issue? and if so, are there any workarounds currently available?Here's a screenshot from Blender, the selected vertex can be moved freely away from the vertical face. Is that what is considered an "open edge"?
Code below, without the final
subtract
code the slicer doesn't complain about any open edges
@nmattia can you supply the name of the slicer? There are many and many are subpar when dealing with mesh issues.
Blender also has 'repair' functions as Blender itself can produce invalid meshes.
My personal favorite is Meshlab. You might want to look at this application.
@z3dev do you mean @nmattia ?
The slicer is PrusaSlicer, which does autorepair. Regardless of the slicer, the blender screenshot does show the issue. IIUC the technical term for the STL rule being broken here is "vertex-to-vertex rule":
Vertex-to-vertex rule. Each triangle must share two vertices with each of its adjacent triangles. In other words, a vertex of one triangle cannot lie on the side of another. fabbers.com, The Stl Format
Or do you mean that, upon import, Blender messed with the Mesh which makes the screenshot moot? I'll admit I didn't read the actual STL output... 😂
Thanks for pointing out Meshlab, I'll keep it in mind!
EDIT: just to clarify, PrusaSlicer & Blender both showed the same issue, or rather both showed an issue at the same spot. PrusaSlicer just highlighted the edges in red, and Blender showed the vertex was on the edge and not connected to another face
Coming in from the Manifold side of things... Please keep in mind that STL is a lossy format regarding manifoldness. Effectively all STLs (even ones produced from a proper manifold) require fixing and that fixing process is heuristic and can easily result in a previously manifold mesh becoming non-manifold, but worse, the results will be different when imported through different software. I would strongly recommend 3MF (or even OBJ) as alternatives that actually encode manifoldness (topological) data. I also authored an EXT_mesh_manifold
extension to glTF that works properly even when you have discontinuous vertex properties on a mesh.
The slicer is PrusaSlicer, which does autorepair. Regardless of the slicer, the blender screenshot does show the issue. IIUC the technical term for the STL rule being broken here is "vertex-to-vertex rule"
This the typical issue reported as booleans operations do not produce 'watertight' meshes. That's why all the generalize functions were created. The output is typically good enough for the slicers to print or to fix.
Or do you mean that, upon import, Blender messed with the Mesh which makes the screenshot moot?
Absolutely not. I was just wondering which slicer was being used. Not all slicers are the same, and Prusa is one of the better ones.
Expected Behavior
Actual Behavior
Meshlab reports 12 non manifold vertices 64 faces over non manifold edges. (I've seen this several times, here's a simple example.)
Steps to Reproduce the Problem
Run this: program output to .stl const { cylinder } = require('@jscad/modeling').primitives const { translate } = require('@jscad/modeling').transforms const { subtract, union, intersect } = require('@jscad/modeling').booleans
const main = () => { h = 8 size = 3 const inner_d = size*0.8 const outer_d = 4+size; c1 = cylinder({radius: outer_d/2, height: h}) c2 = cylinder({radius: inner_d/2, height: h}) let shape = union( subtract(c1, c2), //translate([20, 0, 0],union(c1, translate([3, 0, 0],c2))), //translate([0, 20, 0],intersect(c1, translate([3, 0, 0],c2))) ) return shape; }
module.exports = { main }
Run meshlab on the stl file.
Specifications
OpenJSCAD 2.2.21 [Linux:5.15.0-39-generic,linux:x64]