Skip to content

Commit

Permalink
Updated/added documentation work towards #20
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin-Mattheus-Moerman committed Mar 25, 2024
1 parent 2554ec9 commit dcc3ed7
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 66 deletions.
10 changes: 5 additions & 5 deletions examples/demo_subtri.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ using GeometryBasics

#=
This demo shows the use of `subtri` to refine triangulated meshes. Each
original input triangle spawns 4 triangles for the regined mesh (one central
original input triangle spawns 4 triangles for the refined mesh (one central
one, and 3 at each corner). The following refinement methods are implemented:
method=:linear : This is the default method, and refines the triangles in
a simple linear manor through splitting. Each input edge simply obtains a
new mid-edge node.
method=:loop : This method features Loop-subdivision. Rather than linearly
method=:Loop : This method features Loop-subdivision. Rather than linearly
splitting edges and maintaining the original coordinates, as for the linear
method, this method computes the new points in a special weighted sense
such that the surface effectively approaches a "quartic box spline". Hence
Expand All @@ -31,9 +31,9 @@ Fn1,Vn1=subtri(F,V,1) # Split once, default is same as: Fn1,Vn1=subtri(F,V,1; me
Fn2,Vn2=subtri(F,V,2) # Split twice
Fn3,Vn3=subtri(F,V,3) # Split 3 times

Fn4,Vn4=subtri(F,V,1; method=:loop) # Split once
Fn5,Vn5=subtri(F,V,2; method=:loop) # Split twice
Fn6,Vn6=subtri(F,V,3; method=:loop) # Split 3 times
Fn4,Vn4=subtri(F,V,1; method=:Loop) # Split once
Fn5,Vn5=subtri(F,V,2; method=:Loop) # Split twice
Fn6,Vn6=subtri(F,V,3; method=:Loop) # Split 3 times

## Visualization
fig = Figure(size=(1600,800))
Expand Down
2 changes: 1 addition & 1 deletion examples/demo_subtri_loop.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ titleString = lift(hSlider.value) do stepIndex
end

Mn = lift(hSlider.value) do stepIndex
Fn,Vn = subtri(F,V,stepIndex; method=:loop)
Fn,Vn = subtri(F,V,stepIndex; method=:Loop)
return GeometryBasics.Mesh(Vn,Fn)
end

Expand Down
30 changes: 29 additions & 1 deletion src/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,34 @@ function edgelengths(M::GeometryBasics.Mesh)
return edgelengths(faces(M),coordinates(M))
end


"""
subtri(F,V,n; method = :linear)
subtri(F,V,n; method = :Loop)
# Description
The`subtri` function refines triangulated meshes iteratively. For each iteration
each original input triangle is split into 4 triangles to form the refined mesh
(one central one, and 3 at each corner). The following refinement methods are
implemented:
`method=:linear` : This is the default method, and refines the triangles in a
simple linear manor through splitting. Each input edge simply obtains a new
mid-edge node.
`method=:Loop` : This method features Loop-subdivision. Rather than linearly
splitting edges and maintaining the original coordinates, as for the linear
method, this method computes the new points in a special weighted sense such
that the surface effectively approaches a "quartic box spline". Hence this
method both refines and smoothes the geometry through spline approximation.
# References
[Charles Loop, Smooth Subdivision Surfaces Based on Triangles M.S. Mathematics Thesis, University of Utah. 1987.](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/thesis-10.pdf)
[Jos Stam, Charles Loop, Quad/Triangle Subdivision, doi: 10.1111/1467-8659.t01-2-00647](https://doi.org/10.1111/1467-8659.t01-2-00647)
"""
function subtri(F,V,n; method = :linear)

if iszero(n)
Expand Down Expand Up @@ -1147,7 +1175,7 @@ function subtri(F,V,n; method = :linear)
if method == :linear # Simple linear splitting
# Create complete point set
Vn = [V; simplexcenter(Eu,V)] # Old and new mid-edge points
elseif method == :loop #Loop subdivision
elseif method == :Loop #Loop subdivision

# New mid-edge like vertices
Vm = Vector{GeometryBasics.Point{3, Float64}}(undef,length(Eu))
Expand Down
143 changes: 84 additions & 59 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ end
end
end


@testset "mindist" begin
eps_level = 0.001
V1 = [[1, 2, 3], [0, 0, 0]]
Expand Down Expand Up @@ -659,6 +658,7 @@ end

end


@testset "togeometrybasics_faces" verbose = true begin
# Triangles matrix and vector
Ftm = [1 2 3; 4 5 6]
Expand Down Expand Up @@ -1035,39 +1035,6 @@ end
end


@testset "geosphere(3,1.0)" begin
F, V = geosphere(3, 1.0)

@test F isa Vector{TriangleFace{Int64}}
@test length(F) == 1280

@test V isa Vector{Point3{Float64}}
@test length(V) == 642
end


@testset "hexbox" verbose = true begin
@testset "Single hex box" begin
E,V,F,Fb,CFb_type = hexbox([1.0,1.0,1.0],[1,1,1])
@test E == [[1, 2, 4, 3, 5, 6, 8, 7]]
@test V == Point3{Float64}[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [1.0, 1.0, 1.0]]
@test F == QuadFace{Int64}[[3, 4, 2, 1], [5, 6, 8, 7], [1, 2, 6, 5], [4, 3, 7, 8], [2, 4, 8, 6], [3, 1, 5, 7]]
@test Fb == QuadFace{Int64}[[3, 4, 2, 1], [5, 6, 8, 7], [1, 2, 6, 5], [4, 3, 7, 8], [2, 4, 8, 6], [3, 1, 5, 7]]
@test CFb_type == [1, 2, 3, 4, 5, 6]
end
@testset "2x2x2 hex box" begin
E,V,F,Fb,CFb_type = hexbox([1.0,1.0,1.0],[2,2,2])
@test E[1] == [1, 2, 5, 4, 10, 11, 14, 13]
@test length(E) == 8
@test V[5] == [0.5, 0.5, 0.0]
@test length(V) == 27
@test length(F) == 48
@test length(Fb) == 24
@test CFb_type == [1, 3, 6, 1, 3, 5, 1, 4, 6, 1, 4, 5, 2, 3, 6, 2, 3, 5, 2, 4, 6, 2, 4, 5]
end
end


@testset "simplexcenter" begin

eps_level = 0.001
Expand Down Expand Up @@ -1164,45 +1131,104 @@ end
end



@testset "subtri" begin
r = 1
n = 3
@testset "subtri" verbose = true begin
eps_level = 0.001

M = platonicsolid(4, r)
M = platonicsolid(4, 1.0)
V = coordinates(M)
F = faces(M)
n = 3
@testset "linear" begin
Fn, Vn = subtri(F, V, n; method=:linear)

Fn, Vn = subtri(F, V, n)
@test Fn isa Vector{TriangleFace{Int64}}
@test length(Fn) == 1280
@test Fn[1] == TriangleFace(163, 323, 243)
@test Vn isa Vector{Point3{Float64}}
@test length(Vn) == 642
@test isapprox(Vn[1], [0.0, -0.5257311121191336, -0.85065080835204], atol=eps_level)
end

@test Fn isa Vector{TriangleFace{Int64}}
@test length(Fn) == 1280
@test Fn[1] == TriangleFace(163, 323, 243)
@testset "Loop" begin
Fn, Vn = subtri(F, V, n; method=:Loop)

@test Fn isa Vector{TriangleFace{Int64}}
@test length(Fn) == 1280
@test Fn[1] == TriangleFace(163, 323, 243)
@test Vn isa Vector{Point3{Float64}}
@test length(Vn) == 642
@test isapprox(Vn[1], [0.0, -0.37343167032888536, -0.6042251350677821], atol=eps_level)
end

@test Vn isa Vector{Point3{Float64}}
@test length(Vn) == 642
@test isapprox(Vn[1], [0.0, -0.5257311121191336, -0.85065080835204], atol=eps_level)
end

@testset "dist(Vn, V)" begin
r = 1
n = 3
eps_level = 0.001

M = platonicsolid(4, r)
V = coordinates(M)
@testset "subquad" verbose = true begin
eps_level = 0.001
M = cube(1.0)
F = faces(M)
V = coordinates(M)
n = 3
@testset "linear" begin
Fn, Vn = subquad(F, V, n; method=:linear)

@test Fn isa Vector{QuadFace{Int64}}
@test length(Fn) == 384
@test Fn[1] == QuadFace(1, 99, 291, 187)
@test Vn isa Vector{Point3{Float64}}
@test length(Vn) == 386
@test isapprox(Vn[1], [-0.5773502691896258, -0.5773502691896258, -0.5773502691896258], atol=eps_level)
end

@testset "Catmull_Clark" begin
Fn, Vn = subquad(F, V, n; method=:Catmull_Clark)

@test Fn isa Vector{QuadFace{Int64}}
@test length(Fn) == 384
@test Fn[1] == QuadFace(1, 99, 291, 187)
@test Vn isa Vector{Point3{Float64}}
@test length(Vn) == 386
@test isapprox(Vn[1], [-0.2895661072324513, -0.2895661072324513, -0.2895661072324513], atol=eps_level)
end

_, Vn = subtri(F, V, n)
end

DD = dist(Vn, V)
@testset "geosphere" begin
r = 1.0
n = 3
F, V = geosphere(n, r)
eps_level = 0.001

@test DD isa Matrix{Float64}
@test size(DD) == (642, 12)
@test isapprox(DD[1, :], [0.0, 1.70130161670408, 2.0, 1.0514622242382672, 1.0514622242382672, 1.70130161670408, 1.70130161670408, 1.0514622242382672, 1.0514622242382672, 1.0514622242382672, 1.70130161670408, 1.70130161670408], atol=eps_level)
@test F isa Vector{TriangleFace{Int64}}
@test length(F) == 1280
@test F[1] == [163,323,243]
@test V isa Vector{Point3{Float64}}
@test length(V) == 642
@test isapprox(V[1], [0.0, -0.5257311121191336 , -0.85065080835204], atol=eps_level)
end


@testset "hexbox" verbose = true begin
@testset "Single hex box" begin
E,V,F,Fb,CFb_type = hexbox([1.0,1.0,1.0],[1,1,1])
@test E == [[1, 2, 4, 3, 5, 6, 8, 7]]
@test V == Point3{Float64}[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [1.0, 1.0, 1.0]]
@test F == QuadFace{Int64}[[3, 4, 2, 1], [5, 6, 8, 7], [1, 2, 6, 5], [4, 3, 7, 8], [2, 4, 8, 6], [3, 1, 5, 7]]
@test Fb == QuadFace{Int64}[[3, 4, 2, 1], [5, 6, 8, 7], [1, 2, 6, 5], [4, 3, 7, 8], [2, 4, 8, 6], [3, 1, 5, 7]]
@test CFb_type == [1, 2, 3, 4, 5, 6]
end
@testset "2x2x2 hex box" begin
E,V,F,Fb,CFb_type = hexbox([1.0,1.0,1.0],[2,2,2])
@test E[1] == [1, 2, 5, 4, 10, 11, 14, 13]
@test length(E) == 8
@test V[5] == [0.5, 0.5, 0.0]
@test length(V) == 27
@test length(F) == 48
@test length(Fb) == 24
@test CFb_type == [1, 3, 6, 1, 3, 5, 1, 4, 6, 1, 4, 5, 2, 3, 6, 2, 3, 5, 2, 4, 6, 2, 4, 5]
end
end


@testset "quadsphere" begin
r = 1.0
F, V = quadsphere(3, r)
Expand All @@ -1211,7 +1237,6 @@ end
@test V isa Vector{Point3{Float64}}
@test length(V) == 386
@test isapprox(V[1], [-0.5773502691896258, -0.5773502691896258, -0.5773502691896258], atol=eps_level)

@test F isa Vector{QuadFace{Int64}}
@test length(F) == 384
@test F[1] == [1, 99, 291, 187]
Expand Down

0 comments on commit dcc3ed7

Please sign in to comment.