Skip to content

Commit 205d8b5

Browse files
committed
add a test for precise mode
1 parent ef164d5 commit 205d8b5

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

tests/test_polygons.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,15 @@ def test_project_backface():
117117

118118

119119
def test_project_multi():
120-
mesh = g.trimesh.creation.box() + g.trimesh.creation.box().apply_translation(
121-
[3, 0, 0]
122-
)
123-
proj = mesh.projected(normal=[0, 0, 1])
120+
for ignore_sign, precise in g.itertools.combinations([True, False] * 2, 2):
121+
mesh = g.trimesh.creation.box() + g.trimesh.creation.box().apply_translation(
122+
[3, 0, 0]
123+
)
124+
proj = mesh.projected(normal=[0, 0, 1], ignore_sign=ignore_sign, precise=precise)
124125

125-
assert mesh.body_count == 2
126-
assert len(proj.root) == 2
127-
assert g.np.isclose(proj.area, 2.0)
126+
assert mesh.body_count == 2
127+
assert len(proj.root) == 2
128+
assert g.np.isclose(proj.area, 2.0)
128129

129130

130131
def test_second_moment():

trimesh/path/polygons.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,29 @@ def projected(
828828
vertices_2D = transform_points(mesh.vertices, to_2D)[:, :2]
829829

830830
if precise:
831+
# precise mode just unions triangles as one shapely
832+
# polygon per triangle which historically has been very slow
833+
# but it is more defensible intellectually
831834
faces = mesh.faces[side]
832-
# Cleanup vertices
833-
vertices_2D_rounded = np.round(vertices_2D, int(np.abs(np.round(np.log10(precise_eps))) + 1))
834-
triangles = vertices_2D_rounded[np.column_stack((faces, faces[:, :1]))]
835-
valid = ~(triangles[:,[0,0,2]] == triangles[:,[1,2,1]]).all(axis=2).any(axis=1)
836-
triangles = triangles[valid]
837-
# Union all the polygons
838-
return ops.unary_union([Polygon(f) for f in triangles]).buffer(precise_eps).buffer(-precise_eps)
835+
# round the 2D vertices with slightly more precision
836+
# than our final dilate-erode cleanup
837+
digits = int(np.abs(np.log10(precise_eps)) + 2)
838+
rounded = np.round(vertices_2D, digits)
839+
# get the triangles as closed 4-vertex polygons
840+
triangles = rounded[np.column_stack((faces, faces[:, :1]))]
841+
# do a check for exactly-degenerate triangles where any two
842+
# vertices are exactly identical which means the triangle has
843+
# zero area
844+
valid = ~(triangles[:, [0, 0, 2]] == triangles[:, [1, 2, 1]]).all(axis=2).any(
845+
axis=1
846+
)
847+
# union the valid triangles and then dilate-erode to clean up
848+
# any holes or defects smaller than precise_eps
849+
return (
850+
ops.unary_union([Polygon(f) for f in triangles[valid]])
851+
.buffer(precise_eps)
852+
.buffer(-precise_eps)
853+
)
839854

840855
# a sequence of face indexes that are connected
841856
face_groups = graph.connected_components(adjacency, nodes=np.nonzero(side)[0])

0 commit comments

Comments
 (0)