@@ -81,6 +81,53 @@ function Base.show(io::IO, x::NgonFace{N, T}) where {N, T}
8181 return print (io, name, " (" , join (value .(x), " , " ), " )" )
8282end
8383
84+ # two faces are the same if they match or they just cycle indices
85+ function Base.:(== )(f1:: FT , f2:: FT ) where {N, FT <: AbstractFace{N} }
86+ _, min_i1 = findmin (f1. data)
87+ _, min_i2 = findmin (f2. data)
88+ @inbounds for i in 1 : N
89+ if f1[mod1 (min_i1 + i, end )] != = f2[mod1 (min_i2 + i, end )]
90+ return false
91+ end
92+ end
93+ return true
94+ end
95+ function Base. hash (f:: AbstractFace{N} , h:: UInt ) where {N}
96+ _, min_i = findmin (f. data)
97+ @inbounds for i in min_i: N
98+ h = hash (f[i], h)
99+ end
100+ @inbounds for i in 1 : min_i- 1
101+ h = hash (f[i], h)
102+ end
103+ return h
104+ end
105+ Base. isequal (f1:: AbstractFace , f2:: AbstractFace ) = == (f1, f2)
106+
107+ # Fastpaths
108+ Base.:(== )(f1:: FT , f2:: FT ) where {FT <: AbstractFace{2} } = minmax (f1. data... ) == minmax (f2. data... )
109+ Base. hash (f:: AbstractFace{2} , h:: UInt ) = hash (minmax (f. data... ), h)
110+
111+ function Base.:(== )(f1:: FT , f2:: FT ) where {FT <: AbstractFace{3} }
112+ return (f1. data == f2. data) || (f1. data == (f2[2 ], f2[3 ], f2[1 ])) ||
113+ (f1. data == (f2[3 ], f2[1 ], f2[2 ]))
114+ end
115+ function Base. hash (f:: AbstractFace{3} , h:: UInt )
116+ if f[1 ] < f[2 ]
117+ if f[1 ] < f[3 ]
118+ return hash (f. data, h)
119+ else
120+ return hash ((f[3 ], f[1 ], f[2 ]), h)
121+ end
122+ else
123+ if f[2 ] < f[3 ]
124+ return hash ((f[2 ], f[3 ], f[1 ]), h)
125+ else
126+ return hash ((f[3 ], f[1 ], f[2 ]), h)
127+ end
128+ end
129+ end
130+
84131Face (:: Type{<:NgonFace{N}} , :: Type{T} ) where {N,T} = NgonFace{N,T}
85132Face (F:: Type{NgonFace{N,FT}} , :: Type{T} ) where {FT,N,T} = F
86133
0 commit comments