Skip to content

Commit 91d325b

Browse files
committed
wip dual contours
1 parent 11b2a7a commit 91d325b

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

src/dual_contours.jl

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using LinearAlgebra
2+
using Roots
3+
using GeometryTypes
4+
using FileIO
5+
using StaticArrays
6+
using ForwardDiff
7+
8+
#Cardinal directions
9+
dirs = [ [1,0,0], [0,1,0], [0,0,1] ]
10+
11+
#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]]
14+
15+
16+
#Edges of cube
17+
cube_edges = [(0, 1), (0, 2), (0, 1), (0, 4), (0, 2), (0, 4), (2, 3), (1, 3),
18+
(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)]
20+
21+
22+
#Use non-linear root finding to compute intersection point
23+
function estimate_hermite(f, v0, v1)
24+
l(t) = f((1.0-t)*v0 + t*v1)
25+
dl(t) = ForwardDiff.derivative(l,t)
26+
t0 = find_zero((l,dl),(0, 1))
27+
x0 = (1.0-t0)*v0 + t0*v1
28+
return (x0, ForwardDiff.gradient(f,x0))
29+
end
30+
31+
#Input:
32+
# f = implicit function
33+
# df = gradient of f
34+
# nc = resolution
35+
function dual_contour(f, nc)
36+
37+
#Compute vertices
38+
dc_verts = []
39+
vindex = Dict()
40+
for x in 0:nc, y in 0:nc, z in 0:nc
41+
o = [x,y,z]
42+
43+
#Get signs for cube
44+
cube_signs = [ f(o+v)>0 for v in cube_verts ]
45+
46+
if all(cube_signs) || !any(cube_signs)
47+
continue
48+
end
49+
50+
#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] ]
53+
54+
#Solve qef to get vertex
55+
A = Array{Float64,2}(undef,length(h_data),3)
56+
for i in eachindex(h_data)
57+
A[i,:] = h_data[i][2]
58+
end
59+
b = [ dot(d[1],d[2]) for d in h_data ]
60+
v = A\b
61+
62+
#Throw out failed solutions
63+
if norm(v-o) > 2
64+
continue
65+
end
66+
67+
#Emit one vertex per every cube that crosses
68+
push!(vindex, o => length(dc_verts))
69+
push!(dc_verts, (v, ForwardDiff.gradient(f,v)))
70+
end
71+
72+
#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])
76+
continue
77+
end
78+
79+
#Emit one face per each edge that crosses
80+
o = [x,y,z]
81+
for i in (1,2,3)
82+
for j in 1:i
83+
if haskey(vindex,o + dirs[i]) && haskey(vindex,o + dirs[j]) && haskey(vindex,o + dirs[i] + dirs[j])
84+
# 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
89+
e1 = v1-v2
90+
e2 = v1-v3
91+
c = cross(e1,e2)
92+
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]]] )
95+
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]]] )
98+
end
99+
end
100+
end
101+
end
102+
103+
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 )
127+
end
128+
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)

0 commit comments

Comments
 (0)