我的问题是我有两面墙,在3D空间中表示为2D平面(wallA
和wallB
)。这些墙是重叠的。我需要将其转换为三个墙部分,一个用于wallA.intersect(wallB)
,一个用于wallA.diff(wallB)
,一个用于wallB.diff(wallA)
。
我认为我需要做的是将它们旋转到2D空间,而不改变它们的重叠,执行剪裁以识别差异和相交,然后将新墙旋转回原始平面。
墙壁不一定是垂直的,否则问题可能会更简单。
我的问题的剪辑部分可以使用pyclipper
在2D中轻松解决。我遇到的问题是可以将墙壁可恢复地转换成2D的算法。
根据我的理解,与this question中的步骤类似但不完全相同。我看了transforms3D
这看起来非常有用,但是我不太明白我需要使用哪些函数或什么组合来重现该算法。
这是我想要实现的一个例子,使用一对2 x 2垂直曲面的简单示例,在一个角落中重叠1 x 1正方形。
import pyclipper as pc
wallA= [(0,0,2), (2,0,2), (2,0,0), (0,0,0)]
wallB = [(1,0,3), (3,0,3), (3,0,1), (1,0,1)]
expected_overlaps = [[(1,0,2), (2,0,2), (2,0,1), (1,0,1)]]
wallA_2d = transform_to_2D(wallA, <whatever else is needed>)
wallB_2d = transform_to_2D(wallB, <whatever else is needed>)
scaledA = pc.scale_to_clipper(wallA_2d)
scaledB = pc.scale_to_clipper(wallB_2d)
clipper = pc.Pyclipper()
clipper.AddPath(scaledA, poly_type=pc.PT_SUBJECT, closed=True)
clipper.AddPath(scaledB, poly_type=pc.PT_CLIP, closed=True)
# just showing the intersection - differences are handled similarly
intersections = clipper.Execute(
pc.CT_INTERSECTION, pc.PFT_NONZERO, pc.PFT_NONZERO)
intersections = [pc.scale_from_clipper(i) for i in intersections]
overlaps = [transform_to_3D(i, <whatever else is needed>) for i in intersections]
assert overlaps == expected_overlaps
我正在寻找的是对transform_to_2d
和transform_to_3d
所需步骤的解释。
答案 0 :(得分:2)
您可以简单地投射,而不是旋转。关键是将3d空间映射到2d平面,然后可以反转。 (当您回映时,投影产生的任何失真都将被撤消。)为此,您应首先找到包含两个墙的平面。以下是一些示例代码:
wallA = [(0,0,2), (2,0,2), (2,0,0), (0,0,0)]
wallB = [(1,0,3), (3,0,3), (3,0,1), (1,0,1)]
v = (0, 1, 0) # the normal vector
a = 0 # a number so that v[0] * x + v[1] * y + v[2] * z = a is the equation of the plane containing your walls
# To calculate the normal vector in general,
# you would take the cross product of any two
# vectors in the plane of your walls, e.g.
# (wallA[1] - wallA[0]) X (wallA[2] - wallA[0]).
# You can then solve for a.
proj_axis = max(range(3), key=lambda i: abs(v[i]))
# this just needs to be any number such that v[proj_axis] != 0
def project(x):
# Project onto either the xy, yz, or xz plane. (We choose the one that avoids degenerate configurations, which is the purpose of proj_axis.)
# In this example, we would be projecting onto the xz plane.
return tuple(c for i, c in enumerate(x) if i != proj_axis)
def project_inv(x):
# Returns the vector w in the walls' plane such that project(w) equals x.
w = list(x)
w[proj_axis:proj_axis] = [0.0]
c = a
for i in range(3):
c -= w[i] * v[i]
c /= v[proj_axis]
w[proj_axis] = c
return tuple(w)
projA = [project(x) for x in wallA]
projB = [project(x) for x in wallB]
proj_intersection = intersection(projA, projB) # use your 2d algorithm here
intersection = [project_inv(x) for x in proj_intersection] # this is your intersection in 3d; you can do similar things for the other pieces