Skip to content

Commit 3b7784c

Browse files
authored
Merge pull request #43 from JuliaGeometry/sd/meta
preserve meta when converting
2 parents 009860d + 2313fc1 commit 3b7784c

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

src/meshes.jl

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,25 +110,32 @@ function mesh(primitive::Meshable;
110110
# triangulation.jl
111111
faces = decompose(facetype, positions)
112112
end
113-
attributes = Dict{Symbol, Any}()
113+
114+
# We want to preserve any existing attributes!
115+
attrs = attributes(primitive)
116+
# Make sure this doesn't contain position, we'll add position explicitely via meta!
117+
delete!(attrs, :position)
114118

115119
if uv !== nothing
116-
attributes[:uv] = decompose(UV(uv), primitive)
120+
# this may overwrite an existing :uv, but will only create a copy
121+
# if it has a different eltype, otherwise it should replace it
122+
# with exactly the same instance - which is what we want here
123+
attrs[:uv] = decompose(UV(uv), primitive)
117124
end
118125

119126
if normaltype !== nothing
120127
primitive_normals = normals(primitive)
121128
if primitive_normals !== nothing
122-
attributes[:normals] = decompose(normaltype, primitive_normals)
129+
attrs[:normals] = decompose(normaltype, primitive_normals)
123130
else
124131
# Normals not implemented for primitive, so we calculate them!
125-
n = normals(positions, faces)
132+
n = normals(positions, faces; normaltype=normaltype)
126133
if n !== nothing # ok jeez, this is a 2d mesh which cant have normals
127-
attributes[:normals] = n
134+
attrs[:normals] = n
128135
end
129136
end
130137
end
131-
return Mesh(meta(positions; attributes...), faces)
138+
return Mesh(meta(positions; attrs...), faces)
132139
end
133140

134141
"""
@@ -231,7 +238,7 @@ Attaches metadata to the coordinates of a mesh
231238
"""
232239
function pointmeta(mesh::Mesh; meta_data...)
233240
points = coordinates(mesh)
234-
attr = GeometryBasics.attributes(points)
241+
attr = attributes(points)
235242
delete!(attr, :position) # position == metafree(points)
236243
# delete overlapping attributes so we can replace with `meta_data`
237244
foreach(k-> delete!(attr, k), keys(meta_data))
@@ -253,7 +260,7 @@ Returns the new mesh, and the property!
253260
"""
254261
function pop_pointmeta(mesh::Mesh, property::Symbol)
255262
points = coordinates(mesh)
256-
attr = GeometryBasics.attributes(points)
263+
attr = attributes(points)
257264
delete!(attr, :position) # position == metafree(points)
258265
# delete overlapping attributes so we can replace with `meta_data`
259266
m = pop!(attr, property)
@@ -268,3 +275,7 @@ Attaches metadata to the faces of a mesh
268275
function facemeta(mesh::Mesh; meta_data...)
269276
return Mesh(coordinates(mesh), meta(faces(mesh); meta_data...))
270277
end
278+
279+
function attributes(hasmeta::Mesh)
280+
return Dict{Symbol, Any}((name => getproperty(hasmeta, name) for name in propertynames(hasmeta)))
281+
end

src/metadata.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,18 @@ Table interface for this functionality. Once this is in e.g. Tables.jl,
44
it should be removed from GeometryBasics!
55
=#
66

7+
"""
8+
attributes(hasmeta)
9+
Returns all attributes of meta as a Dict{Symbol, Any}.
10+
Needs to be overloaded, and returns empty dict for non overloaded types!
11+
Gets overloaded by default for all Meta types.
12+
"""
713
function attributes(hasmeta)
8-
return Dict((name => getproperty(hasmeta, name) for name in propertynames(hasmeta)))
14+
return Dict{Symbol, Any}()
15+
end
16+
17+
function attributes(hasmeta::StructArray)
18+
return Dict{Symbol, Any}((name => getproperty(hasmeta, name) for name in propertynames(hasmeta)))
919
end
1020

1121
"""
@@ -88,6 +98,10 @@ macro meta_type(name, mainfield, supertype, params...)
8898
return $MetaName(main; meta...)
8999
end
90100

101+
function GeometryBasics.attributes(hasmeta::$MetaName)
102+
return Dict{Symbol, Any}((name => getproperty(hasmeta, name) for name in propertynames(hasmeta)))
103+
end
104+
91105
function GeometryBasics.meta(elements::AbstractVector{T}; meta...) where T <: $supertype
92106
isempty(meta) && return elements # no meta to add!
93107
n = length(elements)
@@ -127,6 +141,8 @@ macro meta_type(name, mainfield, supertype, params...)
127141
) where {$(params...), Typ, Names, Types}
128142
$MetaName(metafree, NamedTuple{Names, Types}(args))
129143
end
144+
145+
130146
end
131147
return esc(expr)
132148
end

test/runtests.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,27 @@ end
323323
include("geometrytypes.jl")
324324
end
325325

326+
@testset "convert mesh + meta" begin
327+
m = uv_normal_mesh(FRect3D(Vec3f0(-1), Vec3f0(1, 2, 3)))
328+
m_normal = normal_mesh(m)
329+
# make sure we don't loose the uv
330+
@test hasproperty(m_normal, :uv)
331+
@test m == m_normal
332+
# Make sure we don't create any copies
333+
@test m.position === m_normal.position
334+
@test m.normals === m_normal.normals
335+
@test m.uv === m_normal.uv
336+
337+
m = GeometryBasics.mesh(FRect3D(Vec3f0(-1), Vec3f0(1, 2, 3));
338+
uv=Vec2{Float64}, normaltype=Vec3{Float64}, pointtype=Point3{Float64})
339+
m_normal = normal_mesh(m)
340+
@test hasproperty(m_normal, :uv)
341+
@test m.position !== m_normal.position
342+
@test m.normals !== m_normal.normals
343+
# uv stays untouched, since we don't specify the element type in normalmesh
344+
@test m.uv === m_normal.uv
345+
end
346+
326347
@testset "modifying meta" begin
327348
xx = rand(10)
328349
points = rand(Point3f0, 10)

0 commit comments

Comments
 (0)