@@ -259,38 +259,70 @@ end
259
259
"""
260
260
$(SIGNATURES)
261
261
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.
263
278
"""
264
279
function marching_triangles (
265
- coord:: Matrix{Tv } ,
280
+ coord:: Matrix{Tc } ,
266
281
cellnodes:: Matrix{Ti} ,
267
282
func,
283
+ lines,
268
284
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)
273
289
end
274
290
291
+
292
+ """
293
+ $(SIGNATURES)
294
+
295
+
296
+ Variant of `marching_tetrahedra` with multiple grid input
297
+ """
275
298
function marching_triangles (
276
- coords:: Vector{Matrix{Tv }} ,
299
+ coords:: Vector{Matrix{Tc }} ,
277
300
cellnodes:: Vector{Matrix{Ti}} ,
278
301
funcs,
302
+ lines,
279
303
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 }
283
307
points = Vector {Tp} (undef, 0 )
308
+ values = Vector {Tv} (undef, 0 )
309
+ adjacencies = Vector {SVector{2, Ti}} (undef, 0 )
284
310
285
311
for igrid in 1 : length (coords)
286
312
func = funcs[igrid]
287
313
coord = coords[igrid]
288
314
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)
290
321
(i1, i2, i3) = (1 , 2 , 3 )
291
322
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 ]])
293
324
325
+ # sort f[i1] ≤ f[i2] ≤ f[i3]
294
326
f[1 ] <= f[2 ] ? (i1, i2) = (1 , 2 ) : (i1, i2) = (2 , 1 )
295
327
f[i2] <= f[3 ] ? i3 = 3 : (i2, i3) = (3 , i2)
296
328
f[i1] > f[i2] ? (i1, i2) = (i2, i1) : nothing
@@ -305,35 +337,63 @@ function marching_triangles(
305
337
dy21 = coord[2 , n2] - coord[2 , n1]
306
338
dy32 = coord[2 , n3] - coord[2 , n2]
307
339
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])
329
360
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))))
330
368
end
369
+
331
370
return
332
371
end
333
372
334
373
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
+
336
396
end
337
397
end
338
- return points
398
+ return points, adjacencies, values
339
399
end
0 commit comments