numpy-stl — Numpy stl 2.16.3 documentation (2024)

numpy-stl — Numpy stl 2.16.3 documentation (1)numpy-stl — Numpy stl 2.16.3 documentation (2)numpy-stl — Numpy stl 2.16.3 documentation (3)numpy-stl — Numpy stl 2.16.3 documentation (4)numpy-stl — Numpy stl 2.16.3 documentation (5)

Simple library to make working with STL files (and 3D objects in general) fastand easy.

Due to all operations heavily relying on numpy this is one of the fastestSTL editing libraries for Python available.

Requirements for installing:

Installation:

pip install numpy-stl

Initial usage:

After installing the package, you should be able to run the following commandssimilar to how you can run pip.

$ stl2bin your_ascii_stl_file.stl new_binary_stl_file.stl$ stl2ascii your_binary_stl_file.stl new_ascii_stl_file.stl$ stl your_ascii_stl_file.stl new_binary_stl_file.stl

Contributing:

Contributions are always welcome. Please view the guidelines to get started:https://github.com/WoLpH/numpy-stl/blob/develop/CONTRIBUTING.rst

Quickstart

import numpyfrom stl import mesh# Using an existing stl file:your_mesh = mesh.Mesh.from_file('some_file.stl')# Or creating a new mesh (make sure not to overwrite the `mesh` import by# naming it `mesh`):VERTICE_COUNT = 100data = numpy.zeros(VERTICE_COUNT, dtype=mesh.Mesh.dtype)your_mesh = mesh.Mesh(data, remove_empty_areas=False)# The mesh normals (calculated automatically)your_mesh.normals# The mesh vectorsyour_mesh.v0, your_mesh.v1, your_mesh.v2# Accessing individual points (concatenation of v0, v1 and v2 in triplets)assert (your_mesh.points[0][0:3] == your_mesh.v0[0]).all()assert (your_mesh.points[0][3:6] == your_mesh.v1[0]).all()assert (your_mesh.points[0][6:9] == your_mesh.v2[0]).all()assert (your_mesh.points[1][0:3] == your_mesh.v0[1]).all()your_mesh.save('new_stl_file.stl')

Plotting using matplotlib is equally easy:

from stl import meshfrom mpl_toolkits import mplot3dfrom matplotlib import pyplot# Create a new plotfigure = pyplot.figure()axes = mplot3d.Axes3D(figure)# Load the STL files and add the vectors to the plotyour_mesh = mesh.Mesh.from_file('tests/stl_binary/HalfDonut.stl')axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))# Auto scale to the mesh sizescale = your_mesh.points.flatten()axes.auto_scale_xyz(scale, scale, scale)# Show the plot to the screenpyplot.show()

Modifying Mesh objects

from stl import meshimport mathimport numpy# Create 3 faces of a cubedata = numpy.zeros(6, dtype=mesh.Mesh.dtype)# Top of the cubedata['vectors'][0] = numpy.array([[0, 1, 1], [1, 0, 1], [0, 0, 1]])data['vectors'][1] = numpy.array([[1, 0, 1], [0, 1, 1], [1, 1, 1]])# Front facedata['vectors'][2] = numpy.array([[1, 0, 0], [1, 0, 1], [1, 1, 0]])data['vectors'][3] = numpy.array([[1, 1, 1], [1, 0, 1], [1, 1, 0]])# Left facedata['vectors'][4] = numpy.array([[0, 0, 0], [1, 0, 0], [1, 0, 1]])data['vectors'][5] = numpy.array([[0, 0, 0], [0, 0, 1], [1, 0, 1]])# Since the cube faces are from 0 to 1 we can move it to the middle by# substracting .5data['vectors'] -= .5# Generate 4 different meshes so we can rotate them latermeshes = [mesh.Mesh(data.copy()) for _ in range(4)]# Rotate 90 degrees over the Y axismeshes[0].rotate([0.0, 0.5, 0.0], math.radians(90))# Translate 2 points over the X axismeshes[1].x += 2# Rotate 90 degrees over the X axismeshes[2].rotate([0.5, 0.0, 0.0], math.radians(90))# Translate 2 points over the X and Y pointsmeshes[2].x += 2meshes[2].y += 2# Rotate 90 degrees over the X and Y axismeshes[3].rotate([0.5, 0.0, 0.0], math.radians(90))meshes[3].rotate([0.0, 0.5, 0.0], math.radians(90))# Translate 2 points over the Y axismeshes[3].y += 2# Optionally render the rotated cube facesfrom matplotlib import pyplotfrom mpl_toolkits import mplot3d# Create a new plotfigure = pyplot.figure()axes = mplot3d.Axes3D(figure)# Render the cube facesfor m in meshes: axes.add_collection3d(mplot3d.art3d.Poly3DCollection(m.vectors))# Auto scale to the mesh sizescale = numpy.concatenate([m.points for m in meshes]).flatten()axes.auto_scale_xyz(scale, scale, scale)# Show the plot to the screenpyplot.show()

