Skip to content

Commit 73aedef

Browse files
committed
test split_mesh
1 parent 7782992 commit 73aedef

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

src/basic_types.jl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,65 @@ function Base.:(==)(a::Mesh, b::Mesh)
641641
(faces(a) == faces(b)) && (a.views == b.views)
642642
end
643643

644+
"""
645+
strictly_equal_face_vertices(a::Mesh, b::Mesh)
646+
647+
Checks whether mesh a and b are equal in terms of vertices used in their faces.
648+
This allows for vertex data and indices to be synchronously permuted. For
649+
example, this will recognize
650+
```
651+
a = Mesh([a, b, c], [GLTriangleFace(1,2,3)])
652+
b = Mesh([a, c, b], [GLTriangleFace(1,3,2)])
653+
```
654+
as equal, because while the positions and faces have different orders the vertices
655+
in the face are the same:
656+
```
657+
[a, c, b][[1, 3, 2]] == [a, b, c] == [a, b, c][[1,2,3]]
658+
```
659+
660+
This still returns false if the order of faces is permuted, e.g.
661+
`Mesh(ps, [f1, f2]) != Mesh(ps, [f2, f1])`. It also returns false if vertices are
662+
cyclically permuted within a face, i.e. `ps[[1,2,3]] != ps[[2,3,1]]`.
663+
"""
664+
function strictly_equal_face_vertices(a::Mesh, b::Mesh)
665+
# Quick checks
666+
if propertynames(a) != propertynames(b) || length(faces(a)) != length(faces(b))
667+
return false
668+
end
669+
670+
N = length(faces(a))
671+
# for views we want to ignore empty ranges (they don't represent geometry)
672+
# and treat 1:N as no range (as that is used interchangeably)
673+
views1 = filter(view -> length(view) > 0 && (minimum(view) > 1 || maximum(view) < N), a.views)
674+
views2 = filter(view -> length(view) > 0 && (minimum(view) > 1 || maximum(view) < N), b.views)
675+
views1 != views2 && return false
676+
677+
# TODO: Allow different face orders & cyclic permutation within faces.
678+
# E.g. use hash.(data[face]), cyclically permute min to front, hash result
679+
# and add them to heaps (or sets?) so we can compare them at the end
680+
# That should probably be another function as it's probably a significant
681+
# step up in overhead?
682+
for (attrib1, attrib2) in zip(vertex_attributes(a), vertex_attributes(b))
683+
if attrib1 isa FaceView
684+
if !(attrib2 isa FaceView) || length(faces(attrib1)) != length(faces(attrib2))
685+
return false
686+
end
687+
for (f1, f2) in zip(faces(attrib1), faces(attrib2))
688+
values(attrib1)[f1] == values(attrib2)[f2] || return false
689+
end
690+
else
691+
if attrib2 isa FaceView
692+
return false
693+
end
694+
for (f1, f2) in zip(faces(a), faces(b))
695+
attrib1[f1] == attrib2[f2] || return false
696+
end
697+
end
698+
end
699+
700+
return true
701+
end
702+
644703
function Base.iterate(mesh::Mesh, i=1)
645704
return i - 1 < length(mesh) ? (mesh[i], i + 1) : nothing
646705
end

test/meshes.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ end
7070
@test !allunique([idx for f in faces(dm) for idx in f])
7171
@test !allunique([idx for f in faces(dm.normal) for idx in f])
7272

73+
split_meshes = split_mesh(dm)
74+
@test all(GeometryBasics.strictly_equal_face_vertices.(split_meshes, direct_meshes))
75+
7376
indirect_meshes = map(rects) do r
7477
m = GeometryBasics.mesh(coordinates(r), faces(r), normal = normals(r), facetype = QuadFace{Int64})
7578
# Also testing merge of meshes with views
@@ -81,6 +84,9 @@ end
8184
@test im == dm
8285
@test GeometryBasics.facetype(im) == QuadFace{Int64}
8386

87+
split_meshes = split_mesh(im)
88+
@test all(GeometryBasics.strictly_equal_face_vertices.(split_meshes, indirect_meshes))
89+
8490
converted_meshes = map(rects) do r
8591
m = GeometryBasics.Mesh(coordinates(r), faces(r), normal = normals(r))
8692
GeometryBasics.expand_faceviews(m)
@@ -95,6 +101,8 @@ end
95101
@test coordinates(cm) isa Vector
96102
@test allunique([idx for f in faces(cm) for idx in f])
97103

104+
split_meshes = split_mesh(cm)
105+
@test all(GeometryBasics.strictly_equal_face_vertices.(split_meshes, converted_meshes))
98106

99107
mixed_meshes = map(direct_meshes, indirect_meshes, converted_meshes) do dm, im, cm
100108
rand((dm, im, cm)) # (with FaceView, with mesh.views & FaceView, w/o FaceView)

0 commit comments

Comments
 (0)