@@ -259,38 +259,70 @@ end
259259"""
260260 $(SIGNATURES)
261261
262- Collect isoline snippets on triangles ready for linesegments!
262+ March through the given grid and extract points and values for given iso-line levels and/or given intersection lines.
263+ From the returned point list and value list a line plot can be created.
264+
265+ Input:
266+ coord: matrix storing the coordinates of the grid
267+ cellnodes: connectivity matrix
268+ func: function on the grid nodes to be evaluated
269+ lines: vector of line definitions [a,b,c], s.t., ax + by + c = 0 defines a line
270+ levels: vector of levels for the iso-surface
271+
272+ Output:
273+ points: vector of 2D points of the intersections of the grid with the iso-surfaces or lines
274+ adjacencies: vector of 2D vectors storing connected points in the grid
275+ value: interpolated values of `func` at the intersection points
276+
277+ Note that passing both nonempty `lines` and `levels` will create a result with both types of points mixed.
263278"""
264279function marching_triangles (
265- coord:: Matrix{Tv } ,
280+ coord:: Matrix{Tc } ,
266281 cellnodes:: Matrix{Ti} ,
267282 func,
283+ lines,
268284 levels;
269- Tc = Float32,
270- Tp = SVector{2 , Tc }
271- ) where {Tv <: Number , Ti <: Number }
272- return marching_triangles ([coord], [cellnodes], [func], levels; Tc , Tp)
285+ Tv = Float32,
286+ Tp = SVector{2 , Tv }
287+ ) where {Tc <: Number , Ti <: Number }
288+ return marching_triangles ([coord], [cellnodes], [func], lines, levels; Tv , Tp)
273289end
274290
291+
292+ """
293+ $(SIGNATURES)
294+
295+
296+ Variant of `marching_tetrahedra` with multiple grid input
297+ """
275298function marching_triangles (
276- coords:: Vector{Matrix{Tv }} ,
299+ coords:: Vector{Matrix{Tc }} ,
277300 cellnodes:: Vector{Matrix{Ti}} ,
278301 funcs,
302+ lines,
279303 levels;
280- Tc = Float32,
281- Tp = SVector{2 , Tc}
282- ) where {Tv <: Number , Ti <: Number }
304+ Tv = Float32,
305+ Tp = SVector{2 , Tv},
306+ ) where {Tc <: Number , Ti <: Number }
283307 points = Vector {Tp} (undef, 0 )
308+ values = Vector {Tv} (undef, 0 )
309+ adjacencies = Vector {SVector{2, Ti}} (undef, 0 )
284310
285311 for igrid in 1 : length (coords)
286312 func = funcs[igrid]
287313 coord = coords[igrid]
288314
289- function isect (nodes)
315+ # pre-allcate memory
316+ objective_values = Vector {Tv} (undef, size (coord, 2 ))
317+
318+ # the objective_func is used to determine the intersection (line equation or iso levels)
319+ # the value_func is used to interpolate values at the intersections
320+ function isect (nodes, objective_func, value_func)
290321 (i1, i2, i3) = (1 , 2 , 3 )
291322
292- f = (func [nodes[1 ]], func [nodes[2 ]], func [nodes[3 ]])
323+ f = (objective_func [nodes[1 ]], objective_func [nodes[2 ]], objective_func [nodes[3 ]])
293324
325+ # sort f[i1] ≤ f[i2] ≤ f[i3]
294326 f[1 ] <= f[2 ] ? (i1, i2) = (1 , 2 ) : (i1, i2) = (2 , 1 )
295327 f[i2] <= f[3 ] ? i3 = 3 : (i2, i3) = (3 , i2)
296328 f[i1] > f[i2] ? (i1, i2) = (i2, i1) : nothing
@@ -305,35 +337,63 @@ function marching_triangles(
305337 dy21 = coord[2 , n2] - coord[2 , n1]
306338 dy32 = coord[2 , n3] - coord[2 , n2]
307339
308- df31 = f[i3] != f[i1] ? 1 / (f[i3] - f[i1]) : 0.0
309- df21 = f[i2] != f[i1] ? 1 / (f[i2] - f[i1]) : 0.0
310- df32 = f[i3] != f[i2] ? 1 / (f[i3] - f[i2]) : 0.0
311-
312- for level in levels
313- if (f[i1] <= level) && (level < f[i3])
314- α = (level - f[i1]) * df31
315- x1 = coord[1 , n1] + α * dx31
316- y1 = coord[2 , n1] + α * dy31
317-
318- if (level < f[i2])
319- α = (level - f[i1]) * df21
320- x2 = coord[1 , n1] + α * dx21
321- y2 = coord[2 , n1] + α * dy21
322- else
323- α = (level - f[i2]) * df32
324- x2 = coord[1 , n2] + α * dx32
325- y2 = coord[2 , n2] + α * dy32
326- end
327- push! (points, SVector {2, Tc} ((x1, y1)))
328- push! (points, SVector {2, Tc} ((x2, y2)))
340+ df31 = f[i3] != f[i1] ? 1 / (f[i1] - f[i3]) : 0.0
341+ df21 = f[i2] != f[i1] ? 1 / (f[i1] - f[i2]) : 0.0
342+ df32 = f[i3] != f[i2] ? 1 / (f[i2] - f[i3]) : 0.0
343+
344+ if (f[i1] <= 0 ) && (0 < f[i3])
345+ α = f[i1] * df31
346+ x1 = coord[1 , n1] + α * dx31
347+ y1 = coord[2 , n1] + α * dy31
348+ value1 = value_func[n1] + α * (value_func[n3] - value_func[n1])
349+
350+ if (0 < f[i2])
351+ α = f[i1] * df21
352+ x2 = coord[1 , n1] + α * dx21
353+ y2 = coord[2 , n1] + α * dy21
354+ value2 = value_func[n1] + α * (value_func[n2] - value_func[n1])
355+ else
356+ α = f[i2] * df32
357+ x2 = coord[1 , n2] + α * dx32
358+ y2 = coord[2 , n2] + α * dy32
359+ value2 = value_func[n2] + α * (value_func[n3] - value_func[n2])
329360 end
361+
362+ push! (points, SVector {2, Tc} ((x1, y1)))
363+ push! (points, SVector {2, Tc} ((x2, y2)))
364+ push! (values, value1)
365+ push! (values, value2)
366+ # connect last two points
367+ push! (adjacencies, SVector {2, Ti} ((length (points) - 1 , length (points))))
330368 end
369+
331370 return
332371 end
333372
334373 for itri in 1 : size (cellnodes[igrid], 2 )
335- @views isect (cellnodes[igrid][:, itri])
374+ for level in levels
375+ # objective func is iso-level equation
376+ @views @fastmath map! (
377+ inode -> (func[inode] - level),
378+ objective_values,
379+ 1 : size (coord, 2 )
380+ )
381+ @views isect (cellnodes[igrid][:, itri], objective_values, func)
382+ end
383+
384+ for line in lines
385+ @fastmath line_equation (line, coord) = coord[1 ] * line[1 ] + coord[2 ] * line[2 ] + line[3 ]
386+
387+ # objective func is iso-level equation
388+ @views @fastmath map! (
389+ inode -> (line_equation (line, coord[:, inode])),
390+ objective_values,
391+ 1 : size (coord, 2 )
392+ )
393+ @views isect (cellnodes[igrid][:, itri], objective_values, func)
394+ end
395+
336396 end
337397 end
338- return points
398+ return points, adjacencies, values
339399end
0 commit comments