You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在内存中的3D Numpy数组高效填充指定三角形(Python)

Hey Luis,

Great question—filling a 3D triangle in such a large array efficiently is all about minimizing unnecessary computations and leveraging NumPy's vectorized operations instead of slow loops. Here's a step-by-step optimized approach that avoids iterating over your entire 1000x1200x1500 array:

Step 1: Define Core Geometry

First, we'll compute the plane containing your triangle and handle edge cases like colinear points.

import numpy as np

# Your initial empty array
arrayXYZ = np.full((1000, 1200, 1500), np.uint8(0))

# Replace these with your actual triangle vertices
p1 = np.array([x1, y1, z1], dtype=int)
p2 = np.array([x2, y2, z2], dtype=int)
p3 = np.array([x3, y3, z3], dtype=int)

# Calculate the plane's normal vector (defines the triangle's orientation)
v1 = p2 - p1
v2 = p3 - p1
normal = np.cross(v1, v2)
a, b, c = normal

# Handle degenerate case: three points are colinear (no valid triangle)
if np.all(normal == 0):
    print("Points are colinear—no triangle to fill!")
    exit()

Step 2: Limit to Bounding Box

Instead of checking every voxel in the huge array, we only work within the smallest box that encloses the triangle. This drastically cuts down the number of points we need to evaluate.

# Get min/max coordinates for each axis to define the bounding box
x_min, x_max = min(p1[0], p2[0], p3[0]), max(p1[0], p2[0], p3[0])
y_min, y_max = min(p1[1], p2[1], p3[1]), max(p1[1], p2[1], p3[1])
z_min, z_max = min(p1[2], p2[2], p3[2]), max(p1[2], p2[2], p3[2])

# Clamp bounds to your array's dimensions (avoids index errors if vertices are outside the array)
x_min = max(0, x_min)
x_max = min(arrayXYZ.shape[0]-1, x_max)
y_min = max(0, y_min)
y_max = min(arrayXYZ.shape[1]-1, y_max)
z_min = max(0, z_min)
z_max = min(arrayXYZ.shape[2]-1, z_max)

Step 3: Vectorized Plane & Triangle Membership Check

We generate a grid of points within the bounding box, then filter down to only those that lie on the triangle's plane and inside the triangle itself. All operations use NumPy's optimized C-backed functions to avoid slow Python loops.

# Generate a grid of all points in the bounding box
x = np.arange(x_min, x_max + 1)
y = np.arange(y_min, y_max + 1)
z = np.arange(z_min, z_max + 1)
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')  # Matches your array's (x,y,z) indexing

# Check which points lie on the triangle's plane (account for floating-point precision)
plane_eq = a * (xx - p1[0]) + b * (yy - p1[1]) + c * (zz - p1[2])
on_plane = np.isclose(plane_eq, 0, atol=1e-6)

# For points on the plane, check if they're inside the triangle using cross products
# Calculate vectors from triangle vertices to each grid point
ap = np.stack([xx - p1[0], yy - p1[1], zz - p1[2]], axis=-1)
bp = np.stack([xx - p2[0], yy - p2[1], zz - p2[2]], axis=-1)
cp = np.stack([xx - p3[0], yy - p3[1], zz - p3[2]], axis=-1)

# Compute cross products and dot with the normal to check orientation consistency
cross_ab_ap = np.cross(v1, ap)
dot1 = np.dot(cross_ab_ap, normal)
cross_bc_bp = np.cross(p3 - p2, bp)
dot2 = np.dot(cross_bc_bp, normal)
cross_ca_cp = np.cross(p1 - p3, cp)
dot3 = np.dot(cross_ca_cp, normal)

# Points are inside if all dot products have the same sign (or zero, for edges)
inside = ((dot1 >= 0) & (dot2 >= 0) & (dot3 >= 0)) | ((dot1 <= 0) & (dot2 <= 0) & (dot3 <= 0))

# Combine masks to get only valid voxels that are on the plane and inside the triangle
valid_voxels = on_plane & inside

# Extract indices of valid voxels
x_idx = xx[valid_voxels]
y_idx = yy[valid_voxels]
z_idx = zz[valid_voxels]

Step 4: Assign Values to Valid Voxels

Finally, we update the array in one vectorized operation—no loops required.

# Set valid voxels to 255
arrayXYZ[x_idx, y_idx, z_idx] = np.uint8(255)

Key Optimizations

  • Bounding Box Reduction: We only process voxels near the triangle, skipping the vast majority of your array.
  • Vectorized Operations: All checks use NumPy's optimized functions, which are orders of magnitude faster than Python loops.
  • Precision Handling: np.isclose avoids missing points due to tiny floating-point errors in plane calculations.

If you need even more memory efficiency (e.g., if the bounding box is still large), we can solve the plane equation for one axis (e.g., compute z from x and y if the normal's z-component isn't zero) to work with a 2D grid instead of 3D. Just let me know!

内容的提问来源于stack exchange,提问作者Luis Gonçalves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:57:51