跳转到主要内容

用于分析3D表面的复杂网格类。

项目描述

Motmot

Motmot是一个用于分析无色多边形网格(例如STL文件)的复杂网格类,它提供了一个无缝的抽象层,在原始向量网格或更高效的(顶点 + 面积)(也称为(顶点 + 多边形))形式之间。

相关项目

这个库几乎完全专注于分析网格。您很可能需要使用其他库来读取/写入特定格式或简化现有网格。

  • 网格读写

    • numpy-stl:读取和写入STL文件。这是motmot的依赖项。
    • meshio:读取和写入多种网格格式。
    • pymesh:读取和写入STL和OBJ文件。
  • 网格分析

    • PyMesh:一个功能强大的网格库,不幸的是,它依赖于一些相当复杂的C++库,使得它不能普遍安装。它甚至不在PyPI上。
    • trimesh:另一个通用网格库。这个库是纯Python编写,专注于三角形网格,并且最好是封闭的网格。它还附带了一些读写器。这个库非常强大。你很可能用它比用 motmot 更好。
  • 网格清理

    • quad_mesh_simplify:减少(折叠冗余或近似冗余顶点)网格,以大幅度减小文件大小,同时对质量的影响微乎其微。
    • Py_Fast-Quadric-Mesh-Simplification:另一个网格缩减器。这个版本速度更快,但尚未在 PyPI 上发布。

使用方法

motmot 的基本API模仿了 numpy-stl 的API,并进行了一些修改。

初始化

网格可以是

  1. 从头开始使用单个 向量 数组构建。这个数组应该是3D的,形状为 (n, k, 3),其中

    • n 是网格中的多边形数量,
    • k 是每个多边形具有的角的数量,
    • 3 对应于3个轴。即 xyz
    # vectors is a (n, 3, 3) numpy array.
    triangle_mesh = Mesh(vectors)
    
    # vectors is a (n, 4, 3) numpy array.
    square_mesh = Mesh(vectors)
    
  2. 或使用更高效的 顶点+面 形式。

    # `vertices` is an array of points. It should contain no duplicates.
    # `faces` is an integer array indicating which vertices are used to construct
    # each polygon.
    mesh = Mesh(vertices, faces)
    
  3. 从STL文件读取。这使用 numpy-stl 作为底层。目前,STL是 motmot 能够隐式读取的唯一文件格式

    from motmot import Mesh
    mesh = Mesh("some-file.stl")
    
  4. 从lzma、gzip或bzip2压缩的STL文件读取

    from motmot import Mesh
    
    # An lzma compressed STL file. Create using `xz some-file.stl` in bash.
    mesh = Mesh("some-file.stl.xz")
    # A gzip compressed STL file. Create using `gzip some-file.stl` in bash.
    mesh = Mesh("some-file.stl.gz")
    # A bzip2 compressed STL file. Create using `bzip2 some-file.stl` in bash.
    mesh = Mesh("some-file.stl.bz2")
    
  5. 从任何 io.RawIOBase 的子类流式传输。从这里,您可以读取任意来源,例如嵌入式文件、流、归档或其他伪文件。例如,以下代码直接从Web请求中读取STL:

    from urllib import request
    from motmot import Mesh
    
    # Pull an STL file from the internet and load it without an intermediate
    # temporary file.
    url = "https://raw.githubusercontent.com/bwoodsend/vtkplotlib/master/" \
          "vtkplotlib/data/models/rabbit/rabbit.stl"
    
    with request.urlopen(url) as req:
        mesh = Mesh(req)
    

顶点+面网格与向量网格

网格有两种形式。

  1. 一个 向量 网格本质上是一个多边形列表,其中每个多边形是一个点列表(它的角),每个点是 (x, y, z) 三元组。这种形式很简单,但很浪费,因为出现在多个多边形中的点被多次写入,浪费内存和渲染时间。

  2. 一个 顶点+面 网格从 向量 网格中提取所有唯一的点,称它们为 顶点,然后将 向量 中的每个点替换为其从 顶点 中的索引,称这个为 。请注意, 通常也称为 面片多边形

