STLExport Bug(ish)

I don’t know CAD software, but I’ve dabbled with babylon enough that I’ve used it to create some 3d models for printing because I can do parameterized CAD much easier in code (i.e. this hole should always be 7mm from this edge and 10mm from that edge).

I’m using the STLExport functionality, but when I import the STL file into my slicer, it says that I have thousands of open edges and so it can’t figure out what is in and outside of the part. The Prussa slicer does a decent job at trying to guess, but it isn’t good enough for my purposes.

I have found a solution though… I used a different scripting language to just chop off everything past 1/100 of a “unit” (in my case, millimeters) and everything works just fine. What I think is happening is that the edges are sharing logical vertices, but floating point and javascript have some known… uh… peculiarities. So it doesn’t see a vertex as being the same because they’re off by 1/10,000 of a unit.

Personally, I wish there was a better way to handle this higher up the stack before it gets to the stl export (and maybe there is and I’m just unaware). But thats a bigger fish to fry. I would propose supplying a “decimal places” parameter to BABYLON.StlExport that either cuts off everything past X decimal places, or rounds to X decimal places. My gut would have originally said to use rounding… but with all the weirdness that goes on with js and floating point, cutting to X decimals (floor?) feels like there is less chances of edge cases. I can play around with that and see though.

I’m happy to do the work and issue a PR. I just want to make sure it is wanted first.

desired model exported from babylon, as viewed in non-sliced fashion:
image

desired model with extra precision but with many “open edges”. Notice how the teeth on top are mangled.
image

error message from prussa slicer:
image

desired model, sliced (correctly) after removing some precision from the verticies.

FWIW. here is the javascript that will do the truncating the numbers:

stlContent = stlContent.replace(/(-?d+\.\d{2})\d*/ig, "$1");

PS… on another note. I thought for the longest time the STL export was busted. The first argument takes in an array of meshes. I thought it was just going to take in a single mesh. Adding some sort of type checking and throwing an error if it doesn’t get that would be nice. Alternatively, just accepting a single mesh would have been nice as well. Happy to do that work for that PR as well, but I figure that may be a little more controversial.

That feels like a good feature to me :slight_smile: Reducing the number of points is always good not only for topology but filesize too. @sebavan @Deltakosh @RaananW what do you think?

My only suggestion would be to, instead of using a regex to cut the decimals, it would be faster to do it before writing, somewhere around here: Babylon.js/stlSerializer.ts at master · BabylonJS/Babylon.js (github.com)

Usually the way I do cutting to a certain number of places is something like:

function round(number, decimals) {
  const powerTen = Math.pow(10, decimals);
  return Math.floor(number * powerTen) / powerTen; 
}

but others might have better suggestions.

2 Likes

I like it! this could be an option in the loader for sure

Why not just to number.toFixed(10)+0?

I ask purley out of interest for which one would be faster? I’ve seen the power method before but never really thought about it.

Just to avoid the type conversion, my feel is that working with floats the whole pipeline would be faster. But idk if the difference would be big enough :thinking:

Looks like you are correct, learn something new everyday :slight_smile:

2 Likes

soooo… I think I mis-interpreted the results of my truncating the digits off. I’m still getting open edges. The prussa slicer has just been able to fix the ones that are left and so i didn’t realized. I’ve tried rounding to two digits instead of truncating. That too, does not work as desired.

with my primary example. I’m constructing a polygon with holes, and then doing an extrusion. Well, the polygon is actually composed of 52 bezier curves. I’m wondering if I’m making them too detailed and maybe the CreateCubicBezier is making them too precisely. I’m going to try both rounding/truncating the array of points that comes out of cubic bezier, or reduce the number of points per curve. Or maybe both. I’ll post my results.

silly nitpick, but much faster by simply moving Math.pow outside of the loop - you don’t want to recalculate it for every single entry given pow is the slowest operation there anyhow.

@von wanna make a PG with your cylinder setup and Ill take a look?