Extending Mesh objects

from stl import meshimport mathimport numpy# Create 3 faces of a cubedata = numpy.zeros(6, dtype=mesh.Mesh.dtype)# Top of the cubedata['vectors'][0] = numpy.array([[0, 1, 1], [1, 0, 1], [0, 0, 1]])data['vectors'][1] = numpy.array([[1, 0, 1], [0, 1, 1], [1, 1, 1]])# Front facedata['vectors'][2] = numpy.array([[1, 0, 0], [1, 0, 1], [1, 1, 0]])data['vectors'][3] = numpy.array([[1, 1, 1], [1, 0, 1], [1, 1, 0]])# Left facedata['vectors'][4] = numpy.array([[0, 0, 0], [1, 0, 0], [1, 0, 1]])data['vectors'][5] = numpy.array([[0, 0, 0], [0, 0, 1], [1, 0, 1]])# Since the cube faces are from 0 to 1 we can move it to the middle by# substracting .5data['vectors'] -= .5cube_back = mesh.Mesh(data.copy())cube_front = mesh.Mesh(data.copy())# Rotate 90 degrees over the X axis followed by the Y axis followed by the# X axiscube_back.rotate([0.5, 0.0, 0.0], math.radians(90))cube_back.rotate([0.0, 0.5, 0.0], math.radians(90))cube_back.rotate([0.5, 0.0, 0.0], math.radians(90))cube = mesh.Mesh(numpy.concatenate([ cube_back.data.copy(), cube_front.data.copy(),]))# Optionally render the rotated cube facesfrom matplotlib import pyplotfrom mpl_toolkits import mplot3d# Create a new plotfigure = pyplot.figure()axes = mplot3d.Axes3D(figure)# Render the cubeaxes.add_collection3d(mplot3d.art3d.Poly3DCollection(cube.vectors))# Auto scale to the mesh sizescale = cube_back.points.flatten()axes.auto_scale_xyz(scale, scale, scale)# Show the plot to the screenpyplot.show()

Creating Mesh objects from a list of vertices and faces

import numpy as npfrom stl import mesh# Define the 8 vertices of the cubevertices = np.array([\ [-1, -1, -1], [+1, -1, -1], [+1, +1, -1], [-1, +1, -1], [-1, -1, +1], [+1, -1, +1], [+1, +1, +1], [-1, +1, +1]])# Define the 12 triangles composing the cubefaces = np.array([\ [0,3,1], [1,3,2], [0,4,7], [0,7,3], [4,5,6], [4,6,7], [5,1,2], [5,2,6], [2,3,6], [3,7,6], [0,1,5], [0,5,4]])# Create the meshcube = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))for i, f in enumerate(faces): for j in range(3): cube.vectors[i][j] = vertices[f[j],:]# Write the mesh to file "cube.stl"cube.save('cube.stl')

Evaluating Mesh properties (Volume, Center of gravity, Inertia)

