在Python中沿3D路径扫描形状

问题描述 投票:0回答:1

使用 Python(撰写本文时为 3.10.14),如何使用以下方法构建 3D 网格对象(可以以 STL、PLY 或 GLB/GLTF 格式保存):

  • 3D 路径作为扫描轴,
  • 二维矩形

有这些限制:

  • 3D路径是真正的3D路径,这意味着每个坐标在空间上是变化的;它不包含在一个平面中
  • 矩形形状的上边缘和下边缘必须始终水平(这意味着不会发生倾斜,即沿 3D 轴扫描期间形状不会旋转)
  • 3D 路径始终垂直穿过矩形的中心

我们可以将 3D 轨迹视为仅由直线段组成(没有曲线)。这意味着 3D 轴的两段以一定角度相交,即该点的导数不连续。生成的 3D 网格在这些位置不应有孔。因此,“3D 连接样式”应使用给定的帽样式来确定(例如,如here 对于 2 维所述)。

3D 路径以 numpy 3D 数组形式给出,如下所示:

import numpy as np

path = np.array([
    [ 5.6, 10.1,  3.3],
    [ 5.6, 12.4,  9.7],
    [10.2, 27.7, 17.1],
    [25.3, 34.5, 19.2],
    [55. , 28.3, 18.9],
    [80.3, 24.5, 15.4]
])

二维矩形形状作为 Shapely 2.0.3 Polygon 特征给出:

from shapely.geometry import Polygon

polygon = Polygon([[0, 0],[1.2, 0], [1.2, 0.8], [0, 0.8], [0, 0]])

到目前为止我所取得的成就

我目前正在尝试使用 sweep_polygon Trimesh 4.2.3

Numpy 1.26.4 可用),但没有成功,因为每次矩形形状必须改变方向时,它也会沿着它的方向旋转轴,违反了上面的第二个约束。

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

polygon = Polygon([[0, 0],[1.2, 0], [1.2, 0.8], [0, 0.8], [0, 0]])
path = np.array([
    [ 5.6, 10.1,  3.3],
    [ 5.6, 12.4,  9.7],
    [10.2, 27.7, 17.1],
    [25.3, 34.5, 19.2],
    [55. , 28.3, 18.9],
    [80.3, 24.5, 15.4]
])
mesh = sweep_polygon(polygon, path)

此外,

sweep_polygon
医生说:

不能很好地处理尖锐的曲率。

这有点晦涩难懂。

网格在meshlab中渲染。当形状向右上升时,其倾斜清晰可见。

最终目标是在无头服务器上的 Docker 容器中运行它。

python 3d computational-geometry trimesh
1个回答
0
投票

有趣!我一直在研究商店数字孪生的此类问题。这是我一直在使用的代码,根据您的需要进行了一些修改。我在 Jupyter Notebook 中运行了这个,所以如果您使用 GUI,您可能需要做一些额外的工作:

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

path = np.array([
    [5.6, 10.1, 3.3],
    [5.6, 12.4, 9.7],
    [10.2, 27.7, 17.1],
    [25.3, 34.5, 19.2],
    [55.0, 28.3, 18.9],
    [80.3, 24.5, 15.4]
])

rect_width = 1.2
rect_height = 0.8

def generate_mesh_vertices(path, width, height):
    vertices = []
    for point in path:
 
        vertices.append([point[0] - width / 2, point[1] - height / 2, point[2]])
        vertices.append([point[0] + width / 2, point[1] - height / 2, point[2]])
        vertices.append([point[0] + width / 2, point[1] + height / 2, point[2]])
        vertices.append([point[0] - width / 2, point[1] + height / 2, point[2]])
    return np.array(vertices)

def generate_faces_for_path(num_path_points):
    faces = []
    for i in range(num_path_points - 1):
        base_index = i * 4
        faces += [
            [base_index, base_index + 4, base_index + 1],
            [base_index + 1, base_index + 4, base_index + 5],
            [base_index + 1, base_index + 5, base_index + 2],
            [base_index + 2, base_index + 5, base_index + 6],
            [base_index + 2, base_index + 6, base_index + 3],
            [base_index + 3, base_index + 6, base_index + 7],
            [base_index + 3, base_index + 7, base_index],
            [base_index, base_index + 7, base_index + 4]
        ]
    return np.array(faces)

vertices = generate_mesh_vertices(path, rect_width, rect_height)
faces = generate_faces_for_path(len(path))

mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
mesh.export('path_mesh.stl')

import matplotlib.pyplot as plt

scene = trimesh.Scene(mesh)
scene.show()

这给出了

您可以放大和缩小、旋转等。商店有锋利的边缘,但我认为只要您提供正确的数据,我也可以很好地处理平滑的边缘。

© www.soinside.com 2019 - 2024. All rights reserved.