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
624 stars 105 forks source link

Display Textures in MatPlotLib #75

Closed mustafa-qamaruddin closed 6 years ago

mustafa-qamaruddin commented 6 years ago

I have managed to read STL files and display them with Mat Plot Lib. However, all the textures in the files and fine details are lost. What could be wrong?

For example, this is how the original file looks like with different viewer:

original model

This is how it looks like on our system with Numpy STL:

numpy stl view

wolph commented 6 years ago

Unless you've activated one of the cleanup commands such as duplicate removal it shouldn't change the stl.

Without any code or stl files I can't say much more though

Uvar commented 6 years ago

looks like matplotlib is patching the surfaces "wrongly". That can have a plethora of causes, so in terms of SO, a MVRE would be nice. :)

mustafa-qamaruddin commented 6 years ago

Thank you for your reply;

Here you're my code:

    def extract360(self, path_to_file, nr):
        ret = []
        directory = "LEGO"
        if not os.path.exists(directory):
            os.makedirs(directory)
        directory = "%s/%s" % (directory, nr.zfill(10))

        next_idx = len(os.listdir(directory))

        if not os.path.exists(directory):
            os.makedirs(directory)
        angels = [0, 45, 90, 135, 180, 225, 270, 315, 360]
        axes = [
            [0, 0, 0.5],
            [0, 0.5, 0],
            [0.5, 0, 0],
            [0, 0.5, 0.5],
            [0.5, 0, 0.5],
            [0.5, 0.5, 0],
            [0.5, 0.5, 0.5]
        ]
        i = 1
        for angel in angels:
            for axis in axes:
                # Create a new plot
                figure = plt.figure()
                plt_axes = mplot3d.Axes3D(figure)

                plt_axes.set_axis_off()

                # Load the STL files and add the vectors to the plot
                your_mesh = mesh.Mesh.from_file(path_to_file)

                your_mesh.rotate(axis, math.radians(angel))

                plt_axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))

                # Auto scale to the mesh size
                scale = your_mesh.points.flatten(-1)
                plt_axes.auto_scale_xyz(scale, scale, scale)

                # Show the plot to the screen
                f_p = "%s/%010d.jpg" % (directory, next_idx+i)
                plt.savefig(f_p)
                ret.append(f_p)
                plt.close()
                i += 1
        return ret

And here you're the STL file: https://printabrick.org/bricks/30363/zip

mustafa-qamaruddin commented 6 years ago

I have used VTK for the same thing, and I get good results with Textures: https://www.youtube.com/watch?v=2dk2k_9ubpg

Uvar commented 6 years ago

I am glad that other packages yield good results, but step one is the same as I notice with a lot of others: repairing an invalid mesh. I added the fixed stl as well. I hope that one is okay enough for further discussion purposes.

Also attached to this reply: a picture snippet of my matplotlib plotted lego block. This without the axes_off feature or the autoscale. Just fyi, a somewhat similar plot can be generated from the original stl, albeit with some more distorted triangles (for some stackoverflow question I have the plotting set with edgecolor keyword, hence it shows the triangles instead of only the object rendering)

So, matplotlib intricacies seem to be the issue here, rather than numpy-stl. I am unable to reproduce the exact plot you showed at the start though, so it is going to be a tough cookie to help you out with the plotting issues.

lego.zip

image

Uvar commented 6 years ago

As extra bonus, I'll add an example of misdefinition in the mesh:

stl.vectors[679] Out[268]: array([[ -0.91843998, -22.21730995, -7.6724 ], [ 0. , -22.39999962, -7.73329973], [ 0. , -22.39999962, -7.73329973]], dtype=float32)

As you can see, two of the points in the polygon have the same spatial coordinates, leading to a triangle with zero area (a line). It is now undefined how to handle normalization and other operations on this segment; so I am not surprised if scaling operations fail big time in this case. Also, in some cases if the flag is set, I guess these polygons will be cleaned up. There are at least 12 such polygons I could find.

mustafa-qamaruddin commented 6 years ago

Thank you very much.

1- How have you fixed the STL? Is there an automated utility for such?

2- Numpy STL apparently has no issue here, but what's the issue with MatPlotLib? I don't quite get it? Is it edgecolor? axis off?

Thanks again

Uvar commented 6 years ago
  1. by putting it through a third party software. If you google "repair stl files" one of the top hits is an article describing 17 software tools to do so, ranging from free and browser-based to part of a rather expensive commercial package.
  2. I don't think it is the edgecolor keyword; as it only controls whether to show all edges of your mesh or not. This leaves axis_off, auto_scale and the off chance that something went wrong during rotation.