如何生成可构成四面体的随机顶点,修复现有随机生成器异常问题
随机四面体生成器问题修复方案
现有代码核心缺陷
- 点生成逻辑无合理性约束:p3、p4的生成上限设为
p1+p2无几何意义,也没有校验四个点是否共面、共线,容易生成无效点位 - 边长约束未生效:定义的
min_len、max_len参数未实际用到,生成的四面体边长无法符合要求 - 函数变量作用域错误:
surface_normal_form函数中使用的center是外层函数的局部变量,未作为入参传入,运行时会报错
修复步骤
- 重写点位生成逻辑:
- 按顺序生成四个点,每生成一个新点就校验和已有所有点的距离是否在
[min_len, max_len]区间内 - 四个点全部生成后校验混合积绝对值(判断是否共面),阈值可设为1e-6避免浮点误差,如果不符合要求就重新生成
- 按顺序生成四个点,每生成一个新点就校验和已有所有点的距离是否在
- 修正
surface_normal_form函数的入参,把center作为参数传入 - 保留原有体素化生成逻辑不变
修正后代码示例
import numpy as np import itertools def rand_tetrahedron_generator(bounds, min_len, max_len): """ bounds: List - 每个维度的最大长度 min_len: int - 四面体边长最小值 max_len: int - 四面体边长最大值 """ assert len(bounds) == 3 assert min_len <= max_len max_len = min(max_len, bounds[0], bounds[1], bounds[2]) bounds = np.array(bounds) # 有效四面体生成循环 while True: # 生成第一个点 p1 = np.random.randint(low=0, high=bounds, size=3) # 生成第二个点,满足和p1的距离约束 valid_p2 = False for _ in range(100): p2 = np.random.randint(low=0, high=bounds, size=3) dist = np.linalg.norm(p2-p1) if min_len <= dist <= max_len: valid_p2 = True break if not valid_p2: continue # 生成第三个点,满足和p1、p2的距离约束,且三点不共线 valid_p3 = False for _ in range(100): p3 = np.random.randint(low=0, high=bounds, size=3) d1 = np.linalg.norm(p3-p1) d2 = np.linalg.norm(p3-p2) if not (min_len <= d1 <= max_len and min_len <= d2 <= max_len): continue # 检查是否共线:叉积不为0 if np.linalg.norm(np.cross(p2-p1, p3-p1)) > 1e-6: valid_p3 = True break if not valid_p3: continue # 生成第四个点,满足和前三个点的距离约束,且四点不共面 valid_p4 = False for _ in range(100): p4 = np.random.randint(low=0, high=bounds, size=3) d1 = np.linalg.norm(p4-p1) d2 = np.linalg.norm(p4-p2) d3 = np.linalg.norm(p4-p3) if not (min_len <= d1 <= max_len and min_len <= d2 <= max_len and min_len <= d3 <= max_len): continue # 检查是否共面:混合积不为0 v1 = p2 - p1 v2 = p3 - p1 v3 = p4 - p1 scalar_triple = np.dot(v3, np.cross(v1, v2)) if abs(scalar_triple) > 1e-6: valid_p4 = True break if valid_p4: break points = np.array([p1,p2,p3,p4]) center = np.mean(points, axis=0) x, y, z = (np.indices((60, 60, 60))-np.array([20,25,25]).reshape(-1,1,1,1))/8 mx = midpoints(x) my = midpoints(y) mz = midpoints(z) conditions = [] for a,b,c in itertools.combinations(points, 3): a_p, n = surface_normal_form(a,b,c, center) conditions.append((mx-a_p[0])*n[0]+(my-a_p[1])*n[1]+(mz-a_p[2])*n[2] <= 0) simplex = conditions[0] & conditions[1] & conditions[2] & conditions[3] return simplex def surface_normal_form(a,b,c, center): v = b-a w = c-b n = np.cross(v,w) # 法向量朝外 if (center-a)@n > 0: n *= -1 return a, n def midpoints(x): sl = () for i in range(x.ndim): x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]]) / 2.0 sl += np.index_exp[:] return x
效果示例

内容的提问来源于stack exchange,提问作者zx01p
相关产品推荐
相关产品推荐

