wolph / numpy-stl

Simple library to make working with STL files (and 3D objects in general) fast and easy.
http://numpy-stl.readthedocs.org/
BSD 3-Clause "New" or "Revised" License
605 stars 103 forks source link

Losing digits when write ASCII stl file #192

Closed gregnordin closed 2 years ago

gregnordin commented 2 years ago

The current BaseStl._write_ascii method in stl/stl.py uses a format string, %f %f %f, on lines 312-316 to write normal and vertex values, resulting in output like the following in an ascii STL file for a single facet:

facet normal -0.000000 -0.000000 0.000000
  outer loop
    vertex 0.000000 0.000100 0.000025
    vertex 0.000000 0.000000 0.000000
    vertex 0.000000 0.000000 0.000025
  endloop
endfacet

Can the format string be replaced by %e %e %e to ensure that small numbers do not lose precision? My application is focused on geometric features in the micron range (1e-6 meter), and I'm constrained to use ascii stl files.

Besides this issue, I am loving the flexibility that numpy-stl gives me to manipulate stl files--thank you so much for a great project!

wolph commented 2 years ago

Apologies for the slow response, I've been rather busy :)

With regards to increasing the precision I'm slightly worried that some libraries will not support the scientific notation which would break backwards compatibility. Additionally, I think a larger problem is that the library currently defaults to the binary STL format which limits precision to 32 bit floating point numbers. So I doubt that this fix will make any real difference...

As a quick fix you can try right now, you could do:

import numpy
from stl import Mesh

Mesh.dtype = numpy.dtype([
    ('normals', numpy.float64, (3, )),
    ('vectors', numpy.float64, (3, 3)),
    ('attr', numpy.uint16, (1, )),
])

That would increase the precision from 32 bit to 64 bit which is likely to solve your issue. But it will break compatibility with binary STL files which are standardized to 32 bit precision

gregnordin commented 2 years ago

Thanks for the response. No problem about not changing things. For my use case I just edit the numpy-stl package in my virtual environment to use the format string in my original post, and specify ascii mode when I use mesh.Mesh.save. This allows me to do everything I need, which is to load an STL file, sort it's faces, and write sorted faces to separate ascii STL files that I use to create a 3D mesh with labelled faces for computational fluid dynamics simulations with OpenFOAM.

Thanks again for a great package!

wolph commented 2 years ago

I've done a bit more research and you're definitely right, by default %f loses precision. But I found a fix that does not appear to lose any precision: use %r instead.

Can you test if this fixes your issue? I've created a new release with the fix included so a pip3 install -U numpy-stl should do the trick.

gregnordin commented 2 years ago

I just tested using %r and it works great! Thank you so much!