Motmot 使两种形式可以互换。每个 向量顶点 都可以作为所有网格的属性,但根据网格是如何构建的,向量 可能是从 顶点 内部推导出来的,反之亦然。

import numpy as np
from motmot import Mesh

# Define the 8 vertices in a cuboid.
vertices = np.array([
    [0., 0., 0.],
    [3., 0., 0.],
    [0., 5., 0.],
    [3., 5., 0.],
    [0., 0., 9.],
    [3., 0., 9.],
    [0., 5., 9.],
    [3., 5., 9.],
])

# Define the 6 sides of a cube or cuboid.
faces = np.array([
    # Draw a square using vertices[6], vertices[2], vertices[0] and vertices[4]
    [6, 2, 0, 4],
    # Draw a square using vertices[0], vertices[1], vertices[5] and vertices[4]
    [0, 1, 5, 4],
    # And so on...
    [0, 2, 3, 1],
    [5, 1, 3, 7],
    [3, 2, 6, 7],
    [4, 5, 7, 6],
])

# Construct a vertices+faces mesh.
mesh = Mesh(vertices, faces)
# This attribute is set to True to signify that this was originally a faces mesh.
mesh.is_faces_mesh
# Although `vectors` can still be derived automatically.
mesh.vectors

# Construct a vectors mesh.
mesh = Mesh(vertices[faces])
# This attribute is set to False to signify that this was originally a vectors
# mesh.
mesh.is_faces_mesh
# But `vertices` and `faces` can still be derived automatically.
mesh.vertices, mesh.faces

网格属性

这只是一个简要的总结。有关每个属性的更多信息,请参阅 API参考

# Outward normal to each polygon:
>>> mesh.normals
array([[-45.,   0.,   0.],
       [ -0., -27.,  -0.],
       [ -0.,  -0., -15.],
       [ 45.,   0.,  -0.],
       [ -0.,  27.,   0.],
       [  0.,   0.,  15.]])

