@@ -462,15 +462,80 @@ function split_mesh(mesh::Mesh, views::Vector{<: UnitRange{<: Integer}} = mesh.v
462
462
end
463
463
end
464
464
465
+
466
+
467
+ # two faces are the same if they match or they just cycle indices
468
+ """
469
+ cyclic_equal(face1, face2)
470
+
471
+ Returns true if two faces are equal up to a cyclic permutation of their indices.
472
+ E.g. considers `GLTriangleFace(2,3,1)` equal to `GLTriangleFace(1,2,3)` but not
473
+ `GLTriangleFace(2,1,3)`.
474
+ """
475
+ function cyclic_equal (f1:: FT , f2:: FT ) where {N, FT <: AbstractFace{N} }
476
+ _, min_i1 = findmin (f1. data)
477
+ _, min_i2 = findmin (f2. data)
478
+ @inbounds for i in 1 : N
479
+ if f1[mod1 (min_i1 + i, end )] != = f2[mod1 (min_i2 + i, end )]
480
+ return false
481
+ end
482
+ end
483
+ return true
484
+ end
485
+
486
+ """
487
+ cyclic_hash(face[, h::UInt = hash(0)])
488
+
489
+ Creates a hash for the given face that is equal under cyclic permutation of the
490
+ faces indices.
491
+ For example `GLTriangleFace(1,2,3)` will have the same hash as `(2,3,1)` and
492
+ `(3,1,2)`, but be different from `(1,3,2)` and its cyclic permutations.
493
+ """
494
+ function cyclic_hash (f:: AbstractFace{N} , h:: UInt = hash (0 )) where {N}
495
+ _, min_i = findmin (f. data)
496
+ @inbounds for i in min_i: N
497
+ h = hash (f[i], h)
498
+ end
499
+ @inbounds for i in 1 : min_i- 1
500
+ h = hash (f[i], h)
501
+ end
502
+ return h
503
+ end
504
+
505
+ # Fastpaths
506
+ cyclic_equal (f1:: FT , f2:: FT ) where {FT <: AbstractFace{2} } = minmax (f1. data... ) == minmax (f2. data... )
507
+ cyclic_hash (f:: AbstractFace{2} , h:: UInt = hash (0 )) = hash (minmax (f. data... ), h)
508
+
509
+ function cyclic_equal (f1:: FT , f2:: FT ) where {FT <: AbstractFace{3} }
510
+ return (f1. data == f2. data) || (f1. data == (f2[2 ], f2[3 ], f2[1 ])) ||
511
+ (f1. data == (f2[3 ], f2[1 ], f2[2 ]))
512
+ end
513
+ function cyclic_hash (f:: AbstractFace{3} , h:: UInt = hash (0 ))
514
+ if f[1 ] < f[2 ]
515
+ if f[1 ] < f[3 ]
516
+ return hash (f. data, h)
517
+ else
518
+ return hash ((f[3 ], f[1 ], f[2 ]), h)
519
+ end
520
+ else
521
+ if f[2 ] < f[3 ]
522
+ return hash ((f[2 ], f[3 ], f[1 ]), h)
523
+ else
524
+ return hash ((f[3 ], f[1 ], f[2 ]), h)
525
+ end
526
+ end
527
+ end
528
+
529
+
465
530
"""
466
531
remove_duplicates(faces)
467
532
468
533
Uses a Dict to remove duplicates from the given `faces`.
469
534
"""
470
535
function remove_duplicates (fs:: AbstractVector{FT} ) where {FT <: AbstractFace }
471
- hashmap = Dict {FT, Nothing } ()
472
- foreach (k -> setindex! ( hashmap, nothing , k) , fs)
473
- return collect (keys (hashmap))
536
+ hashmap = Dict {UInt64, FT } ()
537
+ foreach (f -> hashmap[ cyclic_hash (f)] = f , fs)
538
+ return collect (values (hashmap))
474
539
end
475
540
476
541
0 commit comments