[Trimesh] Mesh process

发布于 2022-12-21  805 次阅读


Please refresh the page if equations are not rendered correctly.
---------------------------------------------------------------

计算网格与面的交点

利用Trimesh中网格与使用点法线定义的平面的交点来确定截面,然后根据首尾节点的顺序对点进行排序,利用shapely的多边形类进行面积等几何分析。

import numpy as np
import trimesh
from shapely.geometry import Polygon


###########################################
#########                    Functions            ##########
###########################################
def sortLineSegment(polyline):
    '''
    polyline: lines ((m,) in numpy array of (n, 2, 2) float) return by Trimesh module
    根据线段首尾相接(坐标相同)对线段进行排序,
    再去除重复点,最终得到按顺序排列的多边形顶点。
    '''
    sortLineSeg = polyline[0]
    polyline = np.delete(polyline, 0, axis =0)
    lineLeft = polyline.shape[0]
    while True:
        if lineLeft == 0:
            del temp
            break
        for i in np.arange(lineLeft):
            temp = polyline[i]
            condition1 = list(sortLineSeg[-1]) == list(temp[0])
            condition2 = list(sortLineSeg[-1]) == list(temp[1])
            if condition1:
                temp = np.delete(temp, 0, axis =0)
                polyline = np.delete(polyline, i, axis =0)
                sortLineSeg = np.vstack((sortLineSeg, temp))
            elif condition2:
                temp = np.delete(temp, 1, axis =0)
                polyline = np.delete(polyline, i, axis =0)
                sortLineSeg = np.vstack((sortLineSeg, temp))
        lineLeft -= 1
    return sortLineSeg


###########################################
########           Problem solving            ##########
###########################################
# attach to logger so trimesh messages will be printed to console
trimesh.util.attach_to_log()

# 应该使用平滑过的面
#mesh = trimesh.load('D:/04_coding/Python/00_Projects/05_polyKriging/Fabric/weft/0/profile_0.stl')
mesh = trimesh.load('./box.stl')

#plane_origin = [2.0975, 6.974, 4.95]
plane_origin = [0, 0, 0]
plane_normal = np.array([0,0,1])

# polyline: coordinate of points on 3D line segments in space.
polyline, triangles_edge = trimesh.intersections.mesh_plane(mesh,
                                                            plane_normal, plane_origin, return_faces=True)
sortLineSeg = sortLineSegment(polyline)

# 计算面积,高,宽
a = Polygon(sortLineSeg[:,[0,1]])
print(a.centroid.wkt, a.area)

b=np.array([0,0,1])
cosangle = plane_normal.dot(b)/(np.linalg.norm(plane_normal) * np.linalg.norm(b))  
angle = np.arccos(cosangle)/np.pi*180


mesh.is_watertight  # is the current mesh watertight?
mesh.euler_number  # what's the euler number for the mesh?

# the convex hull is another Trimesh object that is available as a property
# lets compare the volume of our mesh with the volume of its convex hull
print(mesh.volume / mesh.convex_hull.volume)

# since the mesh is watertight, it means there is a
# volumetric center of mass which we can set as the origin for our mesh
mesh.vertices -= mesh.center_mass

# what's the moment of inertia for the mesh?
mesh.moment_inertia

### if there are multiple bodies in the mesh we can split the mesh by connected components of 
### face adjacency since this example mesh is a single watertight body we get a list of one mesh
##mesh.split()

# facets are groups of coplanar adjacent faces set each facet to a random color
# colors are 8 bit RGBA by default (n, 4) np.uint8
for facet in mesh.facets:
    mesh.visual.face_colors[facet] = trimesh.visual.random_color()

mesh.show()

### transform method can be passed a (4, 4) matrix and will cleanly apply the transform
##mesh.apply_transform(trimesh.transformations.random_rotation_matrix())

# axis aligned bounding box is available
mesh.bounding_box.bounds
mesh.bounding_box.extents

# a minimum volume oriented bounding box also available
# primitives are subclasses of Trimesh objects which automatically generate
# faces and vertices from data stored in the 'primitive' attribute
mesh.bounding_box_oriented.primitive.extents
mesh.bounding_box_oriented.primitive.transform

# show the mesh appended with its oriented bounding box the bounding box is a
# trimesh.primitives.Box object, which subclasses Trimesh and lazily evaluates 
# to fill in vertices and faces when requested (press w in viewer to see triangles)
(mesh + mesh.bounding_box_oriented).show()

# bounding spheres and bounding cylinders of meshes are also available, and will 
# be the minimum volume version of each except in certain degenerate cases,
# where they will be no worse than a least squares fit version of the primitive.
print(mesh.bounding_box_oriented.volume, mesh.bounding_cylinder.volume,
      mesh.bounding_sphere.volume)

trimesh.proximity.signed_distance(mesh, [[0,0,0]])

利用trimesh计算点到三角形面网格的有符号距离

def surfaceDistance(trimesh, points, partitions=5):
    """
    :param trimesh:
    :param points:
    :param partitions: int, processing the data in several segments to prevent excessive memory usage.
    :return:
    """
    partitions += 1
    points = np.array(points)
    numPoints = points.shape[0]
    parIndex = np.linspace(0, numPoints, partitions)
    parIndex = parIndex.astype(int)

    surfDist = np.zeros(numPoints)
    for i in np.arange(parIndex.shape[0] - 1):
        start = parIndex[i]
        end = parIndex[i + 1]
        surfDist[start:end] = tm.proximity.signed_distance(
            trimesh, points[start:end, :])
        # print(points[start:end, :].shape)
    return surfDist
Everything not saved will be lost.
最后更新于 2023-12-06