Skip to content

Commit

Permalink
implement suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
LasNikas committed Jul 29, 2024
1 parent 9ebce06 commit 5390b26
Show file tree
Hide file tree
Showing 17 changed files with 55 additions and 38 deletions.
2 changes: 1 addition & 1 deletion docs/src/preprocessing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pages = map(file -> joinpath("preprocessing", file), readdir(joinpath("..", "src
### [References](@id references_complex_shape)
- Alec Jacobson, Ladislav Kavan, and Olga Sorkine-Hornung "Robust inside-outside segmentation using generalized winding numbers".
In: ACM Transactions on Graphics, 32.4 (2013), pages 1--12.
[doi: 10.1145/2461912.2461916](https://doi.org/10.1145/2461912.2461916)
[doi: 10.1145/2461912.2461916](https://igl.ethz.ch/projects/winding-number/robust-inside-outside-segmentation-using-generalized-winding-numbers-siggraph-2013-jacobson-et-al.pdf)
- Kai Horman, Alexander Agathos "The point in polygon problem for arbitrary polygons".
In: Computational Geometry, 20.3 (2001), pages 131--144.
[doi: 10.1016/s0925-7721(01)00012-8](https://doi.org/10.1016/S0925-7721(01)00012-8)
8 changes: 4 additions & 4 deletions examples/preprocessing/complex_shape_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ using TrixiParticles

particle_spacing = 0.05

file = "hexagon"
filename = joinpath("examples", "preprocessing", file * ".asc")
filename = "hexagon"
file = joinpath("examples", "preprocessing", "data", filename * ".asc")

geometry = load_geometry(filename)
geometry = load_geometry(file)

trixi2vtk(geometry)

point_in_geometry_algorithm = WindingNumberJacobson(; geometry,
#winding_number_factor=0.4,
hierarchical_winding=true)

# Returns `InitialCondition`.
# Returns `InitialCondition`
shape_sampled = ComplexShape(geometry; particle_spacing, density=1.0,
store_winding_number=true,
point_in_geometry_algorithm)
Expand Down
12 changes: 4 additions & 8 deletions examples/preprocessing/complex_shape_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@ using TrixiParticles

particle_spacing = 0.05

file = "sphere"
filename = joinpath("examples", "preprocessing", file * ".stl")
filename = "sphere"
file = joinpath("examples", "preprocessing", "data", filename * ".stl")

# The following triangle mesh is corrupt.
# For more robustness, use `winding_number_factor=0.4`.
# filename = joinpath("examples", "preprocessing", "drive_gear.stl")

geometry = load_geometry(filename)
geometry = load_geometry(file)

point_in_geometry_algorithm = WindingNumberJacobson(; geometry,
# winding_number_factor=0.4,
hierarchical_winding=true)

# Returns `InitialCondition`.
# Returns `InitialCondition`
shape_sampled = ComplexShape(geometry; particle_spacing, density=1.0,
point_in_geometry_algorithm)

Expand Down
File renamed without changes.
File renamed without changes.
Binary file added examples/preprocessing/data/gear.stl
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file removed examples/preprocessing/drive_gear.stl
Binary file not shown.
Binary file removed examples/preprocessing/gear.stl
Binary file not shown.
4 changes: 2 additions & 2 deletions src/TrixiParticles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ using Adapt: Adapt
using CSV: CSV
using Dates
using DataFrames: DataFrame
using DelimitedFiles
using DelimitedFiles: DelimitedFiles
using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect, PresetTimeCallback
using FastPow: @fastpow
using FileIO: FileIO, File, query, @format_str, Stream, stream
using FileIO: FileIO
using ForwardDiff: ForwardDiff
using GPUArraysCore: AbstractGPUArray
using JSON: JSON
Expand Down
8 changes: 4 additions & 4 deletions src/preprocessing/geometries/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function load_geometry(filename; element_type=Float64)
if file_extension == ".asc"
geometry = load_ascii(filename; ELTYPE, skipstart=1)
elseif file_extension == ".stl"
geometry = load(query(filename); ELTYPE)
geometry = load(FileIO.query(filename); ELTYPE)
else
throw(ArgumentError("Only `.stl` and `.asc` files are supported (yet)."))
end
Expand All @@ -37,17 +37,17 @@ end

# FileIO.jl docs:
# https://juliaio.github.io/FileIO.jl/stable/implementing/#All-at-once-I/O:-implementing-load-and-save
function load(fn::File{format"STL_BINARY"}; element_types...)
function load(fn::FileIO.File{FileIO.format"STL_BINARY"}; element_types...)
open(fn) do s
FileIO.skipmagic(s) # skip over the magic bytes
load(s; element_types...)
end
end

function load(fs::Stream{format"STL_BINARY"}; ELTYPE=Float64)
function load(fs::FileIO.Stream{FileIO.format"STL_BINARY"}; ELTYPE=Float64)
# Binary STL
# https://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL
io = stream(fs)
io = FileIO.stream(fs)
read(io, 80) # Throw out 80 bytes header
n_faces = read(io, UInt32)

Expand Down
35 changes: 25 additions & 10 deletions src/preprocessing/point_in_poly/hierarchical_winding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct HierarchicalWinding{BB}
bounding_box::BB

function HierarchicalWinding(geometry)
# Note that overlapping bounding boxes are perfectly fine
min_corner = geometry.min_corner .- sqrt(eps())
max_corner = geometry.max_corner .+ sqrt(eps())

Expand Down Expand Up @@ -134,6 +135,11 @@ function determine_closure!(closing_faces, min_corner, max_corner, mesh::Triangl
end

else # Face is intersecting the boundaries

# Remove intersecting faces in the calculation of the exterior edges.
# This way, all exterior edges are inside the bounding box, and so will be the closing surface.
# The intersecting faces are later added with opposite orientation,
# so that the closing is actually a closing of the exterior plus intersecting faces.
push!(intersecting_faces, face)
end
end
Expand Down Expand Up @@ -164,6 +170,7 @@ function determine_closure!(closing_faces, min_corner, max_corner, mesh::Triangl
end
end

# See comment above as to why intersecting faces are treated seperately

Check warning on line 173 in src/preprocessing/point_in_poly/hierarchical_winding.jl

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"seperately" should be "separately".
for face in intersecting_faces
v1 = face_vertices_ids[face][1]
v2 = face_vertices_ids[face][2]
Expand All @@ -189,28 +196,27 @@ function determine_closure!(closing_edges, min_corner, max_corner, polygon::Poly
for edge in edges
if is_in_box(edge_vertices[edge][1], min_corner, max_corner) &&
is_in_box(edge_vertices[edge][2], min_corner, max_corner)
# Edge is completely inside the bounding box

v1 = edge_vertices_ids[edge][1]
v2 = edge_vertices_ids[edge][2]

vertex_count[v1] += 1
vertex_count[v2] -= 1
else
else # Edge is intersecting the boundaries

# Remove intersecting edges in the calculation of the exterior vertices.
# This way, all exterior vertices are inside the bounding box,
# and so will be the closing surface.
# The intersecting edges are later added with opposite orientation,
# so that the closing is actually a closing of the exterior plus intersecting edges.
push!(intersecting_edges, edge)
end
end

exterior_vertices = sort(findall(!iszero, vertex_count))

resize!(closing_edges, 0)

for edge in intersecting_edges
v1 = edge_vertices_ids[edge][1]
v2 = edge_vertices_ids[edge][2]

# Flip order of vertices
push!(closing_edges, (v2, v1))
end

if !isempty(exterior_vertices)
closing_vertex = first(exterior_vertices)
end
Expand All @@ -226,6 +232,15 @@ function determine_closure!(closing_edges, min_corner, max_corner, polygon::Poly
push!(closing_edges, edge)
end

# See comment above as to why intersecting edges are treated seperately

Check warning on line 235 in src/preprocessing/point_in_poly/hierarchical_winding.jl

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"seperately" should be "separately".
for edge in intersecting_edges
v1 = edge_vertices_ids[edge][1]
v2 = edge_vertices_ids[edge][2]

# Flip order of vertices
push!(closing_edges, (v2, v1))
end

return closing_edges
end

Expand Down
17 changes: 12 additions & 5 deletions src/preprocessing/point_in_poly/winding_number_jacobson.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ Algorithm for inside-outside segmentation of a complex geometry proposed by Jaco
# Keywords
- `geometry`: Complex geometry returned by [`load_geometry`](@ref) and is only required when using
`hierarchical_winding=true`.
- `hierarchical_winding`: If set to `true`, an optimized hierarchical approach will be used
- `hierarchical_winding`: If set to `true`, an optimized hierarchical approach will be used,
which gives a significant speedup.
It is only supported for 3D geometries yet.
- `winding_number_factor`: For leaky geometries, a factor of `0.4` will give a better inside-outside segmentation.
!!! warning "Experimental Implementation"
Expand Down Expand Up @@ -104,14 +103,20 @@ end

# The following functions distinguish between actual triangles (edges)
# and reconstructed triangles (edges) in the hierarchical winding approach.
# When we reconstruct the triangles then we pass the index of the vertices. Otherwise,
# we pass the coordinates of the vertices.

# `face` holds the coordinates of each vertex
# This method is used, when `naive_winding` is called with `(winding::NaiveWinding)`.
# `face` holds the coordinates of each vertex.
@inline face_vertex(mesh, face, index) = face[index]

# `edge` holds the coordinates of each vertex
@inline edge_vertex(mesh, edge, index) = edge[index]

# `face` holds the index of each vertex

# This method is used, when `naive_winding` is called with `(winding::HierarchicalWinding)`
# and the query point is outside the bounding box. That is, we use the closure of the box.
# `face` holds the index of each vertex.
@inline function face_vertex(mesh, face::NTuple{3, Int}, index)
v_id = face[index]

Expand All @@ -126,7 +131,9 @@ end
end


# `face` is the index of the face
# This method is used, when `naive_winding` is called with `(winding::HierarchicalWinding)`
# and the bounding box is a leaf.
# `face` is the index of the face.
@inline function face_vertex(mesh, face::Int, index)
(; face_vertices) = mesh

Expand Down
7 changes: 3 additions & 4 deletions src/setups/complex_shape.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
grid_offset::Real=0.0, max_nparticles=10^7,
pad_initial_particle_grid=2particle_spacing)
Complex geometry filled with particles. Returns an [`InitialCondition`](@ref).
Sample a complex geometry with particles. Returns an [`InitialCondition`](@ref).
Note that an initial particle grid is generated inside the bounding box of the geometry.
An `point_in_geometry_algorithm` checks if particles are inside the geometry or not.
A `point_in_geometry_algorithm` checks if particles are inside the geometry or not.
For more information about the method see [`WindingNumberJacobson`](@ref) or [`WindingNumberHorman`](@ref).
# Arguments
- `geometry`: Complex geometry returned by [`load_geometry`](@ref).
- `geometry`: Geometry returned by [`load_geometry`](@ref).
# Keywords
- `particle_spacing`: Spacing between the particles.
Expand All @@ -28,7 +28,6 @@ For more information about the method see [`WindingNumberJacobson`](@ref) or [`W
- `pressure`: Scalar to set the pressure of all particles to this value.
This is only used by the [`EntropicallyDampedSPHSystem`](@ref) and
will be overwritten when using an initial pressure function in the system.
Cannot be used together with hydrostatic pressure gradient.
- `point_in_geometry_algorithm`: Algorithm for sampling the complex geometry with particles.
It basically checks whether a particle is inside an object or not.
For more information see [`WindingNumberJacobson`](@ref) or [`WindingNumberHorman`](@ref)
Expand Down

0 comments on commit 5390b26

Please sign in to comment.