import numpy as npfrom stl import mesh# Using an existing closed stl file:your_mesh = mesh.Mesh.from_file('some_file.stl')volume, cog, inertia = your_mesh.get_mass_properties()print("Volume = {0}".format(volume))print("Position of the center of gravity (COG) = {0}".format(cog))print("Inertia matrix at expressed at the COG = {0}".format(inertia[0,:]))print(" {0}".format(inertia[1,:]))print(" {0}".format(inertia[2,:]))

Combining multiple STL files

import mathimport stlfrom stl import meshimport numpy# find the max dimensions, so we can know the bounding box, getting the height,# width, length (because these are the step size)...def find_mins_maxs(obj): minx = obj.x.min() maxx = obj.x.max() miny = obj.y.min() maxy = obj.y.max() minz = obj.z.min() maxz = obj.z.max() return minx, maxx, miny, maxy, minz, maxzdef translate(_solid, step, padding, multiplier, axis): if 'x' == axis: items = 0, 3, 6 elif 'y' == axis: items = 1, 4, 7 elif 'z' == axis: items = 2, 5, 8 else: raise RuntimeError('Unknown axis %r, expected x, y or z' % axis) # _solid.points.shape == [:, ((x, y, z), (x, y, z), (x, y, z))] _solid.points[:, items] += (step * multiplier) + (padding * multiplier)def copy_obj(obj, dims, num_rows, num_cols, num_layers): w, l, h = dims copies = [] for layer in range(num_layers): for row in range(num_rows): for col in range(num_cols): # skip the position where original being copied is if row == 0 and col == 0 and layer == 0: continue _copy = mesh.Mesh(obj.data.copy()) # pad the space between objects by 10% of the dimension being # translated if col != 0: translate(_copy, w, w / 10., col, 'x') if row != 0: translate(_copy, l, l / 10., row, 'y') if layer != 0: translate(_copy, h, h / 10., layer, 'z') copies.append(_copy) return copies# Using an existing stl file:main_body = mesh.Mesh.from_file('ball_and_socket_simplified_-_main_body.stl')# rotate along Ymain_body.rotate([0.0, 0.5, 0.0], math.radians(90))minx, maxx, miny, maxy, minz, maxz = find_mins_maxs(main_body)w1 = maxx - minxl1 = maxy - minyh1 = maxz - minzcopies = copy_obj(main_body, (w1, l1, h1), 2, 2, 1)# I wanted to add another related STL to the final STLtwist_lock = mesh.Mesh.from_file('ball_and_socket_simplified_-_twist_lock.stl')minx, maxx, miny, maxy, minz, maxz = find_mins_maxs(twist_lock)w2 = maxx - minxl2 = maxy - minyh2 = maxz - minztranslate(twist_lock, w1, w1 / 10., 3, 'x')copies2 = copy_obj(twist_lock, (w2, l2, h2), 2, 2, 1)combined = mesh.Mesh(numpy.concatenate([main_body.data, twist_lock.data] + [copy.data for copy in copies] + [copy.data for copy in copies2]))combined.save('combined.stl', mode=stl.Mode.ASCII) # save as ASCII

Known limitations

  • When speedups are enabled the STL name is automatically converted tolowercase.
numpy-stl — Numpy stl 2.16.3 documentation (2024)
Top Articles
Latest Posts
Article information

Author: Kareem Mueller DO

Last Updated:

Views: 5557

Rating: 4.6 / 5 (46 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: Kareem Mueller DO

Birthday: 1997-01-04

Address: Apt. 156 12935 Runolfsdottir Mission, Greenfort, MN 74384-6749

Phone: +16704982844747

Job: Corporate Administration Planner

Hobby: Mountain biking, Jewelry making, Stone skipping, Lacemaking, Knife making, Scrapbooking, Letterboxing

Introduction: My name is Kareem Mueller DO, I am a vivacious, super, thoughtful, excited, handsome, beautiful, combative person who loves writing and wants to share my knowledge and understanding with you.