# Normalised (magnitude of 1.0) outward normal to each polygon:
>>> mesh.units
array([[-1.,  0.,  0.],
       [ 0., -1.,  0.],
       [ 0.,  0., -1.],
       [ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

# Area of each polygon.
>>> mesh.areas
array([45., 27., 15., 45., 27., 15.])

# Total surface area (just a sum of mesh.areas).
>>> mesh.area
174.0

# The number of times each vertex is used (which admittedly
# isn't particularly interesting for a cuboid):
>>> mesh.vertex_counts
array([3, 3, 3, 3, 3, 3, 3, 3], dtype=int32)

# A mapping of which other vertices each vertex is directly connect to.
>>> mesh.vertex_map
RaggedArray.from_nested([
    [1, 7, 3],  # vertices[0] connects to vertices[[1, 7, 3]].
    [2, 6, 0],  # vertices[1] connects to vertices[[2, 6, 0]].
    [4, 1, 3],  # and so on...
    [5, 0, 2],
    [5, 6, 2],
    [4, 7, 3],
    [1, 4, 7],
    [0, 5, 6],
])

# Because this mesh's vertices appear the same number of times,
# this example slightly trivialises the problem. Consider instead
# a mesh with only the first three faces. Not all vertices have
# the same number of neighbours.
>>> mesh[:3].vertex_map
RaggedArray.from_nested([
    [1, 3],
    [2, 6, 0],
    [4, 1, 3],
    [0, 2, 5],
    [5, 2, 6],
    [3, 4],
    [4, 1],
])

# If you prefer to use raw vertices rather than vertex IDs then
# use the connected_vertices() method.
>>> mesh.connected_vertices(mesh.vertices[0])
array([[0., 5., 0.],
       [3., 5., 9.],
       [0., 0., 9.]])

# Similarly, `polygon_map` maps every polygon to each of its neighbours.
# Read the first line of the following as *polygon 0 shares an edge each with
# polygons 4, 2, 1 and 5*.
>>> mesh.polygon_map
array([[4, 2, 1, 5],
       [2, 3, 5, 0],
       [0, 4, 3, 1],
       [1, 2, 4, 5],
       [2, 0, 5, 3],
       [1, 3, 4, 0]])

顶点查找

motmot 利用两个库来查找顶点。

精确查找

将顶点ID转换为真实顶点很容易。只需将它们作为索引传递给 mesh.vertices 即可。

>>> ids = [0, 4, 5, 2]
>>> points = mesh.vertices[ids]
>>> points
array([[0., 0., 0.],
       [0., 0., 9.],
       [3., 0., 9.],
       [0., 5., 0.]])

通过索引 vertex_table 属性进行反向操作。

>>> mesh.vertex_table[points]
array([0, 4, 5, 2], dtype=int64)

需要注意的一些事项

  • 查询点的 dtype 必须与 mesh.dtype 匹配。

  • 与常规Python dict 中的常规浮点数一样,即使是最小的偏差也会导致查找失败。

    >>> mesh.vertex_table[[3., 0., 9.]]
    5
    >>> mesh.vertex_table[[3., 0, 9.00000000001]]
    KeyError: 'key = array([3., 0., 9.]) is not in this table.'
    
模糊查找

为了找到 最近点motmot 使用 KDTree。这里的API非常简单,你很可能希望直接创建和使用 KDTree 而不是使用 motmot 的方法。

将KDTree拟合到mesh.centers(每个多边形的中心),可以在mesh.kdtree属性中找到。

给定一组点定义为

points = np.array([[2., 3.5, 4.2], [2.3, 4.2, 1.1]], mesh.dtype)

找到每个点在网格表面上的最近点

>>> mesh.closest_point(points)
array([[3. , 3.5, 4.2],
       [2.3, 4.2, 0. ]])

或者限制输出仅包含mesh.centers,而不在它们之间进行插值

>>> mesh.closest_point(points, interpolate=False)
array([[3. , 2.5, 4.5],
       [1.5, 2.5, 0. ]])

对于其他任何情况,直接使用mesh.kdtree

惰性

motmot.Mesh使用@functools.cached_property的后端口惰性加载其属性。这允许它们仅在需要时进行计算,从而不会浪费计算您未使用的内容的时间。以mesh.normals为例。在mesh = Mesh(vertices, faces)上不会进行任何计算,因此如果法线从未被使用,则它们永远不会被计算。访问属性mesh.normals会初始化并返回它们,使mesh.normals在外部看起来像是一个常规属性。值被缓存,以确保计算不会运行多次。即mesh.normals is mesh.normals

在修改网格后应重置缓存。大部分操作都是自动完成的。网格修改方法,如rotate()translate()crop(in_place=True)都会自行使受影响的缓存失效。同样,设置任何verticesfacesvectors属性都会重置所有缓存。但是,以原地方式写入这些数组(例如mesh.vectors[:] = x)对motmot来说是不可检测的。在完成原地修改后,请调用mesh.reset()

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

motmot-0.3.2.tar.gz (37.1 kB 查看哈希)

上传时间

构建分布

motmot-0.3.2-py3-none-win_amd64.whl (48.1 kB 查看哈希)

上传时间 Python 3 Windows x86-64

motmot-0.3.2-py3-none-win32.whl (47.6 kB 查看哈希)

上传时间 Python 3 Windows x86

motmot-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (39.2 kB 查看哈希)

上传时间 Python 3 manylinux: glibc 2.17+ ARM64

motmot-0.3.2-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl (39.0 kB 查看哈希)

上传于 Python 3 manylinux: glibc 2.5+ x86-64

motmot-0.3.2-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (38.7 kB 查看哈希值)

上传于 Python 3 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

motmot-0.3.2-py3-none-manylinux_2_5_i686.manylinux1_i686.whl (38.9 kB 查看哈希值)

上传于 Python 3 manylinux: glibc 2.5+ i686

motmot-0.3.2-py3-none-macosx_11_0_arm64.whl (36.7 kB 查看哈希值)

上传于 Python 3 macOS 11.0+ ARM64

motmot-0.3.2-py3-none-macosx_10_6_x86_64.whl (36.7 kB 查看哈希值)

上传于 Python 3 macOS 10.6+ x86-64

由以下支持