Skip to content

Commit a9a3e46

Browse files
committed
first pass at generalized dual contours
1 parent 91d325b commit a9a3e46

File tree

4 files changed

+53
-62
lines changed

4 files changed

+53
-62
lines changed

REQUIRE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
julia 0.7
22
GeometryTypes 0.4
3+
LinearAlgebra
4+
Roots
5+
StaticArrays
6+
ForwardDiff

src/Meshing.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
module Meshing
22

33
using GeometryTypes
4+
using Roots
5+
using ForwardDiff
6+
using LinearAlgebra
7+
using StaticArrays
48

59
abstract type AbstractMeshingAlgorithm end
610

711
include("marching_tetrahedra.jl")
812
include("marching_cubes.jl")
913
include("surface_nets.jl")
14+
include("dual_contours.jl")
1015

1116
export marching_cubes,
1217
MarchingCubes,
1318
MarchingTetrahedra,
14-
NaiveSurfaceNets
19+
NaiveSurfaceNets,
20+
DualContours
1521

1622
end # module

src/dual_contours.jl

Lines changed: 33 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
using LinearAlgebra
2-
using Roots
3-
using GeometryTypes
4-
using FileIO
5-
using StaticArrays
6-
using ForwardDiff
7-
81
#Cardinal directions
9-
dirs = [ [1,0,0], [0,1,0], [0,0,1] ]
2+
const dirs = ( Point(1,0,0), Point(0,1,0), Point(0,0,1) )
103

