@@ -27,12 +27,11 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
2727 if _f isa AbstractVector{<: MultiFace }
2828 if facetype isa MultiFace
2929 # drop faces that facetype doesn't include
30- names = propertynames (facetype)
31- _f = map (f -> MultiFace {names} (getproperty .((f,), names)), _f)
30+ _f = simplify_faces (facetype, _f)
3231 else
3332 # drop faces for vertex attributes that aren't given
3433 names = (:position , keys (vertex_attributes)... )
35- _f2 = map (f -> MultiFace { names} ( getproperty .((f,), names)) , _f)
34+ _f2 = simplify_faces ( names, _f)
3635
3736 # and remap to a simple face type so that decompose can handle the rest
3837 _f, mappings = merge_vertex_indices (_f2)
@@ -47,7 +46,6 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
4746 return Mesh (positions, f; vertex_attributes... )
4847end
4948
50-
5149const SimpleMesh{N, T, FT} = Mesh{N, T, FT, (:position ,), Tuple{Vector{Point{N, T}}}, Vector{FT}}
5250const SimpleTriangleMesh{N} = SimpleMesh{N, Float32, GLTriangleFace}
5351
@@ -123,41 +121,133 @@ function volume(mesh::Mesh)
123121 return sum (volume, mesh)
124122end
125123
124+ # TODO : Is this ok as "public" function?
125+ # MultiFace(f1, f2, f3) + (o1, o2, o3) = MultiFace(f1 + o1, f2 + o2, f3 + o3)
126+ function Base.:+ (f:: MultiFace{N, T, FT, Names, M} , o:: NTuple{M, T} ) where {N, T, FT, Names, M}
127+ return MultiFace {Names} (ntuple (m -> f[m] + o[m], M))
128+ end
129+
126130function Base. merge (meshes:: AbstractVector{<:Mesh} )
127131 return if isempty (meshes)
128132 return Mesh (Point3f[], GLTriangleFace[])
129133 elseif length (meshes) == 1
130134 return meshes[1 ]
131135 else
132- ps = reduce (vcat, coordinates .(meshes))
133- fs = reduce (vcat, faces .(meshes))
134- idx = length (faces (meshes[1 ]))
135- offset = length (coordinates (meshes[1 ]))
136- for mesh in Iterators. drop (meshes, 1 )
137- N = length (faces (mesh))
138- for i = idx .+ (1 : N)
139- fs[i] = fs[i] .+ offset
140- end
141- idx += N
142- offset += length (coordinates (mesh))
136+
137+ m1 = meshes[1 ]
138+
139+ # Check that all meshes use the same VertexAttributes
140+ # Could also do this via typing the function, but maybe error is nice?
141+ names = propertynames (m1. vertex_attributes)
142+ idx = findfirst (m -> propertynames (m. vertex_attributes) != names, meshes)
143+ if idx != = nothing
144+ error (
145+ " Cannot merge meshes with different vertex attributes. " *
146+ " First missmatch between meshes[1] with $names and " *
147+ " meshes[$idx ] with $(propertynames (meshes[idx])) ."
148+ )
143149 end
144- return Mesh (ps, fs)
145- end
146- end
147150
148- function Base. merge (meshes:: AbstractVector{T} ) where T <: MetaMesh
149- isempty (meshes) && return T (Point3f[], GLTriangleFace[])
150- big_mesh = merge (map (Mesh, meshes))
151- big_meta = deepcopy (meta (meshes[1 ]))
152- for mesh in Iterators. drop (meshes, 1 )
153- mm = meta (mesh)
154- for (k, v) in pairs (mm)
155- append! (big_meta[k], v)
151+ # We can't merge MultiFace with standard faces because MutliFace allows
152+ # desynchronizes vertex indices that normal faces assume synchronized.
153+ is_multi = facetype (m1) <: MultiFace
154+
155+ if all (m -> is_multi == (facetype (m) <: MultiFace ), meshes)
156+
157+ # All the same kind of face, can just merge
158+
159+ new_attribs = NamedTuple {names} (map (names) do name
160+ return mapreduce (m -> getproperty (m, name), vcat, meshes)
161+ end )
162+ fs = reduce (vcat, faces .(meshes))
163+
164+ # TODO : is the type difference in offset bad?
165+ idx = length (faces (m1))
166+ offset = is_multi ? length .(values (vertex_attributes (m1))) : length (coordinates (m1))
167+ views = isempty (m1. views) ? [1 : idx] : copy (m1. views)
168+
169+ for mesh in Iterators. drop (meshes, 1 )
170+ # update face indices
171+ N = length (faces (mesh))
172+ for i = idx .+ (1 : N)
173+ fs[i] = fs[i] + offset
174+ end
175+
176+ # add views
177+ if isempty (mesh. views)
178+ push! (views, idx+ 1 : idx+ N)
179+ else
180+ append! (views, (view + idx for view in mesh. views))
181+ end
182+
183+ idx += N
184+ if is_multi
185+ offset = offset .+ length .(values (vertex_attributes (mesh)))
186+ else
187+ offset += length (coordinates (mesh))
188+ end
189+ end
190+
191+ return Mesh (new_attribs, fs, views)
192+
193+ else
194+
195+ # TODO : We can probably simplify this to `merge(merge_vertex_indices.(meshes))`
196+ # but need to check performance
197+
198+
199+ # Varying ace types, need to convert MultiFace
200+ new_attribs = NamedTuple {names} (similar .(values (vertex_attributes (m1)), 0 ))
201+ FT = facetype (m1) <: MultiFace ? eltype (facetype (m1)) : facetype (m1)
202+ remapped_faces = []
203+ new_views = UnitRange{Int}[]
204+ vertex_index_counter = eltype (FT)(1 )
205+
206+ for mesh in meshes
207+ # convert MultiFace mesh to normal faces, synchronizing vertex indices
208+ attribs, fs, views = merge_vertex_indices (
209+ vertex_attributes (mesh), faces (mesh), mesh. views, vertex_index_counter)
210+
211+ # increment first vertex index used by faces of the next iteration
212+ vertex_index_counter += length (attribs[1 ])
213+
214+ # update merged data
215+ for name in names
216+ append! (new_attribs[name], attribs[name])
217+ end
218+
219+ push! (remapped_faces, fs)
220+
221+ if isempty (views)
222+ push! (new_views, 1 : length (fs))
223+ else
224+ append! (new_views, views)
225+ end
226+ end
227+
228+ # We did MultiFace -> normal face, now equalize normal face types
229+ new_faces = reduce (vcat, remapped_faces)
230+
231+ return Mesh (new_attribs, new_faces, new_views)
156232 end
233+
157234 end
158- return MetaMesh (big_mesh, big_meta)
159235end
160236
237+ # TODO : Probably not our problem
238+ # function Base.merge(meshes::AbstractVector{T}) where T <: MetaMesh
239+ # isempty(meshes) && return T(Point3f[], GLTriangleFace[])
240+ # big_mesh = merge(map(Mesh, meshes))
241+ # big_meta = deepcopy(meta(meshes[1]))
242+ # for mesh in Iterators.drop(meshes, 1)
243+ # mm = meta(mesh)
244+ # for (k, v) in pairs(mm)
245+ # append!(big_meta[k], v)
246+ # end
247+ # end
248+ # return MetaMesh(big_mesh, big_meta)
249+ # end
250+
161251# TODO : naming
162252# synchronize_vertex_attributes
163253# merge_vertex_(attribute)_indices
@@ -170,10 +260,28 @@ function merge_vertex_indices(mesh)
170260 return Mesh (attribs, fs, views)
171261end
172262
263+ function merge_vertex_indices (
264+ attribs:: NamedTuple{Names} ,
265+ faces:: AbstractVector{<: FT} ,
266+ views:: Vector{UnitRange{Int}} ,
267+ vertex_index_counter = nothing
268+ ) where {Names, FT <: AbstractFace }
269+
270+ if FT <: MultiFace
271+ error (
272+ " Failed to call correct method. This likely happened because vertex " *
273+ " attributes names $Names do not match face name $(propertynames (first (faces))) ."
274+ )
275+ end
276+
277+ return attribs, faces, views
278+ end
279+
173280function merge_vertex_indices (
174281 attribs:: NamedTuple{Names} ,
175282 faces:: AbstractVector{<: MultiFace{N, T, FT, Names}} ,
176- views:: Vector{UnitRange}
283+ views:: Vector{UnitRange{Int}} ,
284+ vertex_index_counter = T (1 ) # TODO : test 0 vs 1 base
177285 ) where {Names, N, T, FT}
178286
179287 # Note: typing checks for matching Names
@@ -186,17 +294,16 @@ function merge_vertex_indices(
186294
187295 new_attribs = NamedTuple ((Pair (k, similar (v, 0 )) for (k, v) in pairs (attribs)))
188296 new_faces = similar (faces, FT, 0 )
189- new_views = UnitRange[]
297+ new_views = UnitRange{Int} []
190298
299+ # TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
191300 for idxs in views
192- # TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
193- vertex_index_counter = T (length (new_attribs[1 ]) + 1 )
194-
195301 # Generate new face from current view, with the first vertex_index
196302 # corresponding to the first vertex attribute added in this iteration
197303 face_view = view (faces, idxs)
198304 new_faces_in_view, vertex_map = merge_vertex_indices (face_view, vertex_index_counter)
199-
305+ vertex_index_counter += length (vertex_map)
306+
200307 # update vertex attributes
201308 for (name, indices) in pairs (vertex_map)
202309 append! (new_attribs[name], view (attribs[name], indices))
@@ -211,6 +318,17 @@ function merge_vertex_indices(
211318 return new_attribs, new_faces, new_views
212319end
213320
321+ function merge_vertex_indices (
322+ faces:: AbstractVector{FT} ,
323+ vertex_index_counter = T (1 )
324+ ) where {N, T, FT <: AbstractFace{N, T} }
325+
326+ @assert ! (FT <: MultiFace ) " Dispatch failed?"
327+
328+ N_vert = mapreduce (f -> max (f), max, faces)
329+ return faces, (1 : N_vert) .+ vertex_index_counter
330+ end
331+
214332function merge_vertex_indices (
215333 faces:: AbstractVector{<: MultiFace{N, T, FT, Names, N_Attrib}} ,
216334 vertex_index_counter = T (1 )
0 commit comments