1+ using Comodo
2+ using Comodo. GLMakie
3+ using Comodo. GeometryBasics
4+ using Comodo. Statistics
5+ using Comodo. Rotations
6+ using Comodo. LinearAlgebra
7+
8+ function removefaces (F1,boolKeep)
9+ F1_cut = Vector {eltype(F1)} ()
10+ F1_cutout = Vector {eltype(F1)} ()
11+ for f in F1
12+ if all (boolKeep[f])
13+ push! (F1_cut,f)
14+ else
15+ push! (F1_cutout,f)
16+ end
17+ end
18+ return F1_cut,F1_cutout
19+ end
20+
21+ function loopsmooth (V; λ= 0.5 )
22+ nv = length (V)
23+ wSelf = (1.0 - λ)
24+ wOther = λ/ 2.0
25+ for i in eachindex (V)
26+ V[i] = wOther* V[mod1 (i- 1 ,nv)] + wSelf* V[i] + wOther* V[mod1 (i+ 1 ,nv)]
27+ end
28+ return V
29+ end
30+
31+ # ##########################################################
32+
33+ pointSpacing = 2.0
34+ r = 16.0
35+ h = 70.0 # Height = extrusion distance (extent)
36+
37+ rBranch = r/ 2
38+ hBranch = 50.0
39+ filletDistance = rBranch/ 4
40+
41+ # Create base branch
42+ nc = ceil (Int,(2 * pi * r)/ pointSpacing) # Compute number of circumferential points from point spacing
43+ Vc = circlepoints (r,nc;dir= :acw ) # Create points on circle
44+
45+ n = normalizevector (Vec {3, Float64} (0.0 ,0.0 ,1.0 )) # Extrusion direction
46+ direction = :positive
47+ F1,V1 = extrudecurve (Vc; extent= h, direction= :positive , n= n, close_loop= true ,face_type= :quad )
48+ E1b = boundaryedges (F1)
49+
50+ F1t = quad2tri (F1,V1; convert_method = :angle );
51+ N1_V = vertexnormal (F1,V1)
52+ E1 = boundaryedges (F1)
53+
54+ # Define side branch vector and origin
55+ tBranch = 0.25 * π
56+ Q = RotXYZ (tBranch,0.0 ,0.0 )
57+ nz = Vec {3,Float64} (0.0 ,0.0 ,1.0 )
58+ m = Q* nz
59+
60+ m = Vec {3, Float64} (0.0 ,sqrt (2 )/ 2 ,sqrt (2 )/ 2 )
61+ pb = Point {3,Float64} (0.0 ,0.0 ,h/ 4 )
62+
63+ # Define side branch base contour
64+ nc_branch = ceil (Int,(2 * pi * rBranch)/ (pointSpacing)) # Compute number of circumferential points from point spacing
65+ Vc_branch_c = circlepoints (rBranch,nc_branch;dir= :acw ) # Create points on circle
66+ # Q = rotation_between(m,nz)
67+
68+ b = 1.0 / cos (pi - tBranch);
69+ Qb = RotXYZ (0.5 * π,0.0 ,0.0 )
70+
71+
72+ Vc_branch = [pb+ (Q' * v)+ m* hBranch for v in Vc_branch_c]
73+
74+ # Project branch contour onto main
75+ P_intersect = Vector {Point{3,Float64}} (undef,nc_branch)
76+ indIntersect = Vector {Int} (undef,nc_branch)
77+ boolShot = fill (false ,length (F1t))
78+ for i in 1 : nc_branch
79+ p,j = ray_triangle_intersect (F1t,V1,Vc_branch[i],- m; rayType = :ray , triSide = 1 )
80+ P_intersect[i] = p[1 ]
81+ indIntersect[i] = j[1 ]
82+ boolShot[j[1 ]] = true
83+ end
84+ indIntersect_vertices = reduce (vcat,F1t[indIntersect])
85+ pc,jc = ray_triangle_intersect (F1t,V1,pb,m; rayType = :ray , triSide = - 1 )
86+
87+ _,indMin = mindist (P_intersect,V1[indIntersect_vertices]; getIndex= Val (true ))
88+ indNearest = indIntersect_vertices[indMin]
89+
90+ β = [acosd (dot (m,n))/ 2.0 for n in N1_V[indNearest]]
91+ dCut = filletDistance ./ tand .(β)
92+
93+ Vc_branch_ellipse= [pb+ (Qb* Point {3,Float64} (v[1 ], b* v[2 ], v[3 ]))+ m* (r* (1 / cos (tBranch))+ maximum (dCut)) for v in Vc_branch_c];
94+
95+ # March distances from intersection point
96+ V1[indNearest] = P_intersect # Overwrite nearest with intersection points so distances are more accurate
97+ d,dd,l = distmarch (F1,V1,indNearest)
98+
99+ # Cut hole in surface
100+ boolKeep = d .> maximum (dCut)
101+
102+ F1_cut,F1_cutout = removefaces (F1,boolKeep)
103+
104+ C = meshgroup (F1_cut; con_type = :v , indStart= E1b[1 ][1 ], stop_at = 1 )
105+ F1_cut = F1_cut[C.== 1 ]
106+
107+ E1b_cut = boundaryedges (F1_cut)
108+ bool_E1b_cutout = [! in (e,E1b) for e in E1b_cut]
109+
110+ E1_cutout = E1b_cut[bool_E1b_cutout]
111+ indCurve = edges2curve (E1_cutout;remove_last = true )
112+
113+ ME1_cutout = [normalizevector (V1[e[2 ]]- V1[e[1 ]]) for e in E1_cutout]
114+ MV_cutout = simplex2vertexdata (E1_cutout,ME1_cutout,V1)
115+
116+ VE1_cutout = vertex2simplexdata (E1_cutout,V1)
117+ NE1_cutout = vertex2simplexdata (E1_cutout,N1_V)
118+
119+ KV_cutout = cross .(MV_cutout[indCurve],N1_V[indCurve])
120+
121+
122+ V1[indCurve] .= loopsmooth (V1[indCurve]; λ= 1 / 3 )
123+
124+ KV_cutout .= normalizevector (loopsmooth (KV_cutout; λ= 0.5 ))
125+ KV_cutout .= normalizevector (loopsmooth (KV_cutout; λ= 0.5 ))
126+
127+ nc = length (indCurve)
128+ Vc_bez = circlepoints (rBranch,nc;dir= :cw )
129+ Vc_bez = [pb+ (Qb* Point {3,Float64} (v[1 ], b* v[2 ], v[3 ]))+ m* (r* (1 / cos (tBranch))+ maximum (dCut)) for v in Vc_bez];
130+
131+ Vc_bez2 = circlepoints (rBranch,nc;dir= :cw )
132+ Vc_bez2 = [pb+ (Q' * v)+ m* hBranch for v in Vc_bez2];
133+
134+ # Vc_bez2 = circlepoints(rBranch,nc;dir=:cw)
135+ # Vc_bez2 = [pb+(Qb*Point{3,Float64}(v[1], b*v[2], v[3]))+m*hBranch for v in Vc_bez2];
136+
137+
138+ _,iClosest = findmin (norm .(Vc_bez .- V1[indCurve[1 ]]))
139+ if iClosest > 1
140+ circshift! (Vc_bez,nc- iClosest+ 1 )
141+ end
142+
143+ numPointBezier = 8
144+ v1 = filletDistance* 4 # Departure velocity of Hermite equivalent spline
145+ v2 = filletDistance* 4 # Arrival velocity of Hermite equivalent spline
146+ VV_B = []
147+ Vb = Vector {Point{3,Float64}} ()
148+ nEnd = - m
149+ for i in eachindex (indCurve)
150+ nBase = KV_cutout[i]
151+ pb = [V1[indCurve[i]], V1[indCurve[i]] + v1/ 3 * nBase, Vc_bez[i] + v2/ 3 * nEnd,Vc_bez[i]]
152+ vb = nbezier (pb,numPointBezier)
153+ push! (VV_B,vb)
154+ append! (Vb,vb)
155+ end
156+
157+ Fb = grid2surf (Vb,length (indCurve);periodicity= (false ,true ),face_type= :quad )
158+ Eb = boundaryedges (Fb)
159+ indB = reduce (vcat,Eb)
160+ nSmooth = 25
161+ α= 0.1
162+ β= 0.5
163+ Vb = smoothmesh_hc (Fb,Vb, nSmooth, α, β; constrained_points= indB)
164+
165+ Fb2,Vb2 = loftlinear (Vc_bez2,Vc_bez;num_steps= 25 ,close_loop= true ,face_type= :quad )
166+
167+ F,V,C = joingeom (F1_cut,V1,Fb,Vb,Fb2,Vb2)
168+ F,V = remove_unused_vertices (F,V)
169+ F,V = mergevertices (F,V)
170+
171+ ind1 = reduce (vcat,F[C.== 1 ])
172+ ind2 = reduce (vcat,F[C.== 2 ])
173+ ind3 = reduce (vcat,F[C.== 3 ])
174+
175+ con_F2F = con_face_face_v (F)
176+
177+ boolSmooth = C.== 2 # fill(true,length(F))
178+ for q= 1 : 2
179+ for i in findall (boolSmooth)
180+ boolSmooth[con_F2F[i]] .= true
181+ end
182+ end
183+
184+ indConstrain = reduce (vcat,F[.! boolSmooth])
185+
186+ nSmooth = 25
187+ α= 0.1
188+ β= 0.5
189+ V = smoothmesh_hc (F,V, nSmooth, α, β; constrained_points= indConstrain)
190+
191+ E,VE = extrudefaces (F,V; extent= 2.0 , direction= :negative , num_steps= 3 )
192+
193+ FE = element2faces (E)
194+
195+ # # Visualization
196+ linewidth = 6
197+ strokewidth = 0.5
198+ markersize = 20
199+ cmap = cgrad (:Spectral , 3 , categorical = true )
200+
201+ fig = Figure (size= (1900 ,1200 ))
202+ # ax1 = Axis3(fig[1, 1], aspect = :data, xlabel = "X", ylabel = "Y", zlabel = "Z")
203+ # # ax1 = LScene(fig[1,1])
204+
205+ # hp1 = lines!(ax1,Vc,color=:red,linewidth=linewidth, transparency=true, depth_shift=-1.0f-3)
206+ # hp2 = poly!(ax1,GeometryBasics.Mesh(V1,F1_cut), strokewidth=strokewidth,color=:white, strokecolor=:black, shading = FastShading, transparency=false,colormap = :Spectral)
207+ # hp3 = dirplot(ax1,pb,m,scaleval=hBranch,color=:black,linewidth=8)
208+
209+ # hp5 = lines!(ax1,Vc_bez,color=:red,linewidth=linewidth)
210+ # hp5 = lines!(ax1,Vc_bez2,color=:blue,linewidth=linewidth)
211+
212+ # # hp5 = scatter!(ax1,P_intersect,color=:red,markersize=markersize)
213+ # # hp6 = scatter!(ax1,V1[indNearest],color=:cyan,markersize=markersize)
214+
215+ # # dirplot(ax1,V1[indCurve],MV_cutout[indCurve],scaleval=2,color=:blue,linewidth=2)
216+ # # dirplot(ax1,V1[indCurve],KV_cutout,scaleval=2,color=:red,linewidth=2)
217+
218+ # # hp6 = scatter!(ax1,V1[indNear],color=:blue,markersize=markersize)
219+
220+ # # hp6 = scatter!(ax1,V1[indMiddle],color=:cyan,markersize=markersize)
221+
222+
223+ # # scatter!(ax1,Vc_branch,color=:red,markersize=markersize)
224+
225+ # wireframe!(ax1,GeometryBasics.Mesh(V1,E1_cutout),linewidth=linewidth, transparency=false, color=:yellow)
226+
227+ # hp2 = poly!(ax1,GeometryBasics.Mesh(Vb,Fb), strokewidth=strokewidth,color=:white, strokecolor=:black, shading = FastShading, transparency=false,colormap = :Spectral)
228+ # hp2 = poly!(ax1,GeometryBasics.Mesh(Vb2,Fb2), strokewidth=strokewidth,color=:white, strokecolor=:black, shading = FastShading, transparency=false,colormap = :Spectral)
229+
230+ # # Colorbar(fig[1, 2], hp2)
231+
232+ # ax2 = LScene(fig[1,1])
233+
234+ Fs,Vs = separate_vertices (F,V)
235+ Cs = simplex2vertexdata (Fs,C,Vs)
236+
237+ ax1 = AxisGeom (fig[1 , 1 ])
238+ hp11 = meshplot! (ax1,GeometryBasics. Mesh (Vs,Fs), strokewidth= strokewidth,color= Cs, strokecolor= :black , colormap = cmap,colorrange= (0.5 ,3.5 ), stroke_depth_shift= - 0.001f0 )
239+ Colorbar (fig[1 , 2 ], hp11)
240+
241+ FEs,VEs = separate_vertices (FE,VE)
242+
243+ ax2 = AxisGeom (fig[1 , 3 ])
244+ hp21 = meshplot! (ax2,GeometryBasics. Mesh (VEs,FEs), strokewidth= strokewidth,color= :white , strokecolor= :black , colormap = cmap,colorrange= (0.5 ,3.5 ), stroke_depth_shift= - 0.001f0 )
245+
246+ fig
247+
248+
249+ # save("/home/kevin/DATA/Julia/Comodo.jl/assets/temp/branches.png", fig, px_per_unit=5)
0 commit comments