From 6bb52eb06b1b26c1960c0caf333f6bff57c59787 Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Mon, 6 Jan 2025 09:15:39 +0000 Subject: [PATCH 01/12] Attempt to handle AbstractRange types for coordinates vectors --- src/MarchingCubes.jl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/MarchingCubes.jl b/src/MarchingCubes.jl index 346ee45..3f03e41 100644 --- a/src/MarchingCubes.jl +++ b/src/MarchingCubes.jl @@ -69,10 +69,19 @@ struct MC{F,I} vol::Array{F,3}, I::Type{G} = Int; normal_sign::Integer = 1, - x::AbstractVector{F} = F[], - y::AbstractVector{F} = F[], - z::AbstractVector{F} = F[], + x::Union{AbstractVector{F}, AbstractRange{F}} = F[], + y::Union{AbstractVector{F}, AbstractRange{F}} = F[], + z::Union{AbstractVector{F}, AbstractRange{F}} = F[], ) where {F<:AbstractFloat,G<:Integer} = begin + if isa(x,AbstractRange) + x = collect(x) + end + if isa(y,AbstractRange) + y = collect(y) + end + if isa(z,AbstractRange) + z = collect(z) + end abs(normal_sign) == 1 || throw(ArgumentError("`normal_sign` should be either -1 or +1")) m = new{F,I}( size(vol)..., From b6cdef46b386d8af6fadae8153efcb1eb65bdcc7 Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Mon, 6 Jan 2025 12:28:06 +0000 Subject: [PATCH 02/12] Removed need for convert --- src/MarchingCubes.jl | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/MarchingCubes.jl b/src/MarchingCubes.jl index 3f03e41..79e3192 100644 --- a/src/MarchingCubes.jl +++ b/src/MarchingCubes.jl @@ -62,26 +62,17 @@ struct MC{F,I} vertices::Vector{Vertex{F}} # output vertex positions normals::Vector{Normal{F}} # output vertex normals normal_sign::Int # direction of normal vectors (+1 for outward / -1 for inward) - x::RefValue{Vector{F}} - y::RefValue{Vector{F}} - z::RefValue{Vector{F}} + x::RefValue{<:AbstractVector{F}} + y::RefValue{<:AbstractVector{F}} + z::RefValue{<:AbstractVector{F}} MC( vol::Array{F,3}, I::Type{G} = Int; normal_sign::Integer = 1, - x::Union{AbstractVector{F}, AbstractRange{F}} = F[], - y::Union{AbstractVector{F}, AbstractRange{F}} = F[], - z::Union{AbstractVector{F}, AbstractRange{F}} = F[], + x::AbstractVector{F} = F[], + y::AbstractVector{F} = F[], + z::AbstractVector{F} = F[], ) where {F<:AbstractFloat,G<:Integer} = begin - if isa(x,AbstractRange) - x = collect(x) - end - if isa(y,AbstractRange) - y = collect(y) - end - if isa(z,AbstractRange) - z = collect(z) - end abs(normal_sign) == 1 || throw(ArgumentError("`normal_sign` should be either -1 or +1")) m = new{F,I}( size(vol)..., From d3b4c9ed612ccef5706776ca6f721076a777f5fe Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Mon, 6 Jan 2025 14:29:53 +0000 Subject: [PATCH 03/12] Attempt to fix GeometryBasics issue relating to renaming of normals->normal --- src/example.jl | 2 +- test/runtests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/example.jl b/src/example.jl index 7b8ae21..b6fd699 100644 --- a/src/example.jl +++ b/src/example.jl @@ -126,7 +126,7 @@ makemesh_GeometryBasics(GeometryBasics::Module, m::MC) = begin vertices = map(GeometryBasics.Point3f, m.vertices) normals = map(GeometryBasics.Vec3f, m.normals) triangles = map(t -> GeometryBasics.TriangleFace(t...), m.triangles) - GeometryBasics.Mesh(GeometryBasics.meta(vertices; normals), triangles) + GeometryBasics.Mesh(vertices, triangles; normal=normals) end makemesh(mod::Module, m::MC) = diff --git a/test/runtests.jl b/test/runtests.jl index 10e1e55..da18299 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -187,7 +187,7 @@ end msh = MarchingCubes.makemesh(GeometryBasics, mc) @test msh isa GeometryBasics.Mesh @test length(msh.position) == length(mc.vertices) - @test length(msh.normals) == length(mc.normals) + @test length(msh.normal) == length(mc.normals) @test_throws ArgumentError MarchingCubes.makemesh(PlyIO, mc) end From 91e8df9ea927194942a02c8197768f6ff43f8ce3 Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Mon, 6 Jan 2025 14:52:47 +0000 Subject: [PATCH 04/12] Attempt to fix formatting issue --- src/example.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/example.jl b/src/example.jl index b6fd699..dbfd1a8 100644 --- a/src/example.jl +++ b/src/example.jl @@ -126,7 +126,7 @@ makemesh_GeometryBasics(GeometryBasics::Module, m::MC) = begin vertices = map(GeometryBasics.Point3f, m.vertices) normals = map(GeometryBasics.Vec3f, m.normals) triangles = map(t -> GeometryBasics.TriangleFace(t...), m.triangles) - GeometryBasics.Mesh(vertices, triangles; normal=normals) + GeometryBasics.Mesh(vertices, triangles; normal = normals) end makemesh(mod::Module, m::MC) = From bc54eb7eb4d9c4a6c2a5048963d5baf2060a8e62 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Mon, 6 Jan 2025 18:25:32 +0100 Subject: [PATCH 05/12] fix allocations --- src/MarchingCubes.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/MarchingCubes.jl b/src/MarchingCubes.jl index 79e3192..ff673f7 100644 --- a/src/MarchingCubes.jl +++ b/src/MarchingCubes.jl @@ -62,9 +62,9 @@ struct MC{F,I} vertices::Vector{Vertex{F}} # output vertex positions normals::Vector{Normal{F}} # output vertex normals normal_sign::Int # direction of normal vectors (+1 for outward / -1 for inward) - x::RefValue{<:AbstractVector{F}} - y::RefValue{<:AbstractVector{F}} - z::RefValue{<:AbstractVector{F}} + x::RefValue{Vector{F}} + y::RefValue{Vector{F}} + z::RefValue{Vector{F}} MC( vol::Array{F,3}, I::Type{G} = Int; @@ -73,6 +73,9 @@ struct MC{F,I} y::AbstractVector{F} = F[], z::AbstractVector{F} = F[], ) where {F<:AbstractFloat,G<:Integer} = begin + isa(x, AbstractRange) && (x = collect(x)) + isa(y, AbstractRange) && (y = collect(y)) + isa(z, AbstractRange) && (z = collect(z)) abs(normal_sign) == 1 || throw(ArgumentError("`normal_sign` should be either -1 or +1")) m = new{F,I}( size(vol)..., From 9c24fadbc104f4835c8a9fabda97f6c8f0b57458 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Mon, 6 Jan 2025 19:00:39 +0100 Subject: [PATCH 06/12] Update format-check.yml --- .github/workflows/format-check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml index ff80d77..ede02f3 100644 --- a/.github/workflows/format-check.yml +++ b/.github/workflows/format-check.yml @@ -30,6 +30,7 @@ jobs: else @error "Some files have not been formatted !!!" write(stdout, out) + run(`git diff`) exit(1) end ' From cbb43058a739c8ce8e4236db882785abe9bacf31 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Mon, 6 Jan 2025 19:02:51 +0100 Subject: [PATCH 07/12] format --- src/MarchingCubes.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MarchingCubes.jl b/src/MarchingCubes.jl index ff673f7..e68a14c 100644 --- a/src/MarchingCubes.jl +++ b/src/MarchingCubes.jl @@ -76,7 +76,8 @@ struct MC{F,I} isa(x, AbstractRange) && (x = collect(x)) isa(y, AbstractRange) && (y = collect(y)) isa(z, AbstractRange) && (z = collect(z)) - abs(normal_sign) == 1 || throw(ArgumentError("`normal_sign` should be either -1 or +1")) + abs(normal_sign) == 1 || + throw(ArgumentError("`normal_sign` should be either -1 or +1")) m = new{F,I}( size(vol)..., Ref(vol), From fe69512bdaff1c64952fa8c02d691470054cac15 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Mon, 6 Jan 2025 19:03:36 +0100 Subject: [PATCH 08/12] use `lts` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19810de..8b47daf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: version: - - '1.10' # latest LTS + - 'lts' - '1' experimental: - false From ebd0f282fff29c3f005e86c81716b2e88cc93f07 Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Tue, 7 Jan 2025 10:39:54 +0000 Subject: [PATCH 09/12] Added testing for ranged coordinate input --- test/runtests.jl | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index da18299..50d5d13 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,3 @@ -using BenchmarkTools using GeometryBasics using MarchingCubes using Meshes @@ -191,3 +190,41 @@ end @test_throws ArgumentError MarchingCubes.makemesh(PlyIO, mc) end + +@testset "coordinate input variations" begin + epsLevel = 1e-3 # Precission level + + # Define coordinate ranges (also creating 3 different lengths) + nx, ny, nz = 55, 46, 67 # These should be high enough to reach precission level + start_x, stop_x = -1.0, 1.0 # Range limits centered on 0.0 + start_y, stop_y = -1.2, 1.2 # Range limits centered on 0.0 + start_z, stop_z = -2.3, 2.3 # Range limits centered on 0.0 + x = range(start_x, stop_x, length = nx) + y = range(start_y, stop_y, length = ny) + z = range(start_z, stop_z, length = nz) + + # Create image (simple coordinate norm leading to spherical isosurface) + A = [sqrt(x^2 + y^2 + z^2) for x in x, y in y, z in z] + + level = 0.5 # isolevel should produce sphere with this radius + + # Process isosurface with ranged coordinate input + mc_ranged = MC(A,Int; x=x, y=y, z=z) + march(mc_ranged,level) + + # Process isosurface with vector coordinate input + mc_vector = MC(A,Int; x=collect(Float64, x), y=collect(Float64, y), z=collect(Float64, z)) + march(mc_vector,level) + + # Test equivalence between ranged and vector input + @test mc_ranged.vertices == mc_vector.vertices + @test mc_ranged.triangles == mc_vector.triangles + + # Test if coordinate input was used appropriately geometrically as expected + n = length(mc_ranged.vertices) + c = sum(mc_ranged.vertices)/n # Mean coordinate i.e. centre + r = sum(v -> sqrt(sum(v.^2)),mc_ranged.vertices)/n # Mean radius + @test isapprox(c,[0.0,0.0,0.0], atol = epsLevel) # Approximately zero mean for sphere + @test isapprox(r, level, atol = epsLevel) # Approximately radius matching level +end + From 5f59e25f84df6d2c1c8a6c1e0fe777ed9448f92a Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Tue, 7 Jan 2025 10:42:56 +0000 Subject: [PATCH 10/12] Update to tests to conform to format i.e. spaces at equal signs --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 50d5d13..cf4844d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -209,11 +209,11 @@ end level = 0.5 # isolevel should produce sphere with this radius # Process isosurface with ranged coordinate input - mc_ranged = MC(A,Int; x=x, y=y, z=z) + mc_ranged = MC(A,Int; x = x, y = y, z = z) march(mc_ranged,level) # Process isosurface with vector coordinate input - mc_vector = MC(A,Int; x=collect(Float64, x), y=collect(Float64, y), z=collect(Float64, z)) + mc_vector = MC(A,Int; x = collect(Float64, x), y = collect(Float64, y), z = collect(Float64, z)) march(mc_vector,level) # Test equivalence between ranged and vector input From 9d9a5d6ac10a892efae947b901f12c08c03d10c6 Mon Sep 17 00:00:00 2001 From: Kevin-Mattheus-Moerman Date: Tue, 7 Jan 2025 10:49:27 +0000 Subject: [PATCH 11/12] Update to tests to conform to format i.e. spaces afer comma --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index cf4844d..9f6284b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -223,7 +223,7 @@ end # Test if coordinate input was used appropriately geometrically as expected n = length(mc_ranged.vertices) c = sum(mc_ranged.vertices)/n # Mean coordinate i.e. centre - r = sum(v -> sqrt(sum(v.^2)),mc_ranged.vertices)/n # Mean radius + r = sum(v -> sqrt(sum(v.^2)), mc_ranged.vertices)/n # Mean radius @test isapprox(c,[0.0,0.0,0.0], atol = epsLevel) # Approximately zero mean for sphere @test isapprox(r, level, atol = epsLevel) # Approximately radius matching level end From 68b78d877e030c2fe0b240824d18c6257b41af53 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Tue, 7 Jan 2025 13:24:54 +0100 Subject: [PATCH 12/12] update format --- test/runtests.jl | 67 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 9f6284b..4c81f33 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -117,14 +117,6 @@ end MarchingCubes.output(PlyIO, mc, tempname(); verbose = false) end -@testset "types" begin - for F ∈ (Float16, Float32, Float64) - for I ∈ (Int16, Int32, Int64, Int128, UInt16, UInt32, UInt64, UInt128) - @test march(MarchingCubes.scenario(4, 4, 4; F, I)) isa Nothing - end - end -end - @testset "normalize" begin nx, ny, nz = 10, 20, 30 start_x, stop_x = -0.1, 0.1 @@ -192,39 +184,48 @@ end end @testset "coordinate input variations" begin - epsLevel = 1e-3 # Precission level + atol = 1e-3 # precision level + + # define coordinate ranges (also creating 3 different lengths) + nx, ny, nz = 55, 46, 67 # these should be high enough to reach precision level + start_x, stop_x = -1.0, 1.0 # range limits centered on 0 + start_y, stop_y = -1.2, 1.2 # range limits centered on 0 + start_z, stop_z = -2.3, 2.3 # range limits centered on 0 + x = range(start_x, stop_x; length = nx) + y = range(start_y, stop_y; length = ny) + z = range(start_z, stop_z; length = nz) - # Define coordinate ranges (also creating 3 different lengths) - nx, ny, nz = 55, 46, 67 # These should be high enough to reach precission level - start_x, stop_x = -1.0, 1.0 # Range limits centered on 0.0 - start_y, stop_y = -1.2, 1.2 # Range limits centered on 0.0 - start_z, stop_z = -2.3, 2.3 # Range limits centered on 0.0 - x = range(start_x, stop_x, length = nx) - y = range(start_y, stop_y, length = ny) - z = range(start_z, stop_z, length = nz) + # create image (simple coordinate norm leading to spherical isosurface) + A = [√(xi^2 + yi^2 + zi^2) for xi ∈ x, yi ∈ y, zi ∈ z] - # Create image (simple coordinate norm leading to spherical isosurface) - A = [sqrt(x^2 + y^2 + z^2) for x in x, y in y, z in z] + level = 0.5 # isolevel should produce sphere with this radius - level = 0.5 # isolevel should produce sphere with this radius + # process isosurface with ranged coordinate input + mc_ranged = MC(A, Int; x, y, z) + march(mc_ranged, level) - # Process isosurface with ranged coordinate input - mc_ranged = MC(A,Int; x = x, y = y, z = z) - march(mc_ranged,level) + xv, yv, zv = collect.(Float64, (x, y, z)) - # Process isosurface with vector coordinate input - mc_vector = MC(A,Int; x = collect(Float64, x), y = collect(Float64, y), z = collect(Float64, z)) - march(mc_vector,level) + # process isosurface with vector coordinate input + mc_vector = MC(A, Int; x = xv, y = yv, z = zv) + march(mc_vector, level) - # Test equivalence between ranged and vector input + # test equivalence between ranged and vector input @test mc_ranged.vertices == mc_vector.vertices @test mc_ranged.triangles == mc_vector.triangles - - # Test if coordinate input was used appropriately geometrically as expected + + # test if coordinate input was used appropriately geometrically as expected n = length(mc_ranged.vertices) - c = sum(mc_ranged.vertices)/n # Mean coordinate i.e. centre - r = sum(v -> sqrt(sum(v.^2)), mc_ranged.vertices)/n # Mean radius - @test isapprox(c,[0.0,0.0,0.0], atol = epsLevel) # Approximately zero mean for sphere - @test isapprox(r, level, atol = epsLevel) # Approximately radius matching level + c = sum(mc_ranged.vertices) / n # mean coordinate i.e. center + r = sum(v -> √(sum(abs2, v)), mc_ranged.vertices) / n # mean radius + @test isapprox(c, zeros(3); atol) # approximately zero mean for sphere + @test isapprox(r, level; atol) # approximately radius matching level end +@testset "types" begin + for F ∈ (Float16, Float32, Float64), + I ∈ (Int16, Int32, Int64, Int128, UInt16, UInt32, UInt64, UInt128) + + @test march(MarchingCubes.scenario(4, 4, 4; F, I)) isa Nothing + end +end