@@ -23,7 +23,7 @@ Adapt.@adapt_structure Meshbody
2323
2424"""
2525 MeshBody(mesh::Union{Mesh, String};
26- map::Function=(x,t)->x, boundary::Bool=true , half_thk::T=0.f0,
26+ map::Function=(x,t)->x, boundary::Bool=false , half_thk::T=0.f0,
2727 scale::T=1.f0, mem=Array, primitives::Union{BBox, BSphere}) where T
2828
2929Constructor for a MeshBody:
@@ -57,7 +57,7 @@ using LinearAlgebra: cross
5757import ImplicitBVH: BoundingVolume,BBox,BSphere
5858@fastmath @inline inside (x:: SVector , b:: BoundingVolume ) = inside (x, b. volume)
5959@fastmath @inline inside (x:: SVector , b:: BBox ) = all (b. lo.- 4 .≤ x) && all (x .≤ b. up.+ 4 )
60- @fastmath @inline inside (x:: SVector , b:: BSphere ) = sum (abs2,x .- b. x) - b. r^ 2 ≤ 4
60+ @fastmath @inline inside (x:: SVector , b:: BSphere ) = √ sum (abs2,x .- b. x) - b. r ≤ 4
6161
6262import WaterLily: ×
6363# linear shape function to interpolate inside element
@@ -66,25 +66,34 @@ import WaterLily: ×
6666 √ sum (abs2,× (t[:,2 ]- t[:,1 ],p- t[:,1 ]))]
6767@fastmath @inline get_velocity (p:: SVector , tri, vel)= (dA= shape_value (p,tri); vel* dA/ sum (dA))
6868
69+ # brute-force fallback when the BVH is not available
70+ closest (x:: SVector ,mesh) = findmin (tri-> d²_fast (x, tri),mesh)
71+
6972# traverse the BVH
7073import ImplicitBVH: memory_index,unsafe_isvirtual
71- @inline function closest (x:: SVector{D,T} ,bvh:: ImplicitBVH.BVH ,mesh, :: Val{true} ) where {D,T}
74+ @inline function closest (x:: SVector{D,T} ,bvh:: ImplicitBVH.BVH ,mesh;a = floatmax (T),verbose = false ) where {D,T}
7275 tree = bvh. tree; length_nodes = length (bvh. nodes)
73- u= Int32 (0 );a = d = T ( 64 ) # initial guess # TODO sensitive to initial a
76+ u= ncheck = lcheck = tcheck = Int32 (0 ) # initialize
7477 # Depth-First-Search
75- i= 2 ; for _ in 1 : 4 tree . levels ^ 2 # prevent infinite loops
78+ i= 1 ; while true
7679 @inbounds j = memory_index (tree,i)
7780 if j ≤ length_nodes # we are on a node
78- inside (x, bvh. nodes[j]) && (i = 2 i; continue ) # go deeper
81+ verbose && (ncheck += 1 )
82+ dist (x, bvh. nodes[j]) < a && (i = 2 i; continue ) # go deeper if closer than current best
7983 else # we reached a leaf
80- @inbounds j = bvh. leaves[j- length_nodes]. index # correct index in mesh
81- d = d²_fast (x, mesh[j])
82- d< a && (a= d; u= Int32 (j)) # Replace current best
84+ verbose && (lcheck += 1 )
85+ if dist (x, bvh. leaves[j- length_nodes]) < a
86+ verbose && (tcheck += 1 )
87+ @inbounds j = bvh. leaves[j- length_nodes]. index # correct index in mesh
88+ d = d²_fast (x, mesh[j])
89+ d< a && (a= d; u= Int32 (j)) # Replace current best
90+ end
8391 end
8492 i = i>> trailing_ones (i)+ 1 # go to sibling, or uncle etc.
8593 (i== 1 || unsafe_isvirtual (tree, i)) && break # search complete!
8694 end
87- return u,a
95+ verbose && println (" Checked $ncheck nodes, $lcheck leaves, $tcheck triangles" )
96+ return a,u
8897end
8998
9099@inline function down (x,l,r,i)
94103 ((dr ≤ 0 ) || (dr < dl)) && return 2 i+ 1
95104 return 2 i
96105end
97- @inline function closest (x:: SVector{D,T} ,bvh:: BVH ,mesh,:: Val{false} ) where {D,T}
98- tree = bvh. tree; length_nodes = length (bvh. nodes)
99- u= Int32 (1 ); leaf= 0 ; a= d= T (1e6 ) # initial guess
100- # start at top
101- i= 1 ; while leaf < 2 # max check two leafs
102- @inbounds j = memory_index (tree, i)
103- if j ≤ length_nodes # we are on a node
104- @inbounds Il = memory_index (bvh. tree, 2 i)
105- @inbounds Ir = memory_index (bvh. tree, 2 i+ 1 )
106- @inbounds i = down (x, bvh. nodes[Il], bvh. nodes[Ir], i)
107- else # we reached a leaf
108- @inbounds j = bvh. leaves[j- length_nodes]. index # correct index in mesh
109- d = d²_fast (x, mesh[j])
110- d< a && (a= d; u= Int32 (j)) # Replace current best
111- i = i% 2 == 0 ? i+ 1 : i- 1 ; leaf += 1 # check sibling
112- end
113- unsafe_isvirtual (tree, i) && (i = i% 2 == 0 ? i+ 1 : i- 1 ) # go down sibling if virtual
114- end
115- return u,a
116- end
117106
118- # compute the distance to primitive
107+ # compute the square distance to primitive
119108dist (x, b:: BSphere ) = sum (abs2,x .- b. x) - b. r
120109function dist (x, b:: BBox )
121110 c = (b. up .+ b. lo) ./ 2
@@ -124,16 +113,6 @@ function dist(x, b::BBox)
124113end
125114dist (x, b:: BoundingVolume ) = dist (x, b. volume)
126115
127- # old brute-force function
128- @inline function closest (x:: SVector ,mesh)
129- u= Int32 (1 ); a= b= d²_fast (x, mesh[1 ]) # fast method
130- for I in 2 : length (mesh)
131- b = d²_fast (x, mesh[I])
132- b< a && (a= b; u= I) # Replace current best
133- end
134- return u,a
135- end
136-
137116# locate the closest point p to x on triangle tri
138117function locate (x:: SVector{T} ,tri:: SMatrix{T} ) where T
139118 # unpack the triangle vertices
@@ -174,11 +153,10 @@ function WaterLily.measure(body::Meshbody,x::SVector{D,T},t;fastd²=Inf) where {
174153 # map to correct location
175154 ξ = body. map (x,t)
176155 # before we try the bvh
177- ! inside (ξ,body. bvh. nodes[1 ]) && return (T (8 ),zero (x),zero (x))
156+ ! inside (ξ,body. bvh. nodes[1 ]) && return (T (4 ),zero (x),zero (x))
178157 # locate the point on the mesh
179- u,d⁰ = closest (ξ,body. bvh,body. mesh,Val (true ))
180- u== 0 && return (T (8 ),zero (x),zero (x)) # no closest found
181- # u==0 && return check_inside(ξ, body.bvh) # no closest found
158+ _,u = closest (ξ,body. bvh,body. mesh;a = body. boundary ? floatmax (T) : T (16 ))
159+ u== 0 && return (T (4 ),zero (x),zero (x)) # no triangles within distance "a"
182160 # compute the normal and distance
183161 n,p = normal (body. mesh[u]),SVector (locate (ξ,body. mesh[u]))
184162 # signed Euclidian distance
0 commit comments