Skip to content

Commit 7338a32

Browse files
authored
Merge pull request #20 from WIAS-PDELib/feature/marching-lines
Add line definitions to marching_triangles
2 parents 707dfc2 + bd6a91f commit 7338a32

3 files changed

Lines changed: 116 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
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+
## [3.0.0] - 2025-03-03
6+
7+
### Changed
8+
9+
- `marching_triangles` 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

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "GridVisualizeTools"
22
uuid = "5573ae12-3b76-41d9-b48c-81d0b6e61cc5"
3-
authors = ["Jürgen Fuhrmann <juergen-fuhrmann@web.de>"]
4-
version = "2.0.0"
3+
authors = ["Jürgen Fuhrmann <juergen-fuhrmann@web.de>", "Patrick Jaap <patrick.jaap@wias-berlin.de"]
4+
version = "2.1.0"
55

66
[deps]
77
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"

src/marching.jl

Lines changed: 106 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -259,43 +259,81 @@ 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+
Tc: scalar type of coordinates
272+
Tp: vector type of coordinates
273+
Tv: scalar type of function values
274+
275+
Output:
276+
points: vector of 2D points of the intersections of the grid with the iso-surfaces or lines
277+
adjacencies: vector of 2D vectors storing connected points in the grid
278+
value: interpolated values of `func` at the intersection points
279+
280+
Note that passing both nonempty `lines` and `levels` will create a result with both types of points mixed.
263281
"""
264282
function marching_triangles(
265-
coord::Matrix{Tv},
283+
coord::Matrix{T},
266284
cellnodes::Matrix{Ti},
267285
func,
286+
lines,
268287
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)
288+
Tc = T,
289+
Tp = SVector{2, Tc},
290+
Tv = Float64
291+
) where {T <: Number, Ti <: Number}
292+
return marching_triangles([coord], [cellnodes], [func], lines, levels; Tc, Tp, Tv)
273293
end
274294

295+
296+
"""
297+
$(SIGNATURES)
298+
299+
300+
Variant of `marching_triangles` with multiple grid input
301+
"""
275302
function marching_triangles(
276-
coords::Vector{Matrix{Tv}},
303+
coords::Vector{Matrix{T}},
277304
cellnodes::Vector{Matrix{Ti}},
278305
funcs,
306+
lines,
279307
levels;
280-
Tc = Float32,
281-
Tp = SVector{2, Tc}
282-
) where {Tv <: Number, Ti <: Number}
308+
Tc = T,
309+
Tp = SVector{2, Tc},
310+
Tv = Float64
311+
) where {T <: Number, Ti <: Number}
283312
points = Vector{Tp}(undef, 0)
313+
values = Vector{Tv}(undef, 0)
314+
adjacencies = Vector{SVector{2, Ti}}(undef, 0)
284315

285316
for igrid in 1:length(coords)
286317
func = funcs[igrid]
287318
coord = coords[igrid]
288319

289-
function isect(nodes)
320+
# pre-allcate memory for triangle values (3 nodes per triangle)
321+
objective_values = Vector{Tv}(undef, 3)
322+
323+
# the objective_func is used to determine the intersection (line equation or iso levels)
324+
# the value_func is used to interpolate values at the intersections
325+
function isect(tri_nodes, objective_func, value_func)
290326
(i1, i2, i3) = (1, 2, 3)
291327

292-
f = (func[nodes[1]], func[nodes[2]], func[nodes[3]])
328+
# 3 values of the objective function
329+
f = objective_func
293330

331+
# sort f[i1] ≤ f[i2] ≤ f[i3]
294332
f[1] <= f[2] ? (i1, i2) = (1, 2) : (i1, i2) = (2, 1)
295333
f[i2] <= f[3] ? i3 = 3 : (i2, i3) = (3, i2)
296334
f[i1] > f[i2] ? (i1, i2) = (i2, i1) : nothing
297335

298-
(n1, n2, n3) = (nodes[i1], nodes[i2], nodes[i3])
336+
(n1, n2, n3) = (tri_nodes[i1], tri_nodes[i2], tri_nodes[i3])
299337

300338
dx31 = coord[1, n3] - coord[1, n1]
301339
dx21 = coord[1, n2] - coord[1, n1]
@@ -305,35 +343,67 @@ function marching_triangles(
305343
dy21 = coord[2, n2] - coord[2, n1]
306344
dy32 = coord[2, n3] - coord[2, n2]
307345

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)))
346+
df31 = f[i3] != f[i1] ? 1 / (f[i1] - f[i3]) : 0.0
347+
df21 = f[i2] != f[i1] ? 1 / (f[i1] - f[i2]) : 0.0
348+
df32 = f[i3] != f[i2] ? 1 / (f[i2] - f[i3]) : 0.0
349+
350+
if (f[i1] <= 0) && (0 < f[i3])
351+
α = f[i1] * df31
352+
x1 = coord[1, n1] + α * dx31
353+
y1 = coord[2, n1] + α * dy31
354+
value1 = value_func[n1] + α * (value_func[n3] - value_func[n1])
355+
356+
if (0 < f[i2])
357+
α = f[i1] * df21
358+
x2 = coord[1, n1] + α * dx21
359+
y2 = coord[2, n1] + α * dy21
360+
value2 = value_func[n1] + α * (value_func[n2] - value_func[n1])
361+
else
362+
α = f[i2] * df32
363+
x2 = coord[1, n2] + α * dx32
364+
y2 = coord[2, n2] + α * dy32
365+
value2 = value_func[n2] + α * (value_func[n3] - value_func[n2])
329366
end
367+
368+
push!(points, SVector{2, Tc}((x1, y1)))
369+
push!(points, SVector{2, Tc}((x2, y2)))
370+
push!(values, value1)
371+
push!(values, value2)
372+
# connect last two points
373+
push!(adjacencies, SVector{2, Ti}((length(points) - 1, length(points))))
330374
end
375+
331376
return
332377
end
333378

334379
for itri in 1:size(cellnodes[igrid], 2)
335-
@views isect(cellnodes[igrid][:, itri])
380+
381+
# nodes of the current triangle
382+
tri_nodes = @views cellnodes[igrid][:, itri]
383+
384+
for level in levels
385+
# objective func is iso-level equation
386+
@views @fastmath map!(
387+
inode -> (func[inode] - level),
388+
objective_values,
389+
tri_nodes
390+
)
391+
@views isect(tri_nodes, objective_values, func)
392+
end
393+
394+
for line in lines
395+
@fastmath line_equation(line, coord) = coord[1] * line[1] + coord[2] * line[2] + line[3]
396+
397+
# objective func is iso-level equation
398+
@views @fastmath map!(
399+
inode -> (line_equation(line, coord[:, inode])),
400+
objective_values,
401+
tri_nodes
402+
)
403+
@views isect(tri_nodes, objective_values, func)
404+
end
405+
336406
end
337407
end
338-
return points
408+
return points, adjacencies, values
339409
end

0 commit comments

Comments
 (0)