Skip to content

Commit 597cd22

Browse files
committed
Add line argument to marching_triangles and return additional values
The method now also returns the values of the objective function at the intersection points and the adjacency information. Therefore, it is possible to construct a 1D grid from the return values.
1 parent 707dfc2 commit 597cd22

File tree

2 files changed

+103
-35
lines changed

2 files changed

+103
-35
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [unreleased]
6+
7+
### Changed
8+
9+
- `marching_tetrehedra` takes now an additional `lines` argument to compute intersections with given lines and
10+
returns also values and adjacency information to be able to construct a 1D grid
11+
To restore the old behavior, use `lines = []` and neglect the second and third return value
12+
513
## [1.1.1] - 2024-11-02
614
- Update links after move to WIAS-PDELib org
715

src/marching.jl

+95-35
Original file line numberDiff line numberDiff line change
@@ -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
"""
264279
function 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)
273289
end
274290

291+
292+
"""
293+
$(SIGNATURES)
294+
295+
296+
Variant of `marching_tetrahedra` with multiple grid input
297+
"""
275298
function 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
339399
end

0 commit comments

Comments
 (0)