numpy-stl combat 3D modeling [Python]

Imagine that we need to build a 3D model of an object in the python programming language and then visualize it, or prepare a file for printing on a 3D printer. There are several libraries that solve these problems. Let's see how to build a 3D model from points, edges, and primitives in Python. How to perform basic 3D modeling techniques: move, rotate, merge, subtract, etc.

insert image description here

Recommendation: Use NSDT Designer to quickly build programmable 3D scenes.

We'll build a Menger Sponge fractal using numpy-stl, save the model to an stl file, and render the image. Along the way, we took a brief look at data structures and terminology.

All examples are provided for the Linux operating system. Code samples can be found in the GitHub repository.

1. Overview of Numpy-stl

In Numpy-stl, a polygon mesh is structured as follows:
insert image description here

Vertices - list of vertices. Each point is described by three numbers - coordinates in 3-dimensional space.

Next, we'll use Jupyter notebooks. Example: numpy_stl_example_01.ipynb

import numpy as np
from myplot import plot_verticles
vertices = np.array([
[-3, -3, 0],
[+3, -3, 0],
[+3, +3, 0],
[-3, +3, 0],
[+0, +0, +3]
])
plot_verticles(vertices = vertices, isosurf = False)

insert image description here

Although only vertices are described, you can already see what the model would look like if you connected them with triangles:

plot_verticles(vertices = vertices, isosurf = True)

insert image description here

It looks like the face already exists. But now we only have vertices. To create an STL file, let's describe the faces, this can be done manually, or provided by the spatial.ConvexHull function in the scipy library for this operation.

Example: numpy_stl_example_02.ipynb

import numpy as np
from scipy import spatial
from stl import mesh
from myplot import plot_mesh
vertices = np.array(
[
[-3, -3, 0],
[+3, -3, 0],
[+3, +3, 0],
[-3, +3, 0],
[+0, +0, +3]
]
)
hull = spatial.ConvexHull(vertices)
faces = hull.simplices

As a result, the faces array contains this faces description:

array([
[4, 1, 0],
[4, 2, 1],
[3, 4, 0],
[3, 4, 2],
[3, 2, 1],
[3, 1, 0]
], dtype=int32)

Faces - list of faces. Each triangular face is described by three vertices (points). In other words, the position of the point in the vertex array.

For example, the last face contains the numbers 3, 1, 0. So faces are assembled with the points of the 0, 1 and 3 elements of the vertex array:

insert image description here

Mesh - A set of vertices and faces that determine the shape of a polyhedral object.

myramid_mesh = mesh.Mesh(
  np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype)
)
for i, f in enumerate(faces):
  for j in range(3):
    myramid_mesh.vectors[i][j] = vertices[f[j],:]
    plot_mesh(myramid_mesh)

insert image description here

As can be seen from the image, one face of the pyramid is turned upside down. In the example below, the ConvexHull method is not used when constructing the fractal because it arranges the points of the faces in an arbitrary order, which would cause some faces to flip.

myramid_mesh.save('numpy_stl_example_02.stl')

To view STL files, I use a freeware program: Blender.

insert image description here

The spatial.convexhull method is designed to compute convex hulls, and works well with pyramids and cubes. However, in objects with cavities, due to inconsistent points, some points will be lost, and errors will occur when assembling the STL.

This is clearly visible in the 2D example: numpy_stl_example_03.ipynb

import matplotlib.pyplot as plt
from scipy import spatial
import numpy as np
points = np.array([
[0,0],
[-2,0],
[-2,2],
[0,1.5],
[2,2],
[2,0]
])
hull = spatial.ConvexHull(points)

hull.simplices contains face descriptions:

array([
[2, 1],
[2, 4],
[5, 1],
[5, 4]
], dtype=int32)

Let's draw vertices and faces:

plt.plot(points[:,0], points[:,1], 'o')
for simplex in hull.simplices:
  plt.plot(points[simplex, 0], points[simplex, 1], 'k-')

insert image description here

For this case, you can find alternatives to convexhull, or manually describe the edges:

faces = np.array([
[0, 1],
[1, 2],
[2, 3],
[3, 4],
[4, 5],
[5, 0]
])
plt.plot(points[:,0], points[:,1], 'o')
for simplex in faces:
  plt.plot(points[simplex, 0], points[simplex, 1], 'k-')

insert image description here

2. Numpy-stl constructs fractals

Time to build a fractal. There is no boolean subtraction function in Numpy-stl. To construct the Menger Sponge fractal, we took the opposite approach. There are two methods:

  • Build a basic cube mesh. We call it a voxel.
  • Combine multiple voxels into a mesh.

We will construct a fractal from a cube, just like the constructor.

Logical explanation for constructing fractals:

Suppose the fractal face length is 1. Depth of fractal is the count of unique hole sizes. Voxel length depends on depth of the fractal, it is divided by 3 with each new level of depth.
We gonna find the voxel side at depths 1 and 2. Let's simplify the task, turning the fractal from 3 to 1-dimensional case:

If fractal level is 2, then the length of the cube side will be 1 / (3 ** 2) which is equivalent to 1/9. Let's make a set of cubes so that they filled resulting voxel cube by their location. Let's calculate holes area. Exclude voxels that are in holes. In conclusion, unite the remaining voxels in one object and save.

insert image description here

Example: numpy_stl_example_04.ipynb

insert image description here

3. Numpy-stl rendering

To render the image, we send the mesh loaded from the STL file to the plot_mesh function.

Example: numpy_stl_example_05.ipynb
insert image description here


Original link: numpy-stl combat 3D modeling—BimAnt

Guess you like

Origin blog.csdn.net/shebao3333/article/details/130799879