@@ -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,131 @@ 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 : find simplest face type to target
196+
197+ # Varying ace types, need to convert MultiFace
198+ new_attribs = NamedTuple {names} (similar .(values (vertex_attributes (m1)), 0 ))
199+ FT = facetype (m1) <: MultiFace ? eltype (facetype (m1)) : facetype (m1)
200+ remapped_faces = []
201+ new_views = UnitRange{Int}[]
202+ vertex_index_counter = eltype (FT)(1 )
203+
204+ for mesh in meshes
205+ # convert MultiFace mesh to normal faces, synchronizing vertex indices
206+ attribs, fs, views = merge_vertex_indices (
207+ vertex_attributes (mesh), faces (mesh), mesh. views, vertex_index_counter)
208+
209+ # increment first vertex index used by faces of the next iteration
210+ vertex_index_counter += length (attribs[1 ])
211+
212+ # update merged data
213+ for name in names
214+ append! (new_attribs[name], attribs[name])
215+ end
216+
217+ push! (remapped_faces, fs)
218+
219+ if isempty (views)
220+ push! (new_views, 1 : length (fs))
221+ else
222+ append! (new_views, views)
223+ end
224+ end
225+
226+ # We did MultiFace -> normal face, now equalize normal face types
227+ new_faces = reduce (vcat, remapped_faces)
228+
229+ return Mesh (new_attribs, new_faces, new_views)
156230 end
231+
157232 end
158- return MetaMesh (big_mesh, big_meta)
159233end
160234
235+ # TODO : Probably not our problem
236+ # function Base.merge(meshes::AbstractVector{T}) where T <: MetaMesh
237+ # isempty(meshes) && return T(Point3f[], GLTriangleFace[])
238+ # big_mesh = merge(map(Mesh, meshes))
239+ # big_meta = deepcopy(meta(meshes[1]))
240+ # for mesh in Iterators.drop(meshes, 1)
241+ # mm = meta(mesh)
242+ # for (k, v) in pairs(mm)
243+ # append!(big_meta[k], v)
244+ # end
245+ # end
246+ # return MetaMesh(big_mesh, big_meta)
247+ # end
248+
161249# TODO : naming
162250# synchronize_vertex_attributes
163251# merge_vertex_(attribute)_indices
@@ -170,10 +258,28 @@ function merge_vertex_indices(mesh)
170258 return Mesh (attribs, fs, views)
171259end
172260
261+ function merge_vertex_indices (
262+ attribs:: NamedTuple{Names} ,
263+ faces:: AbstractVector{<: FT} ,
264+ views:: Vector{UnitRange{Int}} ,
265+ vertex_index_counter = nothing
266+ ) where {Names, FT <: AbstractFace }
267+
268+ if FT <: MultiFace
269+ error (
270+ " Failed to call correct method. This likely happened because vertex " *
271+ " attributes names $Names do not match face name $(propertynames (first (faces))) ."
272+ )
273+ end
274+
275+ return attribs, faces, views
276+ end
277+
173278function merge_vertex_indices (
174279 attribs:: NamedTuple{Names} ,
175280 faces:: AbstractVector{<: MultiFace{N, T, FT, Names}} ,
176- views:: Vector{UnitRange}
281+ views:: Vector{UnitRange{Int}} ,
282+ vertex_index_counter = T (1 ) # TODO : test 0 vs 1 base
177283 ) where {Names, N, T, FT}
178284
179285 # Note: typing checks for matching Names
@@ -186,17 +292,16 @@ function merge_vertex_indices(
186292
187293 new_attribs = NamedTuple ((Pair (k, similar (v, 0 )) for (k, v) in pairs (attribs)))
188294 new_faces = similar (faces, FT, 0 )
189- new_views = UnitRange[]
295+ new_views = UnitRange{Int} []
190296
297+ # TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
191298 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-
195299 # Generate new face from current view, with the first vertex_index
196300 # corresponding to the first vertex attribute added in this iteration
197301 face_view = view (faces, idxs)
198302 new_faces_in_view, vertex_map = merge_vertex_indices (face_view, vertex_index_counter)
199-
303+ vertex_index_counter += length (vertex_map)
304+
200305 # update vertex attributes
201306 for (name, indices) in pairs (vertex_map)
202307 append! (new_attribs[name], view (attribs[name], indices))
@@ -211,6 +316,17 @@ function merge_vertex_indices(
211316 return new_attribs, new_faces, new_views
212317end
213318
319+ function merge_vertex_indices (
320+ faces:: AbstractVector{FT} ,
321+ vertex_index_counter = T (1 )
322+ ) where {N, T, FT <: AbstractFace{N, T} }
323+
324+ @assert ! (FT <: MultiFace ) " Dispatch failed?"
325+
326+ N_vert = mapreduce (f -> max (f), max, faces)
327+ return faces, (1 : N_vert) .+ vertex_index_counter
328+ end
329+
214330function merge_vertex_indices (
215331 faces:: AbstractVector{<: MultiFace{N, T, FT, Names, N_Attrib}} ,
216332 vertex_index_counter = T (1 )
0 commit comments