@@ -27,12 +27,11 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
27
27
if _f isa AbstractVector{<: MultiFace }
28
28
if facetype isa MultiFace
29
29
# 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)
32
31
else
33
32
# drop faces for vertex attributes that aren't given
34
33
names = (:position , keys (vertex_attributes)... )
35
- _f2 = map (f -> MultiFace { names} ( getproperty .((f,), names)) , _f)
34
+ _f2 = simplify_faces ( names, _f)
36
35
37
36
# and remap to a simple face type so that decompose can handle the rest
38
37
_f, mappings = merge_vertex_indices (_f2)
@@ -47,7 +46,6 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
47
46
return Mesh (positions, f; vertex_attributes... )
48
47
end
49
48
50
-
51
49
const SimpleMesh{N, T, FT} = Mesh{N, T, FT, (:position ,), Tuple{Vector{Point{N, T}}}, Vector{FT}}
52
50
const SimpleTriangleMesh{N} = SimpleMesh{N, Float32, GLTriangleFace}
53
51
@@ -123,41 +121,131 @@ function volume(mesh::Mesh)
123
121
return sum (volume, mesh)
124
122
end
125
123
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
+
126
130
function Base. merge (meshes:: AbstractVector{<:Mesh} )
127
131
return if isempty (meshes)
128
132
return Mesh (Point3f[], GLTriangleFace[])
129
133
elseif length (meshes) == 1
130
134
return meshes[1 ]
131
135
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
+ )
143
149
end
144
- return Mesh (ps, fs)
145
- end
146
- end
147
150
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)
156
230
end
231
+
157
232
end
158
- return MetaMesh (big_mesh, big_meta)
159
233
end
160
234
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
+
161
249
# TODO : naming
162
250
# synchronize_vertex_attributes
163
251
# merge_vertex_(attribute)_indices
@@ -170,10 +258,28 @@ function merge_vertex_indices(mesh)
170
258
return Mesh (attribs, fs, views)
171
259
end
172
260
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
+
173
278
function merge_vertex_indices (
174
279
attribs:: NamedTuple{Names} ,
175
280
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
177
283
) where {Names, N, T, FT}
178
284
179
285
# Note: typing checks for matching Names
@@ -186,17 +292,16 @@ function merge_vertex_indices(
186
292
187
293
new_attribs = NamedTuple ((Pair (k, similar (v, 0 )) for (k, v) in pairs (attribs)))
188
294
new_faces = similar (faces, FT, 0 )
189
- new_views = UnitRange[]
295
+ new_views = UnitRange{Int} []
190
296
297
+ # TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
191
298
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
-
195
299
# Generate new face from current view, with the first vertex_index
196
300
# corresponding to the first vertex attribute added in this iteration
197
301
face_view = view (faces, idxs)
198
302
new_faces_in_view, vertex_map = merge_vertex_indices (face_view, vertex_index_counter)
199
-
303
+ vertex_index_counter += length (vertex_map)
304
+
200
305
# update vertex attributes
201
306
for (name, indices) in pairs (vertex_map)
202
307
append! (new_attribs[name], view (attribs[name], indices))
@@ -211,6 +316,17 @@ function merge_vertex_indices(
211
316
return new_attribs, new_faces, new_views
212
317
end
213
318
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
+
214
330
function merge_vertex_indices (
215
331
faces:: AbstractVector{<: MultiFace{N, T, FT, Names, N_Attrib}} ,
216
332
vertex_index_counter = T (1 )
0 commit comments