Skip to content

Commit 290e220

Browse files
authored
Add convenience function for per-face data (#254)
* add per_face() utility function * add some documentation
1 parent 0c43d8e commit 290e220

File tree

4 files changed

+47
-0
lines changed

4 files changed

+47
-0
lines changed

docs/src/meshes.md

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ On a larger scale this can be useful for memory and performance reason, e.g. whe
3535
It can also simplify some definitions, like for example `Rect3`.
3636
In that case we have 8 positions and 6 normals with FaceViews, or 24 without (assuming per-face normals).
3737

38+
For the relatively common case of per-face data, you can use the `per_face` convenience function.
39+
40+
```@docs
41+
per_face
42+
```
3843

3944
## MetaMesh
4045

src/GeometryBasics.jl

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export expand_faceviews, split_mesh, remove_duplicates
4545
export face_normals
4646
export Tessellation, Normal, UV, UVW
4747
export AbstractMesh, Mesh, MetaMesh, FaceView
48+
export per_face
4849

4950

5051
# all the different predefined mesh types

src/meshes.jl

+27
Original file line numberDiff line numberDiff line change
@@ -585,3 +585,30 @@ function Base.show(io::IO, mesh::MetaMesh{N, T}) where {N, T}
585585
FT = eltype(faces(mesh))
586586
println(io, "MetaMesh{$N, $T, $(FT)}($(join(keys(meta(mesh)), ", ")))")
587587
end
588+
589+
"""
590+
per_face(data, faces)
591+
per_face(data, mesh)
592+
593+
Generates a `FaceView` that applies the given data per face, rather than per
594+
vertex. The result can then be used to create a (new) mesh:
595+
```
596+
mesh(..., attribute_name = per_face(data, faces))
597+
mesh(old_mesh, attribute_name = per_face(data, old_mesh))
598+
```
599+
"""
600+
per_face(data, geom::AbstractGeometry) = per_face(data, faces(geom))
601+
function per_face(data, faces::AbstractVector{<: AbstractFace})
602+
if length(data) != length(faces)
603+
error("Length of per-face data $(length(data)) must match the number of faces $(length(faces))")
604+
end
605+
606+
return FaceView(data, [typeof(f)(i) for (i, f) in enumerate(faces)])
607+
end
608+
function per_face(data, faces::AbstractVector{FT}) where {N, FT <: AbstractFace{N}}
609+
if length(data) != length(faces)
610+
error("Length of per-face data $(length(data)) must match the number of faces $(length(faces))")
611+
end
612+
613+
return FaceView(data, FT.(eachindex(faces)))
614+
end

test/meshes.jl

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ end
2020
p = Point2f[(0, 1), (1, 2), (3, 4), (4, 5)]
2121
m = Mesh(p, f)
2222
@test collect(m) == [Triangle(p[1], p[2], p[3]), GeometryBasics.Quadrilateral(p[1], p[2], p[3], p[4])]
23+
24+
facedata = FaceView([:red, :blue], [TriangleFace(1), QuadFace(2)])
25+
m2 = GeometryBasics.mesh(m, color = facedata)
26+
m3 = expand_faceviews(m2)
27+
@test faces(m3) == GLTriangleFace[(1,2,3), (4,5,6), (4,6,7)]
28+
@test coordinates(m3) == Point2f[[0.0, 1.0], [1.0, 2.0], [3.0, 4.0], [0.0, 1.0], [1.0, 2.0], [3.0, 4.0], [4.0, 5.0]]
29+
@test m3.color == [:red, :red, :red, :blue, :blue, :blue, :blue]
30+
31+
@test per_face([:red, :blue], f) == facedata
32+
@test per_face([:red, :blue], m) == facedata
33+
@test per_face([:red, :blue, :blue], m2) == FaceView([:red, :blue, :blue], GLTriangleFace.(1:3))
34+
@test per_face([:red, :blue, :blue], m3) == FaceView([:red, :blue, :blue], GLTriangleFace.(1:3))
2335
end
2436

2537
@testset "Ambiguous NgonFace constructors" begin
@@ -49,6 +61,8 @@ end
4961
@test normals(m) == GeometryBasics.FaceView([Vec3f(0,0,1)], [QuadFace(1)])
5062
@test isempty(m.views)
5163

64+
@test per_face([Vec3f(0,0,1)], m) == m.normal
65+
5266
@test faces(m2) == [QuadFace(1,2,3,4)]
5367
@test coordinates(m2) == coordinates(m)
5468
@test normals(m2) != normals(m)

0 commit comments

Comments
 (0)