114
#Vertices of cube
12-
cube_verts = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1],
13-
[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
5+
const cube_verts = (Point(0, 0, 0), Point(0, 0, 1), Point(0, 1, 0),
6+
Point(0, 1, 1), Point(1, 0, 0), Point(1, 0, 1),
7+
Point(1, 1, 0), Point(1, 1, 1))
148

159

1610
#Edges of cube
17-
cube_edges = [(0, 1), (0, 2), (0, 1), (0, 4), (0, 2), (0, 4), (2, 3), (1, 3),
11+
const cube_edges_dc = ((0, 1), (0, 2), (0, 1), (0, 4), (0, 2), (0, 4), (2, 3), (1, 3),
1812
(4, 5), (1, 5), (4, 6), (2, 6), (4, 5), (4, 6), (2, 3), (2, 6),
19-
(1, 3), (1, 5), (6, 7), (5, 7), (6, 7), (3, 7), (5, 7), (3, 7)]
13+
(1, 3), (1, 5), (6, 7), (5, 7), (6, 7), (3, 7), (5, 7), (3, 7))
2014

2115

2216
#Use non-linear root finding to compute intersection point
@@ -32,24 +26,28 @@ end
3226
# f = implicit function
3327
# df = gradient of f
3428
# nc = resolution
35-
function dual_contour(f, nc)
29+
function dual_contours(f, bounds::HyperRectangle, nc::NTuple{3,Int})
3630

31+
orig = origin(bounds)
32+
width = widths(bounds)
33+
scale = width ./ Point(nc)
3734
#Compute vertices
3835
dc_verts = []
3936
vindex = Dict()
40-
for x in 0:nc, y in 0:nc, z in 0:nc
41-
o = [x,y,z]
37+
for x in 0:nc[1], y in 0:nc[2], z in 0:nc[3]
38+
idx = Point(x,y,z)
39+
o = Point(x,y,z) .* scale + orig
4240

4341
#Get signs for cube
44-
cube_signs = [ f(o+v)>0 for v in cube_verts ]
42+
cube_signs = [ f(o+(v.*scale))>0 for v in cube_verts ]
4543

4644
if all(cube_signs) || !any(cube_signs)
4745
continue
4846
end
4947

5048
#Estimate hermite data
51-
h_data = [ estimate_hermite(f, o+cube_verts[e[1]+1], o+cube_verts[e[2]+1])
52-
for e in cube_edges if cube_signs[e[1]+1] != cube_signs[e[2]+1] ]
49+
h_data = [ estimate_hermite(f, o+cube_verts[e[1]+1].*scale, o+cube_verts[e[2]+1].*scale)
50+
for e in cube_edges_dc if cube_signs[e[1]+1] != cube_signs[e[2]+1] ]
5351

5452
#Solve qef to get vertex
5553
A = Array{Float64,2}(undef,length(h_data),3)
@@ -65,70 +63,44 @@ function dual_contour(f, nc)
6563
end
6664

6765
#Emit one vertex per every cube that crosses
68-
push!(vindex, o => length(dc_verts))
66+
push!(vindex, idx => length(dc_verts))
6967
push!(dc_verts, (v, ForwardDiff.gradient(f,v)))
7068
end
7169

7270
#Construct faces
73-
dc_faces = []
74-
for x in 0:nc, y in 0:nc, z in 0:nc
75-
if !haskey(vindex,[x,y,z])
71+
dc_faces = Face[]
72+
for x in 0:nc[1], y in 0:nc[2], z in 0:nc[3]
73+
74+
idx = Point(x,y,z)
75+
if !haskey(vindex,idx)
7676
continue
7777
end
7878

7979
#Emit one face per each edge that crosses
80-
o = [x,y,z]
80+
o = Point(x,y,z) .* scale + orig
8181
for i in (1,2,3)
8282
for j in 1:i
83-
if haskey(vindex,o + dirs[i]) && haskey(vindex,o + dirs[j]) && haskey(vindex,o + dirs[i] + dirs[j])
83+
if haskey(vindex,idx+dirs[i]) && haskey(vindex,idx + dirs[j]) && haskey(vindex,idx + dirs[i] + dirs[j])
8484
# determine orientation of the face from the true normal
85-
v1, tn1 = dc_verts[vindex[o]+1]
86-
v2, tn2 = dc_verts[vindex[o+dirs[i]]+1]
87-
v3, tn3 = dc_verts[vindex[o+dirs[j]]+1]
88-
@show v1,v2, v3
85+
v1, tn1 = dc_verts[vindex[idx]+1]
86+
v2, tn2 = dc_verts[vindex[idx+dirs[i]]+1]
87+
v3, tn3 = dc_verts[vindex[idx+dirs[j]]+1]
88+
8989
e1 = v1-v2
9090
e2 = v1-v3
9191
c = cross(e1,e2)
9292
if dot(c, tn1) > 0
93-
push!(dc_faces, [vindex[o], vindex[o+dirs[i]], vindex[o+dirs[j]]] )
94-
push!(dc_faces, [vindex[o+dirs[i]+dirs[j]], vindex[o+dirs[j]], vindex[o+dirs[i]]] )
93+
push!(dc_faces, Face{3,Int}(vindex[idx]+1, vindex[idx+dirs[i]]+1, vindex[idx+dirs[j]]+1) )
94+
push!(dc_faces, Face{3,Int}(vindex[idx+dirs[i]+dirs[j]]+1, vindex[idx+dirs[j]]+1, vindex[idx+dirs[i]]+1) )
9595
else
96-
push!(dc_faces, [vindex[o], vindex[o+dirs[j]], vindex[o+dirs[i]]] )
97-
push!(dc_faces, [vindex[o+dirs[i]+dirs[j]], vindex[o+dirs[i]], vindex[o+dirs[j]]] )
96+
push!(dc_faces, Face{3,Int}(vindex[idx]+1, vindex[idx+dirs[j]]+1, vindex[idx+dirs[i]]+1) )
97+
push!(dc_faces, Face{3,Int}(vindex[idx+dirs[i]+dirs[j]]+1, vindex[idx+dirs[i]]+1, vindex[idx+dirs[j]]+1) )
9898
end
9999
end
100100
end
101101
end
102102

103103
end
104-
return dc_verts, dc_faces
105-
end
106-
107-
108-
center = [16,16,16]
109-
radius = 10
110-
111-
function test_f(x)
112-
d = x-center
113-
return dot(d,d) - radius^2
114-
end
115-
116-
function runion(x,y)
117-
x + y - sqrt(x*x + y*y)
118-
end
119-
120-
function softmax(x,y)
121-
log(exp(3*x)+exp(3*y))/3
122-
end
123-
124-
function test_sq(x)
125-
d = x-center
126-
softmax(softmax(-d[3], d[3]-5), d[1]*d[1] + d[2]*d[2] - radius )
104+
return HomogenousMesh([Point(v[1]...) for v in dc_verts], dc_faces)
127105
end
128106

129-
130-
verts, tris = dual_contour(test_sq, 36)
131-
132-
m = HomogenousMesh([Point(v[1]...) for v in verts], [Face(t[1]+1,t[2]+1,t[3]+1) for t in tris])
133-
134-
save("test2.ply",m)

test/runtests.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ using LinearAlgebra: dot, norm
105105
@test minimum(vertices(mesh)) [-0.5, -0.5, -0.5] atol=0.2
106106
end
107107

108+
@testset "Dual Contours" begin
109+
110+
sphere(v) = sqrt(sum(dot(v,v))) - 1 # sphere
111+
112+
m = Meshing.dual_contours(sphere, HyperRectangle(Vec(-1,-1,-1.),Vec(2,2,2.)), (50,50,50))
113+
@test length(vertices(m)) == 11754
114+
@test length(faces(m)) == 51186
115+
end
116+
108117
@testset "AbstractMeshingAlgorithm interface" begin
109118
f = x -> norm(x) - 0.5
110119
bounds = HyperRectangle(Vec(-1, -1, -1), Vec(2, 2, 2))

0 commit comments

Comments
 (0)