diff --git a/.gitignore b/.gitignore index f6b55de47..57bd56781 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ test/Manifest.toml docs/Manifest.toml /docs/build/ /.vscode -LocalPreferences.toml \ No newline at end of file +LocalPreferences.toml +docs/src/applications/cell_simulation.mp4 diff --git a/docs/liveserver.jl b/docs/liveserver.jl index 3761df289..d27f7ef32 100644 --- a/docs/liveserver.jl +++ b/docs/liveserver.jl @@ -5,12 +5,13 @@ Pkg.instantiate() import LiveServer withenv("LIVESERVER_ACTIVE" => "true") do LiveServer.servedocs(; - launch_browser=true, - foldername=joinpath(repo_root, "docs"), - include_dirs=[joinpath(repo_root, "src")], - skip_dirs=[joinpath(repo_root, "docs/src/tutorials"), + launch_browser = true, + foldername = joinpath(repo_root, "docs"), + include_dirs = [joinpath(repo_root, "src")], + skip_dirs = [ + joinpath(repo_root, "docs/src/tutorials"), joinpath(repo_root, "docs/src/applications"), joinpath(repo_root, "docs/src/figures"), ], ) -end \ No newline at end of file +end diff --git a/docs/make.jl b/docs/make.jl index 2fdd198c4..e5f871421 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -4,8 +4,10 @@ using Literate using Test using Dates -DocMeta.setdocmeta!(DelaunayTriangulation, :DocTestSetup, :(using DelaunayTriangulation, Test); - recursive=true) +DocMeta.setdocmeta!( + DelaunayTriangulation, :DocTestSetup, :(using DelaunayTriangulation, Test); + recursive = true, +) const IS_LIVESERVER = false && get(ENV, "LIVESERVER_ACTIVE", "false") == "true" if IS_LIVESERVER @@ -41,7 +43,7 @@ function add_just_the_code_section(dir, file) file_name, file_ext = splitext(file) file_path = joinpath(dir, file) new_file_path = joinpath(session_tmp, file_name * "_just_the_code" * file_ext) - cp(file_path, new_file_path, force=true) + cp(file_path, new_file_path, force = true) folder = splitpath(dir)[end] # literate_tutorials or literate_applications open(new_file_path, "a") do io write(io, "\n") @@ -74,7 +76,7 @@ for folder in ("tutorials", "applications") # end #end new_file_path = add_just_the_code_section(dir, file) - script = Literate.script(file_path, session_tmp, name=splitext(file)[1] * "_just_the_code_cleaned") + script = Literate.script(file_path, session_tmp, name = splitext(file)[1] * "_just_the_code_cleaned") code = strip(read(script, String)) @info "[$(ct())] Processing $file: Converting markdown script" line_ending_symbol = occursin(code, "\r\n") ? "\r\n" : "\n" @@ -86,12 +88,12 @@ for folder in ("tutorials", "applications") Literate.markdown( new_file_path, outputdir; - documenter=true, - postprocess=editurl_update ∘ post_strip, - credit=true, - name=splitext(file)[1], - execute=!IS_LIVESERVER, - flavor=Literate.DocumenterFlavor(), + documenter = true, + postprocess = editurl_update ∘ post_strip, + credit = true, + name = splitext(file)[1], + execute = !IS_LIVESERVER, + flavor = Literate.DocumenterFlavor(), ) end end @@ -127,7 +129,7 @@ const _PAGES = [ "Voronoi Tessellations" => "tutorials/voronoi.md", "Clipped Voronoi Tessellations" => [ "Clipping to the Convex Hull" => "tutorials/clipped.md", - "Clipping to a Rectangle" => "tutorials/clipped_rectangle.md" + "Clipping to a Rectangle" => "tutorials/clipped_rectangle.md", ], "Centroidal Voronoi Tessellations" => "tutorials/centroidal.md", "Point Location" => "tutorials/point_location.md", @@ -135,7 +137,7 @@ const _PAGES = [ "Convex Hulls" => "tutorials/convex_hull.md", "Pole of Inaccessibility" => "tutorials/pole_of_inaccessibility.md", "Point-in-Polygon Testing" => "tutorials/point_in_polygon.md", - "Using Custom Structs for Primitives and Boundaries" => "tutorials/custom_primitive.md" + "Using Custom Structs for Primitives and Boundaries" => "tutorials/custom_primitive.md", ], "Manual" => [ "Overview" => "manual/overview.md", @@ -168,7 +170,7 @@ const _PAGES = [ "Data Structures" => "extended/data_structures.md", "Algorithm Internals" => "extended/algorithms.md", "Utility Functions" => "extended/utils.md", - ], + ], "Mathematical Details" => [ "Overview" => "math/overview.md", "Delaunay Triangulations" => "math/delaunay.md", @@ -221,34 +223,38 @@ end # Make and deploy makedocs(; - modules=[DelaunayTriangulation], - authors="Daniel VandenHeuvel ", - sitename="DelaunayTriangulation.jl", - format=Documenter.HTML(; - prettyurls=IS_CI, - canonical="https://JuliaGeometry.github.io/DelaunayTriangulation.jl", - edit_link="main", - size_threshold=8000 * 2^10, - size_threshold_warn=1000 * 2^10, - size_threshold_ignore=["api/triangulation.md", "extended/data_structures.md"], - collapselevel=1, - assets=String[], - mathengine=MathJax3(Dict( - :loader => Dict("load" => ["[tex]/physics"]), - :tex => Dict( - "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], - "tags" => "ams", - "packages" => ["base", "ams", "autoload", "physics"], + modules = [DelaunayTriangulation], + authors = "Daniel VandenHeuvel ", + sitename = "DelaunayTriangulation.jl", + format = Documenter.HTML(; + prettyurls = IS_CI, + canonical = "https://JuliaGeometry.github.io/DelaunayTriangulation.jl", + edit_link = "main", + size_threshold = 8000 * 2^10, + size_threshold_warn = 1000 * 2^10, + size_threshold_ignore = ["api/triangulation.md", "extended/data_structures.md"], + collapselevel = 1, + assets = String[], + mathengine = MathJax3( + Dict( + :loader => Dict("load" => ["[tex]/physics"]), + :tex => Dict( + "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], + "tags" => "ams", + "packages" => ["base", "ams", "autoload", "physics"], + ), ), - ))), - linkcheck=false, - warnonly=true, - draft=IS_LIVESERVER, - pages=_PAGES, - pagesonly=true, + ), + ), + linkcheck = false, + warnonly = true, + draft = IS_LIVESERVER, + pages = _PAGES, + pagesonly = true, ) deploydocs(; - repo="github.com/JuliaGeometry/DelaunayTriangulation.jl", - devbranch="main", - push_preview=true) + repo = "github.com/JuliaGeometry/DelaunayTriangulation.jl", + devbranch = "main", + push_preview = true, +) diff --git a/docs/src/applications/cell_simulations.md b/docs/src/applications/cell_simulations.md index 1aedbb6c5..271647d24 100644 --- a/docs/src/applications/cell_simulations.md +++ b/docs/src/applications/cell_simulations.md @@ -46,29 +46,29 @@ We update the triangulation after each step.[^2] ## Implementation Let us now implement this model. First, we define a struct for storing the parameters of our model. -````@example cell_simulations +````julia using DelaunayTriangulation using StableRNGs using LinearAlgebra using StatsBase using CairoMakie -@kwdef mutable struct CellModel - tri::Triangulation - new_r_cache::Vector{NTuple{2,Float64}} # for r(t + Δt) - const α::Float64 - const s::Float64 - const Δt::Float64 - const rng::StableRNGs.LehmerRNG - const final_time::Float64 - const β::Float64 - const K::Float64 - const ϵ::Float64 +Base.@kwdef mutable struct CellModel{P} + tri::Triangulation{P} + new_r_cache::Vector{NTuple{2, Float64}} # for r(t + Δt) + α::Float64 + s::Float64 + Δt::Float64 + rng::StableRNGs.LehmerRNG + final_time::Float64 + β::Float64 + K::Float64 + ϵ::Float64 end ```` Let's now write functions for performing the migration step. -````@example cell_simulations +````julia function migrate_cells!(cells::CellModel) # a more efficient way would be to loop over edges rather than vertices tri = cells.tri for i in each_solid_vertex(tri) @@ -90,11 +90,15 @@ function migrate_cells!(cells::CellModel) # a more efficient way would be to loo end ```` +```` +migrate_cells! (generic function with 1 method) +```` + Now we can write the proliferation functions. First, let us write a function that computes the Voronoi areas. If we had the `VoronoiTessellation` computed, we would just use `get_area`, but we are aiming to avoid having to compute $\mathcal V\mathcal T(\mathcal P)$ directly. -````@example cell_simulations +````julia function polygon_area(points) # this is the same function from the Interpolation section n = DelaunayTriangulation.num_points(points) p, q, r, s = get_point(points, 1, 2, n, n - 1) @@ -103,7 +107,7 @@ function polygon_area(points) # this is the same function from the Interpolation rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -113,7 +117,7 @@ function polygon_area(points) # this is the same function from the Interpolation return area / 2 end function get_voronoi_area(tri::Triangulation, i) - points = NTuple{2,Float64}[] + points = NTuple{2, Float64}[] !DelaunayTriangulation.has_vertex(tri, i) && return (0.0, points) # might not be included anymore due to retriangulation DelaunayTriangulation.is_boundary_node(tri, i)[1] && return (0.0, points) # to prevent boundary cells from proliferating N = get_neighbours(tri, i) @@ -133,10 +137,14 @@ function get_voronoi_area(tri::Triangulation, i) end ```` +```` +get_voronoi_area (generic function with 1 method) +```` + The function `get_voronoi_area` above returns `0` if the cell is on the boundary. Finally, our function for performing the proliferation step is below. -````@example cell_simulations +````julia function proliferate_cells!(cells::CellModel) E = 0.0 Δt = cells.Δt @@ -157,16 +165,20 @@ function proliferate_cells!(cells::CellModel) δ = DelaunayTriangulation.distance_to_polygon(p, get_points(tri), poly) s, c = sincos(θ) q = p .+ (δ * cells.ϵ) .* (c, s) - add_point!(tri, q; rng=cells.rng) + add_point!(tri, q; rng = cells.rng) push!(cells.new_r_cache, q) end return nothing end ```` +```` +proliferate_cells! (generic function with 1 method) +```` + Finally, our simulation function is below. -````@example cell_simulations +````julia function perform_step!(cells::CellModel) proliferate_cells!(cells) migrate_cells!(cells) @@ -174,7 +186,7 @@ function perform_step!(cells::CellModel) end function simulate_cells(cells::CellModel) t = 0.0 - all_points = Vector{Vector{NTuple{2,Float64}}}() + all_points = Vector{Vector{NTuple{2, Float64}}}() push!(all_points, deepcopy(get_points(cells.tri))) while t < cells.final_time perform_step!(cells) @@ -185,36 +197,43 @@ function simulate_cells(cells::CellModel) end ```` +```` +simulate_cells (generic function with 1 method) +```` + ## Example Let us now give an example. Our initial set of points will be randomly chosen inside the rectangle $[-2, 2] \times [-5, 5]$. We use $\alpha = 5$, $s = 2$, $\Delta t = 10^{-3}$, $\beta = 0.25$, $K = 100^2$, and $\epsilon = 0.5$. -````@example cell_simulations +````julia rng = StableRNG(123444) a, b, c, d = -2.0, 2.0, -5.0, 5.0 points = [(a + (b - a) * rand(rng), c + (d - c) * rand(rng)) for _ in 1:10] -tri = triangulate(points; rng=rng) -cells = CellModel(; tri=tri, new_r_cache=similar(points), α=5.0, s=2.0, Δt=1e-3, - β=0.25, K=100.0^2, rng, final_time=25.0, ϵ=0.5) +tri = triangulate(points; rng = rng) +cells = CellModel(; + tri = tri, new_r_cache = similar(points), α = 5.0, s = 2.0, Δt = 1.0e-3, + β = 0.25, K = 100.0^2, rng, final_time = 25.0, ϵ = 0.5, +) results = simulate_cells(cells); -fig = Figure(fontsize=26) +fig = Figure(fontsize = 26) title_obs = Observable(L"t = %$(0.0)") -ax1 = Axis(fig[1, 1], width=1200, height=400, title=title_obs, titlealign=:left) +ax1 = Axis(fig[1, 1], width = 1200, height = 400, title = title_obs, titlealign = :left) Δt = cells.Δt i = Observable(1) -voronoiplot!(ax1, @lift(voronoi(triangulate(results[$i]; rng), clip=true, rng=rng)), - color=:darkgreen, strokecolor=:black, strokewidth=2, show_generators=false) +voronoiplot!( + ax1, @lift(voronoi(triangulate(results[$i]; rng), clip = true, rng = rng)), + color = :darkgreen, strokecolor = :black, strokewidth = 2, show_generators = false, +) xlims!(ax1, -12, 12) ylims!(ax1, -12, 12) resize_to_layout!(fig) t = 0:Δt:cells.final_time -record(fig, "cell_simulation.mp4", 1:10:length(t); framerate=60) do ii +record(fig, "cell_simulation.mp4", 1:10:length(t); framerate = 60) do ii i[] = ii title_obs[] = L"t = %$(((ii-1) * Δt))" end; -nothing #hide ```` ![](cell_simulation.mp4) @@ -229,17 +248,17 @@ using StableRNGs using LinearAlgebra using StatsBase using CairoMakie -@kwdef mutable struct CellModel - tri::Triangulation - new_r_cache::Vector{NTuple{2,Float64}} # for r(t + Δt) - const α::Float64 - const s::Float64 - const Δt::Float64 - const rng::StableRNGs.LehmerRNG - const final_time::Float64 - const β::Float64 - const K::Float64 - const ϵ::Float64 +Base.@kwdef mutable struct CellModel{P} + tri::Triangulation{P} + new_r_cache::Vector{NTuple{2, Float64}} # for r(t + Δt) + α::Float64 + s::Float64 + Δt::Float64 + rng::StableRNGs.LehmerRNG + final_time::Float64 + β::Float64 + K::Float64 + ϵ::Float64 end function migrate_cells!(cells::CellModel) # a more efficient way would be to loop over edges rather than vertices @@ -270,7 +289,7 @@ function polygon_area(points) # this is the same function from the Interpolation rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -280,7 +299,7 @@ function polygon_area(points) # this is the same function from the Interpolation return area / 2 end function get_voronoi_area(tri::Triangulation, i) - points = NTuple{2,Float64}[] + points = NTuple{2, Float64}[] !DelaunayTriangulation.has_vertex(tri, i) && return (0.0, points) # might not be included anymore due to retriangulation DelaunayTriangulation.is_boundary_node(tri, i)[1] && return (0.0, points) # to prevent boundary cells from proliferating N = get_neighbours(tri, i) @@ -319,7 +338,7 @@ function proliferate_cells!(cells::CellModel) δ = DelaunayTriangulation.distance_to_polygon(p, get_points(tri), poly) s, c = sincos(θ) q = p .+ (δ * cells.ϵ) .* (c, s) - add_point!(tri, q; rng=cells.rng) + add_point!(tri, q; rng = cells.rng) push!(cells.new_r_cache, q) end return nothing @@ -332,7 +351,7 @@ function perform_step!(cells::CellModel) end function simulate_cells(cells::CellModel) t = 0.0 - all_points = Vector{Vector{NTuple{2,Float64}}}() + all_points = Vector{Vector{NTuple{2, Float64}}}() push!(all_points, deepcopy(get_points(cells.tri))) while t < cells.final_time perform_step!(cells) @@ -345,23 +364,27 @@ end rng = StableRNG(123444) a, b, c, d = -2.0, 2.0, -5.0, 5.0 points = [(a + (b - a) * rand(rng), c + (d - c) * rand(rng)) for _ in 1:10] -tri = triangulate(points; rng=rng) -cells = CellModel(; tri=tri, new_r_cache=similar(points), α=5.0, s=2.0, Δt=1e-3, - β=0.25, K=100.0^2, rng, final_time=25.0, ϵ=0.5) +tri = triangulate(points; rng = rng) +cells = CellModel(; + tri = tri, new_r_cache = similar(points), α = 5.0, s = 2.0, Δt = 1.0e-3, + β = 0.25, K = 100.0^2, rng, final_time = 25.0, ϵ = 0.5, +) results = simulate_cells(cells); -fig = Figure(fontsize=26) +fig = Figure(fontsize = 26) title_obs = Observable(L"t = %$(0.0)") -ax1 = Axis(fig[1, 1], width=1200, height=400, title=title_obs, titlealign=:left) +ax1 = Axis(fig[1, 1], width = 1200, height = 400, title = title_obs, titlealign = :left) Δt = cells.Δt i = Observable(1) -voronoiplot!(ax1, @lift(voronoi(triangulate(results[$i]; rng), clip=true, rng=rng)), - color=:darkgreen, strokecolor=:black, strokewidth=2, show_generators=false) +voronoiplot!( + ax1, @lift(voronoi(triangulate(results[$i]; rng), clip = true, rng = rng)), + color = :darkgreen, strokecolor = :black, strokewidth = 2, show_generators = false, +) xlims!(ax1, -12, 12) ylims!(ax1, -12, 12) resize_to_layout!(fig) t = 0:Δt:cells.final_time -record(fig, "cell_simulation.mp4", 1:10:length(t); framerate=60) do ii +record(fig, "cell_simulation.mp4", 1:10:length(t); framerate = 60) do ii i[] = ii title_obs[] = L"t = %$(((ii-1) * Δt))" end; diff --git a/docs/src/applications/interpolation.md b/docs/src/applications/interpolation.md index 8ff787f5f..964a15306 100644 --- a/docs/src/applications/interpolation.md +++ b/docs/src/applications/interpolation.md @@ -20,41 +20,10 @@ One way around this is to instead use the Voronoi tessellation to guide the tess We give an example of this below, where we show how $\mathcal D\mathcal T(X)$ may change significant after a small perturbation while $\mathcal V(X)$ does not at the same time. -````@example interpolation -using DelaunayTriangulation #hide -using CairoMakie #hide -A, B, C, D, E, F, G, H = (0.3, 1.1), (-0.1, 0.8), (0.2, 0.3), (0.6, 0.2), (0.8, 0.8), (0.3, 0.9), (0.5503600264347, 0.6814266789918), (1.1, 0.5) #hide -G2 = (0.5496217775447, 0.7146478790414) #hide -fig = Figure() #hide -ax = Axis(fig[1, 1], width=400, height=400, title="Original") #hide -xlims!(ax, -0.2, 1.3) #hide -ylims!(ax, 0.1, 1.2) #hide -points = [A, B, C, D, E, F, G, H] #hide -triplot!(ax, points, show_points=true) #hide -scatter!(ax, [G], color=:red, markersize=14) #hide -hidedecorations!(ax) #hide -ax2 = Axis(fig[2, 1], width=400, height=400) #hide -voronoiplot!(ax2, points, clip=(-0.2, 1.3, 0.1, 1.2)) #hide -xlims!(ax2, -0.2, 1.3) #hide -ylims!(ax2, 0.1, 1.2) #hide -scatter!(ax2, [G], color=:red, markersize=14) #hide -hidedecorations!(ax2) #hide -ax3 = Axis(fig[1, 2], width=400, height=400, title="Perturbed") #hide -points = [A, B, C, D, E, F, G2, H] #hide -triplot!(ax3, points, show_points=true) #hide -hidedecorations!(ax3) #hide -xlims!(ax3, -0.2, 1.3) #hide -ylims!(ax3, 0.1, 1.2) #hide -scatter!(ax3, [G2], color=:red, markersize=14) #hide -ax4 = Axis(fig[2, 2], width=400, height=400) #hide -voronoiplot!(ax4, points, clip=(-0.2, 1.3, 0.1, 1.2)) #hide -scatter!(ax4, [G2], color=:red, markersize=14) #hide -xlims!(ax4, -0.2, 1.3) #hide -ylims!(ax4, 0.1, 1.2) #hide -hidedecorations!(ax4) #hide -resize_to_layout!(fig) #hide -fig #hide -```` + +```@raw html + +``` This observation motivates the use of the Voronoi tessellation to guide the interpolation. @@ -100,7 +69,7 @@ We implement this below.[^1] [^1]: This is more expensive than we need. In NaturalNeighbours.jl, we use the `peek` keyword in `triangulate` to avoid making any changes to the triangulation itself, and use the `InsertionEventHistory` to track all changes made. -````@example interpolation +````julia using DelaunayTriangulation function compute_envelope(tri::Triangulation, point) r = DelaunayTriangulation.num_points(tri) @@ -115,9 +84,13 @@ function compute_envelope(tri::Triangulation, point) end ```` +```` +compute_envelope (generic function with 1 method) +```` + Let's now check that this function works. -````@example interpolation +````julia using CairoMakie using StableRNGs using ElasticArrays @@ -126,17 +99,21 @@ points = ElasticMatrix(randn(rng, 2, 50)) # so that the points are mutable tri = triangulate(points; rng) envelope_vertices, envelope_points = compute_envelope(tri, (0.5, 0.5)) -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -ax2 = Axis(fig[1, 2], width=400, height=400) +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +ax2 = Axis(fig[1, 2], width = 400, height = 400) add_point!(tri, 0.5, 0.5) -triplot!(ax2, tri, show_points=true) -poly!(ax2, envelope_points, color=(:red, 0.2)) +triplot!(ax2, tri, show_points = true) +poly!(ax2, envelope_points, color = (:red, 0.2)) resize_to_layout!(fig) fig ```` +```@raw html + +``` + As we can see, the red region we have computed from our envelope is indeed the envelope we need. ### Computing the Sibsonian coordinates @@ -154,37 +131,41 @@ to compute the part of the area that is contained within the envelope, since eve envelope is unchanged. If we included the entire area, then the area that we subtract off for the intersection we compute later would just cancel it out anyway. Let's zoom in on the envelope and consider a specific example of how we can do this computation. -````@example interpolation -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -lines!(ax, envelope_points, color=:red) +````julia +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +lines!(ax, envelope_points, color = :red) j = 7 # example vertex v = envelope_vertices[j] -scatter!(ax, [get_point(tri, v)], color=:blue) -first_neighbour = envelope_vertices[j-1] +scatter!(ax, [get_point(tri, v)], color = :blue) +first_neighbour = envelope_vertices[j - 1] next_triangle = get_adjacent(tri, first_neighbour, v) -next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j+1]) -last_neighbour = envelope_vertices[j+1] +next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j + 1]) +last_neighbour = envelope_vertices[j + 1] polygon_points = [ get_point(tri, v), (get_point(tri, v) .+ get_point(tri, last_neighbour)) ./ 2, - DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j+1], next_triangle_2)), + DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j + 1], next_triangle_2)), DelaunayTriangulation.triangle_circumcenter(tri, (first_neighbour, v, next_triangle)), - (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2 + (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2, ] -poly!(ax, polygon_points, color=(:blue, 0.5), strokecolor=:blue, strokewidth=2) +poly!(ax, polygon_points, color = (:blue, 0.5), strokecolor = :blue, strokewidth = 2) xlims!(ax, -0.5, 1.4) ylims!(ax, -0.15, 1.4) resize_to_layout!(fig) fig ```` +```@raw html + +``` + The relevant polygon is shown above in blue, associated with the generator shown by the blue point. We need to compute the area of this polygon. This is simple using the [shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula). Our implementation of this is given below. -````@example interpolation +````julia function polygon_area(points) # this is the first formula in the "Other formulae" section of the above Wikipedia article n = DelaunayTriangulation.num_points(points) p, q, r, s = get_point(points, 1, 2, n, n - 1) @@ -193,7 +174,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -203,7 +184,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae return area / 2 end function pre_insertion_area(tri::Triangulation, i, envelope_vertices) # area from the envelope[i]th generator - poly_points = NTuple{2,Float64}[] + poly_points = NTuple{2, Float64}[] u = envelope_vertices[i] prev_index = i == 1 ? length(envelope_vertices) - 1 : i - 1 next_index = i == length(envelope_vertices) ? 1 : i + 1 @@ -226,10 +207,14 @@ function pre_insertion_area(tri::Triangulation, i, envelope_vertices) # area fro end ```` +```` +pre_insertion_area (generic function with 1 method) +```` + The details for the post-insertion area are similar, but now the triangles that we take the circumcenters of are those where the edges instead join with the inserted vertex. The function we use is below. -````@example interpolation +````julia function post_insertion_area(tri::Triangulation, i, envelope_vertices, point) u = envelope_vertices[i] prev_index = i == 1 ? length(envelope_vertices) - 1 : i - 1 @@ -251,13 +236,17 @@ function post_insertion_area(tri::Triangulation, i, envelope_vertices, point) end ```` +```` +post_insertion_area (generic function with 1 method) +```` + Now that we can compute the pre- and post-insertion areas, we can start computing the Sibsonian coordinates. -````@example interpolation +````julia function compute_sibson_coordinates(tri::Triangulation, envelope_vertices, point) coordinates = zeros(length(envelope_vertices) - 1) w = 0.0 - for i in firstindex(envelope_vertices):(lastindex(envelope_vertices)-1) + for i in firstindex(envelope_vertices):(lastindex(envelope_vertices) - 1) pre = max(0.0, pre_insertion_area(tri, i, envelope_vertices)) post = max(0.0, post_insertion_area(tri, i, envelope_vertices, point)) if isnan(post) # need to return the the vector λ = [1] since we are exactly at a data site @@ -271,12 +260,17 @@ function compute_sibson_coordinates(tri::Triangulation, envelope_vertices, point end ```` +```` +compute_sibson_coordinates (generic function with 1 method) +```` + This function gives our $\boldsymbol\lambda$ vector. Notice that, in the computation of these coordinates, we need needed to have $\mathcal V(X)$ directly or make use of the data $z_i$. +## Evaluating the Sibsonian interpolant Now we can evaluate our Sibson interpolant. The following function does this for us. -````@example interpolation +````julia function evaluate_sibson_interpolant(tri::Triangulation, z, point) envelope_vertices, _ = compute_envelope(tri, point) λ = compute_sibson_coordinates(tri, envelope_vertices, point) @@ -294,25 +288,34 @@ function evaluate_sibson_interpolant(tri::Triangulation, z, point) end ```` +```` +evaluate_sibson_interpolant (generic function with 1 method) +```` + Let's now use this function to interpolate some data. -````@example interpolation +````julia f = (x, y) -> sin(x * y) - cos(x - y) * exp(-(x - y)^2) trit = triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 30, 30) zz = [f(x, y) for (x, y) in DelaunayTriangulation.each_point(trit)] xx = LinRange(0.001, 0.999, 20) # handling points on the boundary requires more care than we have discussed here yy = LinRange(0.001, 0.999, 20) fig = Figure(fontsize = 24) -ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"y", title="True function", titlealign=:left, width=400, height=400) +ax = Axis(fig[1, 1], xlabel = L"x", ylabel = L"y", title = "True function", titlealign = :left, width = 400, height = 400) contourf!(ax, xx, yy, f.(xx, yy')) -ax2 = Axis(fig[1, 2], xlabel=L"x", ylabel=L"y", title="Interpolant", titlealign=:left, width=400, height=400) +ax2 = Axis(fig[1, 2], xlabel = L"x", ylabel = L"y", title = "Interpolant", titlealign = :left, width = 400, height = 400) zi = [evaluate_sibson_interpolant(trit, zz, (xᵢ, yᵢ)) for xᵢ in xx, yᵢ in yy] contourf!(ax2, xx, yy, zi) resize_to_layout!(fig) fig ```` +```@raw html + +``` + Works perfectly! + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_applications/interpolation.jl). @@ -339,35 +342,35 @@ points = ElasticMatrix(randn(rng, 2, 50)) # so that the points are mutable tri = triangulate(points; rng) envelope_vertices, envelope_points = compute_envelope(tri, (0.5, 0.5)) -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -ax2 = Axis(fig[1, 2], width=400, height=400) +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +ax2 = Axis(fig[1, 2], width = 400, height = 400) add_point!(tri, 0.5, 0.5) -triplot!(ax2, tri, show_points=true) -poly!(ax2, envelope_points, color=(:red, 0.2)) +triplot!(ax2, tri, show_points = true) +poly!(ax2, envelope_points, color = (:red, 0.2)) resize_to_layout!(fig) fig -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -lines!(ax, envelope_points, color=:red) +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +lines!(ax, envelope_points, color = :red) j = 7 # example vertex v = envelope_vertices[j] -scatter!(ax, [get_point(tri, v)], color=:blue) -first_neighbour = envelope_vertices[j-1] +scatter!(ax, [get_point(tri, v)], color = :blue) +first_neighbour = envelope_vertices[j - 1] next_triangle = get_adjacent(tri, first_neighbour, v) -next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j+1]) -last_neighbour = envelope_vertices[j+1] +next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j + 1]) +last_neighbour = envelope_vertices[j + 1] polygon_points = [ get_point(tri, v), (get_point(tri, v) .+ get_point(tri, last_neighbour)) ./ 2, - DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j+1], next_triangle_2)), + DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j + 1], next_triangle_2)), DelaunayTriangulation.triangle_circumcenter(tri, (first_neighbour, v, next_triangle)), - (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2 + (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2, ] -poly!(ax, polygon_points, color=(:blue, 0.5), strokecolor=:blue, strokewidth=2) +poly!(ax, polygon_points, color = (:blue, 0.5), strokecolor = :blue, strokewidth = 2) xlims!(ax, -0.5, 1.4) ylims!(ax, -0.15, 1.4) resize_to_layout!(fig) @@ -381,7 +384,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -391,7 +394,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae return area / 2 end function pre_insertion_area(tri::Triangulation, i, envelope_vertices) # area from the envelope[i]th generator - poly_points = NTuple{2,Float64}[] + poly_points = NTuple{2, Float64}[] u = envelope_vertices[i] prev_index = i == 1 ? length(envelope_vertices) - 1 : i - 1 next_index = i == length(envelope_vertices) ? 1 : i + 1 @@ -436,7 +439,7 @@ end function compute_sibson_coordinates(tri::Triangulation, envelope_vertices, point) coordinates = zeros(length(envelope_vertices) - 1) w = 0.0 - for i in firstindex(envelope_vertices):(lastindex(envelope_vertices)-1) + for i in firstindex(envelope_vertices):(lastindex(envelope_vertices) - 1) pre = max(0.0, pre_insertion_area(tri, i, envelope_vertices)) post = max(0.0, post_insertion_area(tri, i, envelope_vertices, point)) if isnan(post) # need to return the the vector λ = [1] since we are exactly at a data site @@ -449,8 +452,6 @@ function compute_sibson_coordinates(tri::Triangulation, envelope_vertices, point return coordinates end -### Evaluating the Sibsonian interpolant - function evaluate_sibson_interpolant(tri::Triangulation, z, point) envelope_vertices, _ = compute_envelope(tri, point) λ = compute_sibson_coordinates(tri, envelope_vertices, point) @@ -473,9 +474,9 @@ zz = [f(x, y) for (x, y) in DelaunayTriangulation.each_point(trit)] xx = LinRange(0.001, 0.999, 20) # handling points on the boundary requires more care than we have discussed here yy = LinRange(0.001, 0.999, 20) fig = Figure(fontsize = 24) -ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"y", title="True function", titlealign=:left, width=400, height=400) +ax = Axis(fig[1, 1], xlabel = L"x", ylabel = L"y", title = "True function", titlealign = :left, width = 400, height = 400) contourf!(ax, xx, yy, f.(xx, yy')) -ax2 = Axis(fig[1, 2], xlabel=L"x", ylabel=L"y", title="Interpolant", titlealign=:left, width=400, height=400) +ax2 = Axis(fig[1, 2], xlabel = L"x", ylabel = L"y", title = "Interpolant", titlealign = :left, width = 400, height = 400) zi = [evaluate_sibson_interpolant(trit, zz, (xᵢ, yᵢ)) for xᵢ in xx, yᵢ in yy] contourf!(ax2, xx, yy, zi) resize_to_layout!(fig) diff --git a/docs/src/applications/pde_discretisation.md b/docs/src/applications/pde_discretisation.md index 744985b5b..fd7f247ba 100644 --- a/docs/src/applications/pde_discretisation.md +++ b/docs/src/applications/pde_discretisation.md @@ -28,7 +28,7 @@ $\Omega = \cup_i\mathcal T_i$. We will then approximate the solution $T$ on each For this decomposition, we simply use $\mathcal D\mathcal T(\Omega)$, where $\mathcal D\mathcal T(\Omega)$ is some Delaunay triangulation of points in $\Omega$ with $\partial\mathcal D\mathcal T(\Omega) = \partial\Omega$. Here is our discretisation of our annulus. -````@example pde_discretisation +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -36,31 +36,28 @@ rng = StableRNG(123) R₁ = 1.0 R₂ = 2.0 outer_circle = CircularArc((R₂, 0.0), (R₂, 0.0), (0.0, 0.0)) -inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive=false) -points = NTuple{2,Float64}[] -tri = triangulate(points; rng, boundary_nodes=[[[outer_circle]], [[inner_circle]]]) +inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive = false) +points = NTuple{2, Float64}[] +tri = triangulate(points; rng, boundary_nodes = [[[outer_circle]], [[inner_circle]]]) A = 2π * (R₂^2 - R₁^2) -refine!(tri; max_area=2e-3A, min_angle=33.0, rng) +refine!(tri; max_area = 2.0e-3A, min_angle = 33.0, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## Discretisation of the PDE Now let's determine how we can use the discretisation above to solve the PDE. Central to this approach is the idea of a _control volume_ around each point. In particular, connect the centroids of each triangle to the midpoints of the edges of the triangle. This defines a collection of polygons $\Omega_i$ around each point $\vb x_i$, as shown below in blue. -````@example pde_discretisation -points = NTuple{2,Float64}[] #hide -for T in each_solid_triangle(tri) #hide - u, v, w = triangle_vertices(T) #hide - p, q, r = get_point(tri, u, v, w) #hide - c = DelaunayTriangulation.triangle_centroid(p, q, r) #hide - push!(points, c, (p .+ q) ./ 2, c, (q .+ r) ./ 2, c, (r .+ p) ./ 2) #hide -end #hide -linesegments!(ax, points, color=:blue) #hide -fig #hide -```` + +```@raw html + +``` Consider a particular control volume $\Omega_i$. We integrate our PDE over this domain, writing $\grad^2 = \grad \vdot \grad$ and use the divergence theorem: @@ -119,14 +116,14 @@ is the $i$th standard basis vector, and $b_i = 0$. The solution to this system w Let's now implement these ideas. Some details of this implementation, like how we efficient loop over the mesh for building the system by using edges rather than vertices, have been skipped and are described in more detail [here](https://sciml.github.io/FiniteVolumeMethod.jl/dev/math/). -````@example pde_discretisation +````julia using LinearAlgebra using SparseArrays function solve_met_problem(tri::Triangulation, D) # To start, we need to build a map that takes the vertices from tri # into a range of consecutive integers, since not all vertices are used. - vertex_map = Dict{Int,Int}() - inverse_vertex_map = Dict{Int,Int}() + vertex_map = Dict{Int, Int}() + inverse_vertex_map = Dict{Int, Int}() cur_idx = 1 for i in DelaunayTriangulation.each_point_index(tri) if DelaunayTriangulation.has_vertex(tri, i) @@ -140,10 +137,10 @@ function solve_met_problem(tri::Triangulation, D) nt = num_solid_triangles(tri) cv_volumes = zeros(nv) Ttype = DelaunayTriangulation.triangle_type(tri) - shape_function_coefficients = Dict{Ttype,NTuple{9,Float64}}() - cv_edge_midpoints = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_normals = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_lengths = Dict{Ttype,NTuple{3,Float64}}() + shape_function_coefficients = Dict{Ttype, NTuple{9, Float64}}() + cv_edge_midpoints = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_normals = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_lengths = Dict{Ttype, NTuple{3, Float64}}() sizehint!.((cv_volumes, shape_function_coefficients, cv_edge_midpoints, cv_edge_normals, cv_edge_lengths), nt) for T in each_solid_triangle(tri) u, v, w = triangle_vertices(T) @@ -211,9 +208,11 @@ function solve_met_problem(tri::Triangulation, D) nx, ny = cv_edge_normals[T][edge_index] ℓ = cv_edge_lengths[T][edge_index] Dℓ = D * ℓ - a123 = (Dℓ * (s₁₁ * nx + s₂₁ * ny), + a123 = ( + Dℓ * (s₁₁ * nx + s₂₁ * ny), Dℓ * (s₁₂ * nx + s₂₂ * ny), - Dℓ * (s₁₃ * nx + s₂₃ * ny)) + Dℓ * (s₁₃ * nx + s₂₃ * ny), + ) e1_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₁)[1] e2_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₂)[1] for vert in 1:3 @@ -242,16 +241,24 @@ function solve_met_problem(tri::Triangulation, D) end ```` +```` +solve_met_problem (generic function with 1 method) +```` + ## Solving the System Let's now solve this problem, taking $D = 6.25 \times 10^{-4}$. -````@example pde_discretisation +````julia D = 6.25e-4 T = solve_met_problem(tri, D) -fig, ax, sc = tricontourf(tri, T, levels=0:5:200, extendhigh=:auto) +fig, ax, sc = tricontourf(tri, T, levels = 0:5:200, extendhigh = :auto) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_applications/pde_discretisation.jl). @@ -264,11 +271,11 @@ rng = StableRNG(123) R₁ = 1.0 R₂ = 2.0 outer_circle = CircularArc((R₂, 0.0), (R₂, 0.0), (0.0, 0.0)) -inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive=false) -points = NTuple{2,Float64}[] -tri = triangulate(points; rng, boundary_nodes=[[[outer_circle]], [[inner_circle]]]) +inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive = false) +points = NTuple{2, Float64}[] +tri = triangulate(points; rng, boundary_nodes = [[[outer_circle]], [[inner_circle]]]) A = 2π * (R₂^2 - R₁^2) -refine!(tri; max_area=2e-3A, min_angle=33.0, rng) +refine!(tri; max_area = 2.0e-3A, min_angle = 33.0, rng) fig, ax, sc = triplot(tri) fig @@ -278,8 +285,8 @@ using SparseArrays function solve_met_problem(tri::Triangulation, D) # To start, we need to build a map that takes the vertices from tri # into a range of consecutive integers, since not all vertices are used. - vertex_map = Dict{Int,Int}() - inverse_vertex_map = Dict{Int,Int}() + vertex_map = Dict{Int, Int}() + inverse_vertex_map = Dict{Int, Int}() cur_idx = 1 for i in DelaunayTriangulation.each_point_index(tri) if DelaunayTriangulation.has_vertex(tri, i) @@ -293,10 +300,10 @@ function solve_met_problem(tri::Triangulation, D) nt = num_solid_triangles(tri) cv_volumes = zeros(nv) Ttype = DelaunayTriangulation.triangle_type(tri) - shape_function_coefficients = Dict{Ttype,NTuple{9,Float64}}() - cv_edge_midpoints = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_normals = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_lengths = Dict{Ttype,NTuple{3,Float64}}() + shape_function_coefficients = Dict{Ttype, NTuple{9, Float64}}() + cv_edge_midpoints = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_normals = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_lengths = Dict{Ttype, NTuple{3, Float64}}() sizehint!.((cv_volumes, shape_function_coefficients, cv_edge_midpoints, cv_edge_normals, cv_edge_lengths), nt) for T in each_solid_triangle(tri) u, v, w = triangle_vertices(T) @@ -364,9 +371,11 @@ function solve_met_problem(tri::Triangulation, D) nx, ny = cv_edge_normals[T][edge_index] ℓ = cv_edge_lengths[T][edge_index] Dℓ = D * ℓ - a123 = (Dℓ * (s₁₁ * nx + s₂₁ * ny), + a123 = ( + Dℓ * (s₁₁ * nx + s₂₁ * ny), Dℓ * (s₁₂ * nx + s₂₂ * ny), - Dℓ * (s₁₃ * nx + s₂₃ * ny)) + Dℓ * (s₁₃ * nx + s₂₃ * ny), + ) e1_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₁)[1] e2_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₂)[1] for vert in 1:3 @@ -396,7 +405,7 @@ end D = 6.25e-4 T = solve_met_problem(tri, D) -fig, ax, sc = tricontourf(tri, T, levels=0:5:200, extendhigh=:auto) +fig, ax, sc = tricontourf(tri, T, levels = 0:5:200, extendhigh = :auto) fig ``` diff --git a/docs/src/literate_applications/cell_simulations.jl b/docs/src/literate_applications/cell_simulations.jl index 856918443..fd44c60d9 100644 --- a/docs/src/literate_applications/cell_simulations.jl +++ b/docs/src/literate_applications/cell_simulations.jl @@ -48,7 +48,7 @@ using StatsBase using CairoMakie Base.@kwdef mutable struct CellModel{P} tri::Triangulation{P} - new_r_cache::Vector{NTuple{2,Float64}} # for r(t + Δt) + new_r_cache::Vector{NTuple{2, Float64}} # for r(t + Δt) α::Float64 s::Float64 Δt::Float64 @@ -91,7 +91,7 @@ function polygon_area(points) # this is the same function from the Interpolation rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -101,7 +101,7 @@ function polygon_area(points) # this is the same function from the Interpolation return area / 2 end function get_voronoi_area(tri::Triangulation, i) - points = NTuple{2,Float64}[] + points = NTuple{2, Float64}[] !DelaunayTriangulation.has_vertex(tri, i) && return (0.0, points) # might not be included anymore due to retriangulation DelaunayTriangulation.is_boundary_node(tri, i)[1] && return (0.0, points) # to prevent boundary cells from proliferating N = get_neighbours(tri, i) @@ -142,7 +142,7 @@ function proliferate_cells!(cells::CellModel) δ = DelaunayTriangulation.distance_to_polygon(p, get_points(tri), poly) s, c = sincos(θ) q = p .+ (δ * cells.ϵ) .* (c, s) - add_point!(tri, q; rng=cells.rng) + add_point!(tri, q; rng = cells.rng) push!(cells.new_r_cache, q) end return nothing @@ -156,7 +156,7 @@ function perform_step!(cells::CellModel) end function simulate_cells(cells::CellModel) t = 0.0 - all_points = Vector{Vector{NTuple{2,Float64}}}() + all_points = Vector{Vector{NTuple{2, Float64}}}() push!(all_points, deepcopy(get_points(cells.tri))) while t < cells.final_time perform_step!(cells) @@ -173,23 +173,27 @@ end rng = StableRNG(123444) a, b, c, d = -2.0, 2.0, -5.0, 5.0 points = [(a + (b - a) * rand(rng), c + (d - c) * rand(rng)) for _ in 1:10] -tri = triangulate(points; rng=rng) -cells = CellModel(; tri=tri, new_r_cache=similar(points), α=5.0, s=2.0, Δt=1e-3, - β=0.25, K=100.0^2, rng, final_time=25.0, ϵ=0.5) +tri = triangulate(points; rng = rng) +cells = CellModel(; + tri = tri, new_r_cache = similar(points), α = 5.0, s = 2.0, Δt = 1.0e-3, + β = 0.25, K = 100.0^2, rng, final_time = 25.0, ϵ = 0.5, +) results = simulate_cells(cells); -fig = Figure(fontsize=26) +fig = Figure(fontsize = 26) title_obs = Observable(L"t = %$(0.0)") -ax1 = Axis(fig[1, 1], width=1200, height=400, title=title_obs, titlealign=:left) +ax1 = Axis(fig[1, 1], width = 1200, height = 400, title = title_obs, titlealign = :left) Δt = cells.Δt i = Observable(1) -voronoiplot!(ax1, @lift(voronoi(triangulate(results[$i]; rng), clip=true, rng=rng)), - color=:darkgreen, strokecolor=:black, strokewidth=2, show_generators=false) +voronoiplot!( + ax1, @lift(voronoi(triangulate(results[$i]; rng), clip = true, rng = rng)), + color = :darkgreen, strokecolor = :black, strokewidth = 2, show_generators = false, +) xlims!(ax1, -12, 12) ylims!(ax1, -12, 12) resize_to_layout!(fig) t = 0:Δt:cells.final_time -record(fig, "cell_simulation.mp4", 1:10:length(t); framerate=60) do ii +record(fig, "cell_simulation.mp4", 1:10:length(t); framerate = 60) do ii i[] = ii title_obs[] = L"t = %$(((ii-1) * Δt))" end; diff --git a/docs/src/literate_applications/interpolation.jl b/docs/src/literate_applications/interpolation.jl index c271d8e18..bece9cef3 100644 --- a/docs/src/literate_applications/interpolation.jl +++ b/docs/src/literate_applications/interpolation.jl @@ -20,29 +20,29 @@ using CairoMakie #hide A, B, C, D, E, F, G, H = (0.3, 1.1), (-0.1, 0.8), (0.2, 0.3), (0.6, 0.2), (0.8, 0.8), (0.3, 0.9), (0.5503600264347, 0.6814266789918), (1.1, 0.5) #hide G2 = (0.5496217775447, 0.7146478790414) #hide fig = Figure() #hide -ax = Axis(fig[1, 1], width=400, height=400, title="Original") #hide +ax = Axis(fig[1, 1], width = 400, height = 400, title = "Original") #hide xlims!(ax, -0.2, 1.3) #hide ylims!(ax, 0.1, 1.2) #hide points = [A, B, C, D, E, F, G, H] #hide -triplot!(ax, points, show_points=true) #hide -scatter!(ax, [G], color=:red, markersize=14) #hide +triplot!(ax, points, show_points = true) #hide +scatter!(ax, [G], color = :red, markersize = 14) #hide hidedecorations!(ax) #hide -ax2 = Axis(fig[2, 1], width=400, height=400) #hide -voronoiplot!(ax2, points, clip=(-0.2, 1.3, 0.1, 1.2)) #hide +ax2 = Axis(fig[2, 1], width = 400, height = 400) #hide +voronoiplot!(ax2, points, clip = (-0.2, 1.3, 0.1, 1.2)) #hide xlims!(ax2, -0.2, 1.3) #hide ylims!(ax2, 0.1, 1.2) #hide -scatter!(ax2, [G], color=:red, markersize=14) #hide +scatter!(ax2, [G], color = :red, markersize = 14) #hide hidedecorations!(ax2) #hide -ax3 = Axis(fig[1, 2], width=400, height=400, title="Perturbed") #hide +ax3 = Axis(fig[1, 2], width = 400, height = 400, title = "Perturbed") #hide points = [A, B, C, D, E, F, G2, H] #hide -triplot!(ax3, points, show_points=true) #hide +triplot!(ax3, points, show_points = true) #hide hidedecorations!(ax3) #hide xlims!(ax3, -0.2, 1.3) #hide ylims!(ax3, 0.1, 1.2) #hide -scatter!(ax3, [G2], color=:red, markersize=14) #hide -ax4 = Axis(fig[2, 2], width=400, height=400) #hide -voronoiplot!(ax4, points, clip=(-0.2, 1.3, 0.1, 1.2)) #hide -scatter!(ax4, [G2], color=:red, markersize=14) #hide +scatter!(ax3, [G2], color = :red, markersize = 14) #hide +ax4 = Axis(fig[2, 2], width = 400, height = 400) #hide +voronoiplot!(ax4, points, clip = (-0.2, 1.3, 0.1, 1.2)) #hide +scatter!(ax4, [G2], color = :red, markersize = 14) #hide xlims!(ax4, -0.2, 1.3) #hide ylims!(ax4, 0.1, 1.2) #hide hidedecorations!(ax4) #hide @@ -114,13 +114,13 @@ points = ElasticMatrix(randn(rng, 2, 50)) # so that the points are mutable tri = triangulate(points; rng) envelope_vertices, envelope_points = compute_envelope(tri, (0.5, 0.5)) -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -ax2 = Axis(fig[1, 2], width=400, height=400) +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +ax2 = Axis(fig[1, 2], width = 400, height = 400) add_point!(tri, 0.5, 0.5) -triplot!(ax2, tri, show_points=true) -poly!(ax2, envelope_points, color=(:red, 0.2)) +triplot!(ax2, tri, show_points = true) +poly!(ax2, envelope_points, color = (:red, 0.2)) resize_to_layout!(fig) fig @@ -140,25 +140,25 @@ fig # to compute the part of the area that is contained within the envelope, since everything outside of that # envelope is unchanged. If we included the entire area, then the area that we subtract off for the intersection we compute later # would just cancel it out anyway. Let's zoom in on the envelope and consider a specific example of how we can do this computation. -fig = Figure(fontsize=24) -ax = Axis(fig[1, 1], width=400, height=400) -triplot!(ax, tri, show_points=true) -lines!(ax, envelope_points, color=:red) +fig = Figure(fontsize = 24) +ax = Axis(fig[1, 1], width = 400, height = 400) +triplot!(ax, tri, show_points = true) +lines!(ax, envelope_points, color = :red) j = 7 # example vertex v = envelope_vertices[j] -scatter!(ax, [get_point(tri, v)], color=:blue) -first_neighbour = envelope_vertices[j-1] +scatter!(ax, [get_point(tri, v)], color = :blue) +first_neighbour = envelope_vertices[j - 1] next_triangle = get_adjacent(tri, first_neighbour, v) -next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j+1]) -last_neighbour = envelope_vertices[j+1] +next_triangle_2 = get_adjacent(tri, v, envelope_vertices[j + 1]) +last_neighbour = envelope_vertices[j + 1] polygon_points = [ get_point(tri, v), (get_point(tri, v) .+ get_point(tri, last_neighbour)) ./ 2, - DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j+1], next_triangle_2)), + DelaunayTriangulation.triangle_circumcenter(tri, (v, envelope_vertices[j + 1], next_triangle_2)), DelaunayTriangulation.triangle_circumcenter(tri, (first_neighbour, v, next_triangle)), - (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2 + (get_point(tri, v) .+ get_point(tri, first_neighbour)) ./ 2, ] -poly!(ax, polygon_points, color=(:blue, 0.5), strokecolor=:blue, strokewidth=2) +poly!(ax, polygon_points, color = (:blue, 0.5), strokecolor = :blue, strokewidth = 2) xlims!(ax, -0.5, 1.4) ylims!(ax, -0.15, 1.4) resize_to_layout!(fig) @@ -175,7 +175,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae rx, ry = getxy(r) sx, sy = getxy(s) area = px * (qy - ry) + rx * (py - sy) - for i in 2:(n-1) + for i in 2:(n - 1) p, q, r = get_point(points, i, i + 1, i - 1) px, py = getxy(p) qx, qy = getxy(q) @@ -185,7 +185,7 @@ function polygon_area(points) # this is the first formula in the "Other formulae return area / 2 end function pre_insertion_area(tri::Triangulation, i, envelope_vertices) # area from the envelope[i]th generator - poly_points = NTuple{2,Float64}[] + poly_points = NTuple{2, Float64}[] u = envelope_vertices[i] prev_index = i == 1 ? length(envelope_vertices) - 1 : i - 1 next_index = i == length(envelope_vertices) ? 1 : i + 1 @@ -233,7 +233,7 @@ end function compute_sibson_coordinates(tri::Triangulation, envelope_vertices, point) coordinates = zeros(length(envelope_vertices) - 1) w = 0.0 - for i in firstindex(envelope_vertices):(lastindex(envelope_vertices)-1) + for i in firstindex(envelope_vertices):(lastindex(envelope_vertices) - 1) pre = max(0.0, pre_insertion_area(tri, i, envelope_vertices)) post = max(0.0, post_insertion_area(tri, i, envelope_vertices, point)) if isnan(post) # need to return the the vector λ = [1] since we are exactly at a data site @@ -274,12 +274,12 @@ zz = [f(x, y) for (x, y) in DelaunayTriangulation.each_point(trit)] xx = LinRange(0.001, 0.999, 20) # handling points on the boundary requires more care than we have discussed here yy = LinRange(0.001, 0.999, 20) fig = Figure(fontsize = 24) -ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"y", title="True function", titlealign=:left, width=400, height=400) +ax = Axis(fig[1, 1], xlabel = L"x", ylabel = L"y", title = "True function", titlealign = :left, width = 400, height = 400) contourf!(ax, xx, yy, f.(xx, yy')) -ax2 = Axis(fig[1, 2], xlabel=L"x", ylabel=L"y", title="Interpolant", titlealign=:left, width=400, height=400) +ax2 = Axis(fig[1, 2], xlabel = L"x", ylabel = L"y", title = "Interpolant", titlealign = :left, width = 400, height = 400) zi = [evaluate_sibson_interpolant(trit, zz, (xᵢ, yᵢ)) for xᵢ in xx, yᵢ in yy] contourf!(ax2, xx, yy, zi) resize_to_layout!(fig) fig -# Works perfectly! \ No newline at end of file +# Works perfectly! diff --git a/docs/src/literate_applications/pde_discretisation.jl b/docs/src/literate_applications/pde_discretisation.jl index 511ae73cc..1bd53fc8d 100644 --- a/docs/src/literate_applications/pde_discretisation.jl +++ b/docs/src/literate_applications/pde_discretisation.jl @@ -30,11 +30,11 @@ rng = StableRNG(123) R₁ = 1.0 R₂ = 2.0 outer_circle = CircularArc((R₂, 0.0), (R₂, 0.0), (0.0, 0.0)) -inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive=false) -points = NTuple{2,Float64}[] -tri = triangulate(points; rng, boundary_nodes=[[[outer_circle]], [[inner_circle]]]) +inner_circle = CircularArc((R₁, 0.0), (R₁, 0.0), (0.0, 0.0), positive = false) +points = NTuple{2, Float64}[] +tri = triangulate(points; rng, boundary_nodes = [[[outer_circle]], [[inner_circle]]]) A = 2π * (R₂^2 - R₁^2) -refine!(tri; max_area=2e-3A, min_angle=33.0, rng) +refine!(tri; max_area = 2.0e-3A, min_angle = 33.0, rng) fig, ax, sc = triplot(tri) fig @@ -42,14 +42,14 @@ fig # Now let's determine how we can use the discretisation above to solve the PDE. Central to this approach is the idea of a _control volume_ around # each point. In particular, connect the centroids of each triangle to the midpoints of the edges of the triangle. This defines a collection of polygons # $\Omega_i$ around each point $\vb x_i$, as shown below in blue. -points = NTuple{2,Float64}[] #hide +points = NTuple{2, Float64}[] #hide for T in each_solid_triangle(tri) #hide u, v, w = triangle_vertices(T) #hide p, q, r = get_point(tri, u, v, w) #hide c = DelaunayTriangulation.triangle_centroid(p, q, r) #hide push!(points, c, (p .+ q) ./ 2, c, (q .+ r) ./ 2, c, (r .+ p) ./ 2) #hide end #hide -linesegments!(ax, points, color=:blue) #hide +linesegments!(ax, points, color = :blue) #hide fig #hide # Consider a particular control volume $\Omega_i$. We integrate our PDE over this domain, writing @@ -113,8 +113,8 @@ using SparseArrays function solve_met_problem(tri::Triangulation, D) ## To start, we need to build a map that takes the vertices from tri ## into a range of consecutive integers, since not all vertices are used. - vertex_map = Dict{Int,Int}() - inverse_vertex_map = Dict{Int,Int}() + vertex_map = Dict{Int, Int}() + inverse_vertex_map = Dict{Int, Int}() cur_idx = 1 for i in DelaunayTriangulation.each_point_index(tri) if DelaunayTriangulation.has_vertex(tri, i) @@ -128,10 +128,10 @@ function solve_met_problem(tri::Triangulation, D) nt = num_solid_triangles(tri) cv_volumes = zeros(nv) Ttype = DelaunayTriangulation.triangle_type(tri) - shape_function_coefficients = Dict{Ttype,NTuple{9,Float64}}() - cv_edge_midpoints = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_normals = Dict{Ttype,NTuple{3,NTuple{2,Float64}}}() - cv_edge_lengths = Dict{Ttype,NTuple{3,Float64}}() + shape_function_coefficients = Dict{Ttype, NTuple{9, Float64}}() + cv_edge_midpoints = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_normals = Dict{Ttype, NTuple{3, NTuple{2, Float64}}}() + cv_edge_lengths = Dict{Ttype, NTuple{3, Float64}}() sizehint!.((cv_volumes, shape_function_coefficients, cv_edge_midpoints, cv_edge_normals, cv_edge_lengths), nt) for T in each_solid_triangle(tri) u, v, w = triangle_vertices(T) @@ -199,9 +199,11 @@ function solve_met_problem(tri::Triangulation, D) nx, ny = cv_edge_normals[T][edge_index] ℓ = cv_edge_lengths[T][edge_index] Dℓ = D * ℓ - a123 = (Dℓ * (s₁₁ * nx + s₂₁ * ny), + a123 = ( + Dℓ * (s₁₁ * nx + s₂₁ * ny), Dℓ * (s₁₂ * nx + s₂₂ * ny), - Dℓ * (s₁₃ * nx + s₂₃ * ny)) + Dℓ * (s₁₃ * nx + s₂₃ * ny), + ) e1_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₁)[1] e2_is_bnd = DelaunayTriangulation.is_boundary_node(tri, e₂)[1] for vert in 1:3 @@ -233,5 +235,5 @@ end # Let's now solve this problem, taking $D = 6.25 \times 10^{-4}$. D = 6.25e-4 T = solve_met_problem(tri, D) -fig, ax, sc = tricontourf(tri, T, levels=0:5:200, extendhigh=:auto) -fig \ No newline at end of file +fig, ax, sc = tricontourf(tri, T, levels = 0:5:200, extendhigh = :auto) +fig diff --git a/docs/src/literate_tutorials/centroidal.jl b/docs/src/literate_tutorials/centroidal.jl index 9991dc158..e839ffbef 100644 --- a/docs/src/literate_tutorials/centroidal.jl +++ b/docs/src/literate_tutorials/centroidal.jl @@ -16,7 +16,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src rng = StableRNG(123) points = 25randn(rng, 2, 500) tri = triangulate(points; rng) -vorn = voronoi(tri, clip=true) +vorn = voronoi(tri, clip = true) # To now compute the centroidal tessellation, use [`centroidal_smooth`](@ref). ( # If you want to straight from a triangulation to a centroidal tessellation, you @@ -25,10 +25,10 @@ smooth_vorn = centroidal_smooth(vorn; rng) # Let us now compare the two tessellations. fig = Figure() -ax1 = Axis(fig[1, 1], title="Original", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Smoothed", width=600, height=400) -voronoiplot!(ax1, vorn, colormap=:matter, strokewidth=2) -voronoiplot!(ax2, smooth_vorn, colormap=:matter, strokewidth=2) +ax1 = Axis(fig[1, 1], title = "Original", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Smoothed", width = 600, height = 400) +voronoiplot!(ax1, vorn, colormap = :matter, strokewidth = 2) +voronoiplot!(ax2, smooth_vorn, colormap = :matter, strokewidth = 2) resize_to_layout!(fig) fig @test_reference joinpath(fig_path, "voronoi_ex_5.png") fig #src @@ -37,4 +37,4 @@ fig # do look to be near the centroid of their corresponding tile. Note that # this function `centroidal_smooth` is iterative, and you can control the iteration limits # and the tolerance of the iterations (based on the maximum displacement of any generator at -# each iteration) using the `maxiters` and `tol` keyword arguments. \ No newline at end of file +# each iteration) using the `maxiters` and `tol` keyword arguments. diff --git a/docs/src/literate_tutorials/clipped.jl b/docs/src/literate_tutorials/clipped.jl index 22b2ad8f1..e42f1e9b1 100644 --- a/docs/src/literate_tutorials/clipped.jl +++ b/docs/src/literate_tutorials/clipped.jl @@ -27,13 +27,13 @@ clipped_vorn = voronoi(tri, clip = true) # Note that the clipping has put more polygon vertices in. We compare # the clipped tessellations below. fig = Figure() -ax1 = Axis(fig[1, 1], title="Unclipped", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Clipped", width=600, height=400) -voronoiplot!(ax1, vorn, show_generators=false, colormap=:matter, strokewidth=4) -voronoiplot!(ax2, clipped_vorn, show_generators=false, colormap=:matter, strokewidth=4) +ax1 = Axis(fig[1, 1], title = "Unclipped", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Clipped", width = 600, height = 400) +voronoiplot!(ax1, vorn, show_generators = false, colormap = :matter, strokewidth = 4) +voronoiplot!(ax2, clipped_vorn, show_generators = false, colormap = :matter, strokewidth = 4) resize_to_layout!(fig) fig @test_reference joinpath(fig_path, "voronoi_ex_2.png") fig #src # As you can see, the unbounded polygons, and any polygons that included points -# outside of the convex hull, have now been clipped to the convex hull. \ No newline at end of file +# outside of the convex hull, have now been clipped to the convex hull. diff --git a/docs/src/literate_tutorials/clipped_rectangle.jl b/docs/src/literate_tutorials/clipped_rectangle.jl index 0175e0fda..62399cd89 100644 --- a/docs/src/literate_tutorials/clipped_rectangle.jl +++ b/docs/src/literate_tutorials/clipped_rectangle.jl @@ -11,7 +11,7 @@ # Let us now demonstrate. First, we construct a tessellation of # some example point set. -using DelaunayTriangulation +using DelaunayTriangulation using CairoMakie using ReferenceTests #src using Test #src @@ -32,7 +32,7 @@ vorn = voronoi(tri) # the tessellation to. fig, ax, sc = voronoiplot(vorn) a, b, c, d = -2.0, 3.0, 0.0, 7.0 -lines!(ax, [(a,c),(b,c),(b,d),(a,d),(a,c)], color = :black, linewidth = 4) +lines!(ax, [(a, c), (b, c), (b, d), (a, d), (a, c)], color = :black, linewidth = 4) fig @test_reference joinpath(fig_path, "voronoi_ex_3.png") fig #src @@ -43,11 +43,11 @@ bounding_box = (a, b, c, d) # You can obtain some reasonable defaults for this bounding box using # [DelaunayTriangulation.polygon_bounds(vorn)](@ref polygon_bounds). # The coordinates for each polygon clipped to this box can be obtained as follows. -clipped_coords = Vector{Vector{NTuple{2,Float64}}}(undef, num_polygons(vorn)) +clipped_coords = Vector{Vector{NTuple{2, Float64}}}(undef, num_polygons(vorn)) for i in each_polygon_index(vorn) clipped_coords[i] = get_polygon_coordinates(vorn, i, bounding_box) end -clipped_coords +clipped_coords # Now let's plot these. fig, ax, sc = poly(clipped_coords, color = :white, strokewidth = 4) @@ -56,4 +56,4 @@ fig # As we can see, the polygons have been clipped to the rectangle. # Note that if you just want this for plotting, you can also call `voronoiplot` with the -# `bounding_box` keyword argument. \ No newline at end of file +# `bounding_box` keyword argument. diff --git a/docs/src/literate_tutorials/constrained_edges.jl b/docs/src/literate_tutorials/constrained_edges.jl index 02d565b2a..ba2efb72f 100644 --- a/docs/src/literate_tutorials/constrained_edges.jl +++ b/docs/src/literate_tutorials/constrained_edges.jl @@ -37,16 +37,20 @@ C = Set([(2, 1), (2, 11), (2, 7), (2, 5)]) tri = triangulate(pts) #- -cons_tri = triangulate(pts; segments=C) +cons_tri = triangulate(pts; segments = C) #- fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Constrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) triplot!(ax2, cons_tri, show_constrained_edges = true) resize_to_layout!(fig) diff --git a/docs/src/literate_tutorials/constrained_interior_within_interiors.jl b/docs/src/literate_tutorials/constrained_interior_within_interiors.jl index c010b6da4..c6b126470 100644 --- a/docs/src/literate_tutorials/constrained_interior_within_interiors.jl +++ b/docs/src/literate_tutorials/constrained_interior_within_interiors.jl @@ -23,16 +23,18 @@ curve_1 = [ [(0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0)], [(25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0)], [(25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0)], - [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)] + [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)], ] # outer-most boundary: counter-clockwise curve_2 = [ [(4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0)], [(20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0)], - [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)] + [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)], ] # inner boundary: clockwise curve_3 = [ - [(12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), - (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912)] + [ + (12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), + (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912), + ], ] # this is inside curve_2, so it's counter-clockwise curves = [curve_1, curve_2, curve_3] points = [ @@ -42,9 +44,9 @@ points = [ (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), - (12.0, 13.0), (19.0, 15.0) + (12.0, 13.0), (19.0, 15.0), ] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) # To now triangulate: diff --git a/docs/src/literate_tutorials/constrained_multiply_connected.jl b/docs/src/literate_tutorials/constrained_multiply_connected.jl index 5e81bce23..0a73d562f 100644 --- a/docs/src/literate_tutorials/constrained_multiply_connected.jl +++ b/docs/src/literate_tutorials/constrained_multiply_connected.jl @@ -6,7 +6,7 @@ # load the packages. using DelaunayTriangulation using CairoMakie -using StableRNGs +using StableRNGs using ReferenceTests #src using Test #src fig_path = joinpath(@__DIR__, "../figures") #src @@ -22,26 +22,30 @@ fig_path = joinpath(@__DIR__, "../figures") #src # of the interiors relative to the boundaries are consistent. Note again # that neighbouring segments must connect. curve_1 = [ - [ # first segment + [ + ## first segment (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), - (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0) + (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), ], - [ # second segment + [ + ## second segment (12.0, 28.0), (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), (-4.0, 0.0), (0.0, 0.0), - ] + ], ] # outer: counter-clockwise curve_2 = [ - [ # first segment + [ + ## first segment (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), - (10.0, 22.0), (10.0, 20.0) + (10.0, 22.0), (10.0, 20.0), ], - [ # second segment + [ + ## second segment (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ] + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], ] # inner: clockwise curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] # inner: clockwise curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] # inner: clockwise @@ -57,8 +61,9 @@ points = [ (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points); + (7.0, 7.8), (7.0, 7.4), +] +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points); # Notice that `curve_1` and `curve_2` are split up into multiple segments. For `curve_3` # and `curve_4`, note that we have to wrap the entire vector in a vector, essentially @@ -67,7 +72,7 @@ boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_poi # Now let us triangulate. rng = StableRNG(123) # the triangulation is not unique due to cocircular points tri = triangulate(points; boundary_nodes, rng) -fig, ax, sc = triplot(tri, show_constrained_edges=true, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_constrained_edges = true, show_convex_hull = true) fig @test_reference joinpath(fig_path, "constrained_ex_5.png") fig #src @@ -106,25 +111,25 @@ DelaunayTriangulation.get_all_boundary_nodes(tri) # for demonstration). For this, the order of the boundary edges is appropriate, so we must iterate # in a way that respects the ordering. function get_triangulation_area(tri) - A = 0.0 + A = 0.0 nc = DelaunayTriangulation.num_curves(tri) - for curve_index in 1:nc + for curve_index in 1:nc bn = get_boundary_nodes(tri, curve_index) ns = DelaunayTriangulation.num_sections(bn) - for segment_index in 1:ns + for segment_index in 1:ns bnn = get_boundary_nodes(bn, segment_index) ne = num_boundary_edges(bnn) for i in 1:ne vᵢ = get_boundary_nodes(bnn, i) - vᵢ₊₁ = get_boundary_nodes(bnn, i+1) + vᵢ₊₁ = get_boundary_nodes(bnn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end end end - return A/2 + return A / 2 end A = get_triangulation_area(tri) @test A ≈ get_area(tri) #src @@ -138,7 +143,7 @@ function get_perimeters(tri) total_perimeter = 0.0 nc = DelaunayTriangulation.num_curves(tri) curve_perimeters = zeros(nc) # curve_index => perimeter - segment_perimeters = Dict{NTuple{2,Int},Float64}() # (curve_index, segment_index) => perimeter + segment_perimeters = Dict{NTuple{2, Int}, Float64}() # (curve_index, segment_index) => perimeter for (e, ((curve_index, section_index), node_index)) in get_boundary_edge_map(tri) u, v = edge_vertices(e) p, q = get_point(tri, u, v) @@ -152,7 +157,7 @@ function get_perimeters(tri) end end return total_perimeter, curve_perimeters, segment_perimeters -end +end ℓ, cℓ, sℓ = get_perimeters(tri) @test ℓ ≈ sum(cℓ) #src -@test ℓ ≈ sum(sum.(values(sℓ))) #src \ No newline at end of file +@test ℓ ≈ sum(sum.(values(sℓ))) #src diff --git a/docs/src/literate_tutorials/constrained_multipolygon.jl b/docs/src/literate_tutorials/constrained_multipolygon.jl index 5d2470924..cd15e1899 100644 --- a/docs/src/literate_tutorials/constrained_multipolygon.jl +++ b/docs/src/literate_tutorials/constrained_multipolygon.jl @@ -13,7 +13,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -24,7 +24,7 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "constrained_ex_7.png") fig #src @@ -174,10 +174,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -185,7 +188,7 @@ dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] nodes, points = convert_boundary_points_to_indices(curves) -tri = triangulate(points; boundary_nodes=nodes) +tri = triangulate(points; boundary_nodes = nodes) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "constrained_ex_8.png") fig by=psnr_equality(12) #src \ No newline at end of file +@test_reference joinpath(fig_path, "constrained_ex_8.png") fig by = psnr_equality(12) #src diff --git a/docs/src/literate_tutorials/constrained_outer_boundary.jl b/docs/src/literate_tutorials/constrained_outer_boundary.jl index d16deacb7..6beedd33a 100644 --- a/docs/src/literate_tutorials/constrained_outer_boundary.jl +++ b/docs/src/literate_tutorials/constrained_outer_boundary.jl @@ -19,7 +19,7 @@ pts = [ (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), - (1.34, 6.77), (1.24, 4.15) + (1.34, 6.77), (1.24, 4.15), ] # To define a boundary, we need to provide a counter-clockwise sequence @@ -35,9 +35,9 @@ boundary_points = [ (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), - (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0) + (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0), ] -boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points=pts); +boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points = pts); # The keyword argument `existing_points` is so that the points in `boundary_points` get appended (in-place) to # `pts`, as we see: @@ -53,14 +53,18 @@ cons_tri = triangulate(pts; boundary_nodes) #- fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Constrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) -triplot!(ax2, cons_tri, show_constrained_edges=true, show_convex_hull=true) +triplot!(ax2, cons_tri, show_constrained_edges = true, show_convex_hull = true) resize_to_layout!(fig) fig @test_reference joinpath(fig_path, "constrained_ex_2.png") fig #src @@ -71,8 +75,8 @@ fig # no longer contains every point in `pts`, as by default all triangles away # from the boundary are deleted, so that we do actually have a boundary. If for # some reason you do not want this behaviour, use `delete_holes = false`: -full_tri = triangulate(pts; boundary_nodes, delete_holes=false) -fig, ax, sc = triplot(full_tri, show_constrained_edges=true, show_convex_hull=true) +full_tri = triangulate(pts; boundary_nodes, delete_holes = false) +fig, ax, sc = triplot(full_tri, show_constrained_edges = true, show_convex_hull = true) @test_reference joinpath(fig_path, "constrained_ex_3.png") fig #src # This default behaviour does mean you need to be careful if you use [`DelaunayTriangulation.each_point`](@ref) @@ -83,7 +87,7 @@ fig, ax, sc = triplot(full_tri, show_constrained_edges=true, show_convex_hull=tr # There are multiple methods available for working directly # with the boundary nodes. You can get the boundary nodes # using `get_boundary_nodes(tri)`: -get_boundary_nodes(cons_tri) +get_boundary_nodes(cons_tri) # Later tutorials also consider other methods for working with the boundary # where care needs to be taken with the boundary, or part of the boundary, @@ -98,15 +102,15 @@ function shoelace_area(tri) bn = get_boundary_nodes(tri) n = num_boundary_edges(bn) # length(bn) - 1 in this case since bn[1] = bn[end] A = 0.0 - for i in 1:n + for i in 1:n vᵢ = get_boundary_nodes(bn, i) - vᵢ₊₁ = get_boundary_nodes(bn, i+1) + vᵢ₊₁ = get_boundary_nodes(bn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end - return A/2 + return A / 2 end shoelace_area(cons_tri) @test shoelace_area(cons_tri) ≈ get_area(cons_tri) #src @@ -127,8 +131,8 @@ bn = get_boundary_nodes(cons_tri, I) # same as boundary_nodes for this problem; bn_j = get_boundary_nodes(bn, J) # This returns `23`, which is the start of the edge `e`. The full edge is given by -get_boundary_nodes.(Ref(bn), (J, J+1)) # Ref to not broadcast over bn -@test e == get_boundary_nodes.(Ref(bn), (J, J+1)) #src +get_boundary_nodes.(Ref(bn), (J, J + 1)) # Ref to not broadcast over bn +@test e == get_boundary_nodes.(Ref(bn), (J, J + 1)) #src # To give an example, here's how we compute the perimeter of the triangulation. This only # needs the edges, so we only consider the `keys` of the map. @@ -142,5 +146,5 @@ function get_perimeter(tri) end return ℓ end -get_perimeter(cons_tri) -@test get_perimeter(cons_tri) ≈ sum(norm(get_point(cons_tri, boundary_nodes[i+1]) .- get_point(cons_tri, boundary_nodes[i])) for i in 1:(length(boundary_nodes)-1)) #src +get_perimeter(cons_tri) +@test get_perimeter(cons_tri) ≈ sum(norm(get_point(cons_tri, boundary_nodes[i + 1]) .- get_point(cons_tri, boundary_nodes[i])) for i in 1:(length(boundary_nodes) - 1)) #src diff --git a/docs/src/literate_tutorials/constrained_outer_boundary_segmented.jl b/docs/src/literate_tutorials/constrained_outer_boundary_segmented.jl index 7811ea623..0ff92eec3 100644 --- a/docs/src/literate_tutorials/constrained_outer_boundary_segmented.jl +++ b/docs/src/literate_tutorials/constrained_outer_boundary_segmented.jl @@ -16,7 +16,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src # Now, we define some of the points we will be triangulating. points = [ (2.0, 8.0), (6.0, 4.0), (2.0, 6.0), - (2.0, 4.0), (8.0, 2.0) + (2.0, 4.0), (8.0, 2.0), ] # We now want to define our boundary. The method for providing a boundary to be @@ -33,14 +33,14 @@ boundary_points = [section_1, section_2, section_3] # [`convert_boundary_points_to_indices`](@ref), and then we triangulate. # We also add a constrained edge. E = Set(((6, 9),)) # (0, 0) → (4, 6) -boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points=points) -tri = triangulate(points; boundary_nodes, segments=E) +boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points = points) +tri = triangulate(points; boundary_nodes, segments = E) #- -fig, ax, sc = triplot(tri, show_constrained_edges=true, constrained_edge_linewidth=6) -lines!(ax, section_1, color=:red, linewidth=6) -lines!(ax, section_2, color=:green, linewidth=6) -lines!(ax, section_3, color=:blue, linewidth=6) +fig, ax, sc = triplot(tri, show_constrained_edges = true, constrained_edge_linewidth = 6) +lines!(ax, section_1, color = :red, linewidth = 6) +lines!(ax, section_2, color = :green, linewidth = 6) +lines!(ax, section_3, color = :blue, linewidth = 6) fig @test_reference joinpath(fig_path, "constrained_ex_4.png") fig #src @@ -128,7 +128,7 @@ get_adjacent2vertex(tri, -3) function compute_sum_2(tri) edges = get_adjacent2vertex(tri, -2) s = 0.0 - for e in edges + for e in edges u, v = edge_vertices(e) p, q = get_point(tri, u, v) px, py = getxy(p) @@ -151,4 +151,4 @@ get_neighbours(tri, -2) get_ghost_vertex_map(tri) # In this case, the `i`th section just has the ghost vertex `-i`, but this is typically used -# to deal with the case of multiple boundaries so that we know where a ghost vertex belongs. \ No newline at end of file +# to deal with the case of multiple boundaries so that we know where a ghost vertex belongs. diff --git a/docs/src/literate_tutorials/convex.jl b/docs/src/literate_tutorials/convex.jl index 6aa3ae489..721171275 100644 --- a/docs/src/literate_tutorials/convex.jl +++ b/docs/src/literate_tutorials/convex.jl @@ -14,14 +14,14 @@ fig_path = joinpath(@__DIR__, "../figures") #src points = [ (10.0, 12.0), (7.0, 11.0), (8.0, 6.0), (10.0, 3.0), (14.0, 5.0), (15.0, 10.0), - (13.0, 12.0) + (13.0, 12.0), ] S = 1:7 tri = triangulate_convex(points, 1:7) #- fig, ax, sc = triplot(tri) -fig +fig !USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "convex_ex_1.png") fig #src # This `tri` is our triangulation of the convex polygon. @@ -34,7 +34,7 @@ fig # Let us give a larger example. For simplicity, we triangulate a # a discretised circle. -θ = LinRange(0, 2π, 5000) |> collect +θ = LinRange(0, 2π, 5000) |> collect pop!(θ) x = cos.(θ) y = sin.(θ) @@ -44,16 +44,16 @@ tri = triangulate_convex(points, S) #- fig, ax, sc = triplot(tri) -fig +fig !USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "convex_ex_2.png") fig #src # Here is a comparison of the time it takes to triangulate this # using `triangulate_convex` or `triangulate`. -using BenchmarkTools -@benchmark triangulate_convex($points, $S) +using BenchmarkTools +@benchmark triangulate_convex($points, $S) #- -@benchmark triangulate($points) +@benchmark triangulate($points) # For the smaller example that we started with above, `triangulate_convex` is also -# faster, although not by much (≈15.10 μs versus ≈10.7 μs). \ No newline at end of file +# faster, although not by much (≈15.10 μs versus ≈10.7 μs). diff --git a/docs/src/literate_tutorials/convex_hull.jl b/docs/src/literate_tutorials/convex_hull.jl index 2e1a77f72..65be85435 100644 --- a/docs/src/literate_tutorials/convex_hull.jl +++ b/docs/src/literate_tutorials/convex_hull.jl @@ -35,7 +35,7 @@ get_convex_hull_vertices(tri) # from the points without constructing the triangulation, use [`convex_hull`](@ref): ch = convex_hull(points) ch_points = [get_point(tri, i) for i in DelaunayTriangulation.get_vertices(ch)] -fig, ax, sc = lines(ch_points, color=:red, linewidth=4) +fig, ax, sc = lines(ch_points, color = :red, linewidth = 4) scatter!(ax, points) fig @test_reference joinpath(fig_path, "convex_hull_ex_1.png") fig #src diff --git a/docs/src/literate_tutorials/curve_bounded.jl b/docs/src/literate_tutorials/curve_bounded.jl index c6833782f..09584ff48 100644 --- a/docs/src/literate_tutorials/curve_bounded.jl +++ b/docs/src/literate_tutorials/curve_bounded.jl @@ -37,7 +37,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src n = 50 r = 2.0 xc, yc = 1 / 2, 2.0 -θ = range(0, 2π, length=n + 1) |> collect; +θ = range(0, 2π, length = n + 1) |> collect; θ[end] = θ[begin]; x = xc .+ r * cos.(θ) y = yc .+ r * sin.(θ); @@ -61,9 +61,9 @@ fig, ax, sc = lines(points) # Let's now triangulate this domain. We need to put the arc into its own vector, and we still need to pass a set of # points into `triangulate`: -points = NTuple{2,Float64}[] +points = NTuple{2, Float64}[] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=[arc], rng) +tri = triangulate(points; boundary_nodes = [arc], rng) #- fig, ax, sc = triplot(tri) @@ -78,7 +78,7 @@ fig # # This is probably not what we actually want, though. Instead, we need to refine the domain using mesh refinement. # The syntax for this is the same as in the [refinement tutorial](../tutorials/refinement.md): -refine!(tri; max_area=1e-1, rng) +refine!(tri; max_area = 1.0e-1, rng) fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_2.png") fig #src @@ -113,53 +113,55 @@ fig # to the origin to be smaller than those outside of it. curve = [[arc], [bspl], pce] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; max_area=1e-2, rng, custom_constraint=(_tri, T) -> begin - i, j, k = triangle_vertices(T) - p, q, r = get_point(_tri, i, j, k) - c = (p .+ q .+ r) ./ 3 - return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1e-3 -end) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!( + tri; max_area = 1.0e-2, rng, custom_constraint = (_tri, T) -> begin + i, j, k = triangle_vertices(T) + p, q, r = get_point(_tri, i, j, k) + c = (p .+ q .+ r) ./ 3 + return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1.0e-3 + end, +) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_3.png") fig by=psnr_equality(8) #src +@test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_3.png") fig by = psnr_equality(8) #src # ## A Complicated Multiply-Connected Disjoint Domain # For our last example, we take a complicated case with a domain that is disjoint, and where the individual # domains are multiply-connected. Let us give the domain followed by an explanation of how it is defined: curve = [ [ - [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])] + [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] t = LinRange(0, 1, 1000) fig fig = Figure() ax = Axis(fig[1, 1]) -lines!(ax, [get_point(points, curve[1][1]...)...], color=:red, label="(1, 2, 3)") -lines!(ax, curve[1][2][1].(t), color=:red, linestyle=:dashdot, label="EllipticalArc") -lines!(ax, curve[2][1][1].(t), color=:green, label="BSpline") -lines!(ax, [get_point(points, curve[3][1]...)...], color=:blue, label="(4, 5, 6, 7, 4)") -lines!(ax, curve[4][1][1].(t), color=:purple, label="BezierCurve") -lines!(ax, curve[4][2][1].(t), color=:purple, linestyle=:dashdot, label="CatmullRomSpline") -lines!(ax, [get_point(points, curve[5][1]...)...], color=:orange, label="(12, 11, 10, 12)") -lines!(ax, curve[6][1][1].(t), color=:black, label="CircularArc") +lines!(ax, [get_point(points, curve[1][1]...)...], color = :red, label = "(1, 2, 3)") +lines!(ax, curve[1][2][1].(t), color = :red, linestyle = :dashdot, label = "EllipticalArc") +lines!(ax, curve[2][1][1].(t), color = :green, label = "BSpline") +lines!(ax, [get_point(points, curve[3][1]...)...], color = :blue, label = "(4, 5, 6, 7, 4)") +lines!(ax, curve[4][1][1].(t), color = :purple, label = "BezierCurve") +lines!(ax, curve[4][2][1].(t), color = :purple, linestyle = :dashdot, label = "CatmullRomSpline") +lines!(ax, [get_point(points, curve[5][1]...)...], color = :orange, label = "(12, 11, 10, 12)") +lines!(ax, curve[6][1][1].(t), color = :black, label = "CircularArc") fig[1, 2] = Legend(fig, ax, "Curve") fig @@ -182,8 +184,8 @@ fig # # Let's now triangulate. rng = StableRNG(123) -tri = triangulate(copy(points); boundary_nodes=curve, rng) # copying so that we don't mutate for the next section -refine!(tri; max_area=1e-2) +tri = triangulate(copy(points); boundary_nodes = curve, rng) # copying so that we don't mutate for the next section +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_4.png") fig #src @@ -205,18 +207,18 @@ poly_constraint = (_tri, T) -> begin return true end max_area = if idx == 1 # coarse - 1e-1 + 1.0e-1 elseif idx == 3 # medium - 1e-2 + 1.0e-2 else # dense - 1e-3 + 1.0e-3 end area = DelaunayTriangulation.triangle_area(p, q, r) return area > max_area end rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; custom_constraint=poly_constraint, rng) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!(tri; custom_constraint = poly_constraint, rng) fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_5.png") fig #src @@ -240,7 +242,7 @@ fig # # Let's now meet these requirements. struct Astroid <: DelaunayTriangulation.AbstractParametricCurve - lookup_table::Vector{NTuple{2,Float64}} + lookup_table::Vector{NTuple{2, Float64}} end function (c::Astroid)(t) if t == 0.0 || t == 1.0 @@ -268,7 +270,7 @@ end # Let's now define an astroid curve and triangulate it. function Astroid(n::Int) - lookup_table = Vector{NTuple{2,Float64}}(undef, n) + lookup_table = Vector{NTuple{2, Float64}}(undef, n) c = Astroid(lookup_table) for i in 1:n lookup_table[i] = c((i - 1) / (n - 1)) @@ -277,8 +279,8 @@ function Astroid(n::Int) end rng = StableRNG(123) curve = Astroid(1000) -tri = triangulate(NTuple{2,Float64}[]; boundary_nodes=[curve], rng) -refine!(tri; max_area=1e-2) +tri = triangulate(NTuple{2, Float64}[]; boundary_nodes = [curve], rng) +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) -fig -@test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_6.png") fig #src \ No newline at end of file +fig +@test_reference joinpath(fig_path, "triangulate_curve_bounded_ex_6.png") fig #src diff --git a/docs/src/literate_tutorials/custom_primitive.jl b/docs/src/literate_tutorials/custom_primitive.jl index 51aa0988b..d3b232f5f 100644 --- a/docs/src/literate_tutorials/custom_primitive.jl +++ b/docs/src/literate_tutorials/custom_primitive.jl @@ -48,7 +48,7 @@ struct CustomPolygon segments::Vector{CustomPolygonSegment} end struct CustomPolygons{N} - polygons::NTuple{N,CustomPolygon} + polygons::NTuple{N, CustomPolygon} end # Now, depending on your application you might not need to define all possible methods. For example, if you just want an unconstrained triangulation, all you need are `CustomPoint` @@ -102,8 +102,8 @@ DT.num_sections(poly::CustomPolygon) = length(poly.segments) DT.num_boundary_edges(seg::CustomPolygonSegment) = length(seg.segments) DT.get_boundary_nodes(poly::CustomPolygons, m::Integer) = poly.polygons[m] # go down to the mth polygon DT.get_boundary_nodes(poly::CustomPolygon, m::Integer) = poly.segments[m] # go down to the mth segment -DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m-1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node -DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2,Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) +DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m - 1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node +DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2, Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) # We now have all that we need for defining our custom primitives for constrained triangulations. We can go further and define methods # for working with Voronoi tessellations and centroidal Voronoi tessellations. For these methods, note that these only apply to unconstrained @@ -125,9 +125,9 @@ DT.contains_edge(e::CustomSegment, Es::CustomSegments) = e ∈ Es.segments Base.empty!(triangles::CustomTriangles) = empty!(triangles.triangles) function Base.insert!(seg::CustomPolygonSegment, index, node) - cur_segment = seg.segments[index-1] + cur_segment = seg.segments[index - 1] u, v = edge_vertices(cur_segment) - seg.segments[index-1] = CustomSegment(u, node) + seg.segments[index - 1] = CustomSegment(u, node) insert!(seg.segments, index, CustomSegment(node, v)) return seg end @@ -144,26 +144,31 @@ p8 = CustomPoint(0.75, 0.75) p9 = CustomPoint(0.25, 0.75) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) segments = CustomSegments(Set{CustomSegment}((CustomSegment(2, 7), CustomSegment(8, 3)))) -outer_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), - CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), -]) -inner_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), -]) +outer_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), + CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), + ], +) +inner_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), + ], +) polygons = CustomPolygons((outer_polygon, inner_polygon)); # Now we triangulate and refine. rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=polygons, segments, - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng +tri = triangulate( + points; boundary_nodes = polygons, segments, + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, ) -refine!(tri; max_area=1e-3, rng) +refine!(tri; max_area = 1.0e-3, rng) fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "custom_structs_ex_1.png") fig by = psnr_equality(5.0) #src @@ -172,14 +177,16 @@ fig # this all works. rng = StableRNG(123) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) -tri = triangulate(points; - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng) -vorn = voronoi(tri; clip=true, smooth=true, rng) +tri = triangulate( + points; + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, +) +vorn = voronoi(tri; clip = true, smooth = true, rng) fig, ax, sc = voronoiplot(vorn) fig -@test_reference joinpath(fig_path, "custom_structs_ex_2.png") fig by = psnr_equality(5.0) #src \ No newline at end of file +@test_reference joinpath(fig_path, "custom_structs_ex_2.png") fig by = psnr_equality(5.0) #src diff --git a/docs/src/literate_tutorials/lattice.jl b/docs/src/literate_tutorials/lattice.jl index 352b769b6..66bea1069 100644 --- a/docs/src/literate_tutorials/lattice.jl +++ b/docs/src/literate_tutorials/lattice.jl @@ -23,7 +23,7 @@ fig # lattice manually and `triangulate` those. Here's a comparison of the times. using BenchmarkTools points = get_points(tri) -@benchmark triangulate($points; randomise=$false) # randomise=false because points are already in lattice order, i.e. spatially sorted +@benchmark triangulate($points; randomise = $false) # randomise=false because points are already in lattice order, i.e. spatially sorted #- @benchmark triangulate_rectangle($a, $b, $c, $d, $nx, $ny) @@ -44,11 +44,11 @@ tri @test DelaunayTriangulation.has_ghost_triangles(tri) #src # You can opt into not having these by using `delete_ghosts=true`: -tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary=true, delete_ghosts=true) +tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary = true, delete_ghosts = true) tri #- get_boundary_nodes(tri) #- -DelaunayTriangulation.has_ghost_triangles(tri) \ No newline at end of file +DelaunayTriangulation.has_ghost_triangles(tri) diff --git a/docs/src/literate_tutorials/nearest.jl b/docs/src/literate_tutorials/nearest.jl index d1201e724..7e636ce26 100644 --- a/docs/src/literate_tutorials/nearest.jl +++ b/docs/src/literate_tutorials/nearest.jl @@ -18,13 +18,13 @@ using Test #src points = [ (-3.0, 7.0), (2.0, 6.0), (0.0, 3.0), (0.0, 0.0), (-5.0, 5.0), (-3.0, 1.0), - (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0) + (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0), ] tri = triangulate(points) vorn = voronoi(tri) p, q = (-2.0, 7.5), (0.0, 4.0) -fig, ax, sc = voronoiplot(vorn, markersize=14) -scatter!(ax,[p,q],color=:white,strokecolor=:black,strokewidth=2,markersize=14) +fig, ax, sc = voronoiplot(vorn, markersize = 14) +scatter!(ax, [p, q], color = :white, strokecolor = :black, strokewidth = 2, markersize = 14) fig # To get the nearest neighbour of a point, we use [`get_nearest_neighbour`](@ref). @@ -45,4 +45,4 @@ np_tri = get_nearest_neighbour(tri, p) nq_tri = get_nearest_neighbour(tri, q) @test nq_tri == 3 #src -# Both methods lead to the same results because they use the same algorithm. \ No newline at end of file +# Both methods lead to the same results because they use the same algorithm. diff --git a/docs/src/literate_tutorials/operations_convex_hull_locking.jl b/docs/src/literate_tutorials/operations_convex_hull_locking.jl index 4ba479d8d..82edc205c 100644 --- a/docs/src/literate_tutorials/operations_convex_hull_locking.jl +++ b/docs/src/literate_tutorials/operations_convex_hull_locking.jl @@ -44,4 +44,4 @@ get_boundary_nodes(tri) # Note that this locking/unlocking doesn't actually change anything about the triangulation, # it just adds information into `tri` to treat it as if you had provided -# the convex hull as a constrained boundary to start with. \ No newline at end of file +# the convex hull as a constrained boundary to start with. diff --git a/docs/src/literate_tutorials/operations_flip_edge.jl b/docs/src/literate_tutorials/operations_flip_edge.jl index 39e77aa17..98c70e379 100644 --- a/docs/src/literate_tutorials/operations_flip_edge.jl +++ b/docs/src/literate_tutorials/operations_flip_edge.jl @@ -13,15 +13,15 @@ T4 = points[[2, 3, 4]] #hide fig = Figure() #hide ax1 = Axis(fig[1, 1], width = 600, height = 400) #hide ax2 = Axis(fig[1, 2], width = 600, height = 400) #hide -poly!(ax1, [T1; T2], color=(:white, 0.0), strokewidth=3) #hide -poly!(ax2, [T3; T4], color=(:white, 0.0), strokewidth=3) #hide +poly!(ax1, [T1; T2], color = (:white, 0.0), strokewidth = 3) #hide +poly!(ax2, [T3; T4], color = (:white, 0.0), strokewidth = 3) #hide for ax in (ax1, ax2) #hide hidedecorations!(ax) #hide hidespines!(ax) #hide - text!(ax, [(0.05, -1.1)]; text=[L"p_j"], fontsize=43) #hide - text!(ax, [(0.9, 0.1)]; text=[L"p_k"], fontsize=43) #hide - text!(ax, [(0.05, 1.0)]; text=[L"p_i"], fontsize=43) #hide - text!(ax, [(-1.05, 0.05)]; text=[L"p_\ell"], fontsize=43) #hide + text!(ax, [(0.05, -1.1)]; text = [L"p_j"], fontsize = 43) #hide + text!(ax, [(0.9, 0.1)]; text = [L"p_k"], fontsize = 43) #hide + text!(ax, [(0.05, 1.0)]; text = [L"p_i"], fontsize = 43) #hide + text!(ax, [(-1.05, 0.05)]; text = [L"p_\ell"], fontsize = 43) #hide xlims!(ax, -1.1, 1.1) #hide ylims!(ax, -1.3, 1.3) #hide end #hide @@ -43,7 +43,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src # Let us now define our initial triangulation. points = [(0.0, 0.0), (0.8, 0.0), (1.3, 1.0), (0.0, 1.0)] -tri = triangulate(points); +tri = triangulate(points); # Now, flipping the edge is simple. We simply provide the indices `i` and `j` # for the edge we want to flip. Let us flip the edge `(2, 4)`. @@ -57,4 +57,4 @@ fig # As simple as that. Note that no checks are made for whether the edge is actually in the # triangulation, on the boundary, or if the associated quadrilateral is convex. It is # up to you to check this if needed; one way to check would be to use [`DelaunayTriangulation.is_legal`](@ref), -# as is done inside [`legalise_edge!`](@ref) -- see the [next tutorial](operations_legalise_edge.md). \ No newline at end of file +# as is done inside [`legalise_edge!`](@ref) -- see the [next tutorial](operations_legalise_edge.md). diff --git a/docs/src/literate_tutorials/operations_legalise_edge.jl b/docs/src/literate_tutorials/operations_legalise_edge.jl index ded10c965..417daeec5 100644 --- a/docs/src/literate_tutorials/operations_legalise_edge.jl +++ b/docs/src/literate_tutorials/operations_legalise_edge.jl @@ -32,12 +32,12 @@ points = [ (-1.0, 2.0), (4.0, 6.0), (4.0, 3.0), (-3.0, 7.0), (-6.0, -1.0), (9.0, 5.0), (5.0, -5.0), (-6.0, 7.0), (0.0, 0.0), (-3.0, 4.0), (-5.0, 5.0), (-3.0, -4.0), - (5.0, -1.0), (2.0, -2.0) + (5.0, -1.0), (2.0, -2.0), ] p = (3.0, 2.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig @test_reference joinpath(fig_path, "triangulation_operations_13.png") fig #src @@ -56,7 +56,7 @@ fig # This splitting introduces some new illegal edges, shown in red below. function get_all_illegal_edges(tri) #hide - T = NTuple{2,Float64}[] #hide + T = NTuple{2, Float64}[] #hide for E in each_edge(tri) #hide cert = DelaunayTriangulation.is_legal(tri, E...) #hide if DelaunayTriangulation.is_illegal(cert) #hide @@ -67,7 +67,7 @@ function get_all_illegal_edges(tri) #hide end #hide fig, ax, sc = triplot(tri) #hide T = get_all_illegal_edges(tri) #hide -linesegments!(ax, T, color=:red, linewidth=3) #hide +linesegments!(ax, T, color = :red, linewidth = 3) #hide fig #hide @test_reference joinpath(fig_path, "triangulation_operations_15.png") fig #src @@ -82,4 +82,4 @@ fig, ax, sc = triplot(tri) fig @test_reference joinpath(fig_path, "triangulation_operations_16.png") fig #src -# The triangulation is now Delaunay, and there are no more illegal edges. \ No newline at end of file +# The triangulation is now Delaunay, and there are no more illegal edges. diff --git a/docs/src/literate_tutorials/operations_segment_insertion.jl b/docs/src/literate_tutorials/operations_segment_insertion.jl index 37fdb2489..972f17b6e 100644 --- a/docs/src/literate_tutorials/operations_segment_insertion.jl +++ b/docs/src/literate_tutorials/operations_segment_insertion.jl @@ -9,8 +9,10 @@ using Test #src fig_path = joinpath(@__DIR__, "../figures") #src # Let us now define our initial triangulation. -points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), -(0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8)] +points = [ + (0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), + (0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8), +] tri = triangulate(points) fig, ax, sc = triplot(tri) fig @@ -23,7 +25,7 @@ add_segment!(tri, 1, 3) fig, ax, sc = triplot(tri, show_constrained_edges = true) fig @test_reference joinpath(fig_path, "triangulation_operations_9.png") fig #src - + # Of course, this changed nothing since the segment was already there. We do note, # though, that if we look at the constrained edges get_interior_segments(tri) @@ -44,7 +46,7 @@ fig # if we do this: add_segment!(tri, 8, 2) fig, ax, sc = triplot(tri) -fig +fig @test_reference joinpath(fig_path, "triangulation_operations_11.png") fig #src -# The other constrained edge was partially removed. \ No newline at end of file +# The other constrained edge was partially removed. diff --git a/docs/src/literate_tutorials/operations_split_edge.jl b/docs/src/literate_tutorials/operations_split_edge.jl index 9f21a239f..e33deb977 100644 --- a/docs/src/literate_tutorials/operations_split_edge.jl +++ b/docs/src/literate_tutorials/operations_split_edge.jl @@ -11,13 +11,15 @@ using ReferenceTests #src using Test #src fig_path = joinpath(@__DIR__, "../figures") #src -points = [(0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), +points = [ + (0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), (-2.0, 7.0), (3.0, 6.0), (2.0, -2.0), (-4.0, 1.0), - (1.0, 5.0)] + (1.0, 5.0), +] p = (0.0, 3.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig @test_reference joinpath(fig_path, "triangulation_operations_17.png") fig #src @@ -28,7 +30,7 @@ r = length(points) i, j = 1, 2 split_edge!(tri, i, j, r) fig, ax, sc = triplot(tri) -fig +fig @test_reference joinpath(fig_path, "triangulation_operations_18.png") fig #src # Notice that this has only split the edge in one direction. This is because the @@ -36,7 +38,7 @@ fig # direction, we simply swap the indices. split_edge!(tri, j, i, r) fig, ax, sc = triplot(tri) -fig +fig @test_reference joinpath(fig_path, "triangulation_operations_19.png") fig #src # If you also want to restore the Delaunay property of the triangulation @@ -50,4 +52,4 @@ legalise_edge!(tri, i, k, r) legalise_edge!(tri, k, j, r) # These steps, in particular the steps of splitting both sides of the edge and then -# legalising, are also implemented in [`DelaunayTriangulation.complete_split_edge_and_legalise!`](@ref). \ No newline at end of file +# legalising, are also implemented in [`DelaunayTriangulation.complete_split_edge_and_legalise!`](@ref). diff --git a/docs/src/literate_tutorials/operations_split_triangle.jl b/docs/src/literate_tutorials/operations_split_triangle.jl index d6ff9b15d..f7c443988 100644 --- a/docs/src/literate_tutorials/operations_split_triangle.jl +++ b/docs/src/literate_tutorials/operations_split_triangle.jl @@ -17,7 +17,7 @@ points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)] p = (0.2, 0.5) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig @test_reference joinpath(fig_path, "triangulation_operations_20.png") fig #src @@ -36,4 +36,4 @@ fig # See the [`legalise_edge!` tutorial](operations_legalise_edge.md) for more discussion # about restoring the Delaunay property of the triangulation after using -# `split_triangle!`. \ No newline at end of file +# `split_triangle!`. diff --git a/docs/src/literate_tutorials/operations_vertex_insertion_deletion.jl b/docs/src/literate_tutorials/operations_vertex_insertion_deletion.jl index c5c34a5ad..c18873459 100644 --- a/docs/src/literate_tutorials/operations_vertex_insertion_deletion.jl +++ b/docs/src/literate_tutorials/operations_vertex_insertion_deletion.jl @@ -35,7 +35,7 @@ fig # small number of points. We can also add points that are outside of the triangulation: add_point!(tri, 0.0, 1.0) fig, ax, sc = triplot(tri) -fig +fig @test_reference joinpath(fig_path, "triangulation_operations_3.png") fig #src # One important thing to note here is that, if not for the ghost triangles inside `tri`, @@ -67,7 +67,7 @@ get_convex_hull_vertices(tri) # If we do want to fix the convex hull, we can use [`convex_hull!(tri)`](@ref). convex_hull!(tri) -fig, ax, sc = triplot(tri, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_convex_hull = true) fig @test_reference joinpath(fig_path, "triangulation_operations_4.png") fig #src @@ -101,4 +101,4 @@ fig # Note that in this situation, `points` still contains those points that we have now deleted. # This is the reason to be careful about using, say, [`DelaunayTriangulation.each_point`](@ref) rather than [`each_solid_vertex`](@ref). -# This triangulation is also still Delaunay. \ No newline at end of file +# This triangulation is also still Delaunay. diff --git a/docs/src/literate_tutorials/point_in_polygon.jl b/docs/src/literate_tutorials/point_in_polygon.jl index 19e0cf98c..0eb2a5d15 100644 --- a/docs/src/literate_tutorials/point_in_polygon.jl +++ b/docs/src/literate_tutorials/point_in_polygon.jl @@ -154,10 +154,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -172,7 +175,7 @@ fig = Figure() ax = Axis(fig[1, 1]) scatter!(ax, query_points) for nodes in nodes - lines!(ax, points[reduce(vcat, nodes)], color=:magenta, linewidth=3) + lines!(ax, points[reduce(vcat, nodes)], color = :magenta, linewidth = 3) end fig @@ -187,23 +190,23 @@ fig # here do not use exact arithmetic, unlike other predicates in this package, so there may be some robustness issues # for points very close to the boundary. Here is the first approach: is_inside = [DelaunayTriangulation.distance_to_polygon(q, points, nodes) > 0 for q in query_points] -scatter!(ax, query_points[is_inside], color=:blue) -scatter!(ax, query_points[.!is_inside], color=:red) +scatter!(ax, query_points[is_inside], color = :blue) +scatter!(ax, query_points[.!is_inside], color = :red) fig @test_reference joinpath(fig_path, "point_in_polygon_ex_1.png") fig #src # Here is the second method. -tri = triangulate(points; boundary_nodes=nodes) +tri = triangulate(points; boundary_nodes = nodes) is_inside_2 = [DelaunayTriangulation.dist(tri, q) > 0 for q in query_points]; @test is_inside == is_inside_2 #src # The third method is to use [`find_polygon`](@ref) to find the polygon containing the point. If no such polygon exists, `find_polygon` returns # `0`, so this is what we use to determine if a point is inside or outside the polygon. is_inside_3 = [find_polygon(tri, q) ≠ 0 for q in query_points]; -@test mean(is_inside) ≈ mean(is_inside_3) atol = 1e-2 #src +@test mean(is_inside) ≈ mean(is_inside_3) atol = 1.0e-2 #src # This test is not exactly the same as the previous one (with a difference of about five points) due to points near the boundary. # The fourth method is: hierarchy = DelaunayTriangulation.construct_polygon_hierarchy(points, nodes) is_inside_4 = [find_polygon(hierarchy, points, nodes, q) ≠ 0 for q in query_points]; -@test is_inside_4 == is_inside_3 #src \ No newline at end of file +@test is_inside_4 == is_inside_3 #src diff --git a/docs/src/literate_tutorials/point_location.jl b/docs/src/literate_tutorials/point_location.jl index 380dcde8b..2e3b649c7 100644 --- a/docs/src/literate_tutorials/point_location.jl +++ b/docs/src/literate_tutorials/point_location.jl @@ -26,7 +26,7 @@ using Preferences #src points = [ (-3.0, 6.0), (5.0, 1.0), (-5.0, 3.0), (2.0, -3.0), (5.0, 8.0), (0.0, 0.0), (2.0, 5.0), (-3.0, 1.0), - (-2.0, -1.0), (-1.0, 4.0) + (-2.0, -1.0), (-1.0, 4.0), ] tri = triangulate(points) q = (3.0, 3.0) @@ -46,14 +46,14 @@ DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) # sample some number of points (defaults to $\lceil \sqrt[3]{n}\rceil$, where $n$ is the number of points), # and then start at the point that is closest to `q` out of those sampled, then marching along the triangulation # until `q` is found. This number of samples can be changed using the `m` keyword argument. For example, -V = find_triangle(tri, q, m=10) +V = find_triangle(tri, q, m = 10) @test DelaunayTriangulation.is_inside(DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q)) #src # means that we get a sample of size 10, and start at whichever point is the closest. # (For technical reasons, this sampling is with replacement, so it is possible that the same point is sampled more than once.) # You could also instead specify the point to start at using the `k` keyword argument, in which case no points are sampled. # For example, -V = find_triangle(tri, q, k=6) +V = find_triangle(tri, q, k = 6) @test DelaunayTriangulation.is_inside(DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q)) #src # starts the algorithm at the point `6`. @@ -76,7 +76,7 @@ V = find_triangle(tri, q) # this can be interpreted as meaning that `q` is between the two lines through the points `1` and `5` that # start at a central point of the triangulation. (The index `-1` is just the ghost vertex.) This can # be visualised. -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) scatter!(ax, q) fig !USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "point_location_ex_1.png") fig #src @@ -99,11 +99,11 @@ inner = [[r, z, v, u, w, t, s, r]] boundary_nodes, points = convert_boundary_points_to_indices([outer, inner]) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.01get_area(tri), rng); +refine!(tri; max_area = 0.01get_area(tri), rng); # The issue with concavity is that the ghost triangles can no longer be sensibly defined. # To demonstrate this, see the following plot: -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) fig !USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "point_location_ex_2.png") fig #src @@ -113,10 +113,10 @@ qs = [ (4.0, 5.0), (1.0, 5.6), (0.2, 5.0), (0.0, -1.0), (0.5, 3.5), (2.5, 1.5), (1.0, 2.0), (4.5, 1.0), (6.0, 1.5), - (0.5, 8.5), (1.0, 7.5), (1.2, 1.6) + (0.5, 8.5), (1.0, 7.5), (1.2, 1.6), ] -fig, ax, sc = triplot(tri, show_ghost_edges=false) -scatter!(ax, qs, color=:blue, markersize=16) +fig, ax, sc = triplot(tri, show_ghost_edges = false) +scatter!(ax, qs, color = :blue, markersize = 16) fig !USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "point_location_ex_3.png") fig #src @@ -132,7 +132,7 @@ Vs[end] # will enable a check to be made that the point is actually outside the triangulation whenever # a ghost triangle is to be returned. If the check finds this to not be the case, it # restarts. With these results, we now compute: -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] # Here is how we can actually test that these results are now correct. We cannot directly # use [`DelaunayTriangulation.point_position_relative_to_triangle`](@ref) because it does not @@ -168,24 +168,24 @@ v₁, w₁ = (5.0, 3.0), (4.0, 3.0) new_domain₁ = [[m₁, q₁, o₁, p₁, r₁, s₁, n₁, m₁]] new_domain₂ = [[t₁, w₁, v₁, u₁, t₁]] boundary_nodes, points = convert_boundary_points_to_indices( - [outer, inner, new_domain₁, new_domain₂] + [outer, inner, new_domain₁, new_domain₂], ) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.001get_area(tri), rng) +refine!(tri; max_area = 0.001get_area(tri), rng) qs = [ (0.6, 6.4), (1.4, 0.8), (3.1, 2.9), (6.3, 4.9), (4.6, 3.5), (7.0, 7.0), (8.9, 5.1), (5.8, 0.8), (1.0, 1.5), - (1.5, 2.0), (8.15, 6.0) + (1.5, 2.0), (8.15, 6.0), ] fig, ax, sc = triplot(tri) -scatter!(ax, qs, color=:blue, markersize=16) +scatter!(ax, qs, color = :blue, markersize = 16) fig -!USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "point_location_ex_4.png") fig by=psnr_equality(10) #src +!USE_INEXACTPREDICATES && @test_reference joinpath(fig_path, "point_location_ex_4.png") fig by = psnr_equality(10) #src # Here are the `find_triangle` results. -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] # Again, we can verify that these are all correct as follows. Without `concavity_protection=true`, # these would not be all correct. @@ -202,4 +202,4 @@ for (j, (q, δ, V)) in (enumerate ∘ zip)(qs, δs, Vs) end end results -@test all(results) #src \ No newline at end of file +@test all(results) #src diff --git a/docs/src/literate_tutorials/pole_of_inaccessibility.jl b/docs/src/literate_tutorials/pole_of_inaccessibility.jl index 6390df3d0..7094860cd 100644 --- a/docs/src/literate_tutorials/pole_of_inaccessibility.jl +++ b/docs/src/literate_tutorials/pole_of_inaccessibility.jl @@ -46,24 +46,26 @@ points = [ 2.12497 9.42582 7.27436 2.7979 3.0 4.0 - 5.33697 1.88019]' -outer_boundary = [ # split into segments for demonstration purposes + 5.33697 1.88019 +]' +outer_boundary = [ + ## split into segments for demonstration purposes [1, 4, 3, 2], [2, 9, 10, 11, 8, 7, 12], [12, 6, 13, 5, 14, 15, 16, 17, 16], - [16, 17, 18, 19, 20, 21, 22, 23, 1] + [16, 17, 18, 19, 20, 21, 22, 23, 1], ] inner_1 = [ - [26, 25, 24], [24, 28, 27, 26] + [26, 25, 24], [24, 28, 27, 26], ] inner_2 = [ - [29, 30, 31, 29] + [29, 30, 31, 29], ] boundary_nodes = [outer_boundary, inner_1, inner_2] fig = Figure() ax = Axis(fig[1, 1]) for i in eachindex(boundary_nodes) - lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color=:red) + lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color = :red) end fig @@ -73,7 +75,7 @@ pole = DelaunayTriangulation.pole_of_inaccessibility(points, boundary_nodes) @test pole[2] ≈ 5.372597499999995 #src #- -scatter!(ax, pole, color=:blue, markersize=16) +scatter!(ax, pole, color = :blue, markersize = 16) fig @test_reference joinpath(fig_path, "pole_of_inaccessibility_ex_1.png") fig #src @@ -85,7 +87,7 @@ fig # we get the triangulation. θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -96,19 +98,19 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) # To see the poles, called representative points, we use DelaunayTriangulation.get_representative_point_list(tri) # The keys of the `Dict` refer to the curve index, and the values contain # the coordinates. -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) colors = (:red, :blue, :darkgreen, :purple) for i in eachindex(boundary_nodes) - lines!(ax, points[reduce(vcat, boundary_nodes[i])], color=colors[i], linewidth=6) + lines!(ax, points[reduce(vcat, boundary_nodes[i])], color = colors[i], linewidth = 6) coords = DelaunayTriangulation.get_representative_point_coordinates(tri, i) - scatter!(ax, coords, color=colors[i], markersize=16) + scatter!(ax, coords, color = colors[i], markersize = 16) end fig @test_reference joinpath(fig_path, "pole_of_inaccessibility_ex_2.png") fig #src @@ -116,4 +118,4 @@ fig # Note that the green and purple boundaries have the same pole of inaccessibility. The # first curve, the red curve, is the only one that has the pole of inaccessibility computed # with respect to all other boundaries. You can also see that indeed the ghost edges are all -# oriented relative to the representative points. \ No newline at end of file +# oriented relative to the representative points. diff --git a/docs/src/literate_tutorials/refinement.jl b/docs/src/literate_tutorials/refinement.jl index 235e80aa1..22a50972e 100644 --- a/docs/src/literate_tutorials/refinement.jl +++ b/docs/src/literate_tutorials/refinement.jl @@ -34,7 +34,7 @@ points = tuple.(x, y) tri = triangulate(points; rng) orig_tri = deepcopy(tri) A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.01A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.01A, rng) # The [`refine!`](@ref) function operates on `tri` in-place. If we wanted to review the # statistics of the refined mesh, we can use [`statistics`](@ref): @@ -45,20 +45,20 @@ statistics(tri) # which is about 0.0067. Moreover, the smallest angle is indeed greater than 30. # Let us compare the triangulation pre- and post-refinement. -fig, ax, sc = triplot(orig_tri, axis=(title="Pre-refinement",)) -ax = Axis(fig[1, 2], title="Post-refinement") +fig, ax, sc = triplot(orig_tri, axis = (title = "Pre-refinement",)) +ax = Axis(fig[1, 2], title = "Post-refinement") triplot!(ax, tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_1.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_1.png") fig by = psnr_equality(10) #src # The triangulation is now much finer. There are still some parts with # many more triangles than other regions, but these are mostly near a boundary # or where was a cluster of random points. If we wanted, we could refine again # to try and improve this. -refine!(tri; min_angle=30.0, max_area=0.001A, rng) # 0.1% instead of 1% +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) # 0.1% instead of 1% fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_2.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_2.png") fig by = psnr_equality(10) #src # The quality has now been improved. We could also try improving the minimum # angle further, but even 30 is a bit closer to the limit of convergence (which is @@ -66,7 +66,7 @@ fig # the algorithm just doesn't even converge, instead it reaches the maximum # number of points. test_tri = deepcopy(tri) -refine!(test_tri; min_angle=35.0, max_area=0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going +refine!(test_tri; min_angle = 35.0, max_area = 0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going statistics(test_tri) # As we can see, the smallest angle is about 29 degrees instead of @@ -74,7 +74,7 @@ statistics(test_tri) # resulting triangulation is given below: fig, ax, sc = triplot(test_tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_3.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_3.png") fig by = psnr_equality(10) #src # This is certainly not a suitable triangulation. @@ -82,17 +82,17 @@ fig # that look at the areas and angles. Looking to `tri`, we can plot # these as follows: stats = statistics(tri) -fig = Figure(fontsize=33) +fig = Figure(fontsize = 33) areas = get_all_stat(stats, :area) ./ A angles = first.(get_all_stat(stats, :angles)) # the first is the smallest -ax = Axis(fig[1, 1], xlabel="A/A(Ω)", ylabel="Count", title="Area histogram", width=400, height=400, titlealign=:left) -hist!(ax, areas, bins=0:0.0001:0.0005) -ax = Axis(fig[1, 2], xlabel="θₘᵢₙ", ylabel="Count", title="Angle histogram", width=400, height=400, titlealign=:left) -hist!(ax, rad2deg.(angles), bins=20:2:60) -vlines!(ax, [30.0], color=:red) +ax = Axis(fig[1, 1], xlabel = "A/A(Ω)", ylabel = "Count", title = "Area histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, areas, bins = 0:0.0001:0.0005) +ax = Axis(fig[1, 2], xlabel = "θₘᵢₙ", ylabel = "Count", title = "Angle histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, rad2deg.(angles), bins = 20:2:60) +vlines!(ax, [30.0], color = :red) resize_to_layout!(fig) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_4.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_4.png") fig by = psnr_equality(10) #src # We see that indeed many of the triangle areas are very small, and the angles # are all greater than 30 degrees. @@ -119,14 +119,14 @@ rng = StableRNG(456) tri = triangulate(points; boundary_nodes, rng) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_5.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_5.png") fig by = psnr_equality(10) #src # Let us now refine this triangulation. A = get_area(tri) -refine!(tri; min_angle=27.3, max_area=0.01A, rng) +refine!(tri; min_angle = 27.3, max_area = 0.01A, rng) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_6.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_6.png") fig by = psnr_equality(10) #src # We inspect the plot, and we might think that it's perhaps not fine enough. # Let's use finer constraints and see what happens. Since @@ -134,10 +134,10 @@ fig # with the constraints below is going to take roughly # the same amount of time as if we had refined it with these # constraints in the first place. -refine!(tri; min_angle=33.9, max_area=0.001A, rng) +refine!(tri; min_angle = 33.9, max_area = 0.001A, rng) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_7.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_7.png") fig by = psnr_equality(10) #src # This is indeed much better, but notice that the inner hole # is much more fine than the outer. This is because we are applying the same @@ -173,10 +173,10 @@ end boundary_nodes, points = convert_boundary_points_to_indices(x, y) rng = StableRNG(456) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=30.0, custom_constraint=area_constraint, rng) +refine!(tri; min_angle = 30.0, custom_constraint = area_constraint, rng) fig, ax, sc = triplot(tri) -fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_8.png") fig by=psnr_equality(12) #src +fig +@test_reference joinpath(fig_path, "mesh_refinement_ex_8.png") fig by = psnr_equality(12) #src # This is now much better, and the two parts of the domain are # appropriately refined. Let us extend our custom constraint function to also @@ -196,8 +196,8 @@ rng = StableRNG(456) tri = triangulate(points; boundary_nodes, rng) refine!(tri; custom_constraint, rng) fig, ax, sc = triplot(tri) -fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_9.png") fig by=psnr_equality(10.0) #src +fig +@test_reference joinpath(fig_path, "mesh_refinement_ex_9.png") fig by = psnr_equality(10.0) #src # Indeed, the inner domain is much finer. These examples could be extended # to more complicated cases, for example using adaptive mesh refinement for a numerical @@ -215,7 +215,7 @@ using Downloads using DelimitedFiles boundary_url = "https://gist.githubusercontent.com/DanielVandH/13687b0918e45a416a5c93cd52c91449/raw/a8da6cdc94859fd66bcff85a2307f0f9cd57a18c/boundary.txt" boundary_dir = Downloads.download(boundary_url) -boundary = readdlm(boundary_dir, skipstart=6) +boundary = readdlm(boundary_dir, skipstart = 6) boundary_points = [(boundary[i, 1], boundary[i, 2]) for i in axes(boundary, 1)] reverse!(boundary_points) @@ -225,16 +225,16 @@ rng = StableRNG(789) tri = triangulate(points; boundary_nodes, rng) fig, ax, sc = triplot(tri) fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_10.png") fig by=psnr_equality(10) #src +@test_reference joinpath(fig_path, "mesh_refinement_ex_10.png") fig by = psnr_equality(10) #src # Now let's refine. A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.001A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) #- fig, ax, sc = triplot(tri) -fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_11.png") fig by=psnr_equality(10) #src +fig +@test_reference joinpath(fig_path, "mesh_refinement_ex_11.png") fig by = psnr_equality(10) #src # We see that the triangulation is now adequately refined. There are # still triangles near the boundaries whose minimum angle is less @@ -245,15 +245,15 @@ stats = statistics(tri) angles = first.(get_all_stat(stats, :angles)) # the first is the smallest fig, ax, sc = scatter(rad2deg.(angles)) hlines!(ax, [30.0], color = :red, linewidth = 4) -fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_12.png") fig by=psnr_equality(10) #src +fig +@test_reference joinpath(fig_path, "mesh_refinement_ex_12.png") fig by = psnr_equality(10) #src # As we can see, the vast majority of the triangles satisfy the constraint, # but there are still some that do not. Here is another set of results with a lower minimum angle constraint. boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) rng = StableRNG(789) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=18.73, max_area=0.001A, rng) +refine!(tri; min_angle = 18.73, max_area = 0.001A, rng) fig = Figure(fontsize = 43) ax = Axis(fig[1, 1], width = 600, height = 400) triplot!(tri) @@ -263,8 +263,8 @@ angles = first.(get_all_stat(stats, :angles)) # the first is the smallest scatter!(ax, rad2deg.(angles)) hlines!(ax, [18.73], color = :red, linewidth = 4) resize_to_layout!(fig) -fig -@test_reference joinpath(fig_path, "mesh_refinement_ex_13.png") fig by=psnr_equality(10) #src +fig +@test_reference joinpath(fig_path, "mesh_refinement_ex_13.png") fig by = psnr_equality(10) #src # In this case, all the triangles satisfy the constraint, of course -# at the expense of some other triangles having lesser quality. \ No newline at end of file +# at the expense of some other triangles having lesser quality. diff --git a/docs/src/literate_tutorials/unconstrained.jl b/docs/src/literate_tutorials/unconstrained.jl index d4e0949dd..d817b503b 100644 --- a/docs/src/literate_tutorials/unconstrained.jl +++ b/docs/src/literate_tutorials/unconstrained.jl @@ -21,7 +21,7 @@ points = rand(rng, 2, 500) # just do rand(2, 500) if you are not concerned about # We now triangulate these points by using [`triangulate`](@ref). We pass the `rng` # as a keyword argument, but again if you are not concerned about the RNG (or # set the seed using `Random.seed!`) then you can ignore this. -tri = triangulate(points; rng=rng) +tri = triangulate(points; rng = rng) #- fig, ax, sc = triplot(tri) @@ -43,7 +43,7 @@ function compute_centroid(tri) return s end s = compute_centroid(tri) -@test s ≈ [sum(points[1, :]) / 500, sum(points[2, :]) / 500] atol = 1e-10 #src +@test s ≈ [sum(points[1, :]) / 500, sum(points[2, :]) / 500] atol = 1.0e-10 #src # We need to use the `solid` identifier because triangulations are made up of both _solid_ # and _ghost_ vertices/edges/triangles, for reasons described in the [manual](../manual/ghost_triangles.md). @@ -165,4 +165,4 @@ get_adjacent(tri, 398, 258) # means that `(398, 258)` is a boundary edge and `(398, 258, -1)` is a ghost triangle. # You can test for this case using [`DelaunayTriangulation.is_boundary_edge`](@ref): DelaunayTriangulation.is_boundary_edge(tri, 258, 398) -@test DelaunayTriangulation.is_boundary_edge(tri, 258, 398) #src \ No newline at end of file +@test DelaunayTriangulation.is_boundary_edge(tri, 258, 398) #src diff --git a/docs/src/literate_tutorials/voronoi.jl b/docs/src/literate_tutorials/voronoi.jl index 918a160d0..68182eaaf 100644 --- a/docs/src/literate_tutorials/voronoi.jl +++ b/docs/src/literate_tutorials/voronoi.jl @@ -18,7 +18,7 @@ fig_path = joinpath(@__DIR__, "../figures") #src points = [ (-3.0, 7.0), (1.0, 6.0), (-1.0, 3.0), (-2.0, 4.0), (3.0, -2.0), (5.0, 5.0), - (-4.0, -3.0), (3.0, 8.0) + (-4.0, -3.0), (3.0, 8.0), ] rng = StableRNG(123) tri = triangulate(points; rng) @@ -26,7 +26,7 @@ vorn = voronoi(tri) # To visualise the tessellation, you can use `voronoiplot`. Here, # we also compare the tessellation with its dual triangulation. -fig, ax, sc = voronoiplot(vorn, markersize=13, colormap=:matter, strokecolor=:white, strokewidth=5) +fig, ax, sc = voronoiplot(vorn, markersize = 13, colormap = :matter, strokecolor = :white, strokewidth = 5) triplot!(ax, tri) fig @test_reference joinpath(fig_path, "voronoi_ex_1.png") fig #src @@ -146,7 +146,7 @@ function get_polygon_area(vorn, i) vⱼ = vertices[begin] pⱼ = get_polygon_point(vorn, vⱼ) xⱼ, yⱼ = getxy(pⱼ) - for j in (firstindex(vertices)+1):lastindex(vertices) # same as 2:length(vertices) + for j in (firstindex(vertices) + 1):lastindex(vertices) # same as 2:length(vertices) vⱼ₊₁ = vertices[j] pⱼ₊₁ = get_polygon_point(vorn, vⱼ₊₁) xⱼ₊₁, yⱼ₊₁ = getxy(pⱼ₊₁) diff --git a/docs/src/tutorials/centroidal.md b/docs/src/tutorials/centroidal.md index f09adc05a..97720d01e 100644 --- a/docs/src/tutorials/centroidal.md +++ b/docs/src/tutorials/centroidal.md @@ -12,39 +12,60 @@ in place. This method is only applicable to clipped tessellations. We give a simple example. First, we compute the clipped tessellation of a point set. -````@example centroidal +````julia using DelaunayTriangulation using CairoMakie using StableRNGs rng = StableRNG(123) points = 25randn(rng, 2, 500) tri = triangulate(points; rng) -vorn = voronoi(tri, clip=true) +vorn = voronoi(tri, clip = true) ```` -To now compute the centroidal tessellation, use [`centroidal_smooth`](@ref). +```` +Voronoi Tessellation. + Number of generators: 500 + Number of polygon vertices: 1032 + Number of polygons: 500 +```` + +To now compute the centroidal tessellation, use [`centroidal_smooth`](@ref). ( +If you want to straight from a triangulation to a centroidal tessellation, you +can also just use `smooth_vorn = voronoi(tri, clip = true, smooth = true)`.) -````@example centroidal +````julia smooth_vorn = centroidal_smooth(vorn; rng) ```` +```` +Voronoi Tessellation. + Number of generators: 500 + Number of polygon vertices: 1074 + Number of polygons: 500 +```` + Let us now compare the two tessellations. -````@example centroidal +````julia fig = Figure() -ax1 = Axis(fig[1, 1], title="Original", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Smoothed", width=600, height=400) -voronoiplot!(ax1, vorn, colormap=:matter, strokewidth=2) -voronoiplot!(ax2, smooth_vorn, colormap=:matter, strokewidth=2) +ax1 = Axis(fig[1, 1], title = "Original", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Smoothed", width = 600, height = 400) +voronoiplot!(ax1, vorn, colormap = :matter, strokewidth = 2) +voronoiplot!(ax2, smooth_vorn, colormap = :matter, strokewidth = 2) resize_to_layout!(fig) fig ```` +```@raw html + +``` + As you can see, the tiles are all reasonably uniform, and their generators do look to be near the centroid of their corresponding tile. Note that this function `centroidal_smooth` is iterative, and you can control the iteration limits and the tolerance of the iterations (based on the maximum displacement of any generator at each iteration) using the `maxiters` and `tol` keyword arguments. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/centroidal.jl). @@ -56,15 +77,15 @@ using StableRNGs rng = StableRNG(123) points = 25randn(rng, 2, 500) tri = triangulate(points; rng) -vorn = voronoi(tri, clip=true) +vorn = voronoi(tri, clip = true) smooth_vorn = centroidal_smooth(vorn; rng) fig = Figure() -ax1 = Axis(fig[1, 1], title="Original", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Smoothed", width=600, height=400) -voronoiplot!(ax1, vorn, colormap=:matter, strokewidth=2) -voronoiplot!(ax2, smooth_vorn, colormap=:matter, strokewidth=2) +ax1 = Axis(fig[1, 1], title = "Original", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Smoothed", width = 600, height = 400) +voronoiplot!(ax1, vorn, colormap = :matter, strokewidth = 2) +voronoiplot!(ax2, smooth_vorn, colormap = :matter, strokewidth = 2) resize_to_layout!(fig) fig ``` diff --git a/docs/src/tutorials/clipped.md b/docs/src/tutorials/clipped.md index 596139572..6c0f5d966 100644 --- a/docs/src/tutorials/clipped.md +++ b/docs/src/tutorials/clipped.md @@ -13,7 +13,7 @@ are on the to-do list, but they are not yet implemented.) In the example below, we clip the tessellation to the convex hull of the point set by using `clip=true` in the keyword arguments. -````@example clipped +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -24,25 +24,44 @@ tri = triangulate(points; rng) vorn = voronoi(tri) ```` -````@example clipped +```` +Voronoi Tessellation. + Number of generators: 50 + Number of polygon vertices: 92 + Number of polygons: 50 +```` + +````julia clipped_vorn = voronoi(tri, clip = true) ```` +```` +Voronoi Tessellation. + Number of generators: 50 + Number of polygon vertices: 119 + Number of polygons: 50 +```` + Note that the clipping has put more polygon vertices in. We compare the clipped tessellations below. -````@example clipped +````julia fig = Figure() -ax1 = Axis(fig[1, 1], title="Unclipped", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Clipped", width=600, height=400) -voronoiplot!(ax1, vorn, show_generators=false, colormap=:matter, strokewidth=4) -voronoiplot!(ax2, clipped_vorn, show_generators=false, colormap=:matter, strokewidth=4) +ax1 = Axis(fig[1, 1], title = "Unclipped", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Clipped", width = 600, height = 400) +voronoiplot!(ax1, vorn, show_generators = false, colormap = :matter, strokewidth = 4) +voronoiplot!(ax2, clipped_vorn, show_generators = false, colormap = :matter, strokewidth = 4) resize_to_layout!(fig) fig ```` +```@raw html + +``` + As you can see, the unbounded polygons, and any polygons that included points outside of the convex hull, have now been clipped to the convex hull. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/clipped.jl). @@ -60,10 +79,10 @@ vorn = voronoi(tri) clipped_vorn = voronoi(tri, clip = true) fig = Figure() -ax1 = Axis(fig[1, 1], title="Unclipped", width=600, height=400) -ax2 = Axis(fig[1, 2], title="Clipped", width=600, height=400) -voronoiplot!(ax1, vorn, show_generators=false, colormap=:matter, strokewidth=4) -voronoiplot!(ax2, clipped_vorn, show_generators=false, colormap=:matter, strokewidth=4) +ax1 = Axis(fig[1, 1], title = "Unclipped", width = 600, height = 400) +ax2 = Axis(fig[1, 2], title = "Clipped", width = 600, height = 400) +voronoiplot!(ax1, vorn, show_generators = false, colormap = :matter, strokewidth = 4) +voronoiplot!(ax2, clipped_vorn, show_generators = false, colormap = :matter, strokewidth = 4) resize_to_layout!(fig) fig ``` diff --git a/docs/src/tutorials/clipped_rectangle.md b/docs/src/tutorials/clipped_rectangle.md index 121cfa287..228776a1f 100644 --- a/docs/src/tutorials/clipped_rectangle.md +++ b/docs/src/tutorials/clipped_rectangle.md @@ -15,7 +15,7 @@ but we provide the function [`get_polygon_coordinates`](@ref) for this (this is Let us now demonstrate. First, we construct a tessellation of some example point set. -````@example clipped_rectangle +````julia using DelaunayTriangulation using CairoMakie A = (-3.0, 7.0) @@ -31,45 +31,77 @@ tri = triangulate(points) vorn = voronoi(tri) ```` +```` +Voronoi Tessellation. + Number of generators: 8 + Number of polygon vertices: 9 + Number of polygons: 8 +```` + Let us show the tessellation, and the rectangle we want to clip the tessellation to. -````@example clipped_rectangle +````julia fig, ax, sc = voronoiplot(vorn) a, b, c, d = -2.0, 3.0, 0.0, 7.0 -lines!(ax, [(a,c),(b,c),(b,d),(a,d),(a,c)], color = :black, linewidth = 4) +lines!(ax, [(a, c), (b, c), (b, d), (a, d), (a, c)], color = :black, linewidth = 4) fig ```` +```@raw html + +``` + To apply this clipping, we need to provide a bounding box of the form `(xmin, xmax, ymin, ymax)`. Here, we will use -````@example clipped_rectangle +````julia bounding_box = (a, b, c, d) ```` +```` +(-2.0, 3.0, 0.0, 7.0) +```` + You can obtain some reasonable defaults for this bounding box using [DelaunayTriangulation.polygon_bounds(vorn)](@ref polygon_bounds). The coordinates for each polygon clipped to this box can be obtained as follows. -````@example clipped_rectangle -clipped_coords = Vector{Vector{NTuple{2,Float64}}}(undef, num_polygons(vorn)) +````julia +clipped_coords = Vector{Vector{NTuple{2, Float64}}}(undef, num_polygons(vorn)) for i in each_polygon_index(vorn) clipped_coords[i] = get_polygon_coordinates(vorn, i, bounding_box) end clipped_coords ```` +```` +8-element Vector{Vector{Tuple{Float64, Float64}}}: + [(-2.000000000000001, 7.0), (-2.0, 5.666666666666667), (-1.1363636363636365, 5.954545454545455), (-0.8750000000000009, 7.0), (-2.000000000000001, 7.0)] + [(-0.30000000000000004, 4.7), (2.357142857142857, 2.9285714285714284), (3.0, 5.499999999999999), (3.0, 6.0), (2.0, 7.0), (-0.8750000000000009, 7.0), (-1.1363636363636365, 5.954545454545455), (-0.30000000000000004, 4.7)] + [(0.375, 0.0), (2.710526315789474, 1.868421052631579), (2.357142857142857, 2.9285714285714284), (-0.30000000000000004, 4.7), (-2.0, 3.0), (-2.0, 0.0), (0.375, 0.0)] + [(-2.0, 3.0), (-0.30000000000000004, 4.7), (-1.1363636363636365, 5.954545454545455), (-2.0, 5.666666666666667), (-2.0, 3.0)] + [(3.0, 0.0), (3.0, 1.7857142857142858), (2.710526315789474, 1.868421052631579), (0.375, 0.0), (3.0, 0.0)] + [(3.0, 1.7857142857142858), (3.0, 5.499999999999999), (2.357142857142857, 2.9285714285714284), (2.710526315789474, 1.868421052631579), (3.0, 1.7857142857142858)] + [] + [(3.0, 7.0), (2.0, 7.0), (3.0, 6.0), (3.0, 7.0)] +```` + Now let's plot these. -````@example clipped_rectangle +````julia fig, ax, sc = poly(clipped_coords, color = :white, strokewidth = 4) fig ```` +```@raw html + +``` + As we can see, the polygons have been clipped to the rectangle. Note that if you just want this for plotting, you can also call `voronoiplot` with the `bounding_box` keyword argument. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/clipped_rectangle.jl). @@ -91,12 +123,12 @@ vorn = voronoi(tri) fig, ax, sc = voronoiplot(vorn) a, b, c, d = -2.0, 3.0, 0.0, 7.0 -lines!(ax, [(a,c),(b,c),(b,d),(a,d),(a,c)], color = :black, linewidth = 4) +lines!(ax, [(a, c), (b, c), (b, d), (a, d), (a, c)], color = :black, linewidth = 4) fig bounding_box = (a, b, c, d) -clipped_coords = Vector{Vector{NTuple{2,Float64}}}(undef, num_polygons(vorn)) +clipped_coords = Vector{Vector{NTuple{2, Float64}}}(undef, num_polygons(vorn)) for i in each_polygon_index(vorn) clipped_coords[i] = get_polygon_coordinates(vorn, i, bounding_box) end diff --git a/docs/src/tutorials/constrained_edges.md b/docs/src/tutorials/constrained_edges.md index b213c8c88..f92e5aaa3 100644 --- a/docs/src/tutorials/constrained_edges.md +++ b/docs/src/tutorials/constrained_edges.md @@ -10,14 +10,14 @@ starting with the simple case of only having constrained segments, meaning edges that are forced to be in the final triangulation. To start, let us load in the packages we will need. -````@example constrained_edges +````julia using DelaunayTriangulation using CairoMakie ```` We consider triangulating the following set of points: -````@example constrained_edges +````julia a = (0.0, 0.0) b = (0.0, 1.0) c = (0.0, 2.5) @@ -32,12 +32,35 @@ k = (8.0, 2.5) pts = [a, b, c, d, e, f, g, h, i, j, k] ```` +```` +11-element Vector{Tuple{Float64, Float64}}: + (0.0, 0.0) + (0.0, 1.0) + (0.0, 2.5) + (2.0, 0.0) + (6.0, 0.0) + (8.0, 0.0) + (8.0, 0.5) + (7.5, 1.0) + (4.0, 1.0) + (4.0, 2.5) + (8.0, 2.5) +```` + To now define the segments, we define: -````@example constrained_edges +````julia C = Set([(2, 1), (2, 11), (2, 7), (2, 5)]) ```` +```` +Set{Tuple{Int64, Int64}} with 4 elements: + (2, 5) + (2, 11) + (2, 1) + (2, 7) +```` + With this notation, each `Tuple` is an individual edge to include in the triangulation, with `(i, j)` meaning the edge connecting the points @@ -45,44 +68,85 @@ edge to include in the triangulation, with make the triangulation, comparing it to its unconstrained counterpart. -````@example constrained_edges +````julia tri = triangulate(pts) ```` -````@example constrained_edges -cons_tri = triangulate(pts; segments=C) +```` +Delaunay Triangulation. + Number of vertices: 11 + Number of triangles: 11 + Number of edges: 21 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + +````julia +cons_tri = triangulate(pts; segments = C) ```` -````@example constrained_edges +```` +Delaunay Triangulation. + Number of vertices: 11 + Number of triangles: 11 + Number of edges: 21 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true +```` + +````julia fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Unconstrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) triplot!(ax2, cons_tri, show_constrained_edges = true) resize_to_layout!(fig) fig ```` +```@raw html + +``` + As you can see, the constrained edges in magenta have now been included in the triangulation in (b), whereas in (a) most were previously not included. You can view the constrained edges by using -````@example constrained_edges +````julia get_interior_segments(cons_tri) ```` +```` +Set{Tuple{Int64, Int64}} with 4 elements: + (1, 2) + (2, 5) + (7, 2) + (11, 2) +```` + There is also a function [`get_all_segments`](@ref), which in this case is the same as [`get_interior_segments`](@ref), but in the case of a triangulation with constrained boundaries, it will also include the boundary segments whereas `get_interior_segments` will not; this is demonstrated in the later tutorials. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_edges.jl). @@ -108,15 +172,19 @@ C = Set([(2, 1), (2, 11), (2, 7), (2, 5)]) tri = triangulate(pts) -cons_tri = triangulate(pts; segments=C) +cons_tri = triangulate(pts; segments = C) fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Unconstrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) triplot!(ax2, cons_tri, show_constrained_edges = true) resize_to_layout!(fig) diff --git a/docs/src/tutorials/constrained_interior_within_interiors.md b/docs/src/tutorials/constrained_interior_within_interiors.md index 20178710d..a33f5bfa7 100644 --- a/docs/src/tutorials/constrained_interior_within_interiors.md +++ b/docs/src/tutorials/constrained_interior_within_interiors.md @@ -9,7 +9,7 @@ Now we consider triangulating a domain which has not only an interior boundary, but also an interior boundary inside that interior boundary. To start, let us load the packages. -````@example constrained_interior_within_interiors +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -24,21 +24,23 @@ the orientation of an interior curve is the opposite orientation to the curve it's inside of. Here are the points we will be triangulating. -````@example constrained_interior_within_interiors +````julia curve_1 = [ [(0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0)], [(25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0)], [(25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0)], - [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)] + [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)], ] # outer-most boundary: counter-clockwise curve_2 = [ [(4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0)], [(20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0)], - [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)] + [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)], ] # inner boundary: clockwise curve_3 = [ - [(12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), - (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912)] + [ + (12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), + (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912), + ], ] # this is inside curve_2, so it's counter-clockwise curves = [curve_1, curve_2, curve_3] points = [ @@ -48,20 +50,28 @@ points = [ (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), - (12.0, 13.0), (19.0, 15.0) + (12.0, 13.0), (19.0, 15.0), ] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) +```` + +```` +([[[35, 36, 37, 38, 39, 40], [40, 41, 42, 43, 44, 45], [45, 46, 47, 48, 49, 50], [50, 51, 52, 53, 54, 35]], [[55, 56, 57, 58, 59], [59, 60, 61, 62, 63], [63, 64, 65, 66, 67, 55]], [[68, 69, 70, 71, 72, 73, 74, 68]]], [(3.0, 23.0), (9.0, 24.0), (9.2, 22.0), (14.8, 22.8), (16.0, 22.0), (23.0, 23.0), (22.6, 19.0), (23.8, 17.8), (22.0, 14.0), (22.0, 11.0), (24.0, 6.0), (23.0, 2.0), (19.0, 1.0), (16.0, 3.0), (10.0, 1.0), (11.0, 3.0), (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), (12.0, 13.0), (19.0, 15.0), (0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), (13.13, 16.86), (8.92, 16.4), (8.8, 10.9)]) ```` To now triangulate: -````@example constrained_interior_within_interiors +````julia rng = StableRNG(123) # triangulation is not unique when there are cocircular points tri = triangulate(points; boundary_nodes, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_interior_within_interiors.jl). @@ -75,16 +85,18 @@ curve_1 = [ [(0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0)], [(25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0)], [(25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0)], - [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)] + [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)], ] # outer-most boundary: counter-clockwise curve_2 = [ [(4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0)], [(20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0)], - [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)] + [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)], ] # inner boundary: clockwise curve_3 = [ - [(12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), - (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912)] + [ + (12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), + (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912), + ], ] # this is inside curve_2, so it's counter-clockwise curves = [curve_1, curve_2, curve_3] points = [ @@ -94,9 +106,9 @@ points = [ (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), - (12.0, 13.0), (19.0, 15.0) + (12.0, 13.0), (19.0, 15.0), ] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) rng = StableRNG(123) # triangulation is not unique when there are cocircular points tri = triangulate(points; boundary_nodes, rng) diff --git a/docs/src/tutorials/constrained_multiply_connected.md b/docs/src/tutorials/constrained_multiply_connected.md index e6887f69a..c0efd8dba 100644 --- a/docs/src/tutorials/constrained_multiply_connected.md +++ b/docs/src/tutorials/constrained_multiply_connected.md @@ -9,7 +9,7 @@ We now consider triangulating a domain which has not only a boundary, but also an interior boundary. To start, let us load the packages. -````@example constrained_multiply_connected +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -26,28 +26,32 @@ the interior boundaries must be clockwise so that the orientations of the interiors relative to the boundaries are consistent. Note again that neighbouring segments must connect. -````@example constrained_multiply_connected +````julia curve_1 = [ - [ # first segment + [ + # first segment (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), - (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0) + (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), ], - [ # second segment + [ + # second segment (12.0, 28.0), (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), (-4.0, 0.0), (0.0, 0.0), - ] + ], ] # outer: counter-clockwise curve_2 = [ - [ # first segment + [ + # first segment (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), - (10.0, 22.0), (10.0, 20.0) + (10.0, 22.0), (10.0, 20.0), ], - [ # second segment + [ + # second segment (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ] + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], ] # inner: clockwise curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] # inner: clockwise curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] # inner: clockwise @@ -63,9 +67,9 @@ points = [ (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points); -nothing #hide + (7.0, 7.8), (7.0, 7.4), +] +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points); ```` Notice that `curve_1` and `curve_2` are split up into multiple segments. For `curve_3` @@ -74,64 +78,192 @@ treating them as a single segment. Now let us triangulate. -````@example constrained_multiply_connected +````julia rng = StableRNG(123) # the triangulation is not unique due to cocircular points tri = triangulate(points; boundary_nodes, rng) -fig, ax, sc = triplot(tri, show_constrained_edges=true, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_constrained_edges = true, show_convex_hull = true) fig ```` +```@raw html + +``` + Like before, we examine individual segments by referring to them by their ghost vertices, which are still in the order `-1`, `-2`, and so on in the order of the segments provided in `boundary_nodes`. This is a lot more cumbersome to keep track of than the previous tutorials since there are many more ghost vertices. This is where the boundary fields become much more useful. For instance, the `boundary_edge_map` in this case is given by: -````@example constrained_multiply_connected +````julia get_boundary_edge_map(tri) ```` +```` +Dict{Tuple{Int64, Int64}, Tuple{Tuple{Int64, Int64}, Int64}} with 43 entries: + (61, 62) => ((1, 1), 7) + (58, 59) => ((1, 1), 4) + (93, 90) => ((3, 1), 4) + (56, 57) => ((1, 1), 2) + (55, 56) => ((1, 1), 1) + (96, 97) => ((4, 1), 3) + (92, 93) => ((3, 1), 3) + (75, 76) => ((1, 2), 9) + (97, 94) => ((4, 1), 4) + (71, 72) => ((1, 2), 5) + (67, 68) => ((1, 2), 1) + (77, 78) => ((1, 2), 11) + (60, 61) => ((1, 1), 6) + (88, 89) => ((2, 2), 5) + (66, 67) => ((1, 1), 12) + (69, 70) => ((1, 2), 3) + (76, 77) => ((1, 2), 10) + (73, 74) => ((1, 2), 7) + (91, 92) => ((3, 1), 2) + (64, 65) => ((1, 1), 10) + (80, 81) => ((2, 1), 2) + (84, 85) => ((2, 2), 1) + (89, 79) => ((2, 2), 6) + (87, 88) => ((2, 2), 4) + (68, 69) => ((1, 2), 2) + (59, 60) => ((1, 1), 5) + (70, 71) => ((1, 2), 4) + (81, 82) => ((2, 1), 3) + (94, 95) => ((4, 1), 1) + (90, 91) => ((3, 1), 1) + (72, 73) => ((1, 2), 6) + (62, 63) => ((1, 1), 8) + (83, 84) => ((2, 1), 5) + (65, 66) => ((1, 1), 11) + (74, 75) => ((1, 2), 8) + (78, 55) => ((1, 2), 12) + (85, 86) => ((2, 2), 2) + (86, 87) => ((2, 2), 3) + (95, 96) => ((4, 1), 2) + (63, 64) => ((1, 1), 9) + (57, 58) => ((1, 1), 3) + (82, 83) => ((2, 1), 4) + (79, 80) => ((2, 1), 1) +```` + The `Tuples` in the `values` are now of the form `((I, J), K)`, with `I` the curve index (with `1` being the outer boundary), `J` the segment index, and `K` the position of the edge within the segment. To look at the ghost vertices directly, another useful field is `ghost_vertex_ranges`: -````@example constrained_multiply_connected +````julia get_ghost_vertex_ranges(tri) ```` +```` +Dict{Int64, UnitRange{Int64}} with 6 entries: + -5 => -5:-5 + -1 => -2:-1 + -3 => -4:-3 + -2 => -2:-1 + -4 => -4:-3 + -6 => -6:-6 +```` + This field maps a ghost vertex to the complete set of ghost vertices that might be found on the curve corresponding to that ghost vertex. For example, `-3 => -4:-3` means that the ghost vertex `-3` is part of a curve that, in addition to itself, contains the ghost vertex `-4`. If you want all the ghost vertex, you can use -````@example constrained_multiply_connected +````julia DelaunayTriangulation.all_ghost_vertices(tri) ```` +```` +KeySet for a Dict{Int64, UnitRange{Int64}} with 6 entries. Keys: + -5 + -1 + -3 + -2 + -4 + -6 +```` + which is just `keys(get_ghost_vertex_ranges(tri))`. If you just want to find what curve and what segment a ghost vertex belongs to, you can look at the `ghost_vertex_map`: -````@example constrained_multiply_connected +````julia get_ghost_vertex_map(tri) ```` +```` +Dict{Int64, Tuple{Int64, Int64}} with 6 entries: + -5 => (3, 1) + -1 => (1, 1) + -3 => (2, 1) + -2 => (1, 2) + -4 => (2, 2) + -6 => (4, 1) +```` + So that, for example, `-3 => (2, 1)` means that the ghost vertex `-3` corresponds to the first part (from the second `Tuple` element) of the second curve (from the first `Tuple` element). To get all the boundary nodes, you can use -````@example constrained_multiply_connected +````julia DelaunayTriangulation.get_all_boundary_nodes(tri) ```` +```` +Set{Int64} with 43 elements: + 56 + 55 + 60 + 67 + 73 + 64 + 90 + 63 + 86 + 91 + 62 + 58 + 75 + 92 + 69 + 68 + 82 + 85 + 84 + 77 + 95 + 71 + 66 + 76 + 93 + 59 + 87 + 79 + 81 + 74 + 61 + 94 + 57 + 70 + 88 + 78 + 72 + 83 + 89 + 80 + 96 + 65 + 97 +```` + To give an example of how we can work with this boundary, let us compute the area of the triangulation (a more efficient approach is with [`get_area(tri)`](@ref get_area), but this is just for demonstration). For this, the order of the boundary edges is appropriate, so we must iterate in a way that respects the ordering. -````@example constrained_multiply_connected +````julia function get_triangulation_area(tri) A = 0.0 nc = DelaunayTriangulation.num_curves(tri) @@ -143,31 +275,35 @@ function get_triangulation_area(tri) ne = num_boundary_edges(bnn) for i in 1:ne vᵢ = get_boundary_nodes(bnn, i) - vᵢ₊₁ = get_boundary_nodes(bnn, i+1) + vᵢ₊₁ = get_boundary_nodes(bnn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end end end - return A/2 + return A / 2 end A = get_triangulation_area(tri) ```` +```` +330.0 +```` + This is of course quite a complicated example since we need to take care of the order. If we don't care about order, then the complexity of the code for iterating over a boundary is much simpler. For example, here we compute the perimeter of the boundary, and we also consider the length of each curve and of each segment. -````@example constrained_multiply_connected +````julia function get_perimeters(tri) total_perimeter = 0.0 nc = DelaunayTriangulation.num_curves(tri) curve_perimeters = zeros(nc) # curve_index => perimeter - segment_perimeters = Dict{NTuple{2,Int},Float64}() # (curve_index, segment_index) => perimeter + segment_perimeters = Dict{NTuple{2, Int}, Float64}() # (curve_index, segment_index) => perimeter for (e, ((curve_index, section_index), node_index)) in get_boundary_edge_map(tri) u, v = edge_vertices(e) p, q = get_point(tri, u, v) @@ -185,6 +321,10 @@ end ℓ, cℓ, sℓ = get_perimeters(tri) ```` +```` +(150.2711258282229, [92.61427157873052, 24.0, 20.0, 13.65685424949238], Dict((1, 2) => 49.30056307974577, (3, 1) => 20.0, (1, 1) => 43.31370849898476, (4, 1) => 13.65685424949238, (2, 2) => 12.0, (2, 1) => 12.0)) +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_multiply_connected.jl). @@ -195,26 +335,30 @@ using CairoMakie using StableRNGs curve_1 = [ - [ # first segment + [ + # first segment (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), - (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0) + (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), ], - [ # second segment + [ + # second segment (12.0, 28.0), (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), (-4.0, 0.0), (0.0, 0.0), - ] + ], ] # outer: counter-clockwise curve_2 = [ - [ # first segment + [ + # first segment (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), - (10.0, 22.0), (10.0, 20.0) + (10.0, 22.0), (10.0, 20.0), ], - [ # second segment + [ + # second segment (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ] + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], ] # inner: clockwise curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] # inner: clockwise curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] # inner: clockwise @@ -230,12 +374,13 @@ points = [ (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] -boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points); + (7.0, 7.8), (7.0, 7.4), +] +boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points); rng = StableRNG(123) # the triangulation is not unique due to cocircular points tri = triangulate(points; boundary_nodes, rng) -fig, ax, sc = triplot(tri, show_constrained_edges=true, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_constrained_edges = true, show_convex_hull = true) fig get_boundary_edge_map(tri) @@ -259,15 +404,15 @@ function get_triangulation_area(tri) ne = num_boundary_edges(bnn) for i in 1:ne vᵢ = get_boundary_nodes(bnn, i) - vᵢ₊₁ = get_boundary_nodes(bnn, i+1) + vᵢ₊₁ = get_boundary_nodes(bnn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end end end - return A/2 + return A / 2 end A = get_triangulation_area(tri) @@ -275,7 +420,7 @@ function get_perimeters(tri) total_perimeter = 0.0 nc = DelaunayTriangulation.num_curves(tri) curve_perimeters = zeros(nc) # curve_index => perimeter - segment_perimeters = Dict{NTuple{2,Int},Float64}() # (curve_index, segment_index) => perimeter + segment_perimeters = Dict{NTuple{2, Int}, Float64}() # (curve_index, segment_index) => perimeter for (e, ((curve_index, section_index), node_index)) in get_boundary_edge_map(tri) u, v = edge_vertices(e) p, q = get_point(tri, u, v) diff --git a/docs/src/tutorials/constrained_multipolygon.md b/docs/src/tutorials/constrained_multipolygon.md index 83e264d05..866f0fb9c 100644 --- a/docs/src/tutorials/constrained_multipolygon.md +++ b/docs/src/tutorials/constrained_multipolygon.md @@ -11,13 +11,13 @@ with the outer boundaries being counter-clockwise, and all the interior boundaries clockwise (and other interiors inside interiors counter-clockwise, etc., if you please). Here is a simple example. -````@example constrained_multipolygon +````julia using DelaunayTriangulation using CairoMakie θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -28,14 +28,18 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Here is another example. -````@example constrained_multipolygon +````julia C = (15.7109521325776, 33.244486807457) D = (14.2705719699703, 32.8530791545746) E = (14.3, 27.2) @@ -180,10 +184,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -191,11 +198,15 @@ dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] nodes, points = convert_boundary_points_to_indices(curves) -tri = triangulate(points; boundary_nodes=nodes) +tri = triangulate(points; boundary_nodes = nodes) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_multipolygon.jl). @@ -206,7 +217,7 @@ using CairoMakie θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -217,7 +228,7 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) fig, ax, sc = triplot(tri) fig @@ -365,10 +376,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -376,7 +390,7 @@ dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] nodes, points = convert_boundary_points_to_indices(curves) -tri = triangulate(points; boundary_nodes=nodes) +tri = triangulate(points; boundary_nodes = nodes) fig, ax, sc = triplot(tri) fig ``` diff --git a/docs/src/tutorials/constrained_outer_boundary.md b/docs/src/tutorials/constrained_outer_boundary.md index 7c90ce85e..23323a3d8 100644 --- a/docs/src/tutorials/constrained_outer_boundary.md +++ b/docs/src/tutorials/constrained_outer_boundary.md @@ -10,24 +10,50 @@ having constrained segments, we have a constrained outer boundary. This is especially useful as it allows us to, for example, have a non-convex boundary. To start, let us load in the packages we will need. -````@example constrained_outer_boundary +````julia using DelaunayTriangulation using CairoMakie ```` Now, we define some of the points we will be triangulating. -````@example constrained_outer_boundary +````julia pts = [ (-7.36, 12.55), (-9.32, 8.59), (-9.0, 3.0), (-6.32, -0.27), (-4.78, -1.53), (2.78, -1.41), (-5.42, 1.45), (7.86, 0.67), (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), - (1.34, 6.77), (1.24, 4.15) + (1.34, 6.77), (1.24, 4.15), ] ```` +```` +22-element Vector{Tuple{Float64, Float64}}: + (-7.36, 12.55) + (-9.32, 8.59) + (-9.0, 3.0) + (-6.32, -0.27) + (-4.78, -1.53) + (2.78, -1.41) + (-5.42, 1.45) + (7.86, 0.67) + (10.92, 0.23) + (9.9, 7.39) + (8.14, 4.77) + (13.4, 8.61) + (7.4, 12.27) + (2.2, 13.85) + (-3.48, 10.21) + (-4.56, 7.35) + (3.44, 8.99) + (3.74, 5.87) + (-2.0, 8.0) + (-2.52, 4.81) + (1.34, 6.77) + (1.24, 4.15) +```` + To define a boundary, we need to provide a counter-clockwise sequence of indices corresponding to the boundary points, and the first index must match the last index so the boundary is closed. While we could @@ -37,53 +63,143 @@ tedious to get correct. So, we instead provide the function [`convert_boundary_points_to_indices`](@ref) which takes in a vector of coordinates, and then returns the correct set of indices. Here is how we use it: -````@example constrained_outer_boundary +````julia boundary_points = [ (0.0, 0.0), (2.0, 1.0), (3.98, 2.85), (6.0, 5.0), (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), - (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0) + (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0), ] -boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points=pts); -nothing #hide +boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points = pts); ```` The keyword argument `existing_points` is so that the points in `boundary_points` get appended (in-place) to `pts`, as we see: -````@example constrained_outer_boundary +````julia pts ```` +```` +42-element Vector{Tuple{Float64, Float64}}: + (-7.36, 12.55) + (-9.32, 8.59) + (-9.0, 3.0) + (-6.32, -0.27) + (-4.78, -1.53) + (2.78, -1.41) + (-5.42, 1.45) + (7.86, 0.67) + (10.92, 0.23) + (9.9, 7.39) + (8.14, 4.77) + (13.4, 8.61) + (7.4, 12.27) + (2.2, 13.85) + (-3.48, 10.21) + (-4.56, 7.35) + (3.44, 8.99) + (3.74, 5.87) + (-2.0, 8.0) + (-2.52, 4.81) + (1.34, 6.77) + (1.24, 4.15) + (0.0, 0.0) + (2.0, 1.0) + (3.98, 2.85) + (6.0, 5.0) + (7.0, 7.0) + (7.0, 9.0) + (6.0, 11.0) + (4.0, 12.0) + (2.0, 12.0) + (1.0, 11.0) + (0.0, 9.13) + (-1.0, 11.0) + (-2.0, 12.0) + (-4.0, 12.0) + (-6.0, 11.0) + (-7.0, 9.0) + (-6.94, 7.13) + (-6.0, 5.0) + (-4.0, 3.0) + (-2.0, 1.0) +```` + The `boundary_nodes` is then these indices: -````@example constrained_outer_boundary +````julia boundary_nodes ```` +```` +21-element Vector{Int64}: + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 23 +```` + To now triangulate, we use the `boundary_nodes` keyword argument. Like in the last tutorial, we also give a comparison to the unconstrained version. -````@example constrained_outer_boundary +````julia tri = triangulate(pts) cons_tri = triangulate(pts; boundary_nodes) ```` -````@example constrained_outer_boundary +```` +Delaunay Triangulation. + Number of vertices: 28 + Number of triangles: 34 + Number of edges: 61 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true +```` + +````julia fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Unconstrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) -triplot!(ax2, cons_tri, show_constrained_edges=true, show_convex_hull=true) +triplot!(ax2, cons_tri, show_constrained_edges = true, show_convex_hull = true) resize_to_layout!(fig) fig ```` +```@raw html + +``` + Notice now that the boundary in (b) is not convex, as is clear from the convex hull shown in red. You can access the convex hull using [`get_convex_hull(cons_tri)`](@ref get_convex_hull). We also note that the triangulation @@ -91,11 +207,15 @@ no longer contains every point in `pts`, as by default all triangles away from the boundary are deleted, so that we do actually have a boundary. If for some reason you do not want this behaviour, use `delete_holes = false`: -````@example constrained_outer_boundary -full_tri = triangulate(pts; boundary_nodes, delete_holes=false) -fig, ax, sc = triplot(full_tri, show_constrained_edges=true, show_convex_hull=true) +````julia +full_tri = triangulate(pts; boundary_nodes, delete_holes = false) +fig, ax, sc = triplot(full_tri, show_constrained_edges = true, show_convex_hull = true) ```` +```@raw html + +``` + This default behaviour does mean you need to be careful if you use [`DelaunayTriangulation.each_point`](@ref) or [`DelaunayTriangulation.each_point_index`](@ref), as these iterators will contain all points, possibly iterating over points that aren't in the triangulation. For this reason, it is recommended that you @@ -105,10 +225,35 @@ There are multiple methods available for working directly with the boundary nodes. You can get the boundary nodes using `get_boundary_nodes(tri)`: -````@example constrained_outer_boundary +````julia get_boundary_nodes(cons_tri) ```` +```` +21-element Vector{Int64}: + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 23 +```` + Later tutorials also consider other methods for working with the boundary where care needs to be taken with the boundary, or part of the boundary, being considered. For now, here is an example where we use @@ -119,56 +264,96 @@ A = \dfrac{1}{2}\sum_{i=1}^n \left(y_i + y_{i+1}\right)\left(x_i - x_{i+1}\right ``` Here is one implementation. -````@example constrained_outer_boundary +````julia function shoelace_area(tri) bn = get_boundary_nodes(tri) n = num_boundary_edges(bn) # length(bn) - 1 in this case since bn[1] = bn[end] A = 0.0 for i in 1:n vᵢ = get_boundary_nodes(bn, i) - vᵢ₊₁ = get_boundary_nodes(bn, i+1) + vᵢ₊₁ = get_boundary_nodes(bn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end - return A/2 + return A / 2 end shoelace_area(cons_tri) ```` +```` +119.20499999999998 +```` + We also provide a map that contains the edges as the keys (*not* in order), and the values are `Tuple`s `(I, J)` such that `get_boundary_nodes(get_boundary_nodes(cons_tri, I), J)` gives the corresponding edge. The first call, `bn = get_boundary_nodes(cons_tri, I)` is for obtaining the chain of boundary edges containing the boundary edge, and then `get_boundary_nodes(bn, j)` gets the actual edge. -````@example constrained_outer_boundary +````julia get_boundary_edge_map(cons_tri) ```` +```` +Dict{Tuple{Int64, Int64}, Tuple{Vector{Int64}, Int64}} with 20 entries: + (23, 24) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 1) + (40, 41) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 18) + (25, 26) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 3) + (35, 36) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 13) + (30, 31) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 8) + (29, 30) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 7) + (42, 23) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 20) + (33, 34) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 11) + (38, 39) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 16) + (27, 28) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 5) + (26, 27) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 4) + (39, 40) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 17) + (24, 25) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 2) + (28, 29) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 6) + (41, 42) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 19) + (31, 32) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 9) + (32, 33) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 10) + (34, 35) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 12) + (37, 38) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 15) + (36, 37) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 14) +```` + In our case, the `I` is just `boundary_nodes` since we only have one contiguous boundary. To give an example, take -````@example constrained_outer_boundary +````julia bem = get_boundary_edge_map(cons_tri) e, (I, J) = first(bem) ```` -````@example constrained_outer_boundary +```` +(23, 24) => ([23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 23], 1) +```` + +````julia bn = get_boundary_nodes(cons_tri, I) # same as boundary_nodes for this problem; see the later tutorials bn_j = get_boundary_nodes(bn, J) ```` +```` +23 +```` + This returns `23`, which is the start of the edge `e`. The full edge is given by -````@example constrained_outer_boundary -get_boundary_nodes.(Ref(bn), (J, J+1)) # Ref to not broadcast over bn +````julia +get_boundary_nodes.(Ref(bn), (J, J + 1)) # Ref to not broadcast over bn +```` + +```` +(23, 24) ```` To give an example, here's how we compute the perimeter of the triangulation. This only needs the edges, so we only consider the `keys` of the map. -````@example constrained_outer_boundary +````julia function get_perimeter(tri) bem = get_boundary_edge_map(tri) ℓ = 0.0 @@ -182,6 +367,10 @@ end get_perimeter(cons_tri) ```` +```` +44.23794172896859 +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_outer_boundary.jl). @@ -196,7 +385,7 @@ pts = [ (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), - (1.34, 6.77), (1.24, 4.15) + (1.34, 6.77), (1.24, 4.15), ] boundary_points = [ @@ -204,9 +393,9 @@ boundary_points = [ (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), - (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0) + (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0), ] -boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points=pts); +boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points = pts); pts @@ -216,19 +405,23 @@ tri = triangulate(pts) cons_tri = triangulate(pts; boundary_nodes) fig = Figure() -ax1 = Axis(fig[1, 1], xlabel="x", ylabel=L"y", - title="(a): Unconstrained", titlealign=:left, - width=300, height=300) -ax2 = Axis(fig[1, 2], xlabel="x", ylabel=L"y", - title="(b): Unconstrained", titlealign=:left, - width=300, height=300) +ax1 = Axis( + fig[1, 1], xlabel = "x", ylabel = L"y", + title = "(a): Unconstrained", titlealign = :left, + width = 300, height = 300, +) +ax2 = Axis( + fig[1, 2], xlabel = "x", ylabel = L"y", + title = "(b): Constrained", titlealign = :left, + width = 300, height = 300, +) triplot!(ax1, tri) -triplot!(ax2, cons_tri, show_constrained_edges=true, show_convex_hull=true) +triplot!(ax2, cons_tri, show_constrained_edges = true, show_convex_hull = true) resize_to_layout!(fig) fig -full_tri = triangulate(pts; boundary_nodes, delete_holes=false) -fig, ax, sc = triplot(full_tri, show_constrained_edges=true, show_convex_hull=true) +full_tri = triangulate(pts; boundary_nodes, delete_holes = false) +fig, ax, sc = triplot(full_tri, show_constrained_edges = true, show_convex_hull = true) get_boundary_nodes(cons_tri) @@ -238,13 +431,13 @@ function shoelace_area(tri) A = 0.0 for i in 1:n vᵢ = get_boundary_nodes(bn, i) - vᵢ₊₁ = get_boundary_nodes(bn, i+1) + vᵢ₊₁ = get_boundary_nodes(bn, i + 1) pᵢ, pᵢ₊₁ = get_point(tri, vᵢ, vᵢ₊₁) xᵢ, yᵢ = getxy(pᵢ) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) - A += (yᵢ + yᵢ₊₁)*(xᵢ - xᵢ₊₁) + A += (yᵢ + yᵢ₊₁) * (xᵢ - xᵢ₊₁) end - return A/2 + return A / 2 end shoelace_area(cons_tri) @@ -256,7 +449,7 @@ e, (I, J) = first(bem) bn = get_boundary_nodes(cons_tri, I) # same as boundary_nodes for this problem; see the later tutorials bn_j = get_boundary_nodes(bn, J) -get_boundary_nodes.(Ref(bn), (J, J+1)) # Ref to not broadcast over bn +get_boundary_nodes.(Ref(bn), (J, J + 1)) # Ref to not broadcast over bn function get_perimeter(tri) bem = get_boundary_edge_map(tri) diff --git a/docs/src/tutorials/constrained_outer_boundary_segmented.md b/docs/src/tutorials/constrained_outer_boundary_segmented.md index 233304d30..3f5350c0b 100644 --- a/docs/src/tutorials/constrained_outer_boundary_segmented.md +++ b/docs/src/tutorials/constrained_outer_boundary_segmented.md @@ -12,51 +12,83 @@ for the identification of separate parts of a boundary. This is useful, for exam if you want to assign different boundary conditions on different parts of the boundary for a differential equation problem. To start, let us load in the packages we will need. -````@example constrained_outer_boundary_segmented +````julia using DelaunayTriangulation using CairoMakie ```` Now, we define some of the points we will be triangulating. -````@example constrained_outer_boundary_segmented +````julia points = [ (2.0, 8.0), (6.0, 4.0), (2.0, 6.0), - (2.0, 4.0), (8.0, 2.0) + (2.0, 4.0), (8.0, 2.0), ] ```` +```` +5-element Vector{Tuple{Float64, Float64}}: + (2.0, 8.0) + (6.0, 4.0) + (2.0, 6.0) + (2.0, 4.0) + (8.0, 2.0) +```` + We now want to define our boundary. The method for providing a boundary to be identified into multiple sections is to provided a vector of vectors of indices, where each vector of indices is a section. The last index of each section must match the first index of the next section, including the last with the first section so that the boundary is closed. Here, we provide three . -````@example constrained_outer_boundary_segmented +````julia section_1 = [(0.0, 0.0), (14.0, 0.0)] section_2 = [(14.0, 0.0), (10.0, 4.0), (4.0, 6.0), (2.0, 12.0), (0.0, 14.0)] section_3 = [(0.0, 14.0), (0.0, 0.0)] boundary_points = [section_1, section_2, section_3] ```` +```` +3-element Vector{Vector{Tuple{Float64, Float64}}}: + [(0.0, 0.0), (14.0, 0.0)] + [(14.0, 0.0), (10.0, 4.0), (4.0, 6.0), (2.0, 12.0), (0.0, 14.0)] + [(0.0, 14.0), (0.0, 0.0)] +```` + We now convert these boundary points to indices using [`convert_boundary_points_to_indices`](@ref), and then we triangulate. We also add a constrained edge. -````@example constrained_outer_boundary_segmented +````julia E = Set(((6, 9),)) # (0, 0) → (4, 6) -boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points=points) -tri = triangulate(points; boundary_nodes, segments=E) +boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points = points) +tri = triangulate(points; boundary_nodes, segments = E) ```` -````@example constrained_outer_boundary_segmented -fig, ax, sc = triplot(tri, show_constrained_edges=true, constrained_edge_linewidth=6) -lines!(ax, section_1, color=:red, linewidth=6) -lines!(ax, section_2, color=:green, linewidth=6) -lines!(ax, section_3, color=:blue, linewidth=6) +```` +Delaunay Triangulation. + Number of vertices: 11 + Number of triangles: 14 + Number of edges: 24 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true +```` + +````julia +fig, ax, sc = triplot(tri, show_constrained_edges = true, constrained_edge_linewidth = 6) +lines!(ax, section_1, color = :red, linewidth = 6) +lines!(ax, section_2, color = :green, linewidth = 6) +lines!(ax, section_3, color = :blue, linewidth = 6) fig ```` +```@raw html + +``` + The first section is in red, the second section is in green, and the third section is in blue. We use ghost vertices to identify the sections, where the first section is identified by `-1`, the second by `-2`, and the third by `-3`. @@ -65,25 +97,51 @@ Before we go into how the sections can be worked with, let us make a note regard now that we have both constrained segments and boundary segments which might technically both be thought of as being constrained edges. If we look at `get_interior_segments(tri)`, we get: -````@example constrained_outer_boundary_segmented +````julia get_interior_segments(tri) ```` +```` +Set{Tuple{Int64, Int64}} with 1 element: + (9, 6) +```` + This is just the constrained segment we provided, and not the boundary segment. If we instead want all constrained segments, considering both the boundary segments and the segments provided, we can instead use [`get_all_segments(tri)`](@ref get_all_segments). -````@example constrained_outer_boundary_segmented +````julia get_all_segments(tri) ```` +```` +Set{Tuple{Int64, Int64}} with 7 elements: + (9, 6) + (7, 8) + (8, 9) + (9, 10) + (6, 7) + (10, 11) + (11, 6) +```` + Let us now explore the several ways available for working with this boundary. First, if we just want to work with the boundary edges without caring about the order, we can again use the boundary edge map. -````@example constrained_outer_boundary_segmented +````julia get_boundary_edge_map(tri) ```` +```` +Dict{Tuple{Int64, Int64}, Tuple{Int64, Int64}} with 6 entries: + (7, 8) => (2, 1) + (8, 9) => (2, 2) + (9, 10) => (2, 3) + (6, 7) => (1, 1) + (10, 11) => (2, 4) + (11, 6) => (3, 1) +```` + Remember that the keys are the edges, and the values are `Tuples` that give us (1) the section index, and (2) the position of the edge within that section (more specifically, the position of the first vertex of the edge). This would be useful if, for example, you don't care about the order of the edges, but you do @@ -106,7 +164,7 @@ f(x, y) = \begin{cases} ``` and $\Gamma_i$ denotes the $i$th section. -````@example constrained_outer_boundary_segmented +````julia function section_function(x, y, section_index) f = if abs(section_index) == 1 1.0 @@ -133,25 +191,47 @@ end s = compute_sum(tri) ```` +```` +2.9351669864789773 +```` + An alternative way to look at each section is to use [`get_adjacent2vertex`](@ref) with the associated ghost vertex. -````@example constrained_outer_boundary_segmented +````julia get_adjacent2vertex(tri, -1) ```` -````@example constrained_outer_boundary_segmented +```` +Set{Tuple{Int64, Int64}} with 1 element: + (7, 6) +```` + +````julia get_adjacent2vertex(tri, -2) ```` -````@example constrained_outer_boundary_segmented +```` +Set{Tuple{Int64, Int64}} with 4 elements: + (10, 9) + (8, 7) + (11, 10) + (9, 8) +```` + +````julia get_adjacent2vertex(tri, -3) ```` +```` +Set{Tuple{Int64, Int64}} with 1 element: + (6, 11) +```` + Note that the provided edges are not in order, but this is helpful for considering specific sections. For example, if we just wanted to compute the above sum over the second section, we could do -````@example constrained_outer_boundary_segmented +````julia function compute_sum_2(tri) edges = get_adjacent2vertex(tri, -2) s = 0.0 @@ -168,23 +248,44 @@ end s = compute_sum_2(tri) ```` +```` +1.1812647321356726 +```` + If your application instead wanted all the nodes on the section rather than the edges, you can look at the neighbours to the ghost vertex. For example, all the nodes on the section section can be identified using -````@example constrained_outer_boundary_segmented +````julia get_neighbours(tri, -2) ```` +```` +Set{Int64} with 5 elements: + 7 + 11 + 10 + 9 + 8 +```` + Another field is the `ghost_vertex_map`, which maps a given ghost vertex to the associated section. This is more so useful for internal methods, but you may sometimes need it. -````@example constrained_outer_boundary_segmented +````julia get_ghost_vertex_map(tri) ```` +```` +Dict{Int64, Int64} with 3 entries: + -1 => 1 + -3 => 3 + -2 => 2 +```` + In this case, the `i`th section just has the ghost vertex `-i`, but this is typically used to deal with the case of multiple boundaries so that we know where a ghost vertex belongs. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/constrained_outer_boundary_segmented.jl). @@ -195,7 +296,7 @@ using CairoMakie points = [ (2.0, 8.0), (6.0, 4.0), (2.0, 6.0), - (2.0, 4.0), (8.0, 2.0) + (2.0, 4.0), (8.0, 2.0), ] section_1 = [(0.0, 0.0), (14.0, 0.0)] @@ -204,13 +305,13 @@ section_3 = [(0.0, 14.0), (0.0, 0.0)] boundary_points = [section_1, section_2, section_3] E = Set(((6, 9),)) # (0, 0) → (4, 6) -boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points=points) -tri = triangulate(points; boundary_nodes, segments=E) +boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points = points) +tri = triangulate(points; boundary_nodes, segments = E) -fig, ax, sc = triplot(tri, show_constrained_edges=true, constrained_edge_linewidth=6) -lines!(ax, section_1, color=:red, linewidth=6) -lines!(ax, section_2, color=:green, linewidth=6) -lines!(ax, section_3, color=:blue, linewidth=6) +fig, ax, sc = triplot(tri, show_constrained_edges = true, constrained_edge_linewidth = 6) +lines!(ax, section_1, color = :red, linewidth = 6) +lines!(ax, section_2, color = :green, linewidth = 6) +lines!(ax, section_3, color = :blue, linewidth = 6) fig get_interior_segments(tri) diff --git a/docs/src/tutorials/convex.md b/docs/src/tutorials/convex.md index cdd107500..fa098deb8 100644 --- a/docs/src/tutorials/convex.md +++ b/docs/src/tutorials/convex.md @@ -8,24 +8,40 @@ In this tutorial, we show how we can triangulate convex polygons. The function [`triangulate_convex`](@ref) is used for this. Let us start with a simple example. -````@example convex +````julia using DelaunayTriangulation using CairoMakie points = [ (10.0, 12.0), (7.0, 11.0), (8.0, 6.0), (10.0, 3.0), (14.0, 5.0), (15.0, 10.0), - (13.0, 12.0) + (13.0, 12.0), ] S = 1:7 tri = triangulate_convex(points, 1:7) ```` -````@example convex +```` +Delaunay Triangulation. + Number of vertices: 7 + Number of triangles: 5 + Number of edges: 11 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + +````julia fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This `tri` is our triangulation of the convex polygon. The first input is the set of points, and `S` defines the vertices to take from these points and their order, @@ -37,7 +53,7 @@ needed. Let us give a larger example. For simplicity, we triangulate a a discretised circle. -````@example convex +````julia θ = LinRange(0, 2π, 5000) |> collect pop!(θ) x = cos.(θ) @@ -47,25 +63,68 @@ S = 1:4999 # can also be [1:4999; 1], if you want the array to be circular tri = triangulate_convex(points, S) ```` -````@example convex +```` +Delaunay Triangulation. + Number of vertices: 4999 + Number of triangles: 4997 + Number of edges: 9995 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + +````julia fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Here is a comparison of the time it takes to triangulate this using `triangulate_convex` or `triangulate`. -````@example convex +````julia using BenchmarkTools @benchmark triangulate_convex($points, $S) ```` -````@example convex +```` +BenchmarkTools.Trial: 49 samples with 1 evaluation. + Range (min … max): 61.349 ms … 338.656 ms ┊ GC (min … max): 0.00% … 44.59% + Time (median): 85.144 ms ┊ GC (median): 0.00% + Time (mean ± σ): 103.635 ms ± 51.628 ms ┊ GC (mean ± σ): 11.47% ± 13.37% + + ▃▃█ + ▅▁████▇▃▁▅▅▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▆▅▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃ ▁ + 61.3 ms Histogram: frequency by time 339 ms < + + Memory estimate: 29.99 MiB, allocs estimate: 570415. +```` + +````julia @benchmark triangulate($points) ```` -For the smaller example that we started above, `triangulate_convex` is also +```` +BenchmarkTools.Trial: 11 samples with 1 evaluation. + Range (min … max): 380.657 ms … 633.560 ms ┊ GC (min … max): 0.00% … 0.00% + Time (median): 460.345 ms ┊ GC (median): 0.00% + Time (mean ± σ): 483.507 ms ± 83.921 ms ┊ GC (mean ± σ): 0.00% ± 0.00% + + ▁▁ █▁ ▁ ▁ █ ▁ ▁ + ██▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▁▁█▁▁▁▁▁▁▁█▁▁▁▁▁▁▁▁▁▁▁▁▁█ ▁ + 381 ms Histogram: frequency by time 634 ms < + + Memory estimate: 33.77 MiB, allocs estimate: 630415. +```` + +For the smaller example that we started with above, `triangulate_convex` is also faster, although not by much (≈15.10 μs versus ≈10.7 μs). + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/convex.jl). @@ -77,7 +136,7 @@ using CairoMakie points = [ (10.0, 12.0), (7.0, 11.0), (8.0, 6.0), (10.0, 3.0), (14.0, 5.0), (15.0, 10.0), - (13.0, 12.0) + (13.0, 12.0), ] S = 1:7 tri = triangulate_convex(points, 1:7) diff --git a/docs/src/tutorials/convex_hull.md b/docs/src/tutorials/convex_hull.md index a4a2dec5d..f09706319 100644 --- a/docs/src/tutorials/convex_hull.md +++ b/docs/src/tutorials/convex_hull.md @@ -13,7 +13,7 @@ from the point set directly, using the [monotone chain algorithm](https://en.wik Let us first demonstrate how we compute convex hulls from a triangulation. This is only possible from triangulations without a constrained boundary -````@example convex_hull +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -21,37 +21,83 @@ using StableRNGs We construct a triangulation of a point set. -````@example convex_hull +````julia rng = StableRNG(123) points = randn(rng, 2, 250) tri = triangulate(points; rng) ```` +```` +Delaunay Triangulation. + Number of vertices: 250 + Number of triangles: 489 + Number of edges: 738 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + To get the convex hull, just use [`get_convex_hull`](@ref): -````@example convex_hull +````julia get_convex_hull(tri) ```` +```` +Convex hull. + Vertices: +10-element Vector{Int64}: + 151 + 96 + 43 + 159 + 25 + 147 + 65 + 206 + 199 + 151 +```` + You can also obtain the vertices directly from [`get_convex_hull_vertices`](@ref): -````@example convex_hull +````julia get_convex_hull_vertices(tri) ```` +```` +10-element Vector{Int64}: + 151 + 96 + 43 + 159 + 25 + 147 + 65 + 206 + 199 + 151 +```` + The vertices refer to indices of points in `points`, and they are given in counter-clockwise order. To obtain the convex hull directly from the points without constructing the triangulation, use [`convex_hull`](@ref): -````@example convex_hull +````julia ch = convex_hull(points) ch_points = [get_point(tri, i) for i in DelaunayTriangulation.get_vertices(ch)] -fig, ax, sc = lines(ch_points, color=:red, linewidth=4) +fig, ax, sc = lines(ch_points, color = :red, linewidth = 4) scatter!(ax, points) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/convex_hull.jl). @@ -71,7 +117,7 @@ get_convex_hull_vertices(tri) ch = convex_hull(points) ch_points = [get_point(tri, i) for i in DelaunayTriangulation.get_vertices(ch)] -fig, ax, sc = lines(ch_points, color=:red, linewidth=4) +fig, ax, sc = lines(ch_points, color = :red, linewidth = 4) scatter!(ax, points) fig ``` diff --git a/docs/src/tutorials/curve_bounded.md b/docs/src/tutorials/curve_bounded.md index 889dce4c4..cfa62b093 100644 --- a/docs/src/tutorials/curve_bounded.md +++ b/docs/src/tutorials/curve_bounded.md @@ -10,7 +10,7 @@ of functions introduced in the [refinement tutorial](../tutorials/refinement.md) Let us start by loading in the packages we will need. -````@example curve_bounded +````julia using DelaunayTriangulation using DelaunayTriangulation: EllipticalArc # CairoMakie also exports this using CairoMakie @@ -38,58 +38,2589 @@ We start with a simple domain: a circle. In particular, we consider a circle of radius $r = 2$ centered at $(x, y) = (1/2, 2)$. In past tutorials, we would have defined a domain like this by a set of points around a boundary, e.g.: -````@example curve_bounded +````julia n = 50 r = 2.0 xc, yc = 1 / 2, 2.0 -θ = range(0, 2π, length=n + 1) |> collect; +θ = range(0, 2π, length = n + 1) |> collect; θ[end] = θ[begin]; x = xc .+ r * cos.(θ) y = yc .+ r * sin.(θ); -nothing #hide ```` One problem with this approach is that we had to decide what value of $n$ to use for discretising this boundary. Instead, we can use `CircularArc`. For this, we use: -````@example curve_bounded +````julia p = (xc + r, yc) c = (xc, yc) arc = CircularArc(p, p, c) ```` +```` +(::CircularArc) (generic function with 1 method) +```` + Here, the syntax is `CircularArc(first_point, last_point, centre)`. Since the circle is closed, we use `p` for both `first_point` and `last_point`. Notice that the `arc` is a function. In particular, -````@example curve_bounded -typeof(arc) |> supertype +````julia +typeof(arc) |> supertype |> supertype +```` + +```` +Function ```` If we wanted to look at this circle, we would need to evaluate it at a set of $t \in [0, 1]$. -````@example curve_bounded +````julia t = LinRange(0, 1, 2500) points = arc.(t) ```` -````@example curve_bounded +```` +2500-element Vector{Tuple{Float64, Float64}}: + (2.5, 2.0) + (2.4999936784002426, 2.00502855437152) + (2.499974713640933, 2.0100570769545323) + (2.4999431058419583, 2.015085535960729) + (2.4998988552031305, 2.0201138996022054) + (2.499841962004185, 2.0251421360916586) + (2.4997724266047774, 2.0301702136425908) + (2.499690249444483, 2.0351981004695077) + (2.4995954310427924, 2.0402257647881212) + (2.49948797199911, 2.0452531748155494) + (2.4993678729927487, 2.0502802987705193) + (2.499235134782926, 2.055307104873564) + (2.4990897582087603, 2.0603335613472287) + (2.498931744189264, 2.065359636416266) + (2.4987610937233384, 2.070385298307842) + (2.4985778078897676, 2.0754105152517326) + (2.498381887847211, 2.0804352554805288) + (2.4981733348341963, 2.0854594872298335) + (2.4979521501691133, 2.0904831787384643) + (2.497718335250202, 2.0955062982486545) + (2.4974718915555476, 2.100528814006253) + (2.4972128206430675, 2.105550694260925) + (2.4969411241505046, 2.1105719072663534) + (2.4966568037954158, 2.1155924212804402) + (2.4963598613751605, 2.1206122045655045) + (2.496050298766889, 2.1256312253884855) + (2.4957281179275332, 2.1306494520211428) + (2.4953933208937915, 2.135666852740256) + (2.495045909782116, 2.1406833958278253) + (2.494685886788701, 2.1456990495712738) + (2.494313254189468, 2.150713782263646) + (2.4939280143400513, 2.155727562203809) + (2.493530169675782, 2.1607403576966524) + (2.493119722711676, 2.165752137053289) + (2.4926966760424136, 2.170762868591257) + (2.492261032342328, 2.175772520634716) + (2.491812794365383, 2.1807810615146512) + (2.49135196494516, 2.1857884595690718) + (2.490878546994839, 2.1907946831432112) + (2.490392543507178, 2.1957997005897285) + (2.4898939575544965, 2.2008034802689056) + (2.489382792288655, 2.2058059905488503) + (2.488859050941037, 2.2108071998056955) + (2.488322736822524, 2.2158070764237974) + (2.487773853323481, 2.2208055887959373) + (2.4872124039137287, 2.2258027053235208) + (2.4866383921425252, 2.2307983944167766) + (2.486051821638544, 2.235792624494959) + (2.485452696109849, 2.240785363986543) + (2.4848410193438717, 2.2457765813294284) + (2.4842167952073875, 2.2507662449711368) + (2.483580027646492, 2.255754323369012) + (2.482930720686575, 2.2607407849904186) + (2.4822688784322953, 2.265725598312942) + (2.481594505067554, 2.2707087318245875) + (2.48090760485547, 2.27569015402398) + (2.4802081821383517, 2.280669833420561) + (2.479496241337669, 2.2856477385347915) + (2.4787717869540273, 2.2906238378983472) + (2.4780348235671372, 2.29559810005432) + (2.4772853558357864, 2.300570493557415) + (2.4765233884978093, 2.3055409869741506) + (2.475748926370059, 2.3105095488830574) + (2.474961974348375, 2.315476147874875) + (2.474162537407552, 2.320440752552753) + (2.4733506206013125, 2.325403331532447) + (2.4725262290622676, 2.3303638534425195) + (2.4716893680018917, 2.3353222869245363) + (2.470840042710485, 2.3402786006332654) + (2.4699782585571426, 2.345232763236875) + (2.469104020989718, 2.3501847434171323) + (2.468217335534793, 2.355134509869601) + (2.4673182077976357, 2.3600820313038375) + (2.466406643462174, 2.365027276443593) + (2.4654826482909513, 2.3699702140270054) + (2.464546228125096, 2.374910812806803) + (2.4635973888842813, 2.3798490415504974) + (2.4626361365666893, 2.384784869040583) + (2.461662477248973, 2.389718264074733) + (2.4606764170862157, 2.394649195466) + (2.459677962311895, 2.3995776320430084) + (2.4586671192378438, 2.404503542650155) + (2.4576438942542067, 2.4094268961478047) + (2.456608293829402, 2.414347661412487) + (2.4555603245100817, 2.419265807337093) + (2.454499992921088, 2.4241813028310735) + (2.4534273057654135, 2.4290941168206324) + (2.452342269824156, 2.4340042182489268) + (2.4512448919564793, 2.4389115760762605) + (2.450135179099567, 2.443816159280281) + (2.4490131382685796, 2.4487179368561764) + (2.4478787765566095, 2.4536168778168714) + (2.446732101134638, 2.4585129511932218) + (2.4455731192514882, 2.4634061260342106) + (2.4444018382337793, 2.468296371407146) + (2.4432182654858816, 2.473183656397853) + (2.4420224084898683, 2.4780679501108724) + (2.4408142748054678, 2.4829492216696547) + (2.439593872070019, 2.4878274402167544) + (2.4383612079984185, 2.492702574914026) + (2.437116290383076, 2.4975745949428196) + (2.4358591270938614, 2.5024434695041746) + (2.434589726078059, 2.507309167819015) + (2.433308095360313, 2.5121716591283425) + (2.4320142430425804, 2.5170309126934343) + (2.4307081773040773, 2.5218868977960334) + (2.429389906401229, 2.5267395837385465) + (2.428059438667616, 2.531588939844234) + (2.4267167825139238, 2.536434935457409) + (2.425361946427886, 2.541277539943626) + (2.4239949389742343, 2.5461167226898773) + (2.4226157687946435, 2.550952453104787) + (2.4212244446076747, 2.555784700618803) + (2.4198209752087223, 2.5606134346843907) + (2.4184053694699594, 2.565438624776225) + (2.4169776363402775, 2.570260240391386) + (2.415537784845235, 2.5750782510495505) + (2.4140858240869965, 2.579892626293182) + (2.4126217632442764, 2.5847033356877276) + (2.4111456115722816, 2.5895103488218085) + (2.409657378402652, 2.5943136353074108) + (2.4081570731434025, 2.5991131647800807) + (2.406644705278862, 2.6039089068991133) + (2.405120284369615, 2.6087008313477464) + (2.4035838200524404, 2.613488907833352) + (2.40203532204025, 2.618273106087626) + (2.40047480012203, 2.623053395866783) + (2.398902264162774, 2.6278297469517438) + (2.3973177241034254, 2.6326021291483284) + (2.3957211899608124, 2.6373705122874465) + (2.3941126718275845, 2.642134866225289) + (2.3924921798721495, 2.646895160843517) + (2.3908597243386094, 2.6516513660494527) + (2.3892153155466946, 2.656403451776271) + (2.387558963891699, 2.661151387983188) + (2.3858906798444153, 2.665895144655651) + (2.3842104739510668, 2.6706346918055286) + (2.382518356833243, 2.675369999471301) + (2.3808143391878316, 2.6801010377182495) + (2.37909843178695, 2.684827776638642) + (2.3773706454778774, 2.689550186351928) + (2.3756309911829874, 2.6942682370049233) + (2.3738794798996787, 2.698981898772) + (2.3721161227003043, 2.7036911418552747) + (2.370340930732102, 2.708395936484798) + (2.3685539152171264, 2.713096252918741) + (2.366755087452173, 2.717792061443584) + (2.3649444588087114, 2.722483332374306) + (2.3631220407328115, 2.7271700360545688) + (2.361287844745071, 2.7318521428569085) + (2.3594418824405423, 2.736529623182919) + (2.3575841654886602, 2.7412024474634427) + (2.3557147056331686, 2.7458705861587536) + (2.3538335146920435, 2.750534009758748) + (2.351940604557422, 2.755192688783129) + (2.350035987195523, 2.759846593781591) + (2.3481196746465764, 2.7644956953340105) + (2.3461916790247432, 2.7691399640506273) + (2.344252012518039, 2.7737793705722344) + (2.34230068738826, 2.7784138855703597) + (2.340337715970902, 2.7830434797474553) + (2.3383631106750853, 2.7876681238370784) + (2.3363768839834744, 2.7922877886040816) + (2.334379048452198, 2.7969024448447923) + (2.332369616710775, 2.801512063387201) + (2.3303486014620267, 2.806116615091144) + (2.3283160154820033, 2.8107160708484886) + (2.3262718716199, 2.815310401583316) + (2.3242161827979757, 2.819899578252107) + (2.3221489620114726, 2.8244835718439227) + (2.320070222328533, 2.829062353380591) + (2.317979976890118, 2.8336358939168864) + (2.3158782389099213, 2.8382041645407177) + (2.31376502167429, 2.8427671363733054) + (2.311640338542138, 2.847324780569368) + (2.3095042029448605, 2.851877068317304) + (2.307356628386253, 2.8564239708393706) + (2.305197628442422, 2.8609654593918714) + (2.3030272167617003, 2.8655015052653328) + (2.3008454070645623, 2.8700320797846883) + (2.2986522131435363, 2.874557154309459) + (2.296447648863116, 2.8790767002339352) + (2.2942317281596734, 2.883590688987357) + (2.292004465041374, 2.8880990920340928) + (2.2897658735880824, 2.892601880873824) + (2.287515967951278, 2.8970990270417216) + (2.285254762353965, 2.9015905021086272) + (2.282982271090579, 2.906076277681234) + (2.2806985085269007, 2.910556325402263) + (2.2784034890999623, 2.915030616950646) + (2.2760972273179587, 2.919499124041703) + (2.2737797377601536, 2.923961818427321) + (2.2714510350767885, 2.928418671896131) + (2.2691111339889893, 2.93286965627369) + (2.2667600492886746, 2.937314743422656) + (2.264397795838461, 2.9417539052429675) + (2.262024388571569, 2.9461871136720204) + (2.2596398424917297, 2.950614340684844) + (2.2572441726730883, 2.955035558294283) + (2.254837394260112, 2.959450738551168) + (2.2524195224674886, 2.9638598535444967) + (2.249990572580038, 2.968262875401609) + (2.2475505599526073, 2.972659776288363) + (2.245099500009981, 2.977050528409311) + (2.242637408246779, 2.9814351040078755) + (2.240164300227359, 2.985813475366525) + (2.2376801915857207, 2.9901856148069474) + (2.235185098025405, 2.994551494690227) + (2.2326790353193946, 2.9989110874170195) + (2.2301620193100145, 3.003264365427724) + (2.2276340659088323, 3.007611301202659) + (2.2250951910965586, 3.011951867262237) + (2.222545410922943, 3.016286036167136) + (2.219984741506676, 3.0206137805184756) + (2.217413199035283, 3.0249350729579874) + (2.2148307997650285, 3.0292498861681905) + (2.2122375600208057, 3.033558192872563) + (2.2096334961960387, 3.037859965835714) + (2.2070186247525765, 3.042155177863557) + (2.2043929622205907, 3.04644380180348) + (2.2017565251984674, 3.0507258105445194) + (2.199109330352708, 3.05500117701753) + (2.1964513944178172, 3.0592698741953552) + (2.193782734196203, 3.063531875093001) + (2.1911033665580675, 3.067787152767803) + (2.1884133084412998, 3.072035680319599) + (2.1857125768513708, 3.0762774308908982) + (2.1830011888612244, 3.080512377667051) + (2.180279161611171, 3.08474049387642) + (2.1775465123087776, 3.0889617527905453) + (2.174803258228758, 3.0931761277243184) + (2.172049416712868, 3.097383592036148) + (2.1692850051697903, 3.1015841191281277) + (2.1665100410750293, 3.105777682446207) + (2.1637245419707964, 3.1099642554803575) + (2.160928525465902, 3.1141438117647398) + (2.158122009235645, 3.1183163248778714) + (2.155305011021695, 3.1224817684427952) + (2.15247754863199, 3.126640116127244) + (2.149639639940614, 3.130791341643808) + (2.1467913028876895, 3.1349354187501) + (2.1439325554792648, 3.139072321248925) + (2.1410634157871957, 3.1432020229884396) + (2.1381839019490356, 3.147324497862323) + (2.135294032167918, 3.1514397198099395) + (2.1323938247124437, 3.1555476628165025) + (2.129483297916562, 3.15964830091324) + (2.1265624701794605, 3.16374160817756) + (2.123631359965441, 3.167827558733211) + (2.1206899858038106, 3.171906126750451) + (2.117738366288759, 3.175977286446204) + (2.114776520079243, 3.180041012084228) + (2.11180446589887, 3.1840972779752765) + (2.1088222225357756, 3.188146058477259) + (2.1058298088425094, 3.1921873279954074) + (2.1028272437359132, 3.196221060982432) + (2.0998145461970017, 3.2002472319386874) + (2.096791735270843, 3.2042658154123322) + (2.093758830066438, 3.208276785999491) + (2.0907158497565987, 3.212280118344412) + (2.0876628135778303, 3.2162757871396304) + (2.084599740830204, 3.2202637671261285) + (2.0815266508772403, 3.224244033093492) + (2.0784435631457843, 3.2282165598800727) + (2.075350497125882, 3.2321813223731466) + (2.0722474723706594, 3.236138295509072) + (2.0691345084961963, 3.2400874542734472) + (2.0660116251814054, 3.2440287737012734) + (2.0628788421679043, 3.247962228877105) + (2.059736179259893, 3.2518877949352127) + (2.0565836563240296, 3.2558054470597404) + (2.0534212932893023, 3.259715160484858) + (2.0502491101469036, 3.263616910494923) + (2.047067126950106, 3.267510672424632) + (2.0438753638141343, 3.2713964216591824) + (2.040673840916037, 3.275274133634422) + (2.0374625784945604, 3.2791437838370077) + (2.0342415968500207, 3.2830053478045595) + (2.031010916344174, 3.286858801125816) + (2.02777055740009, 3.290704119440787) + (2.024520540502021, 3.29454127844091) + (2.021260886195273, 3.2983702538692006) + (2.0179916150860757, 3.30219102152041) + (2.014712747841452, 3.306003557241173) + (2.0114243051890894, 3.309807836930165) + (2.008126307917206, 3.3136038365382534) + (2.0048187768744192, 3.3173915320686467) + (2.0015017329696185, 3.3211708995770506) + (1.998175197171826, 3.324941915171816) + (1.9948391905100709, 3.328704555014092) + (1.9914937340732513, 3.332458795317975) + (1.988138849010004, 3.3362046123506612) + (1.98477455652857, 3.3399419824325935) + (1.9814008778966594, 3.343670881937615) + (1.9780178344413182, 3.3473912872931146) + (1.9746254475487934, 3.351103174980179) + (1.971223738664397, 3.3548065215337406) + (1.9678127292923708, 3.3585013035427242) + (1.9643924409957514, 3.362187497650197) + (1.9609628953962321, 3.3658650805535144) + (1.9575241141740274, 3.36953402900447) + (1.954076119067736, 3.37319431980944) + (1.9506189318742029, 3.376845929829531) + (1.947152574448382, 3.380488835980726) + (1.9436770687031972, 3.3841230152340303) + (1.9401924366094052, 3.387748444615617) + (1.9366987001954552, 3.391365101206973) + (1.9331958815473504, 3.394972962145042) + (1.9296840028085085, 3.3985720046223724) + (1.9261630861796208, 3.402162205887257) + (1.9226331539185137, 3.405743543243881) + (1.9190942283400056, 3.4093159940524638) + (1.915546331815768, 3.4128795357293997) + (1.9119894867741825, 3.416434145747405) + (1.9084237157001995, 3.4199798016356584) + (1.904849041135197, 3.4235164809799423) + (1.901265485676837, 3.427044161422785) + (1.897673071978922, 3.430562820663603) + (1.8940718227512545, 3.43407243645884) + (1.8904617607594907, 3.4375729866221114) + (1.8868429088249967, 3.441064449024339) + (1.883215289824707, 3.444546801593895) + (1.8795789266909766, 3.44802002231674) + (1.8759338424114373, 3.451484089236564) + (1.872280060028854, 3.454938980454921) + (1.8686176026409755, 3.458384674131372) + (1.8649464934003928, 3.4618211484836205) + (1.861266755514388, 3.4652483817876516) + (1.8575784122447914, 3.468666352377868) + (1.8538814869078337, 3.4720750386472266) + (1.8501760028739964, 3.4754744190473783) + (1.8464619835678666, 3.4788644720888002) + (1.8427394524679885, 3.4822451763409337) + (1.8390084331067131, 3.4856165104323207) + (1.8352689490700513, 3.488978453050735) + (1.8315210239975255, 3.492330982943322) + (1.827764681582017, 3.495674078916729) + (1.8239999455696192, 3.499007719837241) + (1.8202268397594867, 3.5023318846309155) + (1.8164453880036846, 3.5056465522837117) + (1.8126556142070362, 3.508951701841629) + (1.808857542326976, 3.5122473124108335) + (1.8050511963733935, 3.515533363157794) + (1.801236600408484, 3.5188098333094144) + (1.7974137785465976, 3.5220767021531603) + (1.793582754954083, 3.5253339490371953) + (1.7897435538491384, 3.5285815533705076) + (1.7858961995016567, 3.5318194946230435) + (1.7820407162330723, 3.535047752325833) + (1.7781771284162065, 3.538266306071124) + (1.774305460475116, 3.541475135512507) + (1.7704257368849357, 3.5446742203650476) + (1.7665379821717249, 3.5478635404054115) + (1.7626422209123134, 3.551043075471994) + (1.7587384777341444, 3.5542128054650464) + (1.7548267773151194, 3.5573727103468045) + (1.7509071443834436, 3.5605227701416147) + (1.7469796037174672, 3.56366296493606) + (1.74304418014553, 3.5667932748790845) + (1.7391008985458056, 3.5699136801821227) + (1.7351497838461412, 3.5730241611192213) + (1.7311908610239026, 3.576124698027165) + (1.7272241551058158, 3.579215271305599) + (1.7232496911678077, 3.5822958614171574) + (1.719267494334848, 3.585366448887582) + (1.7152775897807926, 3.588427014305847) + (1.71128000272822, 3.591477538324284) + (1.7072747584482757, 3.594518001658701) + (1.7032618822605117, 3.5975483850885053) + (1.6992413995327242, 3.6005686694568255) + (1.6952133356807961, 3.6035788356706338) + (1.6911777161685355, 3.6065788647008628) + (1.687134566507513, 3.6095687375825296) + (1.6830839122569026, 3.6125484354148565) + (1.6790257790233196, 3.6155179393613848) + (1.6749601924606579, 3.618477230650099) + (1.6708871782699282, 3.621426290573545) + (1.6668067621990965, 3.6243651004889452) + (1.66271897004292, 3.62729364181832) + (1.658623827642784, 3.6302118960486043) + (1.6545213608865406, 3.6331198447317608) + (1.6504115957083418, 3.6360174694849032) + (1.646294558088479, 3.6389047519904074) + (1.6421702740532154, 3.6417816739960287) + (1.6380387696746246, 3.644648217315018) + (1.633900071070423, 3.6475043638262354) + (1.6297542044038076, 3.6503500954742663) + (1.6256011958832874, 3.6531853942695336) + (1.62144107176252, 3.6560102422884135) + (1.6172738583401458, 3.6588246216733475) + (1.6130995819596197, 3.661628514632955) + (1.6089182690090458, 3.6644219034421477) + (1.6047299459210116, 3.667204770442239) + (1.6005346391724196, 3.6699770980410578) + (1.5963323752843188, 3.6727388687130587) + (1.5921231808217406, 3.675490064999433) + (1.5879070823935275, 3.6782306695082183) + (1.5836841066521659, 3.6809606649144104) + (1.5794542802936185, 3.683680033960071) + (1.5752176300571548, 3.686388759454437) + (1.5709741827251813, 3.689086824274031) + (1.5667239651230744, 3.691774211362765) + (1.5624670041190083, 3.694450903732055) + (1.5582033266237862, 3.6971168844609235) + (1.5539329595906717, 3.6997721366961063) + (1.5496559300152153, 3.702416643652162) + (1.5453722649350858, 3.7050503886115767) + (1.5410819914299003, 3.707673354924868) + (1.5367851366210503, 3.710285526010692) + (1.5324817276715315, 3.7128868853559505) + (1.528171791785774, 3.7154774165158897) + (1.5238553562094668, 3.7180571031142087) + (1.5195324482293877, 3.720625928843161) + (1.5152030951732316, 3.7231838774636588) + (1.510867324409435, 3.725730932805375) + (1.5065251633470054, 3.7282670787668453) + (1.5021766394353475, 3.730792299315569) + (1.4978217801640885, 3.733306578488113) + (1.4934606130629065, 3.735809900390211) + (1.4890931657013537, 3.738302249196863) + (1.4847194656886842, 3.740783609152439) + (1.4803395406736795, 3.7432539645707736) + (1.4759534183444725, 3.745713299835268) + (1.4715611264283721, 3.7481615993989896) + (1.4671626926916908, 3.7505988477847683) + (1.4627581449395661, 3.753025029585295) + (1.4583475110157853, 3.7554401294632207) + (1.4539308188026117, 3.7578441321512495) + (1.4495080962206055, 3.7602370224522383) + (1.4450793712284478, 3.762618785239293) + (1.4406446718227668, 3.7649894054558626) + (1.4362040260379563, 3.7673488681158345) + (1.4317574619460016, 3.7696971583036305) + (1.4273050076563019, 3.7720342611742996) + (1.4228466913154905, 3.774360161953613) + (1.4183825411072588, 3.776674845938157) + (1.4139125852521781, 3.778978298495426) + (1.4094368520075204, 3.7812705050639144) + (1.404955369667079, 3.78355145115321) + (1.4004681665609926, 3.785821122344084) + (1.3959752710555626, 3.788079504288585) + (1.3914767115530766, 3.790326582710125) + (1.386972516491627, 3.7925623434035733) + (1.3824627143449322, 3.794786772235347) + (1.3779473336221562, 3.796999855143496) + (1.3734264028677292, 3.7992015781377972) + (1.3688999506611657, 3.8013919272998375) + (1.3643680056168843, 3.803570888783108) + (1.359830596384029, 3.8057384488130848) + (1.3552877516462836, 3.8078945936873216) + (1.3507395001216946, 3.8100393097755334) + (1.3461858705624885, 3.8121725835196836) + (1.3416268917548881, 3.8142944014340685) + (1.3370625925189326, 3.8164047501054066) + (1.3324930017082957, 3.818503616192916) + (1.3279181482101008, 3.820590986428406) + (1.3233380609447407, 3.8226668476163583) + (1.3187527688656946, 3.824731186634009) + (1.3141623009593433, 3.8267839904314322) + (1.3095666862447874, 3.828825246031625) + (1.3049659537736646, 3.8308549405305854) + (1.3003601326299634, 3.8328730610973984) + (1.2957492519298417, 3.8348795949743124) + (1.2911333408214423, 3.836874529476824) + (1.2865124284847074, 3.8388578519937555) + (1.2818865441311948, 3.840829549987336) + (1.277255717003895, 3.842789610993279) + (1.272619976377043, 3.8447380226208647) + (1.2679793515559352, 3.8466747725530137) + (1.2633338718767453, 3.8485998485463684) + (1.2586835667063363, 3.850513238431369) + (1.2540284654420755, 3.85241493011233) + (1.2493685975116506, 3.8543049115675183) + (1.2447039923728815, 3.856183170849227) + (1.2400346795135344, 3.8580496960838535) + (1.2353606884511374, 3.8599044754719714) + (1.2306820487327905, 3.861747497288408) + (1.225998789934981, 3.863578749882318) + (1.2213109416633974, 3.865398221677254) + (1.2166185335527402, 3.8672059011712445) + (1.2119215952665345, 3.869001776936863) + (1.2072201564969454, 3.870785837621302) + (1.202514246964586, 3.872558071946443) + (1.1978038964183337, 3.874318468708931) + (1.193089134635139, 3.876067016780241) + (1.1883699914198385, 3.8778037051067535) + (1.1836464966049676, 3.879528522709819) + (1.178918680050569, 3.881241458685831) + (1.1741865716440079, 3.8829425022062938) + (1.1694502012997785, 3.884631642517892) + (1.1647095989593192, 3.886308868942555) + (1.1599647945908205, 3.8879741708775297) + (1.1552158181890357, 3.889627537795444) + (1.1504626997750944, 3.8912689592443734) + (1.1457054693963076, 3.8928984248479086) + (1.1409441571259817, 3.894515924305221) + (1.1361787930632279, 3.896121447391125) + (1.1314094073327703, 3.8977149839561473) + (1.126636030084756, 3.899296523926587) + (1.121858691494566, 3.900866057304582) + (1.117077421762623, 3.9024235741681697) + (1.1122922511141997, 3.9039690646713527) + (1.1075032097992306, 3.905502519044158) + (1.1027103280921178, 3.907023927592701) + (1.0979136362915407, 3.9085332806992463) + (1.0931131647202659, 3.9100305688222665) + (1.0883089437249527, 3.9115157824965063) + (1.0835010036759631, 3.912988912333039) + (1.0786893749671709, 3.9144499490193274) + (1.0738740880157658, 3.915898883319282) + (1.0690551732620648, 3.917335706073321) + (1.0642326611693191, 3.9187604081984255) + (1.0594065822235188, 3.9201729806881986) + (1.0545769669332046, 3.9215734146129226) + (1.0497438458292705, 3.9229617011196147) + (1.0449072494647735, 3.9243378314320836) + (1.040067208414741, 3.925701796850984) + (1.0352237532759747, 3.9270535887538722) + (1.030376914666859, 3.9283931985952614) + (1.0255267232271685, 3.929720617906674) + (1.0206732096178723, 3.9310358382966957) + (1.0158164045209397, 3.932338851451031) + (1.0109563386391498, 3.9336296491325515) + (1.0060930426958934, 3.934908223181351) + (1.0012265474349809, 3.936174565514796) + (0.9963568836204479, 3.937428668127577) + (0.9914840820363597, 3.9386705230917594) + (0.9866081734866174, 3.9399001225568338) + (0.9817291887947641, 3.9411174587497633) + (0.9768471588037876, 3.9423225239750366) + (0.9719621143759273, 3.943515310614713) + (0.9670740863924796, 3.944695811128473) + (0.9621831057536001, 3.9458640180536655) + (0.957289203378112, 3.947019924005353) + (0.9523924102033061, 3.9481635216763618) + (0.94749275718475, 3.949294803837324) + (0.9425902752960889, 3.9504137633367264) + (0.93768499552885, 3.951520393100956) + (0.9327769488922502, 3.952614686134342) + (0.9278661664129947, 3.9536966355192016) + (0.9229526791350857, 3.9547662344158834) + (0.9180365181196231, 3.9558234760628124) + (0.9131177144446083, 3.956868353776529) + (0.9081962992047505, 3.957900860951735) + (0.9032723035112667, 3.9589209910613334) + (0.8983457584916864, 3.95992873765647) + (0.8934166952896563, 3.9609240943665736) + (0.8884851450647405, 3.9619070548993975) + (0.8835511389922255, 3.9628776130410595) + (0.8786147082629238, 3.9638357626560783) + (0.8736758840829741, 3.9647814976874165) + (0.8687346976736456, 3.9657148121565156) + (0.8637911802711424, 3.9666357001633346) + (0.8588453631264021, 3.9675441558863884) + (0.853897277504901, 3.968440173582784) + (0.8489469546864565, 3.9693237475882546) + (0.8439944259650278, 3.970194872317201) + (0.8390397226485191, 3.9710535422627196) + (0.8340828760585823, 3.971899751996644) + (0.8291239175304173, 3.972733496169574) + (0.8241628784125745, 3.9735547695109137) + (0.8191997900667587, 3.9743635668289) + (0.8142346838676273, 3.975159883010642) + (0.8092675912025942, 3.975943713022146) + (0.8042985434716319, 3.976715051908353) + (0.7993275720870711, 3.9774738947931674) + (0.7943547084734026, 3.978220236879488) + (0.789379984067081, 3.978954073449239) + (0.7844034303163222, 3.979675399863399) + (0.7794250786809069, 3.9803842115620314) + (0.7744449606319823, 3.9810805040643125) + (0.7694631076518613, 3.981764272968559) + (0.7644795512338238, 3.9824355139522583) + (0.7594943228819198, 3.9830942227720936) + (0.7545074541107673, 3.983740395263971) + (0.7495189764453539, 3.984374027343047) + (0.7445289214208402, 3.984995115003753) + (0.7395373205823557, 3.9856036543198208) + (0.7345442054848037, 3.9861996414443093) + (0.729549607692659, 3.986783072609626) + (0.7245535587797703, 3.9873539441275527) + (0.7195560903291585, 3.9879122523892683) + (0.7145572339328197, 3.9884579938653717) + (0.709557021191523, 3.9889911651059027) + (0.7045554837146113, 3.9895117627403667) + (0.699552653119804, 3.990019783477754) + (0.6945485610329931, 3.9905152241065607) + (0.6895432390880455, 3.9909980814948094) + (0.6845367189266041, 3.991468352590069) + (0.679529032197885, 3.991926034419474) + (0.6745202105584791, 3.9923711240897424) + (0.6695102856721529, 3.992803618787196) + (0.664499289209646, 3.993223515777777) + (0.6594872528484717, 3.9936308124070634) + (0.6544742082727191, 3.99402550610029) + (0.6494601871728488, 3.99440759436236) + (0.6444452212454951, 3.9947770747778657) + (0.6394293421932663, 3.9951339450110996) + (0.6344125817245416, 3.99547820280607) + (0.6293949715532725, 3.9958098459865177) + (0.6243765433987831, 3.9961288724559267) + (0.6193573289855671, 3.9964352801975402) + (0.6143373600430886, 3.9967290672743703) + (0.6093166683055831, 3.997010231829213) + (0.6042952855118533, 3.9972787720846585) + (0.5992732434050723, 3.9975346863431023) + (0.5942505737325798, 3.997777972986758) + (0.5892273082456829, 3.998008630477664) + (0.5842034786994563, 3.998226657357696) + (0.5791791168525392, 3.9984320522485755) + (0.5741542544669357, 3.998624813851878) + (0.5691289233078156, 3.998804940949042) + (0.5641031551433107, 3.998972432401376) + (0.5590769817443153, 3.999127287150066) + (0.5540504348842868, 3.9992695042161825) + (0.5490235463390425, 3.999399082700686) + (0.5439963478865589, 3.9995160217844328) + (0.5389688713067736, 3.999620320728182) + (0.533941148381381, 3.999711978872596) + (0.5289132108936325, 3.999790995638249) + (0.5238850906281376, 3.9998573705256297) + (0.5188568193706594, 3.9999111031151413) + (0.5138284289079161, 3.999952193067109) + (0.5087999510273804, 3.9999806401217777) + (0.503771417517076, 3.9999964440993168) + (0.49874286016538, 3.99999960489982) + (0.49371431076081884, 3.9999901225033057) + (0.48868580109186877, 3.999967996969718) + (0.48365736294675626, 3.999933228438926) + (0.4786290281132537, 3.999885817130722) + (0.47360082837848233, 3.9998257633448215) + (0.46857279552870784, 3.99975306746086) + (0.4635449613491415, 3.999667729938393) + (0.45851735762373785, 3.9995697513168884) + (0.453490016134997, 3.9994591322157294) + (0.4484629686637589, 3.999335873334205) + (0.4434362469890056, 3.999199975451508) + (0.4384098828876596, 3.999051439426732) + (0.433383908134383, 3.9988902661988606) + (0.4283583545013757, 3.9987164567867675) + (0.4233332537581781, 3.998530012289206) + (0.418308637671465, 3.9983309338848025) + (0.4132845380048481, 3.9981192228320532) + (0.4082609865186747, 3.9978948804693086) + (0.40323801496982675, 3.9976579082147725) + (0.398215655111519, 3.997408307566488) + (0.3931939386931021, 3.9971460801023313) + (0.38817289745985645, 3.996871227479999) + (0.3831525631527951, 3.9965837514369986) + (0.3781329675084622, 3.9962836537906394) + (0.3731141422587314, 3.995970936438019) + (0.3680961191306091, 3.995645601356011) + (0.3630789298460281, 3.995307650601253) + (0.3580626061216509, 3.9949570863101345) + (0.3530471796686685, 3.994593910698784) + (0.3480326821925994, 3.9942181260630507) + (0.34301914539308886, 3.993829734778495) + (0.3380066009637116, 3.993428739300372) + (0.3329950805917664, 3.993015142163614) + (0.32798461595807926, 3.992588945982816) + (0.3229752387368022, 3.9921501534522212) + (0.31796698059521294, 3.991698767345699) + (0.31295987319351415, 3.991234790516732) + (0.3079539481846365, 3.9907582258983965) + (0.30294923721403344, 3.990269076503343) + (0.29794577191948457, 3.9897673454237776) + (0.292943583930895, 3.989253035831444) + (0.28794270487009455, 3.988726150977602) + (0.28294316635063954, 3.988186694193006) + (0.277944999977612, 3.9876346688878863) + (0.27294823734741874, 3.987070078551926) + (0.26795291004759275, 3.986492926754238) + (0.2629590496565948, 3.985903217143347) + (0.257966687743611, 3.98530095344716) + (0.2529758558683548, 3.9846861394729465) + (0.24798658558086878, 3.9840587791073157) + (0.2429989084213217, 3.9834188763161875) + (0.23801285591981336, 3.982766435144772) + (0.2330284595961714, 3.982101459717541) + (0.22804575095975455, 3.981423954238203) + (0.22306476150925164, 3.980733922989676) + (0.21808552273248605, 3.9800313703340624) + (0.21310806610621158, 3.9793163007126178) + (0.2081324230959169, 3.9785887186457267) + (0.20315862515562555, 3.977848628732872) + (0.19818670372769742, 3.977096035652605) + (0.19321669024262894, 3.9763309441625188) + (0.1882486161188579, 3.975553359099215) + (0.18328251276255958, 3.974763285378276) + (0.17831841156745182, 3.9739607279942306) + (0.17335634391459548, 3.973145692020526) + (0.1683963411721962, 3.9723181826094933) + (0.1634384346954053, 3.971478204992315) + (0.15848265582612486, 3.970625764478995) + (0.15352903589280453, 3.9697608664583197) + (0.1485776062102469, 3.968883516397829) + (0.14362839807940864, 3.9679937198437782) + (0.13868144278720262, 3.9670914824211057) + (0.13373677160629943, 3.9661768098333945) + (0.12879441579493284, 3.9652497078628395) + (0.12385440659669739, 3.964310182370207) + (0.11891677524035393, 3.963358239294803) + (0.11398155293963175, 3.9623938846544293) + (0.10904877089303083, 3.96141712454535) + (0.1041184602836242, 3.9604279651422525) + (0.09919065227886392, 3.959426412698205) + (0.09426537803037893, 3.958412473544623) + (0.08934266867378182, 3.957386154091223) + (0.08442255532847087, 3.956347460825986) + (0.07950506909743288, 3.955296400315115) + (0.07459024106704815, 3.9542329792029935) + (0.06967810230689275, 3.953157204212145) + (0.06476868386954143, 3.952069082143188) + (0.05986201679037262, 3.9509686198747946) + (0.054958132087371325, 3.949855824363647) + (0.05005706076093469, 3.948730702644393) + (0.04515883379367325, 3.947593261829602) + (0.04026348215021819, 3.946443509109719) + (0.03537103677702291, 3.9452814517530213) + (0.030481528602168406, 3.9441070971055696) + (0.025594988535169227, 3.942920452591164) + (0.0207114474667755, 3.941721525711297) + (0.01583093626877885, 3.9405103240451034) + (0.010953485793817996, 3.9392868552493163) + (0.0060791268751832495, 3.9380511270582153) + (0.0012078903266202201, 3.9368031472835794) + (-0.003660193057863248, 3.9355429238146376) + (-0.008525092504192422, 3.9342704646180175) + (-0.013386777258420968, 3.9329857777376978) + (-0.01824521658692213, 3.9316888712949543) + (-0.023100379776587743, 3.9303797534883103) + (-0.027952236135019404, 3.929058432593485) + (-0.03280075499072321, 3.92772491696334) + (-0.037645905693303394, 3.9263792150278274) + (-0.04248765761365747, 3.925021335293936) + (-0.04732598014416578, 3.9236512863456383) + (-0.052160842698890764, 3.9222690768438353) + (-0.056992214713766476, 3.9208747155263026) + (-0.061820065646792766, 3.919468211207634) + (-0.06664436497822834, 3.9180495727791866) + (-0.0714650822107844, 3.916618809209025) + (-0.07628218686981458, 3.9151759295418644) + (-0.08109564850351203, 3.913720942899012) + (-0.08590543668309869, 3.912253858478311) + (-0.09071152100301905, 3.910774685554082) + (-0.0955138710811323, 3.9092834334770634) + (-0.10031245655890164, 3.907780111674356) + (-0.10510724710159125, 3.9062647296493562) + (-0.10989821239845421, 3.9047372969817045) + (-0.1146853221629257, 3.903197823327218) + (-0.11946854613281366, 3.901646318417833) + (-0.12424785407049144, 3.9000827920615424) + (-0.1290232157630854, 3.8985072541423342) + (-0.13379460102267127, 3.8969197146201293) + (-0.1385619796864609, 3.8953201835307163) + (-0.14332532161699463, 3.8937086709856903) + (-0.14808459670233132, 3.8920851871723894) + (-0.15283977485623934, 3.890449742353828) + (-0.15759082601838426, 3.888802346868634) + (-0.16233772015452286, 3.887143011130982) + (-0.16708042725669037, 3.8854717456305283) + (-0.17181891734339105, 3.8837885609323446) + (-0.17655316045978642, 3.8820934676768513) + (-0.18128312667788704, 3.8803864765797487) + (-0.186008786096739, 3.878667598431952) + (-0.190730108842615, 3.8769368440995207) + (-0.19544706506920295, 3.8751942245235913) + (-0.2001596249577925, 3.873439750720306) + (-0.20486775871746676, 3.8716734337807477) + (-0.20957143658528887, 3.869895284870864) + (-0.21427062882648962, 3.868105315231401) + (-0.2189653057346559, 3.86630353617783) + (-0.22365543763191986, 3.8644899591002773) + (-0.22834099486914472, 3.8626645954634515) + (-0.23302194782611307, 3.860827456806571) + (-0.23769826691171458, 3.8589785547432904) + (-0.24236992256413015, 3.8571179009616294) + (-0.24703688525102319, 3.855245507223896) + (-0.2516991254697236, 3.8533613853666138) + (-0.2563566137474148, 3.851465547300447) + (-0.2610093206413199, 3.8495580050101257) + (-0.2656572167388891, 3.8476387705543686) + (-0.27030027265798173, 3.8457078560658076) + (-0.2749384590470575, 3.843765273750911) + (-0.27957174658535855, 3.8418110358899074) + (-0.2842001059830954, 3.8398451548367056) + (-0.2888235079816325, 3.8378676430188197) + (-0.2934419233536737, 3.8358785129372865) + (-0.2980553229034437, 3.8338777771665917) + (-0.30266367746687806, 3.831865448354586) + (-0.3072669579118036, 3.8298415392224054) + (-0.31186513513812375, 3.827806062564395) + (-0.3164581800780024, 3.825759031248022) + (-0.3210460636960488, 3.8237004582138) + (-0.3256287569894972, 3.821630356475204) + (-0.33020623098839574, 3.819548739118588) + (-0.3347784567557861, 3.8174556193031037) + (-0.33934540538788627, 3.815351010260618) + (-0.3439070480142753, 3.8132349252956255) + (-0.3484633557980751, 3.8111073777851683) + (-0.35301429993612976, 3.808968381178752) + (-0.3575598516591929, 3.8068179489982557) + (-0.3620999822321057, 3.804656094837851) + (-0.36663466295397995, 3.802482832363915) + (-0.37116386515837896, 3.800298175314943) + (-0.37568756021350014, 3.7981021375014623) + (-0.38020571952235216, 3.7958947328059454) + (-0.38471831452294114, 3.7936759751827216) + (-0.3892253166884476, 3.7914458786578873) + (-0.39372669752740774, 3.7892044573292214) + (-0.39822242858389345, 3.786951725366092) + (-0.40271248143769334, 3.7846876970093684) + (-0.4071968277044886, 3.782412386571332) + (-0.411675439036038, 3.780125808435586) + (-0.4161482871203529, 3.77782797705696) + (-0.42061534368187825, 3.775518906961426) + (-0.4250765804816702, 3.7731986127460004) + (-0.4295319693175761, 3.7708671090786536) + (-0.43398148202440934, 3.7685244106982205) + (-0.43842509047413236, 3.7661705324143013) + (-0.4428627665760311, 3.7638054891071726) + (-0.44729448227689317, 3.761429295727692) + (-0.45172020956118586, 3.759041967297202) + (-0.4561399204512334, 3.7566435189074388) + (-0.4605535870073909, 3.754233965720432) + (-0.4649611813282257, 3.7518133229684136) + (-0.46936267555069067, 3.749381605953717) + (-0.4737580418503009, 3.746938830048685) + (-0.47814725244130996, 3.744485010695568) + (-0.482530279576886, 3.7420201634064303) + (-0.48690709554928413, 3.7395443037630507) + (-0.4912776726900263, 3.737057447416822) + (-0.49564198337007326, 3.734559610088655) + (-0.49999999999999956, 3.7320508075688776) + (-0.5043516950301692, 3.7295310557171346) + (-0.5086970409509064, 3.7270003704622896) + (-0.5130360102926739, 3.7244587678023215) + (-0.5173685756262447, 3.7219062638042253) + (-0.5216947095628743, 3.7193428746039094) + (-0.5260143847544758, 3.7167686164060942) + (-0.5303275738937923, 3.7141835054842094) + (-0.5346342497145666, 3.7115875581802924) + (-0.538934384991719, 3.708980790904883) + (-0.5432279525415151, 3.70636322013692) + (-0.5475149252217393, 3.703734862423638) + (-0.5517952759318665, 3.7010957343804636) + (-0.556068977613233, 3.6984458526909068) + (-0.560336003249206, 3.6957852341064594) + (-0.5645963258653581, 3.693113895446488) + (-0.5688499185296347, 3.690431853598125) + (-0.5730967543525256, 3.687739125516167) + (-0.5773368064872342, 3.685035728222962) + (-0.5815700481298491, 3.6823216788083055) + (-0.5857964525195094, 3.6795969944293327) + (-0.5900159929385786, 3.676861692310408) + (-0.5942286427128112, 3.674115789743015) + (-0.5984343752115215, 3.6713593040856516) + (-0.6026331638477518, 3.6685922527637174) + (-0.6068249820784415, 3.665814653269402) + (-0.6110098034045923, 3.663026523161579) + (-0.6151876013714395, 3.6602278800656904) + (-0.6193583495686159, 3.6574187416736375) + (-0.6235220216303214, 3.6545991257436694) + (-0.6276785912354874, 3.6517690501002695) + (-0.6318280321079452, 3.6489285326340424) + (-0.6359703180165892, 3.6460775913016037) + (-0.640105422775546, 3.6432162441254627) + (-0.6442333202443389, 3.6403445091939117) + (-0.6483539843280519, 3.6374624046609094) + (-0.6524673889774961, 3.634569948745967) + (-0.6565735081893742, 3.631667159734032) + (-0.6606723160064429, 3.6287540559753766) + (-0.6647637865176801, 3.6258306558854754) + (-0.668847893858447, 3.6228969779448947) + (-0.6729246122106516, 3.619953040699172) + (-0.6769939158029126, 3.616998862758699) + (-0.6810557789107203, 3.614034462798608) + (-0.6851101758566025, 3.6110598595586487) + (-0.6891570810102843, 3.6080750718430714) + (-0.6931964687888519, 3.60508011852051) + (-0.6972283136569111, 3.602075018523861) + (-0.701252590126753, 3.5990597908501627) + (-0.7052692727585126, 3.5960344545604794) + (-0.7092783361603296, 3.5929990287797744) + (-0.7132797549885108, 3.5899535326967955) + (-0.7172735039476865, 3.58689798556395) + (-0.7212595577909746, 3.5838324066971836) + (-0.7252378913201385, 3.5807568154758593) + (-0.7292084793857465, 3.5776712313426335) + (-0.7331712968873285, 3.5745756738033343) + (-0.7371263187735393, 3.571470162426838) + (-0.7410735200423133, 3.568354716844943) + (-0.7450128757410239, 3.5652293567522513) + (-0.7489443609666413, 3.562094101906037) + (-0.7528679508658898, 3.5589489721261263) + (-0.7567836206354033, 3.5557939872947726) + (-0.7606913455218853, 3.5526291673565256) + (-0.7645911008222634, 3.5494545323181113) + (-0.7684828618838451, 3.5462701022483003) + (-0.7723666041044748, 3.543075897277787) + (-0.776242302932689, 3.539871937599054) + (-0.7801099338678701, 3.5366582434662552) + (-0.7839694724604036, 3.5334348351950773) + (-0.7878208943118312, 3.5302017331626163) + (-0.7916641750750057, 3.5269589578072504) + (-0.7954992904542444, 3.523706529628507) + (-0.7993262162054835, 3.520444469186935) + (-0.8031449281364285, 3.517172797103976) + (-0.8069554021067118, 3.5138915340618304) + (-0.8107576140280421, 3.5106007008033306) + (-0.8145515398643575, 3.507300318131807) + (-0.8183371556319774, 3.5039904069109573) + (-0.8221144373997544, 3.5006709880647158) + (-0.825883361289224, 3.497342082577121) + (-0.8296439034747585, 3.494003711492179) + (-0.833396040183715, 3.490655895913738) + (-0.8371397476965874, 3.487298657005346) + (-0.8408750023471552, 3.483932015990125) + (-0.8446017805226338, 3.480555994150631) + (-0.848320058663822, 3.477170612828724) + (-0.8520298132652544, 3.473775893425429) + (-0.8557310208753472, 3.470371857400804) + (-0.8594236580965473, 3.466958526273801) + (-0.8631077015854798, 3.4635359216221344) + (-0.8667831280530973, 3.46010406508214) + (-0.8704499142648234, 3.4566629783486427) + (-0.8741080370407037, 3.4532126831748147) + (-0.8777574732555502, 3.449753201372041) + (-0.8813981998390881, 3.446284554809781) + (-0.8850301937761016, 3.4428067654154297) + (-0.8886534321065771, 3.4393198551741806) + (-0.8922678919258531, 3.435823846128884) + (-0.8958735503847612, 3.4323187603799097) + (-0.8994703846897716, 3.4288046200850077) + (-0.9030583721031376, 3.4252814474591653) + (-0.9066374899430394, 3.42174926477447) + (-0.9102077155837252, 3.4182080943599678) + (-0.9137690264556582, 3.41465795860152) + (-0.9173214000456564, 3.4110988799416644) + (-0.9208648138970357, 3.407530880879472) + (-0.9243992456097523, 3.403953983970404) + (-0.9279246728405437, 3.40036821182617) + (-0.9314410733030689, 3.3967735871145894) + (-0.9349484247680524, 3.3931701325594394) + (-0.9384467050634218, 3.3895578709403162) + (-0.9419358920744492, 3.385936825092494) + (-0.945415963743891, 3.382307017906774) + (-0.9488868980721277, 3.3786684723293443) + (-0.9523486731173003, 3.3750212113616347) + (-0.955801266995453, 3.3713652580601687) + (-0.9592446578806693, 3.3677006355364205) + (-0.9626788240052102, 3.364027366956666) + (-0.966103743659652, 3.3603454755418394) + (-0.9695193951930243, 3.356654984567384) + (-0.9729257570129435, 3.3529559173631074) + (-0.9763228075857542, 3.349248297313032) + (-0.9797105254366627, 3.3455321478552476) + (-0.9830888891498724, 3.341807492481763) + (-0.98645787736872, 3.3380743547383602) + (-0.9898174687958115, 3.33433275822444) + (-0.9931676421931526, 3.33058272659288) + (-0.9965083763822891, 3.326824283549877) + (-0.9998396502444362, 3.323057452854806) + (-1.0031614427206141, 3.3192822583200616) + (-1.0064737328117808, 3.3154987238109124) + (-1.0097764995789629, 3.3117068732453503) + (-1.0130697221433915, 3.3079067305939365) + (-1.0163533796866315, 3.3040983198796514) + (-1.0196274514507142, 3.300281665177744) + (-1.0228919167382688, 3.2964567906155766) + (-1.0261467549126515, 3.292623720372477) + (-1.0293919453980784, 3.28878247867958) + (-1.032627467679754, 3.284933089819678) + (-1.0358533013040017, 3.281075578127067) + (-1.039069425878393, 3.2772099679873916) + (-1.042275821071874, 3.2733362838374926) + (-1.045472466614899, 3.2694545501652508) + (-1.0486593422995536, 3.2655647915094326) + (-1.0518364279796861, 3.2616670324595347) + (-1.0550037035710311, 3.257761297655631) + (-1.058161149051341, 3.253847611788213) + (-1.0613087444605087, 3.2499259995980365) + (-1.0644464699006961, 3.2459964858759633) + (-1.0675743055364593, 3.2420590954628077) + (-1.0706922315948724, 3.238113853249175) + (-1.073800228365655, 3.234160784175309) + (-1.0768982762012955, 3.230199913230928) + (-1.0799863555171758, 3.226231265455074) + (-1.0830644467916941, 3.22225486593595) + (-1.08613253056639, 3.2182707398107615) + (-1.089190587446065, 3.2142789122655597) + (-1.0922385980989076, 3.210279408535081) + (-1.0952765432566147, 3.2062722539025867) + (-1.0983044037145127, 3.2022574736997047) + (-1.1013221603316798, 3.1982350933062684) + (-1.1043297940310672, 3.1942051381501564) + (-1.107327285799617, 3.1901676337071327) + (-1.1103146166883866, 3.1861226055006853) + (-1.1132917678126661, 3.1820700791018623) + (-1.1162587203520973, 3.1780100801291136) + (-1.119215455550794, 3.173942634248128) + (-1.12216195471746, 3.16986776717167) + (-1.1250981992255058, 3.1657855046594197) + (-1.1280241705131697, 3.1616958725178055) + (-1.130939850083632, 3.1575988965998456) + (-1.1338452195051336, 3.1534946028049813) + (-1.1367402604110917, 3.1493830170789163) + (-1.139624954500217, 3.145264165413448) + (-1.1424992835366272, 3.14113807384631) + (-1.1453632293499647, 3.137004768461001) + (-1.148216773835511, 3.1328642753866243) + (-1.151059898954299, 3.128716620797718) + (-1.1538925867332304, 3.124561830914096) + (-1.156714819265187, 3.1203999320006757) + (-1.1595265787091436, 3.116230950367317) + (-1.1623278472902825, 3.112054912368654) + (-1.1651186073001052, 3.1078718444039266) + (-1.1678988410965438, 3.103681772916816) + (-1.170668531104073, 3.0994847243952774) + (-1.1734276598138216, 3.095280725371371) + (-1.1761762097836812, 3.0910698024210976) + (-1.1789141636384197, 3.0868519821642257) + (-1.1816415040697883, 3.0826272912641266) + (-1.1843582138366326, 3.078395756427606) + (-1.1870642757650014, 3.0741574044047324) + (-1.1897596727482531, 3.069912261988672) + (-1.1924443877471673, 3.065660356015516) + (-1.1951184037900504, 3.0614017133641114) + (-1.1977817039728433, 3.0571363609558935) + (-1.200434271459228, 3.052864325754712) + (-1.203076089480735, 3.0485856347666638) + (-1.2057071413368474, 3.044300315039922) + (-1.2083274103951087, 3.0400083936645617) + (-1.2109368800912268, 3.035709897772392) + (-1.2135355339291787, 3.031404854536784) + (-1.2161233554813147, 3.0270932911724975) + (-1.2187003283884634, 3.0227752349355104) + (-1.2212664363600325, 3.0184507131228466) + (-1.2238216631741148, 3.0141197530724013) + (-1.2263659926775894, 3.009782382162771) + (-1.2288994087862233, 3.005438627813079) + (-1.231421895484774, 3.001088517482801) + (-1.2339334368270904, 2.996732078671593) + (-1.2364340169362127, 2.9923693389191186) + (-1.2389236200044744, 2.9880003258048724) + (-1.2414022302936019, 2.983625066948006) + (-1.2438698321348125, 2.979243590007155) + (-1.2463264099289153, 2.9748559226802627) + (-1.2487719481464088, 2.9704620927044054) + (-1.2512064313275788, 2.9660621278556185) + (-1.2536298440825973, 2.961656055948719) + (-1.2560421710916185, 2.9572439048371293) + (-1.2584433971048767, 2.952825702412703) + (-1.2608335069427825, 2.948401476605547) + (-1.263212485496018, 2.943971255383846) + (-1.2655803177256324, 2.939535066753687) + (-1.2679369886631386, 2.9350929387588773) + (-1.270282483410606, 2.930644899480773) + (-1.2726167871407554, 2.9261909770380976) + (-1.2749398850970535, 2.9217311995867656) + (-1.2772517625938042, 2.917265595319707) + (-1.2795524050162435, 2.9127941924666834) + (-1.2818417978206305, 2.9083170192941137) + (-1.2841199265343413, 2.9038341041048943) + (-1.2863867767559565, 2.899345475238223) + (-1.288642334155357, 2.894851161069413) + (-1.2908865844738118, 2.89035119000972) + (-1.2931195135240685, 2.8858455905061606) + (-1.2953411071904437, 2.88133439104133) + (-1.2975513514289105, 2.876817620133228) + (-1.2997502322671903, 2.8722953063350705) + (-1.301937735804838, 2.8677674782351166) + (-1.3041138482133323, 2.8632341644564825) + (-1.3062785557361616, 2.858695393656963) + (-1.3084318446889105, 2.8541511945288516) + (-1.3105737014593486, 2.8496015957987564) + (-1.3127041125075147, 2.845046626227419) + (-1.3148230643658028, 2.8404863146095343) + (-1.3169305436390475, 2.8359206897735665) + (-1.319026537004608, 2.8313497805815695) + (-1.3211110312124532, 2.8267736159290013) + (-1.323184013085245, 2.822192224744543) + (-1.3252454695184221, 2.817605635989916) + (-1.3272953874802815, 2.813013878659699) + (-1.329333754012063, 2.808416981781143) + (-1.3313605562280284, 2.8038149744139917) + (-1.3333757813155458, 2.799207885650293) + (-1.3353794165351685, 2.7945957446142184) + (-1.3373714492207167, 2.7899785804618773) + (-1.3393518667793571, 2.785356422381134) + (-1.341320656691683, 2.78072929959142) + (-1.3432778065117916, 2.776097241343556) + (-1.3452233038673658, 2.7714602769195595) + (-1.3471571364597497, 2.766818435632463) + (-1.3490792920640275, 2.76217174682613) + (-1.350989758529101, 2.757520239875068) + (-1.3528885237777666, 2.7528639441842393) + (-1.354775575806789, 2.748202889188885) + (-1.356650902686981, 2.7435371043543277) + (-1.3585144925632773, 2.7388666191757918) + (-1.3603663336548077, 2.7341914631782154) + (-1.3622064142549746, 2.729511665916063) + (-1.364034722731525, 2.72482725697314) + (-1.365851247526624, 2.720138265962406) + (-1.3676559771569292, 2.715444722525784) + (-1.369448900213662, 2.7107466563339777) + (-1.3712300053626805, 2.7060440970862816) + (-1.372999281344551, 2.701337074510392) + (-1.374756716974619, 2.696625618362222) + (-1.3765023011430795, 2.691909758425712) + (-1.378236022815048, 2.6871895245126414) + (-1.3799578710306304, 2.682464946462439) + (-1.381667834904991, 2.677736054141997) + (-1.3833659036284232, 2.6730028774454784) + (-1.3850520664664152, 2.6682654462941335) + (-1.3867263127597211, 2.663523790636106) + (-1.3883886319244259, 2.658777940446244) + (-1.390039013452013, 2.654027925725914) + (-1.391677446909431, 2.6492737765028065) + (-1.3933039219391599, 2.6445155228307504) + (-1.3949184282592744, 2.639753194789523) + (-1.3965209556635125, 2.6349868224846538) + (-1.3981114940213373, 2.6302164360472418) + (-1.3996900332780016, 2.6254420656337603) + (-1.4012565634546124, 2.6206637414258687) + (-1.402811074648193, 2.615881493630219) + (-1.4043535570317451, 2.611095352478269) + (-1.405884000854313, 2.6063053482260874) + (-1.4074023964410434, 2.601511511154163) + (-1.408908734193247, 2.596713871567216) + (-1.4104030045884592, 2.591912459794003) + (-1.4118851981805014, 2.587107306187127) + (-1.413355305599538, 2.5822984411228473) + (-1.414813317552139, 2.5774858950008834) + (-1.416259224821336, 2.572669698244226) + (-1.417693018266682, 2.5678498812989425) + (-1.419114688824309, 2.5630264746339875) + (-1.4205242275069845, 2.558199508741006) + (-1.4219216254041689, 2.5533690141341463) + (-1.4233068736820724, 2.548535021349861) + (-1.4246799635837095, 2.5436975609467183) + (-1.4260408864289558, 2.5388566635052054) + (-1.4273896336146015, 2.5340123596275395) + (-1.4287261966144067, 2.5291646799374696) + (-1.4300505669791552, 2.524313655080088) + (-1.4313627363367074, 2.519459315721632) + (-1.432662696392054, 2.5146016925492916) + (-1.4339504389273676, 2.509740816271016) + (-1.4352259558020557, 2.5048767176153204) + (-1.436489238952811, 2.5000094273310878) + (-1.437740280393663, 2.495138976187382) + (-1.438979072216028, 2.490265394973244) + (-1.4402056065887605, 2.485388714497504) + (-1.441419875758201, 2.4805089655885837) + (-1.4426218720482258, 2.4756261790943035) + (-1.4438115878602953, 2.4707403858816854) + (-1.4449890156735021, 2.4658516168367575) + (-1.4461541480446194, 2.460959902864362) + (-1.4473069776081464, 2.4560652748879552) + (-1.448447497076356, 2.4511677638494183) + (-1.4495756992393403, 2.4462674007088547) + (-1.4506915769650572, 2.4413642164443994) + (-1.4517951231993744, 2.4364582420520193) + (-1.452886330966114, 2.4315495085453227) + (-1.4539651933670972, 2.426638046955358) + (-1.455031703582188, 2.4217238883304186) + (-1.4560858548693356, 2.4168070637358494) + (-1.4571276405646176, 2.411887604253846) + (-1.4581570540822815, 2.406965540983265) + (-1.459174088914787, 2.402040905039418) + (-1.460178738632847, 2.397113727553884) + (-1.4611709968854687, 2.3921840396743055) + (-1.4621508573999917, 2.387251872564197) + (-1.4631183139821309, 2.382317257402744) + (-1.4640733605160121, 2.3773802253846106) + (-1.4650159909642138, 2.3724408077197356) + (-1.4659461993678036, 2.367499035633141) + (-1.466863979846376, 2.3625549403647312) + (-1.4677693265980907, 2.357608553169099) + (-1.4686622338997077, 2.3526599053153228) + (-1.469542696106624, 2.3477090280867756) + (-1.4704107076529105, 2.3427559527809207) + (-1.4712662630513451, 2.337800710709118) + (-1.4721093568934494, 2.332843333196424) + (-1.4729399838495212, 2.3278838515813955) + (-1.47375813866867, 2.32292229721589) + (-1.4745638161788477, 2.3179587014648693) + (-1.475357011286884, 2.3129930957061986) + (-1.4761377189785165, 2.30802551133045) + (-1.4769059343184243, 2.3030559797407038) + (-1.477661652450257, 2.2980845323523496) + (-1.4784048685966673, 2.293111200592887) + (-1.47913557805934, 2.2881360159017303) + (-1.4798537762190223, 2.2831590097300056) + (-1.480559458535553, 2.2781802135403537) + (-1.481252620547891, 2.273199658806732) + (-1.4819332578741433, 2.268217377014212) + (-1.4826013662115936, 2.263233399658787) + (-1.4832569413367278, 2.2582477582471667) + (-1.4838999791052625, 2.2532604842965807) + (-1.4845304754521707, 2.2482716093345787) + (-1.4851484263917063, 2.243281164898831) + (-1.4857538280174312, 2.2382891825369304) + (-1.4863466765022384, 2.2332956938061908) + (-1.4869269680983772, 2.22830073027345) + (-1.4874946991374762, 2.2233043235148684) + (-1.4880498660305672, 2.21830650511573) + (-1.488592465268107, 2.2133073066702407) + (-1.489122493420001, 2.2083067597813333) + (-1.4896399471356228, 2.203304896060464) + (-1.4901448231438372, 2.1983017471274136) + (-1.4906371182530205, 2.1932973446100865) + (-1.4911168293510795, 2.1882917201443126) + (-1.4915839534054731, 2.183284905373646) + (-1.49203848746323, 2.1782769319491653) + (-1.4924804286509674, 2.1732678315292757) + (-1.4929097741749102, 2.1682576357795047) + (-1.493326521320908, 2.1632463763723035) + (-1.493730667454452, 2.1582340849868498) + (-1.4941222100206921, 2.1532207933088423) + (-1.4945011465444529, 2.148206533030304) + (-1.4948674746302495, 2.1431913358493837) + (-1.4952211919623022, 2.1381752334701494) + (-1.4955622963045516, 2.133158257602392) + (-1.4958907855006727, 2.1281404399614265) + (-1.4962066574740882, 2.1231218122678865) + (-1.4965099102279817, 2.118102406247527) + (-1.4968005418453112, 2.113082253631026) + (-1.4970785504888195, 2.108061386153777) + (-1.4973439344010473, 2.1030398355556965) + (-1.4975966919043437, 2.098017633581016) + (-1.497836821400877, 2.092994811978087) + (-1.4980643213726448, 2.0879714024991762) + (-1.4982791903814832, 2.0829474369002696) + (-1.498481427069076, 2.0779229469408658) + (-1.4986710301569643, 2.0728979643837797) + (-1.498847998446553, 2.06787252099494) + (-1.4990123308191194, 2.0628466485431876) + (-1.4991640262358203, 2.057820378800076) + (-1.4993030837376977, 2.052793743539673) + (-1.4994295024456856, 2.0477667745383537) + (-1.4995432815606158, 2.042739503574604) + (-1.4996444203632224, 2.0377119624288187) + (-1.499732918214146, 2.0326841828831) + (-1.4998087745539388, 2.0276561967210593) + (-1.4998719889030672, 2.0226280357276125) + (-1.4999225608619158, 2.017599731688781) + (-1.4999604901107884, 2.012571316391489) + (-1.4999857764099118, 2.0075428216233657) + (-1.4999984195994363, 2.0025142791725443) + (-1.4999984195994363, 1.9974857208274561) + (-1.4999857764099118, 1.9924571783766345) + (-1.4999604901107884, 1.9874286836085122) + (-1.4999225608619158, 1.9824002683112198) + (-1.4998719889030672, 1.977371964272388) + (-1.4998087745539388, 1.9723438032789409) + (-1.499732918214146, 1.9673158171169005) + (-1.4996444203632224, 1.9622880375711829) + (-1.499543281560616, 1.9572604964253968) + (-1.4994295024456856, 1.952233225461647) + (-1.4993030837376977, 1.9472062564603274) + (-1.4991640262358203, 1.9421796211999234) + (-1.4990123308191197, 1.9371533514568138) + (-1.498847998446553, 1.9321274790050607) + (-1.4986710301569643, 1.9271020356162214) + (-1.498481427069076, 1.9220770530591345) + (-1.4982791903814832, 1.91705256309973) + (-1.498064321372645, 1.9120285975008242) + (-1.4978368214008773, 1.9070051880219134) + (-1.4975966919043437, 1.9019823664189854) + (-1.4973439344010473, 1.8969601644443042) + (-1.4970785504888195, 1.8919386138462224) + (-1.4968005418453112, 1.8869177463689748) + (-1.4965099102279817, 1.8818975937524727) + (-1.4962066574740882, 1.876878187732115) + (-1.4958907855006727, 1.871859560038574) + (-1.4955622963045516, 1.8668417423976091) + (-1.4952211919623022, 1.8618247665298513) + (-1.4948674746302495, 1.856808664150616) + (-1.494501146544453, 1.8517934669696965) + (-1.4941222100206921, 1.8467792066911584) + (-1.4937306674544522, 1.8417659150131518) + (-1.493326521320908, 1.8367536236276967) + (-1.4929097741749102, 1.831742364220495) + (-1.4924804286509674, 1.8267321684707247) + (-1.4920384874632298, 1.8217230680508343) + (-1.4915839534054731, 1.8167150946263553) + (-1.4911168293510795, 1.811708279855688) + (-1.4906371182530205, 1.806702655389915) + (-1.4901448231438372, 1.801698252872587) + (-1.4896399471356228, 1.7966951039395354) + (-1.4891224934200011, 1.7916932402186674) + (-1.488592465268107, 1.7866926933297596) + (-1.4880498660305672, 1.7816934948842718) + (-1.4874946991374762, 1.7766956764851318) + (-1.486926968098377, 1.7716992697265495) + (-1.4863466765022384, 1.76670430619381) + (-1.4857538280174312, 1.76171081746307) + (-1.4851484263917065, 1.7567188351011702) + (-1.4845304754521707, 1.751728390665422) + (-1.4838999791052625, 1.746739515703419) + (-1.4832569413367278, 1.7417522417528337) + (-1.4826013662115936, 1.7367666003412128) + (-1.4819332578741435, 1.731782622985789) + (-1.481252620547891, 1.7268003411932689) + (-1.4805594585355533, 1.7218197864596476) + (-1.4798537762190225, 1.7168409902699948) + (-1.4791355780593398, 1.7118639840982692) + (-1.4784048685966673, 1.7068887994071138) + (-1.477661652450257, 1.7019154676476511) + (-1.4769059343184245, 1.6969440202592976) + (-1.4761377189785168, 1.6919744886695502) + (-1.475357011286884, 1.687006904293801) + (-1.4745638161788477, 1.6820412985351312) + (-1.4737581386686698, 1.6770777027841097) + (-1.4729399838495214, 1.6721161484186056) + (-1.4721093568934494, 1.6671566668035767) + (-1.4712662630513453, 1.6621992892908837) + (-1.4704107076529105, 1.65724404721908) + (-1.469542696106624, 1.652290971913224) + (-1.4686622338997077, 1.6473400946846777) + (-1.467769326598091, 1.6423914468309015) + (-1.4668639798463765, 1.6374450596352699) + (-1.4659461993678036, 1.6325009643668598) + (-1.4650159909642138, 1.6275591922802641) + (-1.4640733605160121, 1.6226197746153899) + (-1.4631183139821307, 1.6176827425972555) + (-1.462150857399992, 1.6127481274358042) + (-1.4611709968854687, 1.607815960325695) + (-1.4601787386328473, 1.6028862724461168) + (-1.459174088914787, 1.5979590949605824) + (-1.4581570540822812, 1.5930344590167347) + (-1.4571276405646176, 1.5881123957461543) + (-1.4560858548693356, 1.583192936264151) + (-1.4550317035821883, 1.5782761116695818) + (-1.4539651933670974, 1.5733619530446425) + (-1.452886330966114, 1.5684504914546769) + (-1.4517951231993744, 1.5635417579479813) + (-1.4506915769650572, 1.5586357835556013) + (-1.4495756992393403, 1.5537325992911457) + (-1.448447497076356, 1.5488322361505822) + (-1.4473069776081464, 1.5439347251120452) + (-1.4461541480446194, 1.5390400971356386) + (-1.4449890156735024, 1.534148383163243) + (-1.4438115878602953, 1.5292596141183152) + (-1.442621872048226, 1.5243738209056967) + (-1.4414198757582013, 1.5194910344114168) + (-1.4402056065887607, 1.5146112855024962) + (-1.4389790722160283, 1.5097346050267564) + (-1.437740280393663, 1.5048610238126185) + (-1.4364892389528112, 1.4999905726689127) + (-1.4352259558020561, 1.495123282384681) + (-1.4339504389273678, 1.4902591837289845) + (-1.4326626963920543, 1.4853983074507098) + (-1.4313627363367074, 1.4805406842783686) + (-1.4300505669791552, 1.4756863449199122) + (-1.428726196614407, 1.4708353200625308) + (-1.4273896336146015, 1.465987640372461) + (-1.4260408864289562, 1.4611433364947959) + (-1.4246799635837097, 1.4563024390532826) + (-1.4233068736820724, 1.4514649786501383) + (-1.421921625404169, 1.4466309858658541) + (-1.4205242275069843, 1.4418004912589937) + (-1.4191146888243091, 1.4369735253660139) + (-1.417693018266682, 1.432150118701058) + (-1.4162592248213364, 1.4273303017557755) + (-1.4148133175521391, 1.422514104999117) + (-1.413355305599538, 1.4177015588771522) + (-1.4118851981805016, 1.4128926938128736) + (-1.4104030045884595, 1.4080875402059974) + (-1.4089087341932474, 1.4032861284327853) + (-1.4074023964410436, 1.3984884888458373) + (-1.405884000854313, 1.3936946517739124) + (-1.4043535570317454, 1.3889046475217315) + (-1.4028110746481928, 1.3841185063697807) + (-1.4012565634546128, 1.3793362585741327) + (-1.3996900332780018, 1.3745579343662402) + (-1.3981114940213377, 1.3697835639527596) + (-1.3965209556635128, 1.3650131775153467) + (-1.3949184282592744, 1.360246805210477) + (-1.39330392193916, 1.3554844771692498) + (-1.3916774469094313, 1.350726223497194) + (-1.3900390134520135, 1.3459720742740875) + (-1.388388631924426, 1.3412220595537563) + (-1.3867263127597211, 1.3364762093638938) + (-1.3850520664664154, 1.331734553705867) + (-1.383365903628423, 1.3269971225545212) + (-1.3816678349049913, 1.3222639458580043) + (-1.3799578710306304, 1.3175350535375614) + (-1.3782360228150479, 1.3128104754873582) + (-1.3765023011430797, 1.3080902415742885) + (-1.374756716974619, 1.303374381637778) + (-1.3729992813445515, 1.2986629254896092) + (-1.3712300053626807, 1.293955902913719) + (-1.3694489002136625, 1.2892533436660234) + (-1.3676559771569294, 1.2845552774742164) + (-1.365851247526624, 1.2798617340375937) + (-1.3640347227315253, 1.2751727430268605) + (-1.3622064142549748, 1.2704883340839372) + (-1.3603663336548082, 1.265808536821786) + (-1.3585144925632773, 1.2611333808242087) + (-1.3566509026869809, 1.256462895645672) + (-1.354775575806789, 1.2517971108111157) + (-1.3528885237777664, 1.2471360558157603) + (-1.3509897585291017, 1.2424797601249338) + (-1.3490792920640278, 1.2378282531738702) + (-1.34715713645975, 1.2331815643675381) + (-1.345223303867366, 1.2285397230804413) + (-1.3432778065117916, 1.2239027586564437) + (-1.3413206566916833, 1.2192707004085805) + (-1.3393518667793574, 1.2146435776188667) + (-1.3373714492207174, 1.2100214195381238) + (-1.3353794165351687, 1.205404255385782) + (-1.3333757813155456, 1.2007921143497065) + (-1.3313605562280286, 1.1961850255860087) + (-1.3293337540120629, 1.1915830182188567) + (-1.3272953874802822, 1.1869861213403023) + (-1.3252454695184224, 1.1823943640100845) + (-1.3231840130852452, 1.1778077752554577) + (-1.3211110312124534, 1.1732263840709993) + (-1.3190265370046077, 1.1686502194184303) + (-1.3169305436390477, 1.164079310226434) + (-1.314823064365803, 1.159513685390466) + (-1.312704112507515, 1.1549533737725812) + (-1.3105737014593488, 1.150398404201244) + (-1.3084318446889103, 1.145848805471148) + (-1.3062785557361618, 1.1413046063430377) + (-1.3041138482133325, 1.136765835543518) + (-1.3019377358048383, 1.1322325217648839) + (-1.2997502322671906, 1.12770469366493) + (-1.2975513514289108, 1.1231823798667726) + (-1.295341107190444, 1.1186656089586704) + (-1.2931195135240687, 1.1141544094938398) + (-1.290886584473812, 1.1096488099902804) + (-1.2886423341553572, 1.1051488389305877) + (-1.2863867767559567, 1.1006545247617776) + (-1.2841199265343415, 1.0961658958951062) + (-1.2818417978206307, 1.0916829807058868) + (-1.2795524050162437, 1.0872058075333173) + (-1.2772517625938045, 1.0827344046802936) + (-1.274939885097054, 1.0782688004132346) + (-1.2726167871407557, 1.0738090229619028) + (-1.2702824834106066, 1.0693551005192283) + (-1.2679369886631389, 1.064907061241123) + (-1.2655803177256326, 1.0604649332463136) + (-1.2632124854960183, 1.0560287446161543) + (-1.2608335069427827, 1.0515985233944534) + (-1.2584433971048774, 1.0471742975872984) + (-1.2560421710916188, 1.0427560951628712) + (-1.2536298440825975, 1.0383439440512814) + (-1.251206431327579, 1.0339378721443817) + (-1.2487719481464088, 1.0295379072955944) + (-1.246326409928916, 1.0251440773197387) + (-1.2438698321348127, 1.0207564099928454) + (-1.2414022302936025, 1.016374933051995) + (-1.2389236200044746, 1.011999674195128) + (-1.2364340169362125, 1.007630661080881) + (-1.2339334368270907, 1.0032679213284075) + (-1.2314218954847742, 0.9989114825171994) + (-1.228899408786224, 0.994561372186922) + (-1.2263659926775896, 0.9902176178372291) + (-1.2238216631741148, 0.9858802469275982) + (-1.2212664363600327, 0.981549286877154) + (-1.2187003283884632, 0.9772247650644894) + (-1.2161233554813153, 0.9729067088275034) + (-1.213535533929179, 0.9685951454632162) + (-1.2109368800912275, 0.9642901022276089) + (-1.208327410395109, 0.9599916063354388) + (-1.2057071413368472, 0.9556996849600778) + (-1.2030760894807353, 0.9514143652333367) + (-1.2004342714592282, 0.9471356742452883) + (-1.197781703972844, 0.9428636390441079) + (-1.1951184037900509, 0.9385982866358891) + (-1.192444387747167, 0.934339643984484) + (-1.1897596727482533, 0.9300877380113286) + (-1.1870642757650012, 0.9258425955952676) + (-1.1843582138366335, 0.9216042435723952) + (-1.1816415040697885, 0.9173727087358738) + (-1.1789141636384204, 0.9131480178357758) + (-1.1761762097836814, 0.908930197578903) + (-1.1734276598138214, 0.9047192746286288) + (-1.1706685311040739, 0.9005152756047239) + (-1.167898841096544, 0.8963182270831844) + (-1.165118607300106, 0.8921281555960747) + (-1.162327847290283, 0.8879450876313464) + (-1.1595265787091433, 0.8837690496326822) + (-1.1567148192651875, 0.8796000679993248) + (-1.1538925867332306, 0.8754381690859043) + (-1.1510598989542997, 0.8712833792022829) + (-1.1482167738355111, 0.8671357246133764) + (-1.1453632293499645, 0.8629952315389984) + (-1.1424992835366274, 0.8588619261536905) + (-1.1396249545002168, 0.8547358345865519) + (-1.1367402604110926, 0.850616982921085) + (-1.1338452195051338, 0.8465053971950189) + (-1.1309398500836327, 0.8424011034001555) + (-1.12802417051317, 0.8383041274821947) + (-1.1250981992255056, 0.8342144953405799) + (-1.1221619547174602, 0.83013223282833) + (-1.1192154555507943, 0.8260573657518722) + (-1.1162587203520982, 0.8219899198708875) + (-1.1132917678126664, 0.8179299208981383) + (-1.1103146166883864, 0.8138773944993145) + (-1.1073272857996173, 0.8098323662928673) + (-1.104329794031067, 0.8057948618498434) + (-1.1013221603316807, 0.8017649066937327) + (-1.0983044037145129, 0.7977425263002957) + (-1.0952765432566154, 0.7937277460974144) + (-1.092238598098908, 0.7897205914649195) + (-1.0891905874460648, 0.7857210877344398) + (-1.0861325305663905, 0.7817292601892392) + (-1.0830644467916946, 0.7777451340640502) + (-1.0799863555171767, 0.7737687345449269) + (-1.0768982762012957, 0.7698000867690724) + (-1.0738002283656547, 0.7658392158246912) + (-1.0706922315948726, 0.7618861467508253) + (-1.067574305536459, 0.7579409045371923) + (-1.0644464699006964, 0.7540035141240367) + (-1.061308744460509, 0.7500740004019641) + (-1.0581611490513412, 0.7461523882117875) + (-1.0550037035710316, 0.7422387023443695) + (-1.051836427979686, 0.7383329675404648) + (-1.0486593422995538, 0.7344352084905676) + (-1.0454724666148993, 0.7305454498347492) + (-1.0422758210718746, 0.7266637161625074) + (-1.0390694258783932, 0.7227900320126088) + (-1.035853301304002, 0.7189244218729334) + (-1.0326274676797544, 0.7150669101803224) + (-1.0293919453980787, 0.7112175213204206) + (-1.0261467549126517, 0.7073762796275236) + (-1.0228919167382693, 0.7035432093844236) + (-1.019627451450715, 0.6997183348222569) + (-1.016353379686632, 0.6959016801203486) + (-1.013069722143392, 0.692093269406064) + (-1.0097764995789633, 0.6882931267546499) + (-1.0064737328117812, 0.6845012761890881) + (-1.003161442720615, 0.6807177416799393) + (-0.9998396502444364, 0.6769425471451942) + (-0.9965083763822893, 0.6731757164501231) + (-0.9931676421931528, 0.6694172734071209) + (-0.9898174687958112, 0.6656672417755598) + (-0.9864578773687211, 0.6619256452616409) + (-0.9830888891498728, 0.6581925075182371) + (-0.9797105254366636, 0.6544678521447536) + (-0.9763228075857546, 0.6507517026869685) + (-0.9729257570129433, 0.6470440826368922) + (-0.9695193951930245, 0.6433450154326166) + (-0.9661037436596525, 0.6396545244581611) + (-0.9626788240052111, 0.6359726330433351) + (-0.9592446578806697, 0.6322993644635799) + (-0.9558012669954528, 0.6286347419398308) + (-0.9523486731173005, 0.6249787886383655) + (-0.9488868980721274, 0.6213315276706555) + (-0.9454159637438921, 0.6176929820932271) + (-0.9419358920744496, 0.6140631749075065) + (-0.9384467050634226, 0.6104421290596844) + (-0.9349484247680528, 0.6068298674405612) + (-0.9314410733030687, 0.6032264128854101) + (-0.9279246728405439, 0.5996317881738298) + (-0.9243992456097525, 0.5960460160295966) + (-0.9208648138970368, 0.5924691191205291) + (-0.9173214000456567, 0.5889011200583356) + (-0.9137690264556579, 0.5853420413984796) + (-0.9102077155837256, 0.5817919056400327) + (-0.9066374899430392, 0.5782507352255297) + (-0.9030583721031387, 0.5747185525408356) + (-0.899470384689772, 0.5711953799149929) + (-0.8958735503847621, 0.567681239620091) + (-0.8922678919258535, 0.5641761538711163) + (-0.8886534321065769, 0.5606801448258192) + (-0.8850301937761018, 0.5571932345845707) + (-0.8813981998390885, 0.5537154451902193) + (-0.8777574732555513, 0.55024679862796) + (-0.874108037040704, 0.5467873168251858) + (-0.870449914264823, 0.5433370216513571) + (-0.8667831280530978, 0.5398959349178603) + (-0.8631077015854802, 0.5364640783778658) + (-0.8594236580965482, 0.5330414737261999) + (-0.8557310208753477, 0.5296281425991969) + (-0.8520298132652542, 0.5262241065745707) + (-0.8483200586638224, 0.5228293871712766) + (-0.8446017805226333, 0.5194440058493688) + (-0.8408750023471561, 0.5160679840098759) + (-0.8371397476965878, 0.5127013429946541) + (-0.8333960401837162, 0.509344104086263) + (-0.8296439034747587, 0.5059962885078209) + (-0.8258833612892238, 0.5026579174228789) + (-0.8221144373997549, 0.49932901193528445) + (-0.8183371556319776, 0.4960095930890427) + (-0.8145515398643586, 0.4926996818681939) + (-0.8107576140280426, 0.4893992991966696) + (-0.8069554021067116, 0.4861084659381689) + (-0.8031449281364282, 0.48282720289602366) + (-0.799326216205483, 0.47955553081306457) + (-0.7954992904542448, 0.47629347037149317) + (-0.7916641750750062, 0.4730410421927498) + (-0.7878208943118317, 0.4697982668373839) + (-0.7839694724604038, 0.46656516480492316) + (-0.780109933867869, 0.4633417565337439) + (-0.7762423029326895, 0.46012806240094584) + (-0.7723666041044743, 0.45692410272221284) + (-0.7684828618838462, 0.45372989775170014) + (-0.764591100822263, 0.45054546768188874) + (-0.7606913455218851, 0.447370832643474) + (-0.756783620635403, 0.4442060127052272) + (-0.7528679508658895, 0.4410510278738733) + (-0.7489443609666415, 0.4379058980939632) + (-0.7450128757410244, 0.43477064324774917) + (-0.7410735200423137, 0.43164528315505724) + (-0.7371263187735397, 0.42852983757316276) + (-0.7331712968873276, 0.42542432619666504) + (-0.729208479385747, 0.4223287686573669) + (-0.7252378913201383, 0.4192431845241402) + (-0.7212595577909757, 0.4161675933028173) + (-0.7172735039476861, 0.41310201443605) + (-0.7132797549885106, 0.4100464673032045) + (-0.7092783361603301, 0.4070009712202258) + (-0.705269272758513, 0.40396554543952123) + (-0.7012525901267535, 0.4009402091498373) + (-0.6972283136569115, 0.3979249814761394) + (-0.6931964687888523, 0.3949198814794903) + (-0.6891570810102854, 0.39192492815692925) + (-0.685110175856602, 0.38894014044135106) + (-0.6810557789107214, 0.3859655372013926) + (-0.6769939158029123, 0.3830011372413007) + (-0.6729246122106534, 0.38004695930082955) + (-0.6688478938584475, 0.3771030220551055) + (-0.6647637865176805, 0.3741693441145246) + (-0.6606723160064434, 0.37124594402462385) + (-0.6565735081893747, 0.36833284026596824) + (-0.6524673889774972, 0.3654300512540338) + (-0.648353984328053, 0.36253759533909125) + (-0.64423332024434, 0.3596554908060887) + (-0.6401054227755472, 0.3567837558745377) + (-0.6359703180165888, 0.3539224086983961) + (-0.6318280321079464, 0.3510714673659585) + (-0.6276785912354879, 0.3482309498997309) + (-0.6235220216303232, 0.3454008742563317) + (-0.6193583495686164, 0.34258125832636277) + (-0.6151876013714397, 0.33977211993431) + (-0.6110098034045928, 0.3369734768384214) + (-0.6068249820784419, 0.3341853467305984) + (-0.6026331638477529, 0.3314077472362835) + (-0.5984343752115227, 0.32864069591434886) + (-0.5942286427128125, 0.32588421025698566) + (-0.5900159929385798, 0.32313830768959306) + (-0.585796452519509, 0.3204030055706668) + (-0.5815700481298502, 0.31767832119169515) + (-0.5773368064872346, 0.31496427177703845) + (-0.5730967543525274, 0.31226087448383444) + (-0.5688499185296352, 0.30956814640187513) + (-0.5645963258653584, 0.3068861045535125) + (-0.5603360032492064, 0.3042147658935408) + (-0.5560689776132335, 0.3015541473090937) + (-0.5517952759318676, 0.2989042656195371) + (-0.5475149252217406, 0.2962651375763623) + (-0.5432279525415162, 0.2936367798630808) + (-0.5389343849917201, 0.291019209095118) + (-0.5346342497145664, 0.2884124418197074) + (-0.5303275738937918, 0.2858164945157906) + (-0.5260143847544763, 0.2832313835939062) + (-0.5216947095628748, 0.280657125396091) + (-0.5173685756262452, 0.27809373619577493) + (-0.5130360102926743, 0.2755412321976787) + (-0.5086970409509068, 0.2729996295377106) + (-0.5043516950301696, 0.2704689442828656) + (-0.5000000000000009, 0.26794919243112303) + (-0.4956419833700745, 0.2654403899113458) + (-0.491277672690026, 0.2629425525831779) + (-0.4869070955492837, 0.2604556962369493) + (-0.48253027957688566, 0.2579798365935695) + (-0.4781472524413104, 0.25551498930443217) + (-0.47375804185030135, 0.25306116995131545) + (-0.4693626755506911, 0.25061839404628317) + (-0.46496118132822617, 0.2481866770315868) + (-0.46055358700739135, 0.245766034279568) + (-0.45613992045123386, 0.24335648109256147) + (-0.4517202095611855, 0.24095803270279736) + (-0.4472944822768944, 0.23857070427230864) + (-0.44286276657603074, 0.23619451089282717) + (-0.43842509047413203, 0.23382946758569845) + (-0.433981482024409, 0.23147558930177947) + (-0.42953196931757576, 0.22913289092134592) + (-0.42507658048167063, 0.226801387254) + (-0.4206153436818787, 0.2244810930385741) + (-0.41614828712035334, 0.22217202294303995) + (-0.4116754390360384, 0.21987419156441468) + (-0.4071968277044875, 0.21758761342866717) + (-0.4027124814376938, 0.2153123029906321) + (-0.3982224285838931, 0.21304827463390796) + (-0.39372669752740896, 0.21079554267077927) + (-0.3892253166884473, 0.2085541213421125) + (-0.3847183145229408, 0.20632402481727863) + (-0.3802057195223518, 0.20410526719405442) + (-0.3756875602134998, 0.20189786249853747) + (-0.3711638651583794, 0.19970182468505704) + (-0.3666346629539804, 0.19751716763608518) + (-0.36209998223210615, 0.19534390516214906) + (-0.35755985165919335, 0.19318205100174457) + (-0.35301429993612865, 0.19103161882124753) + (-0.3484633557980755, 0.18889262221483172) + (-0.34390704801427496, 0.18676507470437453) + (-0.3393454053878875, 0.18464898973938304) + (-0.33477845675578577, 0.18254438069689605) + (-0.33020623098839574, 0.18045126088141217) + (-0.32562875698949734, 0.17836964352479634) + (-0.3210460636960488, 0.1762995417862001) + (-0.3164581800780033, 0.17424096875197836) + (-0.3118651351381245, 0.17219393743560563) + (-0.30726695791180436, 0.17015846077759478) + (-0.30266367746687894, 0.1681345516454147) + (-0.29805532290344294, 0.16612222283340783) + (-0.29344192335367447, 0.16412148706271368) + (-0.2888235079816326, 0.16213235698118034) + (-0.2842001059830971, 0.1601548451632948) + (-0.27957174658535855, 0.15818896411009264) + (-0.2749384590470576, 0.15623472624908907) + (-0.27030027265798173, 0.15429214393419266) + (-0.2656572167388891, 0.15236122944563157) + (-0.26100932064132076, 0.15044199498987454) + (-0.2563566137474157, 0.14853445269955334) + (-0.2516991254697245, 0.1466386146333869) + (-0.24703688525102407, 0.14475449277610486) + (-0.24236992256412937, 0.14288209903837057) + (-0.23769826691171547, 0.14102144525671) + (-0.23302194782611307, 0.13917254319342898) + (-0.22834099486914639, 0.1373354045365489) + (-0.22365543763191986, 0.13551004089972252) + (-0.2189653057346559, 0.13369646382217004) + (-0.21427062882648962, 0.13189468476859934) + (-0.20957143658528943, 0.13010471512913635) + (-0.20486775871746765, 0.12832656621925254) + (-0.20015962495779338, 0.126560249279694) + (-0.19544706506920384, 0.12480577547640936) + (-0.19073010884261632, 0.12306315590047956) + (-0.18600878609673854, 0.1213324015680477) + (-0.18128312667788837, 0.11961352342025178) + (-0.17655316045978642, 0.11790653232314874) + (-0.17181891734339272, 0.11621143906765607) + (-0.1670804272566908, 0.1145282543694719) + (-0.1623377201545233, 0.1128569888690183) + (-0.1575908260183847, 0.11119765313136631) + (-0.1528397748562399, 0.10955025764617221) + (-0.14808459670233254, 0.10791481282761084) + (-0.14332532161699596, 0.10629132901430993) + (-0.13856197968646222, 0.10467981646928415) + (-0.1337946010226725, 0.10308028537987113) + (-0.12902321576308506, 0.10149274585766532) + (-0.12424785407049266, 0.09991720793845804) + (-0.1194685461328141, 0.09835368158216728) + (-0.11468532216292615, 0.09680217667278224) + (-0.10989821239845476, 0.09526270301829554) + (-0.1051072471015917, 0.09373527035064377) + (-0.10031245655890209, 0.09221988832564443) + (-0.09551387108113274, 0.09071656652293658) + (-0.09071152100302038, 0.08922531444591875) + (-0.08590543668310002, 0.08774614152168958) + (-0.08109564850351336, 0.0862790571009886) + (-0.07628218686981425, 0.08482407045813556) + (-0.07146508221078407, 0.08338119079097472) + (-0.06664436497822879, 0.08195042722081358) + (-0.06182006564679321, 0.08053178879236644) + (-0.05699221471376703, 0.0791252844736976) + (-0.05216084269889132, 0.07773092315616492) + (-0.047325980144166224, 0.07634871365436191) + (-0.042487657613657914, 0.0749786647060644) + (-0.037645905693304726, 0.07362078497217328) + (-0.032800754990724545, 0.07227508303666053) + (-0.02795223613501907, 0.07094156740651503) + (-0.02310037977658741, 0.06962024651168952) + (-0.018245216586921686, 0.06831112870504574) + (-0.013386777258420635, 0.06701422226230203) + (-0.008525092504192866, 0.06572953538198223) + (-0.003660193057863692, 0.06445707618536245) + (0.0012078903266197205, 0.06319685271642062) + (0.00607912687518275, 0.06194887294178475) + (0.010953485793819273, 0.060713144750683457) + (0.015830936268777906, 0.059489675954896626) + (0.02071144746677589, 0.05827847428870303) + (0.025594988535167895, 0.05707954740883636) + (0.030481528602168795, 0.05589290289443061) + (0.03537103677702286, 0.05471854824697897) + (0.04026348215021813, 0.053556490890280806) + (0.04515883379367319, 0.05240673817039809) + (0.05005706076093425, 0.05126929735560681) + (0.054958132087370826, 0.05014417563635276) + (0.05986201679037173, 0.04903138012520536) + (0.06476868386954054, 0.04793091785681214) + (0.06967810230689359, 0.046842795787854774) + (0.07459024106704726, 0.045767020797006674) + (0.07950506909743327, 0.04470359968488524) + (0.0844225553284691, 0.04365253917401457) + (0.08934266867378182, 0.04261384590877704) + (0.09426537803037893, 0.04158752645537711) + (0.09919065227886387, 0.04057358730179472) + (0.10411846028362415, 0.03957203485774774) + (0.10904877089302994, 0.03858287545465) + (0.1139815529396308, 0.0376061153455709) + (0.11891677524035305, 0.0366417607051972) + (0.12385440659669644, 0.03568981762979284) + (0.12879441579493367, 0.03475029213716074) + (0.1337367716062985, 0.03382319016660573) + (0.13868144278720257, 0.03290851757889457) + (0.14362839807940686, 0.03200628015622198) + (0.14857760621024685, 0.03111648360217112) + (0.15352903589280453, 0.030239133541680285) + (0.1584826558261248, 0.029374235521005154) + (0.16343843469540525, 0.028521795007684814) + (0.16839634117219526, 0.027681817390507124) + (0.17335634391459454, 0.0268543079794743) + (0.17831841156745087, 0.02603927200576961) + (0.1832825127625587, 0.025236714621724277) + (0.18824861611885874, 0.024446640900784633) + (0.193216690242628, 0.023669055837481467) + (0.19818670372769737, 0.022903964347394945) + (0.20315862515562372, 0.022151371267128406) + (0.20813242309591684, 0.02141128135427328) + (0.21310806610621152, 0.02068369928738223) + (0.218085522732486, 0.01996862966593782) + (0.22306476150925159, 0.0192660770103239) + (0.22804575095975366, 0.018576045761797166) + (0.23302845959617047, 0.017898540282459185) + (0.23801285591981242, 0.01723356485522798) + (0.24299890842132083, 0.016581123683812704) + (0.24798658558086917, 0.01594122089268457) + (0.25297585586835347, 0.015313860527053524) + (0.257966687743611, 0.014699046552840267) + (0.262959049656593, 0.01409678285665339) + (0.2679529100475927, 0.013507073245761836) + (0.27294823734741824, 0.012929921448074477) + (0.2779449999776115, 0.012365331112113687) + (0.2829431663506391, 0.011813305806994023) + (0.2879427048700936, 0.01127384902239803) + (0.2929435839308936, 0.010746964168555806) + (0.29794577191948324, 0.010232654576222355) + (0.302949237214032, 0.009730923496657384) + (0.30795394818463684, 0.00924177410160354) + (0.31295987319351276, 0.0087652094832682) + (0.31796698059521245, 0.00830123265430105) + (0.3229752387368017, 0.007849846547778982) + (0.3279846159580788, 0.0074110540171838934) + (0.33299508059176597, 0.006984857836386249) + (0.33800660096371116, 0.006571260699628212) + (0.3430191453930884, 0.006170265221504989) + (0.3480326821925981, 0.005781873936949733) + (0.3530471796686671, 0.0054060893012164435) + (0.35806260612164953, 0.005042913689865314) + (0.3630789298460267, 0.0046923493987474085) + (0.36809611913060947, 0.004354398643989343) + (0.37311414225873185, 0.00402906356198085) + (0.3781329675084617, 0.003716346209360344) + (0.3831525631527946, 0.0034162485630013784) + (0.38817289745985595, 0.0031287725200015437) + (0.3931939386931016, 0.0028539198976689217) + (0.3982156551115185, 0.002591692433511872) + (0.40323801496982536, 0.0023420917852274847) + (0.4082609865186734, 0.0021051195306913684) + (0.4132845380048485, 0.0018807771679469898) + (0.41830863767146537, 0.0016690661151972375) + (0.4233332537581785, 0.0014699877107944292) + (0.4283583545013761, 0.0012835432132327629) + (0.4333839081343825, 0.0011097338011394342) + (0.4384098828876591, 0.0009485605732681979) + (0.4434362469890051, 0.0008000245484918178) + (0.4484629686637584, 0.0006641266657951839) + (0.4534900161349965, 0.0005408677842706489) + (0.45851735762373735, 0.00043024868311158926) + (0.4635449613491419, 0.0003322700616072982) + (0.46857279552870645, 0.0002469325391398769) + (0.4736008283784827, 0.00017423665517868336) + (0.47862902811325414, 0.00011418286927789012) + (0.4836573629467562, 6.677156107381954e-5) + (0.4886858010918687, 3.200303028161322e-5) + (0.49371431076081834, 9.877496694121746e-6) + (0.4987428601653795, 3.9510017990629365e-7) + (0.5037714175170755, 3.555900683238633e-6) + (0.5087999510273795, 1.9359878222324767e-5) + (0.513828428907917, 4.780693289108129e-5) + (0.5188568193706581, 8.889688485846925e-5) + (0.5238850906281379, 0.00014262947437027051) + (0.5289132108936312, 0.00020900436175064208) + (0.533941148381381, 0.00028802112740411445) + (0.5389688713067736, 0.0003796792718182562) + (0.5439963478865588, 0.0004839782155670047) + (0.5490235463390419, 0.0006009172993142187) + (0.5540504348842864, 0.0007304957838176751) + (0.5590769817443147, 0.0008727128499341763) + (0.5641031551433098, 0.0010275675986242128) + (0.5691289233078146, 0.0011950590509581804) + (0.5741542544669365, 0.001375186148122376) + (0.5791791168525378, 0.0015679477514247697) + (0.5842034786994568, 0.0017733426423041099) + (0.5892273082456816, 0.0019913695223361394) + (0.5942505737325798, 0.002222027013242034) + (0.5992732434050723, 0.0024653136568975054) + (0.6042952855118532, 0.002721227915341462) + (0.6093166683055826, 0.0029897681707868884) + (0.6143373600430881, 0.003270932725629505) + (0.6193573289855662, 0.0035647198024597593) + (0.6243765433987821, 0.0038711275440728166) + (0.6293949715532716, 0.004190154013482106) + (0.6344125817245421, 0.004521797193929977) + (0.6394293421932649, 0.004866054988900359) + (0.6444452212454955, 0.005222925222134078) + (0.6494601871728469, 0.005592405637639519) + (0.654474208272719, 0.005974493899710165) + (0.6594872528484717, 0.006369187592936587) + (0.6644992892096454, 0.0067764842222231) + (0.6695102856721524, 0.0071963812128037485) + (0.6745202105584787, 0.007628875910257404) + (0.6795290321978841, 0.008073965580526199) + (0.6845367189266031, 0.008531647409930843) + (0.6895432390880445, 0.009001918505190387) + (0.6945485610329935, 0.009484775893439323) + (0.6995526531198026, 0.009980216522245788) + (0.7045554837146117, 0.010488237259633326) + (0.7095570211915211, 0.011008834894097319) + (0.7145572339328197, 0.011542006134628524) + (0.7195560903291585, 0.012087747610731503) + (0.7245535587797698, 0.012646055872447048) + (0.7295496076926585, 0.013216927390373945) + (0.7345442054848028, 0.013800358555690728) + (0.7395373205823547, 0.014396345680179223) + (0.7445289214208388, 0.015004884996247414) + (0.7495189764453526, 0.01562597265695298) + (0.7545074541107671, 0.016259604736029054) + (0.759494322881918, 0.016905777227906205) + (0.7644795512338238, 0.017564486047741523) + (0.7694631076518608, 0.01823572703144083) + (0.7744449606319819, 0.018919495935687758) + (0.7794250786809065, 0.019615788437968407) + (0.7844034303163213, 0.020324600136600868) + (0.7893799840670801, 0.021045926550760985) + (0.7943547084734017, 0.021779763120511664) + (0.7993275720870696, 0.022526105206832403) + (0.8042985434716305, 0.023284948091646607) + (0.8092675912025928, 0.02405628697785378) + (0.8142346838676272, 0.024840116989358174) + (0.8191997900667586, 0.02563643317109965) + (0.8241628784125745, 0.026445230489086535) + (0.8291239175304168, 0.027266503830425837) + (0.8340828760585819, 0.028100248003355865) + (0.8390397226485187, 0.028946457737280218) + (0.8439944259650269, 0.029805127682799082) + (0.8489469546864555, 0.030676252411744986) + (0.8538972775049, 0.03155982641721633) + (0.8588453631264008, 0.032455844113611354) + (0.8637911802711429, 0.033364299836665445) + (0.8687346976736461, 0.034285187843484444) + (0.873675884082974, 0.0352185023125835) + (0.8786147082629236, 0.03616423734392149) + (0.8835511389922255, 0.03712238695894077) + (0.88848514506474, 0.03809294510060246) + (0.8934166952896557, 0.039075905633426666) + (0.8983457584916859, 0.0400712623435302) + (0.9032723035112658, 0.04107900893866634) + (0.9081962992047514, 0.04209913904826501) + (0.9131177144446074, 0.043131646223470765) + (0.9180365181196235, 0.04417652393718785) + (0.9229526791350862, 0.0452337655841164) + (0.927866166412995, 0.04630336448079864) + (0.9327769488922502, 0.04738531386565814) + (0.93768499552885, 0.04847960689904385) + (0.9425902752960883, 0.04958623666327333) + (0.9474927571847496, 0.0507051961626761) + (0.9523924102033057, 0.051836478323638246) + (0.9572892033781127, 0.052980075994646825) + (0.9621831057535992, 0.054135981946334066) + (0.9670740863924799, 0.05530418887152688) + (0.9719621143759258, 0.056484689385286835) + (0.9768471588037875, 0.05767747602496365) + (0.981729188794764, 0.05888254125023673) + (0.9866081734866174, 0.06009987744316647) + (0.9914840820363593, 0.0613294769082402) + (0.9963568836204474, 0.06257133187242281) + (1.0012265474349804, 0.06382543448520384) + (1.0060930426958925, 0.06509177681864875) + (1.010956338639149, 0.06637035086744825) + (1.0158164045209404, 0.0676611485489691) + (1.020673209617871, 0.06896416170330366) + (1.025526723227169, 0.07027938209332629) + (1.0303769146668578, 0.07160680140473819) + (1.0352237532759747, 0.07294641124612755) + (1.040067208414741, 0.0742982031490158) + (1.0449072494647735, 0.07566216856791619) + (1.04974384582927, 0.07703829888038483) + (1.0545769669332041, 0.07842658538707714) + (1.0594065822235184, 0.07982701931180114) + (1.0642326611693183, 0.08123959180157425) + (1.069055173262064, 0.0826642939266784) + (1.0738740880157662, 0.08410111668071774) + (1.0786893749671695, 0.08555005098067214) + (1.0835010036759636, 0.0870110876669612) + (1.0883089437249511, 0.08848421750349322) + (1.0931131647202657, 0.08996943117773348) + (1.0979136362915407, 0.0914667193007539) + (1.1027103280921173, 0.09297607240729877) + (1.1075032097992301, 0.09449748095584187) + (1.1122922511141993, 0.09603093532864704) + (1.117077421762622, 0.0975764258318299) + (1.1218586914945652, 0.09913394269541786) + (1.126636030084755, 0.10070347607341268) + (1.1314094073327707, 0.10228501604385287) + (1.1361787930632266, 0.10387855260887457) + (1.140944157125982, 0.10548407569477947) + (1.1457054693963058, 0.10710157515209073) + (1.1504626997750942, 0.10873104075562656) + (1.1552158181890357, 0.11037246220455588) + (1.15996479459082, 0.11202582912247006) + (1.1647095989593188, 0.11369113105744488) + (1.169450201299778, 0.11536835748210827) + (1.174186571644007, 0.11705749779370578) + (1.1789186800505682, 0.11875854131416874) + (1.1836464966049662, 0.1204714772901807) + (1.188369991419839, 0.12219629489324646) + (1.1930891346351373, 0.12393298321975799) + (1.1978038964183335, 0.12568153129106907) + (1.2025142469645842, 0.12744192805355614) + (1.207220156496945, 0.12921416237869798) + (1.211921595266534, 0.13099822306313658) + (1.2166185335527393, 0.13279409882875504) + (1.2213109416633965, 0.13460177832274534) + (1.2259987899349802, 0.13642125011768158) + (1.2306820487327892, 0.13825250271159106) + (1.2353606884511361, 0.14009552452802798) + (1.2400346795135333, 0.14195030391614605) + (1.2447039923728815, 0.14381682915077287) + (1.2493685975116506, 0.1456950884324817) + (1.2540284654420755, 0.14758506988766995) + (1.2586835667063359, 0.14948676156863105) + (1.2633338718767448, 0.1514001514536314) + (1.2679793515559348, 0.15332522744698607) + (1.272619976377042, 0.15526197737913505) + (1.277255717003894, 0.15721038900672046) + (1.281886544131194, 0.15917045001266383) + (1.286512428484706, 0.16114214800624405) + (1.291133340821441, 0.1631254705231755) + (1.2957492519298421, 0.1651204050256876) + (1.3003601326299634, 0.16712693890260155) + (1.3049659537736646, 0.16914505946941438) + (1.3095666862447874, 0.171174753968375) + (1.3141623009593428, 0.17321600956856753) + (1.3187527688656941, 0.17526881336599076) + (1.3233380609447403, 0.17733315238364122) + (1.3279181482101, 0.17940901357159333) + (1.3324930017082948, 0.18149638380708377) + (1.3370625925189317, 0.18359524989459342) + (1.3416268917548884, 0.1857055985659315) + (1.346185870562489, 0.18782741648031687) + (1.350739500121695, 0.18996069022446682) + (1.3552877516462836, 0.19210540631267858) + (1.3598305963840287, 0.19426155118691524) + (1.3643680056168843, 0.1964291112168921) + (1.3688999506611652, 0.198608072700162) + (1.3734264028677288, 0.20079842186220276) + (1.3779473336221573, 0.20300014485650442) + (1.3824627143449313, 0.20521322776465278) + (1.3869725164916276, 0.20743765659642688) + (1.3914767115530755, 0.20967341728987487) + (1.3959752710555628, 0.21192049571141536) + (1.4004681665609926, 0.21417887765591592) + (1.404955369667079, 0.2164485488467902) + (1.40943685200752, 0.21872949493608562) + (1.4139125852521777, 0.22102170150457412) + (1.4183825411072584, 0.2233251540618426) + (1.4228466913154896, 0.22563983804638643) + (1.427305007656301, 0.22796573882569993) + (1.4317574619460025, 0.23030284169636972) + (1.4362040260379552, 0.23265113188416486) + (1.440644671822767, 0.23501059454413764) + (1.4450793712284467, 0.23738121476070617) + (1.4495080962206055, 0.23976297754776166) + (1.4539308188026117, 0.24215586784875076) + (1.4583475110157853, 0.2445598705367793) + (1.4627581449395657, 0.2469749704147044) + (1.4671626926916903, 0.24940115221523151) + (1.4715611264283717, 0.25183840060101037) + (1.4759534183444716, 0.25428670016473176) + (1.4803395406736788, 0.25674603542922614) + (1.484719465688685, 0.2592163908475613) + (1.4890931657013526, 0.26169775080313595) + (1.493460613062907, 0.26419009960978923) + (1.4978217801640874, 0.26669342151188635) + (1.5021766394353475, 0.26920770068443134) + (1.5065251633470054, 0.27173292123315496) + (1.5108673244094346, 0.2742690671946246) + (1.5152030951732312, 0.2768161225363408) + (1.5195324482293873, 0.27937407115683865) + (1.5238553562094659, 0.2819428968857911) + (1.5281717917857731, 0.28452258348410986) + (1.5324817276715308, 0.2871131146440489) + (1.5367851366210505, 0.28971447398930805) + (1.5410819914298992, 0.2923266450751316) + (1.5453722649350863, 0.29494961138842357) + (1.5496559300152137, 0.2975833563478367) + (1.5539329595906717, 0.3002278633038935) + (1.5582033266237862, 0.3028831155390763) + (1.562467004119008, 0.30554909626794435) + (1.566723965123074, 0.3082257886372346) + (1.5709741827251809, 0.3109131757259691) + (1.575217630057154, 0.31361124054556244) + (1.5794542802936178, 0.3163199660399285) + (1.583684106652165, 0.3190393350855889) + (1.5879070823935277, 0.3217693304917819) + (1.5921231808217393, 0.32450993500056624) + (1.5963323752843188, 0.32726113128694134) + (1.6005346391724178, 0.33002290195894113) + (1.6047299459210116, 0.332795229557761) + (1.6089182690090456, 0.3355780965578523) + (1.613099581959619, 0.33837148536704476) + (1.6172738583401454, 0.34117537832665246) + (1.6214410717625196, 0.343989757711586) + (1.6256011958832866, 0.34681460573046574) + (1.6297542044038067, 0.3496499045257331) + (1.6339000710704221, 0.35249563617376367) + (1.6380387696746248, 0.35535178268498213) + (1.642170274053214, 0.3582183260039702) + (1.646294558088479, 0.3610952480095926) + (1.6504115957083416, 0.36398253051509655) + (1.6545213608865401, 0.366880155268239) + (1.6586238276427836, 0.3697881039513957) + (1.6627189700429192, 0.3727063581816794) + (1.6668067621990958, 0.37563489951105433) + (1.6708871782699275, 0.3785737094264545) + (1.6749601924606567, 0.38152276934990015) + (1.6790257790233185, 0.38448206063861456) + (1.6830839122569028, 0.38745156458514374) + (1.687134566507513, 0.39043126241747017) + (1.6911777161685355, 0.39342113529913747) + (1.6952133356807961, 0.39642116432936647) + (1.6992413995327238, 0.39943133054317426) + (1.7032618822605112, 0.4024516149114945) + (1.7072747584482753, 0.4054819983412987) + (1.7112800027282193, 0.40852246167571526) + (1.7152775897807917, 0.41157298569415235) + (1.7192674943348474, 0.41463355111241773) + (1.723249691167808, 0.41770413858284305) + (1.727224155105816, 0.4207847286944013) + (1.7311908610239028, 0.4238753019728354) + (1.7351497838461412, 0.4269758388807785) + (1.7391008985458054, 0.4300863198178768) + (1.7430441801455299, 0.4332067251209153) + (1.7469796037174667, 0.43633703506394017) + (1.750907144383443, 0.4394772298583849) + (1.7548267773151187, 0.4426272896531951) + (1.7587384777341435, 0.4457871945349532) + (1.7626422209123138, 0.4489569245280065) + (1.766537982171724, 0.4521364595945876) + (1.7704257368849359, 0.45532577963495235) + (1.774305460475116, 0.45852486448749286) + (1.7781771284162065, 0.4617336939288763) + (1.782040716233072, 0.464952247674167) + (1.7858961995016565, 0.46818050537695655) + (1.7897435538491382, 0.47141844662949195) + (1.7935827549540826, 0.47466605096280445) + (1.7974137785465971, 0.4779232978468393) + (1.801236600408485, 0.48119016669058645) + (1.8050511963733926, 0.48446663684220503) + (1.8088575423269764, 0.4877526875891671) + (1.8126556142070354, 0.49104829815837037) + (1.8164453880036846, 0.4943534477162881) + (1.820226839759487, 0.49766811536908473) + (1.8239999455696192, 0.5009922801627587) + (1.8277646815820168, 0.5043259210832711) + (1.831521023997525, 0.5076690170566778) + (1.8352689490700511, 0.5110215469492645) + (1.8390084331067125, 0.5143834895676789) + (1.8427394524679879, 0.5177548236590654) + (1.8464619835678673, 0.5211355279112002) + (1.8501760028739955, 0.524525580952621) + (1.853881486907834, 0.5279249613527737) + (1.8575784122447905, 0.5313336476221313) + (1.861266755514388, 0.5347516182123484) + (1.8649464934003925, 0.5381788515163792) + (1.8686176026409755, 0.5416153258686278) + (1.8722800600288536, 0.5450610195450787) + (1.875933842411437, 0.5485159107634356) + (1.879578926690976, 0.551979977683259) + (1.8832152898247063, 0.5554531984061044) + (1.886842908824996, 0.5589355509756604) + (1.890461760759491, 0.562427013377889) + (1.8940718227512536, 0.5659275635411587) + (1.8976730719789223, 0.5694371793363977) + (1.9012654856768356, 0.572955838577214) + (1.904849041135197, 0.5764835190200579) + (1.9084237157001993, 0.5800201983643414) + (1.911989486774182, 0.5835658542525946) + (1.9155463318157675, 0.5871204642706) + (1.9190942283400052, 0.5906840059475358) + (1.922633153918513, 0.5942564567561179) + (1.9261630861796202, 0.597837794112742) + (1.9296840028085076, 0.6014279953776267) + (1.9331958815473507, 0.605027037854958) + (1.936698700195454, 0.6086348987930261) + (1.9401924366094054, 0.612251555384383) + (1.9436770687031961, 0.6158769847659684) + (1.9471525744483817, 0.6195111640192736) + (1.9506189318742027, 0.6231540701704685) + (1.9540761190677356, 0.6268056801905593) + (1.957524114174027, 0.6304659709955294) + (1.9609628953962315, 0.6341349194464849) + (1.9643924409957507, 0.6378125023498025) + (1.9678127292923702, 0.6414986964572749) + (1.971223738664396, 0.6451934784662583) + (1.9746254475487937, 0.648896825019821) + (1.9780178344413173, 0.6526087127068845) + (1.9814008778966594, 0.6563291180623854) + (1.98477455652857, 0.6600580175674065) + (1.9881388490100038, 0.6637953876493388) + (1.9914937340732508, 0.6675412046820244) + (1.9948391905100704, 0.6712954449859074) + (1.9981751971718256, 0.6750580848281833) + (2.0015017329696176, 0.6788291004229488) + (2.004818776874419, 0.6826084679313524) + (2.0081263079172045, 0.6863961634617459) + (2.0114243051890885, 0.6901921630698338) + (2.014712747841452, 0.6939964427588274) + (2.0179916150860757, 0.6978089784795902) + (2.0212608861952726, 0.701629746130799) + (2.024520540502021, 0.70545872155909) + (2.02777055740009, 0.7092958805592124) + (2.0310109163441736, 0.7131411988741836) + (2.03424159685002, 0.7169946521954398) + (2.03746257849456, 0.7208562161629914) + (2.0406738409160363, 0.7247258663655769) + (2.0438753638141347, 0.7286035783408178) + (2.0470671269501066, 0.7324893275753679) + (2.050249110146904, 0.7363830895050776) + (2.0534212932893023, 0.740284839515142) + (2.0565836563240296, 0.7441945529402596) + (2.059736179259893, 0.7481122050647868) + (2.062878842167904, 0.7520377711228949) + (2.066011625181405, 0.7559712262987264) + (2.0691345084961963, 0.7599125457265519) + (2.072247472370659, 0.7638617044909277) + (2.0753504971258825, 0.7678186776268541) + (2.0784435631457834, 0.7717834401199262) + (2.0815266508772408, 0.7757559669065084) + (2.084599740830204, 0.7797362328738717) + (2.0876628135778303, 0.7837242128603694) + (2.0907158497565987, 0.7877198816555881) + (2.093758830066438, 0.791723214000509) + (2.096791735270843, 0.7957341845876673) + (2.0998145461970017, 0.7997527680613123) + (2.102827243735913, 0.8037789390175676) + (2.1058298088425103, 0.8078126720045933) + (2.1088222225357747, 0.8118539415227395) + (2.11180446589887, 0.8159027220247239) + (2.1147765200792423, 0.8199589879157707) + (2.1177383662887594, 0.8240227135537963) + (2.1206899858038106, 0.8280938732495491) + (2.123631359965441, 0.8321724412667886) + (2.12656247017946, 0.8362583918224402) + (2.129483297916562, 0.8403516990867599) + (2.1323938247124428, 0.8444523371834973) + (2.1352940321679177, 0.8485602801900598) + (2.138183901949035, 0.852675502137676) + (2.141063415787196, 0.8567979770115608) + (2.143932555479264, 0.860927678751074) + (2.14679130288769, 0.8650645812499) + (2.149639639940613, 0.8692086583561911) + (2.15247754863199, 0.8733598838727561) + (2.155305011021695, 0.8775182315572045) + (2.1581220092356443, 0.8816836751221282) + (2.160928525465902, 0.8858561882352598) + (2.1637245419707956, 0.8900357445196418) + (2.1665100410750284, 0.8942223175537922) + (2.16928500516979, 0.8984158808718716) + (2.172049416712867, 0.9026164079638515) + (2.1748032582287586, 0.9068238722756821) + (2.1775465123087767, 0.9110382472094536) + (2.180279161611171, 0.9152595061235804) + (2.1830011888612235, 0.9194876223329473) + (2.1857125768513708, 0.9237225691091018) + (2.1884133084412998, 0.927964319680401) + (2.191103366558067, 0.9322128472321969) + (2.193782734196203, 0.9364681249069988) + (2.196451394417817, 0.9407301258046443) + (2.1991093303527074, 0.9449988229824695) + (2.2017565251984674, 0.9492741894554797) + (2.20439296222059, 0.953556198196519) + (2.207018624752577, 0.9578448221364435) + (2.2096334961960378, 0.9621400341642845) + (2.2122375600208057, 0.966441807127437) + (2.2148307997650276, 0.970750113831808) + (2.217413199035283, 0.9750649270420126) + (2.2199847415066754, 0.9793862194815244) + (2.222545410922943, 0.9837139638328636) + (2.2250951910965586, 0.9880481327377626) + (2.2276340659088323, 0.9923886987973403) + (2.230162019310014, 0.9967356345722753) + (2.2326790353193937, 1.0010889125829796) + (2.235185098025404, 1.0054485053097717) + (2.237680191585721, 1.009814385193053) + (2.240164300227358, 1.0141865246334736) + (2.242637408246779, 1.0185648959921243) + (2.2450995000099803, 1.0229494715906873) + (2.2475505599526073, 1.027340223711637) + (2.2499905725800375, 1.0317371245983906) + (2.2524195224674886, 1.036140146455503) + (2.254837394260111, 1.0405492614488314) + (2.2572441726730883, 1.0449644417057162) + (2.259639842491729, 1.0493856593151547) + (2.2620243885715685, 1.0538128863279788) + (2.2643977958384607, 1.0582460947570311) + (2.266760049288675, 1.062685256577344) + (2.2691111339889893, 1.0671303437263102) + (2.2714510350767885, 1.071581328103869) + (2.2737797377601536, 1.0760381815726792) + (2.2760972273179583, 1.0805008759582964) + (2.2784034890999623, 1.0849693830493532) + (2.2806985085269003, 1.0894436745977365) + (2.282982271090579, 1.0939237223187654) + (2.285254762353965, 1.0984094978913714) + (2.287515967951278, 1.102900972958277) + (2.289765873588083, 1.1073981191261764) + (2.292004465041374, 1.1119009079659075) + (2.294231728159674, 1.1164093110126434) + (2.296447648863116, 1.1209232997660645) + (2.2986522131435363, 1.1254428456905408) + (2.3008454070645623, 1.1299679202153117) + (2.3030272167617003, 1.1344984947346668) + (2.3051976284424214, 1.1390345406081281) + (2.3073566283862528, 1.1435760291606285) + (2.3095042029448614, 1.148122931682697) + (2.311640338542137, 1.1526752194306307) + (2.3137650216742904, 1.157232863626695) + (2.3158782389099217, 1.1617958354592826) + (2.317979976890118, 1.1663641060831136) + (2.320070222328533, 1.170937646619409) + (2.3221489620114726, 1.1755164281560768) + (2.3242161827979757, 1.1801004217478925) + (2.3262718716198996, 1.1846895984166832) + (2.328316015482003, 1.1892839291515107) + (2.3303486014620267, 1.1938833849088568) + (2.3323696167107744, 1.198487936612798) + (2.334379048452199, 1.203097555155208) + (2.3363768839834735, 1.2077122113959171) + (2.3383631106750853, 1.2123318761629216) + (2.340337715970902, 1.216956520252545) + (2.34230068738826, 1.22158611442964) + (2.344252012518039, 1.2262206294277656) + (2.346191679024743, 1.2308600359493722) + (2.3481196746465764, 1.235504304665989) + (2.3500359871955228, 1.2401534062184083) + (2.3519406045574214, 1.2448073112168703) + (2.353833514692044, 1.2494659902412524) + (2.355714705633168, 1.2541294138412453) + (2.3575841654886607, 1.258797552536558) + (2.3594418824405414, 1.2634703768170796) + (2.361287844745071, 1.2681478571430918) + (2.3631220407328115, 1.2728299639454312) + (2.3649444588087114, 1.277516667625694) + (2.366755087452173, 1.2822079385564156) + (2.368553915217126, 1.2869037470812588) + (2.3703409307321017, 1.2916040635152015) + (2.3721161227003034, 1.2963088581447244) + (2.373879479899678, 1.301018101227999) + (2.3756309911829874, 1.305731762995077) + (2.3773706454778765, 1.3104498136480704) + (2.37909843178695, 1.3151722233613583) + (2.3808143391878316, 1.3198989622817492) + (2.382518356833243, 1.3246300005286986) + (2.3842104739510668, 1.3293653081944714) + (2.3858906798444153, 1.334104855344349) + (2.3875589638916987, 1.3388486120168117) + (2.389215315546694, 1.3435965482237284) + (2.3908597243386094, 1.3483486339505464) + (2.392492179872149, 1.3531048391564822) + (2.394112671827584, 1.3578651337747099) + (2.3957211899608124, 1.362629487712554) + (2.397317724103425, 1.3673978708516703) + (2.398902264162774, 1.3721702530482567) + (2.4004748001220295, 1.3769466041332152) + (2.40203532204025, 1.3817268939123737) + (2.4035838200524404, 1.386511092166648) + (2.4051202843696147, 1.3912991686522531) + (2.406644705278862, 1.396091093100886) + (2.408157073143402, 1.4008868352199184) + (2.4096573784026516, 1.4056863646925881) + (2.411145611572281, 1.4104896511781906) + (2.412621763244276, 1.415296664312271) + (2.4140858240869965, 1.4201073737068186) + (2.4155377848452346, 1.4249217489504482) + (2.4169776363402775, 1.4297397596086137) + (2.4184053694699585, 1.4345613752237731) + (2.4198209752087223, 1.4393865653156093) + (2.4212244446076743, 1.4442152993811965) + (2.422615768794643, 1.4490475468952122) + (2.423994938974234, 1.4538832773101218) + (2.4253619464278855, 1.4587224600563733) + (2.4267167825139233, 1.46356506454259) + (2.4280594386676158, 1.4684110601557647) + (2.4293899064012283, 1.4732604162614524) + (2.4307081773040773, 1.4781131022039669) + (2.4320142430425795, 1.4829690873065644) + (2.433308095360313, 1.4878283408716575) + (2.434589726078059, 1.492690832180985) + (2.4358591270938614, 1.497556530495825) + (2.4371162903830754, 1.5024254050571797) + (2.4383612079984185, 1.5072974250859732) + (2.4395938720700188, 1.512172559783245) + (2.4408142748054678, 1.5170507783303444) + (2.442022408489868, 1.5219320498891262) + (2.443218265485881, 1.5268163436021458) + (2.4444018382337793, 1.5317036285928545) + (2.4455731192514882, 1.5365938739657894) + (2.446732101134638, 1.5414870488067782) + (2.4478787765566095, 1.5463831221831283) + (2.449013138268579, 1.551282063143823) + (2.4501351790995667, 1.5561838407197186) + (2.4512448919564793, 1.561088423923739) + (2.4523422698241557, 1.5659957817510723) + (2.453427305765413, 1.5709058831793665) + (2.454499992921088, 1.5758186971689256) + (2.4555603245100817, 1.5807341926629075) + (2.456608293829402, 1.5856523385875134) + (2.4576438942542067, 1.5905731038521953) + (2.4586671192378438, 1.595496457349845) + (2.459677962311895, 1.6004223679569913) + (2.4606764170862157, 1.6053508045339997) + (2.4616624772489724, 1.6102817359252664) + (2.4626361365666893, 1.6152151309594167) + (2.4635973888842817, 1.6201509584495035) + (2.464546228125096, 1.625089187193196) + (2.4654826482909513, 1.630029785972995) + (2.4664066434621734, 1.634972723556406) + (2.4673182077976357, 1.6399179686961627) + (2.468217335534793, 1.6448654901303994) + (2.469104020989718, 1.6498152565828677) + (2.469978258557142, 1.6547672367631248) + (2.470840042710485, 1.6597213993667344) + (2.4716893680018917, 1.6646777130754633) + (2.4725262290622676, 1.6696361465574798) + (2.473350620601312, 1.6745966684675522) + (2.4741625374075524, 1.6795592474472478) + (2.4749619743483744, 1.6845238521251238) + (2.475748926370059, 1.689490451116943) + (2.4765233884978093, 1.694459013025848) + (2.4772853558357864, 1.6994295064425853) + (2.4780348235671372, 1.70440189994568) + (2.4787717869540273, 1.7093761621016526) + (2.479496241337669, 1.7143522614652082) + (2.4802081821383517, 1.7193301665794385) + (2.48090760485547, 1.7243098459760196) + (2.4815945050675534, 1.7292912681754116) + (2.482268878432295, 1.734274401687057) + (2.482930720686575, 1.739259215009582) + (2.483580027646492, 1.7442456766309866) + (2.484216795207388, 1.7492337550288635) + (2.4848410193438712, 1.7542234186705703) + (2.485452696109849, 1.7592146360134573) + (2.486051821638544, 1.7642073755050414) + (2.4866383921425252, 1.769201605583223) + (2.4872124039137287, 1.774197294676479) + (2.487773853323481, 1.779194411204062) + (2.488322736822524, 1.784192923576202) + (2.488859050941037, 1.7891928001943036) + (2.489382792288655, 1.7941940094511484) + (2.4898939575544965, 1.799196519731095) + (2.490392543507178, 1.8042002994102704) + (2.490878546994839, 1.8092053168567888) + (2.49135196494516, 1.8142115404309265) + (2.491812794365383, 1.8192189384853488) + (2.492261032342328, 1.8242274793652837) + (2.4926966760424136, 1.8292371314087426) + (2.4931197227116755, 1.8342478629467103) + (2.4935301696757817, 1.8392596423033472) + (2.4939280143400513, 1.8442724377961903) + (2.494313254189468, 1.849286217736353) + (2.494685886788701, 1.854300950428725) + (2.4950459097821165, 1.8593166041721751) + (2.4953933208937915, 1.8643331472597429) + (2.4957281179275332, 1.8693505479788575) + (2.496050298766889, 1.8743687746115127) + (2.4963598613751605, 1.8793877954344955) + (2.4966568037954158, 1.8844075787195596) + (2.4969411241505046, 1.889428092733646) + (2.4972128206430675, 1.8944493057390746) + (2.4974718915555476, 1.8994711859937463) + (2.497718335250202, 1.9044937017513446) + (2.4979521501691133, 1.9095168212615343) + (2.4981733348341963, 1.9145405127701651) + (2.498381887847211, 1.9195647445194712) + (2.4985778078897676, 1.9245894847482656) + (2.4987610937233384, 1.9296147016921583) + (2.498931744189264, 1.934640363583734) + (2.4990897582087603, 1.939666438652771) + (2.499235134782926, 1.9446928951264353) + (2.4993678729927487, 1.9497197012294802) + (2.49948797199911, 1.9547468251844495) + (2.4995954310427924, 1.9597742352118779) + (2.499690249444483, 1.9648018995304912) + (2.4997724266047774, 1.969829786357408) + (2.499841962004185, 1.9748578639083398) + (2.4998988552031305, 1.9798861003977948) + (2.4999431058419583, 1.984914464039271) + (2.499974713640933, 1.9899429230454677) + (2.4999936784002426, 1.9949714456284795) + (2.5, 2.0) +```` + +````julia fig, ax, sc = lines(points) ```` +```@raw html + +``` + Let's now triangulate this domain. We need to put the arc into its own vector, and we still need to pass a set of points into `triangulate`: -````@example curve_bounded -points = NTuple{2,Float64}[] +````julia +points = NTuple{2, Float64}[] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=[arc], rng) +tri = triangulate(points; boundary_nodes = [arc], rng) ```` -````@example curve_bounded +```` +Delaunay Triangulation. + Number of vertices: 8 + Number of triangles: 6 + Number of edges: 13 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: true + Weighted: false + Constrained: true +```` + +````julia fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Notice that the domain doesn't look like a circle yet. This is because using `triangulate` on the curve just by itself isn't enough. In fact, the triangulation returned in this case is simply one where: @@ -99,12 +2630,16 @@ curve just by itself isn't enough. In fact, the triangulation returned in this c This is probably not what we actually want, though. Instead, we need to refine the domain using mesh refinement. The syntax for this is the same as in the [refinement tutorial](../tutorials/refinement.md): -````@example curve_bounded -refine!(tri; max_area=1e-1, rng) +````julia +refine!(tri; max_area = 1.0e-1, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Much better! We have now triangulated our first curve-bounded domain. ## A Boundary Defined by Multiple Parametric Curves @@ -112,10 +2647,24 @@ We now take a domain which is defined by three separate curves: a circular arc, For piecewise linear curves, we use the same method as we would in previous tutorials, where instead of using coordinates to define the boundary we use numbers that refer to points in the point set. To start, the point set we will be using is -````@example curve_bounded +````julia points = [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0)] ```` +```` +10-element Vector{Tuple{Float64, Float64}}: + (0.1, 0.1) + (0.15, 0.15) + (0.23, 0.23) + (0.009, 0.11) + (0.0, -2.0) + (0.2, -1.7) + (0.000591, 0.00019) + (0.111, -0.005) + (-0.0001, -0.00991) + (1.0, 0.0) +```` + Now, for the boundary, we will take: - A circular arc defined between $(1, 0)$ and $(0, 1)$ centred at $(0, 0)$. @@ -124,81 +2673,102 @@ Now, for the boundary, we will take: We can define these curves as follows: -````@example curve_bounded +````julia arc = CircularArc((1.0, 0.0), (0.0, 1.0), (0.0, 0.0)) bspl = BSpline([(0.0, 1.0), (-1.0, 2.0), (-2.0, 0.0), (-2.0, -1.0), (0.0, -2.0)]) pce = [5, 6, 10] ```` +```` +3-element Vector{Int64}: + 5 + 6 + 10 +```` + Notice that we still must make sure that the curves connect, and that together the curves define a positively-oriented boundary. The domain we get from this looks like: -````@example curve_bounded +````julia t = LinRange(0, 1, 1000) pts = vcat(arc.(t), bspl.(t), points[pce]) fig, ax, sc = lines(pts) fig ```` +```@raw html + +``` + Let's now get a triangulation of this domain. We will use a custom constraint to force triangles closer to the origin to be smaller than those outside of it. -````@example curve_bounded +````julia curve = [[arc], [bspl], pce] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; max_area=1e-2, rng, custom_constraint=(_tri, T) -> begin - i, j, k = triangle_vertices(T) - p, q, r = get_point(_tri, i, j, k) - c = (p .+ q .+ r) ./ 3 - return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1e-3 -end) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!( + tri; max_area = 1.0e-2, rng, custom_constraint = (_tri, T) -> begin + i, j, k = triangle_vertices(T) + p, q, r = get_point(_tri, i, j, k) + c = (p .+ q .+ r) ./ 3 + return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1.0e-3 + end, +) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## A Complicated Multiply-Connected Disjoint Domain For our last example, we take a complicated case with a domain that is disjoint, and where the individual domains are multiply-connected. Let us give the domain followed by an explanation of how it is defined: -````@example curve_bounded +````julia curve = [ [ - [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])] + [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] t = LinRange(0, 1, 1000) fig fig = Figure() ax = Axis(fig[1, 1]) -lines!(ax, [get_point(tri, curve[1][1]...)...], color=:red, label="(1, 2, 3)") -lines!(ax, curve[1][2][1].(t), color=:red, linestyle=:dashdot, label="EllipticalArc") -lines!(ax, curve[2][1][1].(t), color=:green, label="BSpline") -lines!(ax, [get_point(tri, curve[3][1]...)...], color=:blue, label="(4, 5, 6, 7, 4)") -lines!(ax, curve[4][1][1].(t), color=:purple, label="BezierCurve") -lines!(ax, curve[4][2][1].(t), color=:purple, linestyle=:dashdot, label="CatmullRomSpline") -lines!(ax, [get_point(tri, curve[5][1]...)...], color=:orange, label="(12, 11, 10, 12)") -lines!(ax, curve[6][1][1].(t), color=:black, label="CircularArc") +lines!(ax, [get_point(points, curve[1][1]...)...], color = :red, label = "(1, 2, 3)") +lines!(ax, curve[1][2][1].(t), color = :red, linestyle = :dashdot, label = "EllipticalArc") +lines!(ax, curve[2][1][1].(t), color = :green, label = "BSpline") +lines!(ax, [get_point(points, curve[3][1]...)...], color = :blue, label = "(4, 5, 6, 7, 4)") +lines!(ax, curve[4][1][1].(t), color = :purple, label = "BezierCurve") +lines!(ax, curve[4][2][1].(t), color = :purple, linestyle = :dashdot, label = "CatmullRomSpline") +lines!(ax, [get_point(points, curve[5][1]...)...], color = :orange, label = "(12, 11, 10, 12)") +lines!(ax, curve[6][1][1].(t), color = :black, label = "CircularArc") fig[1, 2] = Legend(fig, ax, "Curve") fig ```` +```@raw html + +``` + Let's walk through the definition of `curve`. - The first domain that is defined is the red curve in the above figure, defined in terms of a piecewise linear portion and an elliptical arc. @@ -218,14 +2788,18 @@ the curves connect at the correct points. Let's now triangulate. -````@example curve_bounded +````julia rng = StableRNG(123) -tri = triangulate(copy(points); boundary_nodes=curve, rng) # copying so that we don't mutate for the next section -refine!(tri; max_area=1e-2) +tri = triangulate(copy(points); boundary_nodes = curve, rng) # copying so that we don't mutate for the next section +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ### Using Custom Constraints to Control Refinement Let's give another example of using custom constraints to better control the refinement within different domains. Referencing the previous figure where we showed each domain by colour, let us try and use a coarse mesh in the region bounded between the red and green @@ -235,7 +2809,7 @@ purple and orange curves. To do this, we must have a method for deciding which r To write this function, we note that the indices of these polygons are 1, 3, and 4 for the red, blue, and purple regions, respectively. -````@example curve_bounded +````julia poly_constraint = (_tri, T) -> begin i, j, k = triangle_vertices(T) p, q, r = get_point(_tri, i, j, k) @@ -245,22 +2819,26 @@ poly_constraint = (_tri, T) -> begin return true end max_area = if idx == 1 # coarse - 1e-1 + 1.0e-1 elseif idx == 3 # medium - 1e-2 + 1.0e-2 else # dense - 1e-3 + 1.0e-3 end area = DelaunayTriangulation.triangle_area(p, q, r) return area > max_area end rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; custom_constraint=poly_constraint, rng) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!(tri; custom_constraint = poly_constraint, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## Defining a New Parametric Curve Let us now give an example where we define a domain by a parametric curve that is not provided natively by this package. For this example, we consider the astroid, where @@ -280,9 +2858,9 @@ with this package we need: Let's now meet these requirements. -````@example curve_bounded +````julia struct Astroid <: DelaunayTriangulation.AbstractParametricCurve - lookup_table::Vector{NTuple{2,Float64}} + lookup_table::Vector{NTuple{2, Float64}} end function (c::Astroid)(t) if t == 0.0 || t == 1.0 @@ -311,9 +2889,9 @@ end Let's now define an astroid curve and triangulate it. -````@example curve_bounded +````julia function Astroid(n::Int) - lookup_table = Vector{NTuple{2,Float64}}(undef, n) + lookup_table = Vector{NTuple{2, Float64}}(undef, n) c = Astroid(lookup_table) for i in 1:n lookup_table[i] = c((i - 1) / (n - 1)) @@ -322,12 +2900,16 @@ function Astroid(n::Int) end rng = StableRNG(123) curve = Astroid(1000) -tri = triangulate(NTuple{2,Float64}[]; boundary_nodes=[curve], rng) -refine!(tri; max_area=1e-2) +tri = triangulate(NTuple{2, Float64}[]; boundary_nodes = [curve], rng) +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/curve_bounded.jl). @@ -342,7 +2924,7 @@ using LinearAlgebra n = 50 r = 2.0 xc, yc = 1 / 2, 2.0 -θ = range(0, 2π, length=n + 1) |> collect; +θ = range(0, 2π, length = n + 1) |> collect; θ[end] = θ[begin]; x = xc .+ r * cos.(θ) y = yc .+ r * sin.(θ); @@ -351,21 +2933,21 @@ p = (xc + r, yc) c = (xc, yc) arc = CircularArc(p, p, c) -typeof(arc) |> supertype +typeof(arc) |> supertype |> supertype t = LinRange(0, 1, 2500) points = arc.(t) fig, ax, sc = lines(points) -points = NTuple{2,Float64}[] +points = NTuple{2, Float64}[] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=[arc], rng) +tri = triangulate(points; boundary_nodes = [arc], rng) fig, ax, sc = triplot(tri) fig -refine!(tri; max_area=1e-1, rng) +refine!(tri; max_area = 1.0e-1, rng) fig, ax, sc = triplot(tri) fig @@ -382,55 +2964,57 @@ fig curve = [[arc], [bspl], pce] rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; max_area=1e-2, rng, custom_constraint=(_tri, T) -> begin - i, j, k = triangle_vertices(T) - p, q, r = get_point(_tri, i, j, k) - c = (p .+ q .+ r) ./ 3 - return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1e-3 -end) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!( + tri; max_area = 1.0e-2, rng, custom_constraint = (_tri, T) -> begin + i, j, k = triangle_vertices(T) + p, q, r = get_point(_tri, i, j, k) + c = (p .+ q .+ r) ./ 3 + return norm(c) < 1 / 2 && DelaunayTriangulation.triangle_area(p, q, r) > 1.0e-3 + end, +) fig, ax, sc = triplot(tri) fig curve = [ [ - [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])] + [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] t = LinRange(0, 1, 1000) fig fig = Figure() ax = Axis(fig[1, 1]) -lines!(ax, [get_point(tri, curve[1][1]...)...], color=:red, label="(1, 2, 3)") -lines!(ax, curve[1][2][1].(t), color=:red, linestyle=:dashdot, label="EllipticalArc") -lines!(ax, curve[2][1][1].(t), color=:green, label="BSpline") -lines!(ax, [get_point(tri, curve[3][1]...)...], color=:blue, label="(4, 5, 6, 7, 4)") -lines!(ax, curve[4][1][1].(t), color=:purple, label="BezierCurve") -lines!(ax, curve[4][2][1].(t), color=:purple, linestyle=:dashdot, label="CatmullRomSpline") -lines!(ax, [get_point(tri, curve[5][1]...)...], color=:orange, label="(12, 11, 10, 12)") -lines!(ax, curve[6][1][1].(t), color=:black, label="CircularArc") +lines!(ax, [get_point(points, curve[1][1]...)...], color = :red, label = "(1, 2, 3)") +lines!(ax, curve[1][2][1].(t), color = :red, linestyle = :dashdot, label = "EllipticalArc") +lines!(ax, curve[2][1][1].(t), color = :green, label = "BSpline") +lines!(ax, [get_point(points, curve[3][1]...)...], color = :blue, label = "(4, 5, 6, 7, 4)") +lines!(ax, curve[4][1][1].(t), color = :purple, label = "BezierCurve") +lines!(ax, curve[4][2][1].(t), color = :purple, linestyle = :dashdot, label = "CatmullRomSpline") +lines!(ax, [get_point(points, curve[5][1]...)...], color = :orange, label = "(12, 11, 10, 12)") +lines!(ax, curve[6][1][1].(t), color = :black, label = "CircularArc") fig[1, 2] = Legend(fig, ax, "Curve") fig rng = StableRNG(123) -tri = triangulate(copy(points); boundary_nodes=curve, rng) # copying so that we don't mutate for the next section -refine!(tri; max_area=1e-2) +tri = triangulate(copy(points); boundary_nodes = curve, rng) # copying so that we don't mutate for the next section +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) fig @@ -443,23 +3027,23 @@ poly_constraint = (_tri, T) -> begin return true end max_area = if idx == 1 # coarse - 1e-1 + 1.0e-1 elseif idx == 3 # medium - 1e-2 + 1.0e-2 else # dense - 1e-3 + 1.0e-3 end area = DelaunayTriangulation.triangle_area(p, q, r) return area > max_area end rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=curve, rng) -refine!(tri; custom_constraint=poly_constraint, rng) +tri = triangulate(points; boundary_nodes = curve, rng) +refine!(tri; custom_constraint = poly_constraint, rng) fig, ax, sc = triplot(tri) fig struct Astroid <: DelaunayTriangulation.AbstractParametricCurve - lookup_table::Vector{NTuple{2,Float64}} + lookup_table::Vector{NTuple{2, Float64}} end function (c::Astroid)(t) if t == 0.0 || t == 1.0 @@ -486,7 +3070,7 @@ function DelaunayTriangulation.thrice_differentiate(c::Astroid, t) end function Astroid(n::Int) - lookup_table = Vector{NTuple{2,Float64}}(undef, n) + lookup_table = Vector{NTuple{2, Float64}}(undef, n) c = Astroid(lookup_table) for i in 1:n lookup_table[i] = c((i - 1) / (n - 1)) @@ -495,8 +3079,8 @@ function Astroid(n::Int) end rng = StableRNG(123) curve = Astroid(1000) -tri = triangulate(NTuple{2,Float64}[]; boundary_nodes=[curve], rng) -refine!(tri; max_area=1e-2) +tri = triangulate(NTuple{2, Float64}[]; boundary_nodes = [curve], rng) +refine!(tri; max_area = 1.0e-2) fig, ax, sc = triplot(tri) fig ``` diff --git a/docs/src/tutorials/custom_primitive.md b/docs/src/tutorials/custom_primitive.md index 7e74b32d4..4332b220b 100644 --- a/docs/src/tutorials/custom_primitive.md +++ b/docs/src/tutorials/custom_primitive.md @@ -13,18 +13,17 @@ already defined for most methods that can be overloaded for these primitives, bu completely new structs you are required to define many new methods. The packages we will be using are loaded below. -````@example custom_primitive +````julia using DelaunayTriangulation using CairoMakie using Random using StableRNGs const DT = DelaunayTriangulation; -nothing #hide ```` Let us now define our custom structs. -````@example custom_primitive +````julia struct CustomPoint x::Float64 y::Float64 @@ -54,14 +53,14 @@ struct CustomPolygon segments::Vector{CustomPolygonSegment} end struct CustomPolygons{N} - polygons::NTuple{N,CustomPolygon} + polygons::NTuple{N, CustomPolygon} end ```` Now, depending on your application you might not need to define all possible methods. For example, if you just want an unconstrained triangulation, all you need are `CustomPoint` and `CustomPoints`. So, let's define our methods for increasing complexity. First, for unconstrained triangulations, all we need to define are: -````@example custom_primitive +````julia DT.getx(p::CustomPoint) = p.x DT.gety(p::CustomPoint) = p.y DT.number_type(::Type{CustomPoint}) = Float64 @@ -87,9 +86,13 @@ Base.length(triangles::CustomTriangles) = length(triangles.triangles) CustomTriangles() = CustomTriangles(Vector{CustomTriangle}()) ```` +```` +Main.var"##309".CustomTriangles +```` + Now let's suppose we want to add in some segments. For this, we also need the following methods. -````@example custom_primitive +````julia DT.construct_edge(::Type{CustomSegment}, i, j) = CustomSegment(i, j) DT.initial(e::CustomSegment) = e.i DT.terminal(e::CustomSegment) = e.j @@ -103,9 +106,13 @@ Base.length(segments::CustomSegments) = length(segments.segments) CustomSegments() = CustomSegments(Set{CustomSegment}()) ```` +```` +Main.var"##309".CustomSegments +```` + Next, we want to allow for defining a boundary. For this, we need the following methods. -````@example custom_primitive +````julia DT.has_multiple_curves(::CustomPolygons{N}) where {N} = N > 1 DT.has_multiple_curves(::CustomPolygon) = false DT.has_multiple_curves(::CustomPolygonSegment) = false @@ -117,8 +124,8 @@ DT.num_sections(poly::CustomPolygon) = length(poly.segments) DT.num_boundary_edges(seg::CustomPolygonSegment) = length(seg.segments) DT.get_boundary_nodes(poly::CustomPolygons, m::Integer) = poly.polygons[m] # go down to the mth polygon DT.get_boundary_nodes(poly::CustomPolygon, m::Integer) = poly.segments[m] # go down to the mth segment -DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m-1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node -DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2,Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) +DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m - 1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node +DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2, Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) ```` We now have all that we need for defining our custom primitives for constrained triangulations. We can go further and define methods @@ -126,13 +133,13 @@ for working with Voronoi tessellations and centroidal Voronoi tessellations. For triangulations, so you of course would not have to define the methods we have just defined for segments and boundaries. For Voronoi tessellations, no extra methods are needed, except for -````@example custom_primitive +````julia Base.empty!(segments::CustomSegments) = empty!(segments.segments) ```` if we specify `EdgesType` inside `triangulate` together with `clip=true` (and not otherwise). For centroidal Voronoi tessellations, we need -````@example custom_primitive +````julia DT.set_point!(points::CustomPoints, i, x, y) = points.points[i] = CustomPoint(x, y) ```` @@ -140,7 +147,7 @@ We also need to consider methods needed for mesh refinement. We could also consi but an example of this is already given in the [curve bounded tutorial](../tutorials/curve_bounded.md), so we will only consider methods with piecewise linear boundaries. For refinement, we need the following methods: -````@example custom_primitive +````julia Base.pop!(points::CustomPoints) = pop!(points.points) DT.push_point!(points::CustomPoints, x, y) = push!(points.points, CustomPoint(x, y)) @@ -149,9 +156,9 @@ DT.contains_edge(e::CustomSegment, Es::CustomSegments) = e ∈ Es.segments Base.empty!(triangles::CustomTriangles) = empty!(triangles.triangles) function Base.insert!(seg::CustomPolygonSegment, index, node) - cur_segment = seg.segments[index-1] + cur_segment = seg.segments[index - 1] u, v = edge_vertices(cur_segment) - seg.segments[index-1] = CustomSegment(u, node) + seg.segments[index - 1] = CustomSegment(u, node) insert!(seg.segments, index, CustomSegment(node, v)) return seg end @@ -159,7 +166,7 @@ end Now we have all that we need. Let's now demonstrate that this works. First, let's define the points, segments, and the boundary. -````@example custom_primitive +````julia p1 = CustomPoint(0.0, 0.0) p2 = CustomPoint(1.0, 0.0) p3 = CustomPoint(1.0, 1.0) @@ -171,53 +178,66 @@ p8 = CustomPoint(0.75, 0.75) p9 = CustomPoint(0.25, 0.75) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) segments = CustomSegments(Set{CustomSegment}((CustomSegment(2, 7), CustomSegment(8, 3)))) -outer_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), - CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), -]) -inner_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), -]) +outer_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), + CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), + ], +) +inner_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), + ], +) polygons = CustomPolygons((outer_polygon, inner_polygon)); -nothing #hide ```` Now we triangulate and refine. -````@example custom_primitive +````julia rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=polygons, segments, - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng +tri = triangulate( + points; boundary_nodes = polygons, segments, + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, ) -refine!(tri; max_area=1e-3, rng) +refine!(tri; max_area = 1.0e-3, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Now let's give an example of a centroidal Voronoi tessellation to show that this all works. -````@example custom_primitive +````julia rng = StableRNG(123) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) -tri = triangulate(points; - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng) -vorn = voronoi(tri; clip=true, rng) -vorn_cs = centroidal_smooth(vorn; rng) -fig, ax, sc = voronoiplot(vorn_cs) +tri = triangulate( + points; + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, +) +vorn = voronoi(tri; clip = true, smooth = true, rng) +fig, ax, sc = voronoiplot(vorn) fig ```` +```@raw html + +``` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/custom_primitive.jl). @@ -258,7 +278,7 @@ struct CustomPolygon segments::Vector{CustomPolygonSegment} end struct CustomPolygons{N} - polygons::NTuple{N,CustomPolygon} + polygons::NTuple{N, CustomPolygon} end DT.getx(p::CustomPoint) = p.x @@ -308,8 +328,8 @@ DT.num_sections(poly::CustomPolygon) = length(poly.segments) DT.num_boundary_edges(seg::CustomPolygonSegment) = length(seg.segments) DT.get_boundary_nodes(poly::CustomPolygons, m::Integer) = poly.polygons[m] # go down to the mth polygon DT.get_boundary_nodes(poly::CustomPolygon, m::Integer) = poly.segments[m] # go down to the mth segment -DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m-1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node -DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2,Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) +DT.get_boundary_nodes(seg::CustomPolygonSegment, m::Integer) = m > length(seg.segments) ? DT.terminal(seg.segments[m - 1]) : DT.initial(seg.segments[m]) # go down to the mth edge and extract the left node +DT.get_boundary_nodes(poly::CustomPolygons, (m, n)::NTuple{2, Int32}) = DT.get_boundary_nodes(DT.get_boundary_nodes(poly, m), n) Base.empty!(segments::CustomSegments) = empty!(segments.segments) @@ -323,9 +343,9 @@ DT.contains_edge(e::CustomSegment, Es::CustomSegments) = e ∈ Es.segments Base.empty!(triangles::CustomTriangles) = empty!(triangles.triangles) function Base.insert!(seg::CustomPolygonSegment, index, node) - cur_segment = seg.segments[index-1] + cur_segment = seg.segments[index - 1] u, v = edge_vertices(cur_segment) - seg.segments[index-1] = CustomSegment(u, node) + seg.segments[index - 1] = CustomSegment(u, node) insert!(seg.segments, index, CustomSegment(node, v)) return seg end @@ -341,40 +361,46 @@ p8 = CustomPoint(0.75, 0.75) p9 = CustomPoint(0.25, 0.75) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) segments = CustomSegments(Set{CustomSegment}((CustomSegment(2, 7), CustomSegment(8, 3)))) -outer_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), - CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), -]) -inner_polygon = CustomPolygon([ - CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), -]) +outer_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(1, 2), CustomSegment(2, 3)]), + CustomPolygonSegment([CustomSegment(3, 4), CustomSegment(4, 1)]), + ], +) +inner_polygon = CustomPolygon( + [ + CustomPolygonSegment([CustomSegment(6, 9), CustomSegment(9, 8), CustomSegment(8, 7), CustomSegment(7, 6)]), + ], +) polygons = CustomPolygons((outer_polygon, inner_polygon)); rng = StableRNG(123) -tri = triangulate(points; boundary_nodes=polygons, segments, - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng +tri = triangulate( + points; boundary_nodes = polygons, segments, + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, ) -refine!(tri; max_area=1e-3, rng) +refine!(tri; max_area = 1.0e-3, rng) fig, ax, sc = triplot(tri) fig rng = StableRNG(123) points = CustomPoints([p1, p2, p3, p4, p5, p6, p7, p8, p9]) -tri = triangulate(points; - IntegerType=Int32, - EdgeType=CustomSegment, - TriangleType=CustomTriangle, - EdgesType=CustomSegments, - TrianglesType=CustomTriangles, - rng) -vorn = voronoi(tri; clip=true, rng) -vorn_cs = centroidal_smooth(vorn; rng) -fig, ax, sc = voronoiplot(vorn_cs) +tri = triangulate( + points; + IntegerType = Int32, + EdgeType = CustomSegment, + TriangleType = CustomTriangle, + EdgesType = CustomSegments, + TrianglesType = CustomTriangles, + rng, +) +vorn = voronoi(tri; clip = true, smooth = true, rng) +fig, ax, sc = voronoiplot(vorn) fig ``` diff --git a/docs/src/tutorials/lattice.md b/docs/src/tutorials/lattice.md index a4cb9b0a2..ee5312c0e 100644 --- a/docs/src/tutorials/lattice.md +++ b/docs/src/tutorials/lattice.md @@ -10,7 +10,7 @@ $[a, b] \times [c, d]$. Rather than using `triangulate`, you can use [`triangulate_rectangle`](@ref) for this purpose. To start, we give a simple example -````@example lattice +````julia using DelaunayTriangulation using CairoMakie @@ -21,52 +21,189 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This can be much faster than if we just construct the points in the lattice manually and `triangulate` those. Here's a comparison of the times. -````@example lattice +````julia using BenchmarkTools points = get_points(tri) -@benchmark triangulate($points; randomise=$false) # randomise=false because points are already in lattice order, i.e. spatially sorted +@benchmark triangulate($points; randomise = $false) # randomise=false because points are already in lattice order, i.e. spatially sorted +```` + +```` +BenchmarkTools.Trial: 500 samples with 1 evaluation. + Range (min … max): 6.044 ms … 540.161 ms ┊ GC (min … max): 0.00% … 68.94% + Time (median): 7.578 ms ┊ GC (median): 0.00% + Time (mean ± σ): 9.985 ms ± 26.893 ms ┊ GC (mean ± σ): 14.84% ± 6.34% + + ▁▇▁ ▅▃▇█▂▁ ▄█▃▂▄▄▂ + ███▇██████▅███████▆█▄▇▆▆▆▄▄▅▅▃▆▄▆▁▆▄▂▃▃▃▂▃▃▃▂▁▂▁▁▁▃▁▁▁▂▁▁▁▂ ▄ + 6.04 ms Histogram: frequency by time 13.1 ms < + + Memory estimate: 3.02 MiB, allocs estimate: 71021. ```` -````@example lattice +````julia @benchmark triangulate_rectangle($a, $b, $c, $d, $nx, $ny) ```` +```` +BenchmarkTools.Trial: 4768 samples with 1 evaluation. + Range (min … max): 531.000 μs … 642.144 ms ┊ GC (min … max): 0.00% … 99.83% + Time (median): 736.300 μs ┊ GC (median): 0.00% + Time (mean ± σ): 1.040 ms ± 9.377 ms ┊ GC (mean ± σ): 20.63% ± 6.29% + + ▁▄▆██▅▅▄ + ▂▅█████████▇▇▆▄▄▄▄▅▄▄▅▄▄▄▄▄▃▃▃▃▂▂▂▂▂▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▃ + 531 μs Histogram: frequency by time 1.88 ms < + + Memory estimate: 981.52 KiB, allocs estimate: 2850. +```` + This difference would be more pronounced for larger `nx, ny`. Note that the output of `triangulate_rectangle` treats the boundary as a constrained boundary: -````@example lattice +````julia get_boundary_nodes(tri) ```` +```` +4-element Vector{Vector{Int64}}: + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250] + [250, 249, 248, 247, 246, 245, 244, 243, 242, 241] + [241, 231, 221, 211, 201, 191, 181, 171, 161, 151, 141, 131, 121, 111, 101, 91, 81, 71, 61, 51, 41, 31, 21, 11, 1] +```` + This boundary is split into four separate sections, one for each side of the rectangle. If you would prefer to keep the boundary as one contiguous section, use `single_boundary=true`. Moreover, note that this `tri` has ghost triangles: -````@example lattice +````julia tri ```` +```` +Delaunay Triangulation. + Number of vertices: 250 + Number of triangles: 432 + Number of edges: 681 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true +```` + You can opt into not having these by using `delete_ghosts=true`: -````@example lattice -tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary=true, delete_ghosts=true) +````julia +tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary = true, delete_ghosts = true) tri ```` -````@example lattice +```` +Delaunay Triangulation. + Number of vertices: 250 + Number of triangles: 432 + Number of edges: 681 + Has boundary nodes: true + Has ghost triangles: false + Curve-bounded: false + Weighted: false + Constrained: true +```` + +````julia get_boundary_nodes(tri) ```` -````@example lattice +```` +67-element Vector{Int64}: + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 20 + 30 + 40 + 50 + 60 + 70 + 80 + 90 + 100 + 110 + 120 + 130 + 140 + 150 + 160 + 170 + 180 + 190 + 200 + 210 + 220 + 230 + 240 + 250 + 249 + 248 + 247 + 246 + 245 + 244 + 243 + 242 + 241 + 231 + 221 + 211 + 201 + 191 + 181 + 171 + 161 + 151 + 141 + 131 + 121 + 111 + 101 + 91 + 81 + 71 + 61 + 51 + 41 + 31 + 21 + 11 + 1 +```` + +````julia DelaunayTriangulation.has_ghost_triangles(tri) ```` +```` +false +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/lattice.jl). @@ -83,7 +220,7 @@ fig using BenchmarkTools points = get_points(tri) -@benchmark triangulate($points; randomise=$false) # randomise=false because points are already in lattice order, i.e. spatially sorted +@benchmark triangulate($points; randomise = $false) # randomise=false because points are already in lattice order, i.e. spatially sorted @benchmark triangulate_rectangle($a, $b, $c, $d, $nx, $ny) @@ -91,7 +228,7 @@ get_boundary_nodes(tri) tri -tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary=true, delete_ghosts=true) +tri = triangulate_rectangle(a, b, c, d, nx, ny; single_boundary = true, delete_ghosts = true) tri get_boundary_nodes(tri) diff --git a/docs/src/tutorials/nearest.md b/docs/src/tutorials/nearest.md index cd3974818..f59ff98a3 100644 --- a/docs/src/tutorials/nearest.md +++ b/docs/src/tutorials/nearest.md @@ -12,7 +12,7 @@ given a point `p` find the Voronoi tile `P` containing it. Here we give an examp of how we can use triangulations or tessellations to find the nearest neighbour in the point set to a given point. First, we load in the packages we need. -````@example nearest +````julia using DelaunayTriangulation using CairoMakie ```` @@ -20,43 +20,64 @@ using CairoMakie Now we define the tessellation we will use for this example. The white points shown are the points that we will query. -````@example nearest +````julia points = [ (-3.0, 7.0), (2.0, 6.0), (0.0, 3.0), (0.0, 0.0), (-5.0, 5.0), (-3.0, 1.0), - (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0) + (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0), ] tri = triangulate(points) vorn = voronoi(tri) p, q = (-2.0, 7.5), (0.0, 4.0) -fig, ax, sc = voronoiplot(vorn, markersize=14) -scatter!(ax,[p,q],color=:white,strokecolor=:black,strokewidth=2,markersize=14) +fig, ax, sc = voronoiplot(vorn, markersize = 14) +scatter!(ax, [p, q], color = :white, strokecolor = :black, strokewidth = 2, markersize = 14) fig ```` +```@raw html + +``` + To get the nearest neighbour of a point, we use [`get_nearest_neighbour`](@ref). -````@example nearest +````julia np = get_nearest_neighbour(vorn, p) ```` -````@example nearest +```` +1 +```` + +````julia nq = get_nearest_neighbour(vorn, q) ```` +```` +3 +```` + We see that the nearest point in `points` to `p` is the first point, and to `q` it is the third point. We note that we could have also performed this query without constructing `vorn` directly, instead using `tri`: -````@example nearest +````julia np_tri = get_nearest_neighbour(tri, p) ```` -````@example nearest +```` +1 +```` + +````julia nq_tri = get_nearest_neighbour(tri, q) ```` +```` +3 +```` + Both methods lead to the same results because they use the same algorithm. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/nearest.jl). @@ -68,13 +89,13 @@ using CairoMakie points = [ (-3.0, 7.0), (2.0, 6.0), (0.0, 3.0), (0.0, 0.0), (-5.0, 5.0), (-3.0, 1.0), - (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0) + (2.0, -3.0), (5.0, 5.0), (-4.0, 3.0), ] tri = triangulate(points) vorn = voronoi(tri) p, q = (-2.0, 7.5), (0.0, 4.0) -fig, ax, sc = voronoiplot(vorn, markersize=14) -scatter!(ax,[p,q],color=:white,strokecolor=:black,strokewidth=2,markersize=14) +fig, ax, sc = voronoiplot(vorn, markersize = 14) +scatter!(ax, [p, q], color = :white, strokecolor = :black, strokewidth = 2, markersize = 14) fig np = get_nearest_neighbour(vorn, p) diff --git a/docs/src/tutorials/operations_convex_hull_locking.md b/docs/src/tutorials/operations_convex_hull_locking.md index 845a2eb05..5a6aef34c 100644 --- a/docs/src/tutorials/operations_convex_hull_locking.md +++ b/docs/src/tutorials/operations_convex_hull_locking.md @@ -15,7 +15,7 @@ inside `refine!` when providing an unconstrained triangulation for mesh refinement. Let us give an example of how this can be done, in case you want to do this for your own application. -````@example operations_convex_hull_locking +````julia using DelaunayTriangulation using CairoMakie @@ -24,30 +24,54 @@ tri = triangulate(points) get_boundary_nodes(tri) ```` +```` +Int64[] +```` + As you can see, the boundary nodes field is empty. We can lock the convex hull using [`lock_convex_hull!`](@ref): -````@example operations_convex_hull_locking +````julia lock_convex_hull!(tri) get_boundary_nodes(tri) ```` +```` +11-element Vector{Int64}: + 4 + 1 + 37 + 6 + 27 + 24 + 31 + 5 + 14 + 8 + 4 +```` + Now the boundary nodes field is not empty. Note that if you try and lock the convex hull again, you will get an error because `DelaunayTriangulation.has_boundary_nodes(tri)` is now true. To now unlock the convex hull, we use [`unlock_convex_hull!`](@ref): -````@example operations_convex_hull_locking +````julia unlock_convex_hull!(tri) get_boundary_nodes(tri) ```` +```` +Int64[] +```` + This function will error if it detects that the existing boundary isn't actually equal to the convex hull. Note that this locking/unlocking doesn't actually change anything about the triangulation, it just adds information into `tri` to treat it as if you had provided the convex hull as a constrained boundary to start with. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_convex_hull_locking.jl). diff --git a/docs/src/tutorials/operations_flip_edge.md b/docs/src/tutorials/operations_flip_edge.md index 197ac1672..3ee33565b 100644 --- a/docs/src/tutorials/operations_flip_edge.md +++ b/docs/src/tutorials/operations_flip_edge.md @@ -9,31 +9,10 @@ This tutorial shows we can flip edges in a triangulation. Edge flipping is the f edge `(i, j)` to the edge `(k, ℓ)`, where `(i, j)` and `(k, ℓ)` are diagonals of the quadrilateral formed by $p_ip_jp_kp_l$. The edge flip is illustrated below. -````@example operations_flip_edge -using CairoMakie #hide -points = [(0.0, -1.0), (1.0, 0.0), (0.0, 1.0), (-1.0, 0.0)] #hide -T1 = points[[1, 2, 3]] #hide -T2 = points[[1, 3, 4]] #hide -T3 = points[[1, 2, 4]] #hide -T4 = points[[2, 3, 4]] #hide -fig = Figure() #hide -ax1 = Axis(fig[1, 1], width = 600, height = 400) #hide -ax2 = Axis(fig[1, 2], width = 600, height = 400) #hide -poly!(ax1, [T1; T2], color=(:white, 0.0), strokewidth=3) #hide -poly!(ax2, [T3; T4], color=(:white, 0.0), strokewidth=3) #hide -for ax in (ax1, ax2) #hide - hidedecorations!(ax) #hide - hidespines!(ax) #hide - text!(ax, [(0.05, -1.1)]; text=[L"p_j"], fontsize=43) #hide - text!(ax, [(0.9, 0.1)]; text=[L"p_k"], fontsize=43) #hide - text!(ax, [(0.05, 1.0)]; text=[L"p_i"], fontsize=43) #hide - text!(ax, [(-1.05, 0.05)]; text=[L"p_\ell"], fontsize=43) #hide - xlims!(ax, -1.1, 1.1) #hide - ylims!(ax, -1.3, 1.3) #hide -end #hide -resize_to_layout!(fig) #hide -fig #hide -```` + +```@raw html + +``` Note that this edge flip only makes sense if the quadrilateral is convex. If the quadrilateral is not convex, then the edge flip @@ -43,23 +22,22 @@ quadrilateral is convex inside the [`flip_edge!`](@ref) function. Let us now showcase how we can flip edges. First, we load in the packages we need. -````@example operations_flip_edge +````julia using DelaunayTriangulation using CairoMakie ```` Let us now define our initial triangulation. -````@example operations_flip_edge +````julia points = [(0.0, 0.0), (0.8, 0.0), (1.3, 1.0), (0.0, 1.0)] tri = triangulate(points); -nothing #hide ```` Now, flipping the edge is simple. We simply provide the indices `i` and `j` for the edge we want to flip. Let us flip the edge `(2, 4)`. -````@example operations_flip_edge +````julia fig, ax, sc = triplot(tri, axis = (title = "Before flipping",)) ax2 = Axis(fig[1, 2], title = "After flipping") flip_edge!(tri, 2, 4) @@ -67,10 +45,15 @@ triplot!(ax2, tri) fig ```` +```@raw html + +``` + As simple as that. Note that no checks are made for whether the edge is actually in the triangulation, on the boundary, or if the associated quadrilateral is convex. It is up to you to check this if needed; one way to check would be to use [`DelaunayTriangulation.is_legal`](@ref), as is done inside [`legalise_edge!`](@ref) -- see the [next tutorial](operations_legalise_edge.md). + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_flip_edge.jl). diff --git a/docs/src/tutorials/operations_ghost_triangles.md b/docs/src/tutorials/operations_ghost_triangles.md index 0e41d6bd9..f2180fd0c 100644 --- a/docs/src/tutorials/operations_ghost_triangles.md +++ b/docs/src/tutorials/operations_ghost_triangles.md @@ -11,23 +11,39 @@ As we discussed in the [vertex insertion/deletion example](operations_vertex_ins ghost triangles are needed when we are making updates outside of the boundary of the current triangulation. -````@example operations_ghost_triangles +````julia using DelaunayTriangulation using CairoMakie ```` Let us take an example triangulation. -````@example operations_ghost_triangles +````julia points = [(-1.0, -1.0), (1.0, -1.0), (0.0, 1.0)] tri = triangulate(points) ```` -````@example operations_ghost_triangles +```` +Delaunay Triangulation. + Number of vertices: 3 + Number of triangles: 1 + Number of edges: 3 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + +````julia fig, ax, sc = triplot(tri, show_ghost_edges = true) fig ```` +```@raw html + +``` + The ghost triangles are represented by the convex regions bounded by the blue lines. By default, `triangulate` will keep these ghost triangles. If you want to remove them, you'd have to use @@ -36,88 +52,163 @@ ghost triangles. If you want to remove them, you'd have to use If you do need to query whether your triangulation already has ghost triangles, use -````@example operations_ghost_triangles +````julia DelaunayTriangulation.has_ghost_triangles(tri) ```` +```` +true +```` + To clear the ghost triangles, use -````@example operations_ghost_triangles +````julia delete_ghost_triangles!(tri) DelaunayTriangulation.has_ghost_triangles(tri) ```` +```` +false +```` + An important note for us to make is that ghost triangles are not just there as a concept, but they are actually physically stored. Adding them back with [`add_ghost_triangles!`](@ref), we have: -````@example operations_ghost_triangles +````julia add_ghost_triangles!(tri) get_triangles(tri) ```` +```` +Set{Tuple{Int64, Int64, Int64}} with 4 elements: + (3, 2, -1) + (1, 2, 3) + (1, 3, -1) + (2, 1, -1) +```` + See that there is not just the triangle `(1, 2, 3)`, but also `(3, 2, -1)`, `(1, 3, -1)`, and `(2, 1, -1)` (where the ghost triangles are also oriented counter-clockwise). For example, -````@example operations_ghost_triangles +````julia get_adjacent(tri, 3, 2) ```` -````@example operations_ghost_triangles +```` +-1 +```` + +````julia get_adjacent(tri, 3, -1) ```` -````@example operations_ghost_triangles +```` +1 +```` + +````julia get_adjacent(tri, -1, 2) ```` -````@example operations_ghost_triangles +```` +1 +```` + +````julia get_neighbours(tri, -1) ```` -````@example operations_ghost_triangles +```` +Set{Int64} with 3 elements: + 2 + 3 + 1 +```` + +````julia get_adjacent2vertex(tri, -1) ```` +```` +Set{Tuple{Int64, Int64}} with 3 elements: + (3, 2) + (1, 3) + (2, 1) +```` + If we delete them, they are no longer there. -````@example operations_ghost_triangles +````julia delete_ghost_triangles!(tri) get_triangles(tri) ```` +```` +Set{Tuple{Int64, Int64, Int64}} with 1 element: + (1, 2, 3) +```` + As a last note, we remark that the ghost vertices that define the vertex of these ghost triangles is still there regardless of whether the triangulation has ghost triangles. Thus, for example, the following still work -````@example operations_ghost_triangles +````julia get_neighbours(tri, -1) ```` -````@example operations_ghost_triangles +```` +Set{Int64} with 3 elements: + 2 + 3 + 1 +```` + +````julia get_adjacent2vertex(tri, -1) ```` -````@example operations_ghost_triangles +```` +Set{Tuple{Int64, Int64}} with 3 elements: + (3, 2) + (1, 3) + (2, 1) +```` + +````julia get_adjacent(tri, 3, 2) ```` +```` +-1 +```` + You can remove them from the graph, using -````@example operations_ghost_triangles +````julia DelaunayTriangulation.delete_ghost_vertices_from_graph!(tri) ```` +```` +Graph + Number of edges: 6 + Number of vertices: 3 +```` + so that e.g. `get_neighbours(tri, -1)` is then an error. This will still not remove them from the `adjacent` and `adjacent2vertex` maps, but it does mean for example that -````@example operations_ghost_triangles +````julia collect(each_solid_vertex(tri)) == collect(each_vertex(tri)) ```` +```` +true +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_ghost_triangles.jl). diff --git a/docs/src/tutorials/operations_legalise_edge.md b/docs/src/tutorials/operations_legalise_edge.md index 87f7f5a03..194554efa 100644 --- a/docs/src/tutorials/operations_legalise_edge.md +++ b/docs/src/tutorials/operations_legalise_edge.md @@ -27,7 +27,7 @@ such an insertion; this is the main step of the algorithm of Guibas et al. (1992 We use this tutorial to demonstrate how this can be used. First, let us define some initial triangulation. -````@example operations_legalise_edge +````julia using DelaunayTriangulation using CairoMakie @@ -35,22 +35,26 @@ points = [ (-1.0, 2.0), (4.0, 6.0), (4.0, 3.0), (-3.0, 7.0), (-6.0, -1.0), (9.0, 5.0), (5.0, -5.0), (-6.0, 7.0), (0.0, 0.0), (-3.0, 4.0), (-5.0, 5.0), (-3.0, -4.0), - (5.0, -1.0), (2.0, -2.0) + (5.0, -1.0), (2.0, -2.0), ] p = (3.0, 2.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig ```` +```@raw html + +``` + The blue point is the point to be added. It is inside the triangle `(9, 14, 3)`. To insert it, follow Guibas et al. (1992) and connect the edges of `(9, 14, 3)` to the new point. This is done using [`split_triangle!`](@ref). (Note: the function [`DelaunayTriangulation.complete_split_triangle_and_legalise!`](@ref) does the splitting and the legalising all in the same step, but we do not demonstrate this here.) -````@example operations_legalise_edge +````julia push!(points, p) r = length(points) i, j, k = 9, 14, 3 @@ -59,31 +63,23 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This splitting introduces some new illegal edges, shown in red below. -````@example operations_legalise_edge -function get_all_illegal_edges(tri) #hide - T = NTuple{2,Float64}[] #hide - for E in each_edge(tri) #hide - cert = DelaunayTriangulation.is_legal(tri, E...) #hide - if DelaunayTriangulation.is_illegal(cert) #hide - push!(T, get_point(tri, E...)...) #hide - end #hide - end #hide - return T #hide -end #hide -fig, ax, sc = triplot(tri) #hide -T = get_all_illegal_edges(tri) #hide -linesegments!(ax, T, color=:red, linewidth=3) #hide -fig #hide -```` + +```@raw html + +``` To fix this, we use `legalise_edge!`. This functions take in a single edge, so to legalise all the new edges we apply the function to each edge of the triangle that the point resides in. (The function [`DelaunayTriangulation.legalise_split_triangle!`](@ref) also performs these three calls below.) -````@example operations_legalise_edge +````julia legalise_edge!(tri, i, j, r) legalise_edge!(tri, j, k, r) legalise_edge!(tri, k, i, r) @@ -91,7 +87,12 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + The triangulation is now Delaunay, and there are no more illegal edges. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_legalise_edge.jl). @@ -104,12 +105,12 @@ points = [ (-1.0, 2.0), (4.0, 6.0), (4.0, 3.0), (-3.0, 7.0), (-6.0, -1.0), (9.0, 5.0), (5.0, -5.0), (-6.0, 7.0), (0.0, 0.0), (-3.0, 4.0), (-5.0, 5.0), (-3.0, -4.0), - (5.0, -1.0), (2.0, -2.0) + (5.0, -1.0), (2.0, -2.0), ] p = (3.0, 2.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig push!(points, p) diff --git a/docs/src/tutorials/operations_segment_insertion.md b/docs/src/tutorials/operations_segment_insertion.md index 666f79175..2acc4c8a8 100644 --- a/docs/src/tutorials/operations_segment_insertion.md +++ b/docs/src/tutorials/operations_segment_insertion.md @@ -7,38 +7,55 @@ EditURL = "https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/d This tutorial shows how we can add segments into a triangulation. First, load the packages we need: -````@example operations_segment_insertion +````julia using DelaunayTriangulation using CairoMakie ```` Let us now define our initial triangulation. -````@example operations_segment_insertion -points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), -(0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8)] +````julia +points = [ + (0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), + (0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8), +] tri = triangulate(points) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + To add a segment, we use [`add_segment!`](@ref), providing the vertices for the points that a segment should be added between. Let us add a segment between `(0.0, 0.0)` and `(1.0, 1.0)`, which corresponds to vertices `1` and `3`. -````@example operations_segment_insertion +````julia add_segment!(tri, 1, 3) fig, ax, sc = triplot(tri, show_constrained_edges = true) fig ```` +```@raw html + +``` + Of course, this changed nothing since the segment was already there. We do note, though, that if we look at the constrained edges -````@example operations_segment_insertion +````julia get_interior_segments(tri) ```` +```` +Set{Tuple{Int64, Int64}} with 3 elements: + (1, 6) + (5, 3) + (5, 6) +```` + then we notice that the segment `(1, 3)` was converted into the segments `(1, 6)`, `(5, 3)`, and `(5, 6)`. This is because the segment `(1, 3)` crossed through other vertices, and so the algorithm automatically breaks down the segments into a sequence of connected collinear @@ -46,23 +63,32 @@ segments. Now we add a segment that was not already there. -````@example operations_segment_insertion +````julia add_segment!(tri, 1, 8) fig, ax, sc = triplot(tri, show_constrained_edges = true) fig ```` +```@raw html + +``` + Currently, the segments that you add must not intersect at an angle (they can be collinear with other edges as we have demonstrated above). To see what happens if we do this: -````@example operations_segment_insertion +````julia add_segment!(tri, 8, 2) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + The other constrained edge was partially removed. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_segment_insertion.jl). @@ -71,8 +97,10 @@ You can view the source code for this file [here](https://github.com/JuliaGeomet using DelaunayTriangulation using CairoMakie -points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), -(0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8)] +points = [ + (0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), + (0.9, 0.9), (0.5, 0.5), (0.2, 0.5), (0.5, 0.8), +] tri = triangulate(points) fig, ax, sc = triplot(tri) fig diff --git a/docs/src/tutorials/operations_split_edge.md b/docs/src/tutorials/operations_split_edge.md index 66ad0a5c9..59dbe9311 100644 --- a/docs/src/tutorials/operations_split_edge.md +++ b/docs/src/tutorials/operations_split_edge.md @@ -10,24 +10,30 @@ close to being on, an edge `(i, j)`. In this tutorial, we show how the [`split_edge!`](@ref) function can be used for putting a point on this edge. First, let us consider the following triangulation. -````@example operations_split_edge +````julia using DelaunayTriangulation using CairoMakie -points = [(0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), +points = [ + (0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), (-2.0, 7.0), (3.0, 6.0), (2.0, -2.0), (-4.0, 1.0), - (1.0, 5.0)] + (1.0, 5.0), +] p = (0.0, 3.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig ```` +```@raw html + +``` + We want to add the blue point onto the edge shown, which is `(1, 2)`. To do this, we can use the function `split_edge!`. -````@example operations_split_edge +````julia push!(points, p) r = length(points) i, j = 1, 2 @@ -36,21 +42,29 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Notice that this has only split the edge in one direction. This is because the edges in this case are treated as being oriented. To split the edge in the other direction, we simply swap the indices. -````@example operations_split_edge +````julia split_edge!(tri, j, i, r) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + If you also want to restore the Delaunay property of the triangulation following this splitting, you need to use [`legalise_edge!`](@ref). In this example, though, there are no illegal edges. If there were, we would use -````@example operations_split_edge +````julia k = get_adjacent(tri, i, r) # get_adjacent(tri, i, j) before split_edge!(tri, i, j) legalise_edge!(tri, j, k, r) legalise_edge!(tri, k, i, r) @@ -59,8 +73,21 @@ legalise_edge!(tri, i, k, r) legalise_edge!(tri, k, j, r) ```` +```` +Delaunay Triangulation. + Number of vertices: 10 + Number of triangles: 14 + Number of edges: 23 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + These steps, in particular the steps of splitting both sides of the edge and then legalising, are also implemented in [`DelaunayTriangulation.complete_split_edge_and_legalise!`](@ref). + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_split_edge.jl). @@ -69,13 +96,15 @@ You can view the source code for this file [here](https://github.com/JuliaGeomet using DelaunayTriangulation using CairoMakie -points = [(0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), +points = [ + (0.0, 0.0), (0.0, 4.0), (2.0, 3.0), (-2.0, 3.0), (-2.0, 7.0), (3.0, 6.0), (2.0, -2.0), (-4.0, 1.0), - (1.0, 5.0)] + (1.0, 5.0), +] p = (0.0, 3.0) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig push!(points, p) diff --git a/docs/src/tutorials/operations_split_triangle.md b/docs/src/tutorials/operations_split_triangle.md index ab25037f5..929498e23 100644 --- a/docs/src/tutorials/operations_split_triangle.md +++ b/docs/src/tutorials/operations_split_triangle.md @@ -12,7 +12,7 @@ that triangle into three new triangles. This is called *triangle splitting*. Let us give an example. -````@example operations_split_triangle +````julia using DelaunayTriangulation using CairoMakie @@ -20,17 +20,21 @@ points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)] p = (0.2, 0.5) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig ```` +```@raw html + +``` + The blue point shows the point we want to add into the triangulation using [`split_triangle!`](@ref). To use this, we provide (1) the index of the point in `points` and (2) the triangle that the point is in. The index of the point will be `4` after pushing `p` into `points`, and in this simple example the triangle that `p` is in is `(1, 2, 3)`. -````@example operations_split_triangle +````julia push!(points, p) r = length(points) i, j, k = 1, 2, 3 @@ -39,9 +43,14 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + See the [`legalise_edge!` tutorial](operations_legalise_edge.md) for more discussion about restoring the Delaunay property of the triangulation after using `split_triangle!`. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_split_triangle.jl). @@ -54,7 +63,7 @@ points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)] p = (0.2, 0.5) tri = triangulate(points) fig, ax, sc = triplot(tri) -scatter!(ax, [p], markersize=14) +scatter!(ax, [p], markersize = 14) fig push!(points, p) diff --git a/docs/src/tutorials/operations_vertex_insertion_deletion.md b/docs/src/tutorials/operations_vertex_insertion_deletion.md index f36d3e3c2..a8c29d076 100644 --- a/docs/src/tutorials/operations_vertex_insertion_deletion.md +++ b/docs/src/tutorials/operations_vertex_insertion_deletion.md @@ -9,7 +9,7 @@ This tutorial demonstrates how to insert and delete vertices from a triangulation while maintaining the Delaunay property of the triangulation. First, load the packages we need: -````@example operations_vertex_insertion_deletion +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -17,13 +17,17 @@ using StableRNGs Let us now define our initial triangulation. -````@example operations_vertex_insertion_deletion +````julia points = [(0.0, 0.0), (2.0, 0.0), (1.0, 2.0)] tri = triangulate(points) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Note that we use a structure for `points` that is mutable so that points can be pushed into it. @@ -33,31 +37,40 @@ is a method which uses the index of the vertex rather than the coordinates, but we don't use that here as the points to be added are not already in `points`. Here, we add a point at `(1.0, 0.5)`. -````@example operations_vertex_insertion_deletion +````julia add_point!(tri, 1.0, 0.5) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This is still a valid Delaunay triangulation, unsurprisingly due to the small number of points. We can also add points that are outside of the triangulation: -````@example operations_vertex_insertion_deletion +````julia add_point!(tri, 0.0, 1.0) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + One important thing to note here is that, if not for the ghost triangles inside `tri`, adding a point outside of the triangulation would not work. Here is an example of this failing. -````@example operations_vertex_insertion_deletion +````julia delete_ghost_triangles!(tri) -try #hide -add_point!(tri, 2.0, 1.5) -catch e #hide -println(e) #hide -end #hide + add_point!(tri, 2.0, 1.5) +```` + +```` +BoundsError([(0.0, 0.0), (2.0, 0.0), (1.0, 2.0), (1.0, 0.5), (0.0, 1.0)], (0,)) + ```` This is a `BoundsError`, because the triangulation has had to @@ -67,38 +80,70 @@ perform some operation including a point outside of the boundary, you need to be sure that you have ghost triangles, which you can query using [`DelaunayTriangulation.has_ghost_triangles`](@ref). -````@example operations_vertex_insertion_deletion +````julia DelaunayTriangulation.has_ghost_triangles(tri) ```` -````@example operations_vertex_insertion_deletion +```` +false +```` + +````julia add_ghost_triangles!(tri) ```` -````@example operations_vertex_insertion_deletion +```` +Delaunay Triangulation. + Number of vertices: 5 + Number of triangles: 4 + Number of edges: 8 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false +```` + +````julia DelaunayTriangulation.has_ghost_triangles(tri) ```` +```` +true +```` + Another issue is that the convex hull is not updated as we add (or delete) points for performance reasons: -````@example operations_vertex_insertion_deletion +````julia get_convex_hull_vertices(tri) ```` +```` +4-element Vector{Int64}: + 3 + 1 + 2 + 3 +```` + If we do want to fix the convex hull, we can use [`convex_hull!(tri)`](@ref). -````@example operations_vertex_insertion_deletion +````julia convex_hull!(tri) -fig, ax, sc = triplot(tri, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_convex_hull = true) fig ```` +```@raw html + +``` + We now have the same triangulation that we would have had if we had done `triangulate` on this set of points originally. To now push this further, let's add in a bunch of random points. -````@example operations_vertex_insertion_deletion +````julia rng = StableRNG(123) for _ in 1:1000 new_point = 2rand(rng, 2) @@ -108,12 +153,16 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Let us now demonstrate how to delete points. To do this, we use [`delete_point!`](@ref). This function takes vertices rather than coordinates, identifying the corresponding point in `points` by its index. Let us demonstrate this operation by deleting all points within a distance of `1/2` around `(1.0, 1.0)`. -````@example operations_vertex_insertion_deletion +````julia vertices_to_delete = Iterators.filter(each_solid_vertex(tri)) do i p = get_point(tri, i) r2 = (getx(p) - 1.0)^2 + (gety(p) - 1.0)^2 @@ -126,9 +175,14 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Note that in this situation, `points` still contains those points that we have now deleted. This is the reason to be careful about using, say, [`DelaunayTriangulation.each_point`](@ref) rather than [`each_solid_vertex`](@ref). This triangulation is also still Delaunay. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/operations_vertex_insertion_deletion.jl). @@ -152,7 +206,7 @@ fig, ax, sc = triplot(tri) fig delete_ghost_triangles!(tri) -add_point!(tri, 2.0, 1.5) + add_point!(tri, 2.0, 1.5) DelaunayTriangulation.has_ghost_triangles(tri) @@ -163,7 +217,7 @@ DelaunayTriangulation.has_ghost_triangles(tri) get_convex_hull_vertices(tri) convex_hull!(tri) -fig, ax, sc = triplot(tri, show_convex_hull=true) +fig, ax, sc = triplot(tri, show_convex_hull = true) fig rng = StableRNG(123) diff --git a/docs/src/tutorials/point_in_polygon.md b/docs/src/tutorials/point_in_polygon.md index 885767abf..b20709126 100644 --- a/docs/src/tutorials/point_in_polygon.md +++ b/docs/src/tutorials/point_in_polygon.md @@ -7,7 +7,7 @@ EditURL = "https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/d This tutorial shows how we can perform point-in-polygon testing, and how we can find a polygon containing a point. First, let us build this ploygon. -````@example point_in_polygon +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -156,10 +156,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -174,11 +177,15 @@ fig = Figure() ax = Axis(fig[1, 1]) scatter!(ax, query_points) for nodes in nodes - lines!(ax, points[reduce(vcat, nodes)], color=:magenta, linewidth=3) + lines!(ax, points[reduce(vcat, nodes)], color = :magenta, linewidth = 3) end fig ```` +```@raw html + +``` + To now determine which of these query points are inside any of the magenta regions, we have several methods: - Using [`DelaunayTriangulation.distance_to_polygon`](@ref), check if the distance to the polygon is positive (inside) or negative (outside). - Triangulate the domain and use [`DelaunayTriangulation.dist`](@ref) to get the distance from a point to the triangulation. @@ -190,33 +197,37 @@ for example, you might already have a triangulation and want to use that. We als here do not use exact arithmetic, unlike other predicates in this package, so there may be some robustness issues for points very close to the boundary. Here is the first approach: -````@example point_in_polygon +````julia is_inside = [DelaunayTriangulation.distance_to_polygon(q, points, nodes) > 0 for q in query_points] -scatter!(ax, query_points[is_inside], color=:blue) -scatter!(ax, query_points[.!is_inside], color=:red) +scatter!(ax, query_points[is_inside], color = :blue) +scatter!(ax, query_points[.!is_inside], color = :red) fig ```` +```@raw html + +``` + Here is the second method. -````@example point_in_polygon -tri = triangulate(points; boundary_nodes=nodes) -is_inside_2 = [DelaunayTriangulation.dist(tri, q) > 0 for q in query_points] +````julia +tri = triangulate(points; boundary_nodes = nodes) +is_inside_2 = [DelaunayTriangulation.dist(tri, q) > 0 for q in query_points]; ```` The third method is to use [`find_polygon`](@ref) to find the polygon containing the point. If no such polygon exists, `find_polygon` returns `0`, so this is what we use to determine if a point is inside or outside the polygon. -````@example point_in_polygon -is_inside_3 = [find_polygon(tri, q) ≠ 0 for q in query_points] +````julia +is_inside_3 = [find_polygon(tri, q) ≠ 0 for q in query_points]; ```` This test is not exactly the same as the previous one (with a difference of about five points) due to points near the boundary. The fourth method is: -````@example point_in_polygon +````julia hierarchy = DelaunayTriangulation.construct_polygon_hierarchy(points, nodes) -is_inside_4 = [find_polygon(hierarchy, points, nodes, q) ≠ 0 for q in query_points] +is_inside_4 = [find_polygon(hierarchy, points, nodes, q) ≠ 0 for q in query_points]; ```` ## Just the code @@ -372,10 +383,13 @@ J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] -A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] +A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], +] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -390,22 +404,22 @@ fig = Figure() ax = Axis(fig[1, 1]) scatter!(ax, query_points) for nodes in nodes - lines!(ax, points[reduce(vcat, nodes)], color=:magenta, linewidth=3) + lines!(ax, points[reduce(vcat, nodes)], color = :magenta, linewidth = 3) end fig is_inside = [DelaunayTriangulation.distance_to_polygon(q, points, nodes) > 0 for q in query_points] -scatter!(ax, query_points[is_inside], color=:blue) -scatter!(ax, query_points[.!is_inside], color=:red) +scatter!(ax, query_points[is_inside], color = :blue) +scatter!(ax, query_points[.!is_inside], color = :red) fig -tri = triangulate(points; boundary_nodes=nodes) -is_inside_2 = [DelaunayTriangulation.dist(tri, q) > 0 for q in query_points] +tri = triangulate(points; boundary_nodes = nodes) +is_inside_2 = [DelaunayTriangulation.dist(tri, q) > 0 for q in query_points]; -is_inside_3 = [find_polygon(tri, q) ≠ 0 for q in query_points] +is_inside_3 = [find_polygon(tri, q) ≠ 0 for q in query_points]; hierarchy = DelaunayTriangulation.construct_polygon_hierarchy(points, nodes) -is_inside_4 = [find_polygon(hierarchy, points, nodes, q) ≠ 0 for q in query_points] +is_inside_4 = [find_polygon(hierarchy, points, nodes, q) ≠ 0 for q in query_points]; ``` --- diff --git a/docs/src/tutorials/point_location.md b/docs/src/tutorials/point_location.md index 18c554e3c..1ab5485bf 100644 --- a/docs/src/tutorials/point_location.md +++ b/docs/src/tutorials/point_location.md @@ -19,7 +19,7 @@ a keyword argument `concavity_protection` to make an extra check to guarantee ev We start with a simple example, demonstrating point location on an unconstrained triangulation. -````@example point_location +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -27,7 +27,7 @@ using StableRNGs points = [ (-3.0, 6.0), (5.0, 1.0), (-5.0, 3.0), (2.0, -3.0), (5.0, 8.0), (0.0, 0.0), (2.0, 5.0), (-3.0, 1.0), - (-2.0, -1.0), (-1.0, 4.0) + (-2.0, -1.0), (-1.0, 4.0), ] tri = triangulate(points) q = (3.0, 3.0) @@ -36,35 +36,55 @@ scatter!(ax, q) fig ```` +```@raw html + +``` + The aim is to, from `tri`, find which triangle contains the point `q` shown. Using the `find_triangle` function, this is simple. -````@example point_location +````julia V = find_triangle(tri, q) ```` +```` +(2, 7, 6) +```` + The result means that the triangle `(2, 7, 6)` contains the point, as we can easily check: -````@example point_location +````julia DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) ```` +```` +Certificate.Inside = 0 +```` + When we provide no keyword arguments, the default behaviour of `find_triangle` is to first sample some number of points (defaults to $\lceil \sqrt[3]{n}\rceil$, where $n$ is the number of points), and then start at the point that is closest to `q` out of those sampled, then marching along the triangulation until `q` is found. This number of samples can be changed using the `m` keyword argument. For example, -````@example point_location -V = find_triangle(tri, q, m=10) +````julia +V = find_triangle(tri, q, m = 10) +```` + +```` +(7, 6, 2) ```` means that we get a sample of size 10, and start at whichever point is the closest. -(For technical reasons, this sample is with replacement, so it is possible that the same point is sampled more than once.) +(For technical reasons, this sampling is with replacement, so it is possible that the same point is sampled more than once.) You could also instead specify the point to start at using the `k` keyword argument, in which case no points are sampled. For example, -````@example point_location -V = find_triangle(tri, q, k=6) +````julia +V = find_triangle(tri, q, k = 6) +```` + +```` +(2, 7, 6) ```` starts the algorithm at the point `6`. @@ -75,37 +95,49 @@ or `(k, i, j)` could be returned. The point `q` does not have to be in the triangulation. For example, consider the following point. -````@example point_location +````julia q = (-5.0, 8.0) fig, ax, sc = triplot(tri) scatter!(ax, q) fig ```` +```@raw html + +``` + We obtain: -````@example point_location +````julia V = find_triangle(tri, q) ```` +```` +(1, 5, -1) +```` + See that the result is a ghost triangle `(1, 5, -1)`. As discussed in the [manual](../manual/ghost_triangles.md), this can be interpreted as meaning that `q` is between the two lines through the points `1` and `5` that start at a central point of the triangulation. (The index `-1` is just the ghost vertex.) This can be visualised. -````@example point_location -fig, ax, sc = triplot(tri, show_ghost_edges=true) +````julia +fig, ax, sc = triplot(tri, show_ghost_edges = true) scatter!(ax, q) fig ```` +```@raw html + +``` + ## Region with concave boundaries and holes Now we give an example of point location for a reason with holes. Since the case where all boundaries are convex is reasonably straight forward, here we consider concave boundaries and discuss methods for improving the speed of the algorithm in this case. First, let us give our example triangulation. -````@example point_location +````julia a, b, c = (0.0, 8.0), (0.0, 6.0), (0.0, 4.0) d, e, f = (0.0, 2.0), (0.0, 0.0), (2.0, 0.0) g, h, i = (4.0, 0.0), (6.0, 0.0), (8.0, 0.0) @@ -119,60 +151,97 @@ inner = [[r, z, v, u, w, t, s, r]] boundary_nodes, points = convert_boundary_points_to_indices([outer, inner]) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.01get_area(tri), rng); -nothing #hide +refine!(tri; max_area = 0.01get_area(tri), rng); ```` The issue with concavity is that the ghost triangles can no longer be sensibly defined. To demonstrate this, see the following plot: -````@example point_location -fig, ax, sc = triplot(tri, show_ghost_edges=true) +````julia +fig, ax, sc = triplot(tri, show_ghost_edges = true) fig ```` +```@raw html + +``` + The ghost edges now intersect the boundary, which doesn't make sense, and creates difficulties. Let us now demonstrate how the function still works here. We try finding the blue points shown below. -````@example point_location +````julia qs = [ (4.0, 5.0), (1.0, 5.6), (0.2, 5.0), (0.0, -1.0), (0.5, 3.5), (2.5, 1.5), (1.0, 2.0), (4.5, 1.0), (6.0, 1.5), - (0.5, 8.5), (1.0, 7.5), (1.2, 1.6) + (0.5, 8.5), (1.0, 7.5), (1.2, 1.6), ] -fig, ax, sc = triplot(tri, show_ghost_edges=false) -scatter!(ax, qs, color=:blue, markersize=16) +fig, ax, sc = triplot(tri, show_ghost_edges = false) +scatter!(ax, qs, color = :blue, markersize = 16) fig ```` +```@raw html + +``` + Now let's find the triangles. -````@example point_location +````julia Vs = [find_triangle(tri, q; rng) for q in qs] ```` +```` +12-element Vector{Tuple{Int64, Int64, Int64}}: + (35, 12, -3) + (77, 56, 76) + (84, 55, 74) + (71, 6, -2) + (102, 47, 89) + (-4, 54, 25) + (24, -4, 18) + (57, 60, 37) + (69, 70, 39) + (94, 17, -3) + (17, 81, 80) + (24, -4, 18) +```` + While we do find some triangles, they may not all be correct. For example, the triangle found for `(1.2, 1.6)` is -````@example point_location +````julia Vs[end] ```` -but the point `(1.2, 1.6)` is actually inside the triangulation. We can even see -this if we run `find_triangle` again: - -````@example point_location -V = find_triangle(tri, (1.2, 1.6); rng) +```` +(24, -4, 18) ```` +but the point `(1.2, 1.6)` is actually inside the triangulation. To protect against this, you need to use `concavity_protection=true`, which will enable a check to be made that the point is actually outside the triangulation whenever a ghost triangle is to be returned. If the check finds this to not be the case, it restarts. With these results, we now compute: -````@example point_location -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +````julia +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] +```` + +```` +12-element Vector{Tuple{Int64, Int64, Int64}}: + (35, 12, -3) + (77, 56, 76) + (55, 74, 84) + (71, 6, -2) + (89, 102, 47) + (-4, 54, 25) + (18, 24, -4) + (50, 59, 37) + (39, 69, 70) + (94, 17, -3) + (17, 81, 80) + (23, 41, 22) ```` Here is how we can actually test that these results are now correct. We cannot directly @@ -181,7 +250,7 @@ know that the ghost triangles are invalid. Instead, we find the distance of each triangulation's boundary using [`DelaunayTriangulation.dist`](@ref) so that we can classify it as being inside or outside of the triangulation, and then check the type of the found triangle. -````@example point_location +````julia δs = [DelaunayTriangulation.dist(tri, q) for q in qs] results = Vector{Bool}(undef, length(qs)) for (j, (q, δ, V)) in (enumerate ∘ zip)(qs, δs, Vs) @@ -197,6 +266,22 @@ end results ```` +```` +12-element Vector{Bool}: + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +```` + As we see, the triangles are now all correct. ## Disjoint domains @@ -205,7 +290,7 @@ domains that are disjoint to the current domain, thus allowing us to demonstrate how `find_triangle` applies here. The new domain is below, along with the points we will be searching for. -````@example point_location +````julia m₁, n₁, o₁ = (6.0, 8.0), (8.0, 8.0), (8.0, 4.0) p₁, q₁, r₁ = (10.0, 4.0), (6.0, 6.0), (8.0, 6.0) s₁, t₁, u₁ = (9.0, 7.0), (4.0, 4.0), (5.0, 4.0) @@ -213,32 +298,51 @@ v₁, w₁ = (5.0, 3.0), (4.0, 3.0) new_domain₁ = [[m₁, q₁, o₁, p₁, r₁, s₁, n₁, m₁]] new_domain₂ = [[t₁, w₁, v₁, u₁, t₁]] boundary_nodes, points = convert_boundary_points_to_indices( - [outer, inner, new_domain₁, new_domain₂] + [outer, inner, new_domain₁, new_domain₂], ) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.001get_area(tri), rng) +refine!(tri; max_area = 0.001get_area(tri), rng) qs = [ (0.6, 6.4), (1.4, 0.8), (3.1, 2.9), (6.3, 4.9), (4.6, 3.5), (7.0, 7.0), (8.9, 5.1), (5.8, 0.8), (1.0, 1.5), - (1.5, 2.0), (8.15, 6.0) + (1.5, 2.0), (8.15, 6.0), ] fig, ax, sc = triplot(tri) -scatter!(ax, qs, color=:blue, markersize=16) +scatter!(ax, qs, color = :blue, markersize = 16) fig ```` +```@raw html + +``` + Here are the `find_triangle` results. -````@example point_location -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +````julia +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] +```` + +```` +11-element Vector{Tuple{Int64, Int64, Int64}}: + (422, 348, 368) + (435, 797, 434) + (180, 46, -3) + (486, 88, -2) + (947, 777, 773) + (748, 642, 718) + (575, 620, 815) + (117, 803, 918) + (237, 804, 840) + (18, -4, 294) + (715, 29, -5) ```` Again, we can verify that these are all correct as follows. Without `concavity_protection=true`, these would not be all correct. -````@example point_location +````julia δs = [DelaunayTriangulation.dist(tri, q) for q in qs] results = Vector{Bool}(undef, length(qs)) for (j, (q, δ, V)) in (enumerate ∘ zip)(qs, δs, Vs) @@ -254,6 +358,21 @@ end results ```` +```` +11-element Vector{Bool}: + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/point_location.jl). @@ -266,7 +385,7 @@ using StableRNGs points = [ (-3.0, 6.0), (5.0, 1.0), (-5.0, 3.0), (2.0, -3.0), (5.0, 8.0), (0.0, 0.0), (2.0, 5.0), (-3.0, 1.0), - (-2.0, -1.0), (-1.0, 4.0) + (-2.0, -1.0), (-1.0, 4.0), ] tri = triangulate(points) q = (3.0, 3.0) @@ -278,9 +397,9 @@ V = find_triangle(tri, q) DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) -V = find_triangle(tri, q, m=10) +V = find_triangle(tri, q, m = 10) -V = find_triangle(tri, q, k=6) +V = find_triangle(tri, q, k = 6) q = (-5.0, 8.0) fig, ax, sc = triplot(tri) @@ -289,7 +408,7 @@ fig V = find_triangle(tri, q) -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) scatter!(ax, q) fig @@ -306,28 +425,26 @@ inner = [[r, z, v, u, w, t, s, r]] boundary_nodes, points = convert_boundary_points_to_indices([outer, inner]) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.01get_area(tri), rng); +refine!(tri; max_area = 0.01get_area(tri), rng); -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) fig qs = [ (4.0, 5.0), (1.0, 5.6), (0.2, 5.0), (0.0, -1.0), (0.5, 3.5), (2.5, 1.5), (1.0, 2.0), (4.5, 1.0), (6.0, 1.5), - (0.5, 8.5), (1.0, 7.5), (1.2, 1.6) + (0.5, 8.5), (1.0, 7.5), (1.2, 1.6), ] -fig, ax, sc = triplot(tri, show_ghost_edges=false) -scatter!(ax, qs, color=:blue, markersize=16) +fig, ax, sc = triplot(tri, show_ghost_edges = false) +scatter!(ax, qs, color = :blue, markersize = 16) fig Vs = [find_triangle(tri, q; rng) for q in qs] Vs[end] -V = find_triangle(tri, (1.2, 1.6); rng) - -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] δs = [DelaunayTriangulation.dist(tri, q) for q in qs] results = Vector{Bool}(undef, length(qs)) @@ -350,22 +467,22 @@ v₁, w₁ = (5.0, 3.0), (4.0, 3.0) new_domain₁ = [[m₁, q₁, o₁, p₁, r₁, s₁, n₁, m₁]] new_domain₂ = [[t₁, w₁, v₁, u₁, t₁]] boundary_nodes, points = convert_boundary_points_to_indices( - [outer, inner, new_domain₁, new_domain₂] + [outer, inner, new_domain₁, new_domain₂], ) rng = StableRNG(125123) tri = triangulate(points; rng, boundary_nodes) -refine!(tri; max_area=0.001get_area(tri), rng) +refine!(tri; max_area = 0.001get_area(tri), rng) qs = [ (0.6, 6.4), (1.4, 0.8), (3.1, 2.9), (6.3, 4.9), (4.6, 3.5), (7.0, 7.0), (8.9, 5.1), (5.8, 0.8), (1.0, 1.5), - (1.5, 2.0), (8.15, 6.0) + (1.5, 2.0), (8.15, 6.0), ] fig, ax, sc = triplot(tri) -scatter!(ax, qs, color=:blue, markersize=16) +scatter!(ax, qs, color = :blue, markersize = 16) fig -Vs = [find_triangle(tri, q; rng, concavity_protection=true) for q in qs] +Vs = [find_triangle(tri, q; rng, concavity_protection = true) for q in qs] δs = [DelaunayTriangulation.dist(tri, q) for q in qs] results = Vector{Bool}(undef, length(qs)) diff --git a/docs/src/tutorials/pole_of_inaccessibility.md b/docs/src/tutorials/pole_of_inaccessibility.md index 6a1d546ec..211442de9 100644 --- a/docs/src/tutorials/pole_of_inaccessibility.md +++ b/docs/src/tutorials/pole_of_inaccessibility.md @@ -13,7 +13,7 @@ triangulation tutorials. In particular, the algorithm we use works for polygons interior holes, or even nested holes, as well as for multipolygons. We give a simple example. First, let us define our polygon. -````@example pole_of_inaccessibility +````julia using DelaunayTriangulation using CairoMakie @@ -48,39 +48,53 @@ points = [ 2.12497 9.42582 7.27436 2.7979 3.0 4.0 - 5.33697 1.88019]' -outer_boundary = [ # split into segments for demonstration purposes + 5.33697 1.88019 +]' +outer_boundary = [ + # split into segments for demonstration purposes [1, 4, 3, 2], [2, 9, 10, 11, 8, 7, 12], [12, 6, 13, 5, 14, 15, 16, 17, 16], - [16, 17, 18, 19, 20, 21, 22, 23, 1] + [16, 17, 18, 19, 20, 21, 22, 23, 1], ] inner_1 = [ - [26, 25, 24], [24, 28, 27, 26] + [26, 25, 24], [24, 28, 27, 26], ] inner_2 = [ - [29, 30, 31, 29] + [29, 30, 31, 29], ] boundary_nodes = [outer_boundary, inner_1, inner_2] fig = Figure() ax = Axis(fig[1, 1]) for i in eachindex(boundary_nodes) - lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color=:red) + lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color = :red) end fig ```` +```@raw html + +``` + To now find the pole of inaccessibility, use [`DelaunayTriangulation.pole_of_inaccessibility`](@ref): -````@example pole_of_inaccessibility +````julia pole = DelaunayTriangulation.pole_of_inaccessibility(points, boundary_nodes) ```` -````@example pole_of_inaccessibility -scatter!(ax, pole, color=:blue, markersize=16) +```` +(-1.0785225000000003, 5.3725974999999995) +```` + +````julia +scatter!(ax, pole, color = :blue, markersize = 16) fig ```` +```@raw html + +``` + This shows that the point inside the red region that is furthest from the boundary is the blue point shown. @@ -88,10 +102,10 @@ We note that triangulations also store the poles of inaccessibility for each bou as these are used to define the orientation of a ghost edge. Here is an example. First, we get the triangulation. -````@example pole_of_inaccessibility +````julia θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -102,33 +116,58 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) +```` + +```` +Delaunay Triangulation. + Number of vertices: 76 + Number of triangles: 76 + Number of edges: 152 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true ```` To see the poles, called representative points, we use -````@example pole_of_inaccessibility +````julia DelaunayTriangulation.get_representative_point_list(tri) ```` +```` +Dict{Int64, DelaunayTriangulation.RepresentativeCoordinates{Int64, Float64}} with 4 entries: + 4 => RepresentativeCoordinates{Int64, Float64}(3.0, -4.79892e-17, 0) + 2 => RepresentativeCoordinates{Int64, Float64}(-1.7996e-17, -2.02455e-17, 0) + 3 => RepresentativeCoordinates{Int64, Float64}(3.0, -4.49899e-17, 0) + 1 => RepresentativeCoordinates{Int64, Float64}(0.50341, -0.499994, 0) +```` + The keys of the `Dict` refer to the curve index, and the values contain the coordinates. -````@example pole_of_inaccessibility -fig, ax, sc = triplot(tri, show_ghost_edges=true) +````julia +fig, ax, sc = triplot(tri, show_ghost_edges = true) colors = (:red, :blue, :darkgreen, :purple) for i in eachindex(boundary_nodes) - lines!(ax, points[reduce(vcat, boundary_nodes[i])], color=colors[i], linewidth=6) + lines!(ax, points[reduce(vcat, boundary_nodes[i])], color = colors[i], linewidth = 6) coords = DelaunayTriangulation.get_representative_point_coordinates(tri, i) - scatter!(ax, coords, color=colors[i], markersize=16) + scatter!(ax, coords, color = colors[i], markersize = 16) end fig ```` +```@raw html + +``` + Note that the green and purple boundaries have the same pole of inaccessibility. The first curve, the red curve, is the only one that has the pole of inaccessibility computed with respect to all other boundaries. You can also see that indeed the ghost edges are all oriented relative to the representative points. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/pole_of_inaccessibility.jl). @@ -168,35 +207,37 @@ points = [ 2.12497 9.42582 7.27436 2.7979 3.0 4.0 - 5.33697 1.88019]' -outer_boundary = [ # split into segments for demonstration purposes + 5.33697 1.88019 +]' +outer_boundary = [ + # split into segments for demonstration purposes [1, 4, 3, 2], [2, 9, 10, 11, 8, 7, 12], [12, 6, 13, 5, 14, 15, 16, 17, 16], - [16, 17, 18, 19, 20, 21, 22, 23, 1] + [16, 17, 18, 19, 20, 21, 22, 23, 1], ] inner_1 = [ - [26, 25, 24], [24, 28, 27, 26] + [26, 25, 24], [24, 28, 27, 26], ] inner_2 = [ - [29, 30, 31, 29] + [29, 30, 31, 29], ] boundary_nodes = [outer_boundary, inner_1, inner_2] fig = Figure() ax = Axis(fig[1, 1]) for i in eachindex(boundary_nodes) - lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color=:red) + lines!(ax, points[:, reduce(vcat, boundary_nodes[i])], color = :red) end fig pole = DelaunayTriangulation.pole_of_inaccessibility(points, boundary_nodes) -scatter!(ax, pole, color=:blue, markersize=16) +scatter!(ax, pole, color = :blue, markersize = 16) fig θ = LinRange(0, 2π, 20) |> collect θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 -xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() +xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 global cx @@ -207,16 +248,16 @@ for i in 1:2 cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) -tri = triangulate(points; boundary_nodes=boundary_nodes) +tri = triangulate(points; boundary_nodes = boundary_nodes) DelaunayTriangulation.get_representative_point_list(tri) -fig, ax, sc = triplot(tri, show_ghost_edges=true) +fig, ax, sc = triplot(tri, show_ghost_edges = true) colors = (:red, :blue, :darkgreen, :purple) for i in eachindex(boundary_nodes) - lines!(ax, points[reduce(vcat, boundary_nodes[i])], color=colors[i], linewidth=6) + lines!(ax, points[reduce(vcat, boundary_nodes[i])], color = colors[i], linewidth = 6) coords = DelaunayTriangulation.get_representative_point_coordinates(tri, i) - scatter!(ax, coords, color=colors[i], markersize=16) + scatter!(ax, coords, color = colors[i], markersize = 16) end fig ``` diff --git a/docs/src/tutorials/refinement.md b/docs/src/tutorials/refinement.md index 7c132f892..6b016fffb 100644 --- a/docs/src/tutorials/refinement.md +++ b/docs/src/tutorials/refinement.md @@ -16,7 +16,7 @@ can also be refined as discussed in [this tutorial](../tutorials/curve_bounded.m Let us start by loading in the packages we will need. -````@example refinement +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -27,10 +27,10 @@ Let us start with a simple example, refining an unconstrained triangulation. We will constrain the triangulation such that the minimum angle is 30 degrees, and the maximum area of a triangulation is 1% of the triangulation's total area. Note that below we need to make sure `points` is mutable, else -it is not possible to push points into the triangulation. Here we use a tuple, but you +it is not possible to push points into the triangulation. Here we use a vector, but you could also use e.g. an `ElasticMatrix` from [ElasticArrays.jl](https://github.com/JuliaArrays/ElasticArrays.jl). -````@example refinement +````julia rng = StableRNG(123) x = rand(rng, 50) y = rand(rng, 50) @@ -38,81 +38,157 @@ points = tuple.(x, y) tri = triangulate(points; rng) orig_tri = deepcopy(tri) A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.01A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.01A, rng) +```` + +```` +Delaunay Triangulation. + Number of vertices: 293 + Number of triangles: 522 + Number of edges: 814 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false ```` The [`refine!`](@ref) function operates on `tri` in-place. If we wanted to review the statistics of the refined mesh, we can use [`statistics`](@ref): -````@example refinement +````julia statistics(tri) ```` +```` +Delaunay Triangulation Statistics. + Triangulation area: 0.6676219360027273 + Number of vertices: 294 + Number of solid vertices: 293 + Number of ghost vertices: 1 + Number of edges: 876 + Number of solid edges: 814 + Number of ghost edges: 62 + Number of triangles: 584 + Number of solid triangles: 522 + Number of ghost triangles: 62 + Number of boundary segments: 0 + Number of interior segments: 0 + Number of segments: 0 + Number of convex hull vertices: 62 + Smallest angle: 30.093123918976033° + Largest angle: 115.1681501036418° + Smallest area: 2.101315544214238e-5 + Largest area: 0.006504759798840958 + Smallest radius-edge ratio: 0.5783859342412219 + Largest radius-edge ratio: 0.997194082313877 +```` + As we can see, the maximum area of a triangle is about 0.0064, which is indeed less than 1% of the triangulation's area, which is about 0.0067. Moreover, the smallest angle is indeed greater than 30. Let us compare the triangulation pre- and post-refinement. -````@example refinement -fig, ax, sc = triplot(orig_tri, axis=(title="Pre-refinement",)) -ax = Axis(fig[1, 2], title="Post-refinement") +````julia +fig, ax, sc = triplot(orig_tri, axis = (title = "Pre-refinement",)) +ax = Axis(fig[1, 2], title = "Post-refinement") triplot!(ax, tri) fig ```` +```@raw html + +``` + The triangulation is now much finer. There are still some parts with -many more triangles than other regions, but this is most nearly a boundary +many more triangles than other regions, but these are mostly near a boundary or where was a cluster of random points. If we wanted, we could refine again to try and improve this. -````@example refinement -refine!(tri; min_angle=30.0, max_area=0.001A, rng) # 0.1% instead of 1% +````julia +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) # 0.1% instead of 1% fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + The quality has now been improved. We could also try improving the minimum angle further, but even 30 is a bit closer to the limit of convergence (which is about 33.9 degrees). For example, if we try a minimum angle of 35 degrees, the algorithm just doesn't even converge, instead it reaches the maximum number of points. -````@example refinement +````julia test_tri = deepcopy(tri) -refine!(test_tri; min_angle=35.0, max_area=0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going +refine!(test_tri; min_angle = 35.0, max_area = 0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going statistics(test_tri) ```` +```` +Delaunay Triangulation Statistics. + Triangulation area: 0.6676219360027283 + Number of vertices: 5001 + Number of solid vertices: 5000 + Number of ghost vertices: 1 + Number of edges: 14997 + Number of solid edges: 14855 + Number of ghost edges: 142 + Number of triangles: 9998 + Number of solid triangles: 9856 + Number of ghost triangles: 142 + Number of boundary segments: 0 + Number of interior segments: 0 + Number of segments: 0 + Number of convex hull vertices: 142 + Smallest angle: 29.178318890457142° + Largest angle: 117.10742856878393° + Smallest area: 3.296647038397725e-6 + Largest area: 0.0006659872224699419 + Smallest radius-edge ratio: 0.5773574317028193 + Largest radius-edge ratio: 1.0255793759836065 +```` + As we can see, the smallest angle is about 29 degrees instead of 35 degrees, and there are now 5000 points in the triangulation. The resulting triangulation is given below: -````@example refinement +````julia fig, ax, sc = triplot(test_tri) fig ```` +```@raw html + +``` + This is certainly not a suitable triangulation. One useful figure to look at for these plots are histograms that look at the areas and angles. Looking to `tri`, we can plot these as follows: -````@example refinement +````julia stats = statistics(tri) -fig = Figure(fontsize=33) +fig = Figure(fontsize = 33) areas = get_all_stat(stats, :area) ./ A angles = first.(get_all_stat(stats, :angles)) # the first is the smallest -ax = Axis(fig[1, 1], xlabel="A/A(Ω)", ylabel="Count", title="Area histogram", width=400, height=400, titlealign=:left) -hist!(ax, areas, bins=0:0.0001:0.0005) -ax = Axis(fig[1, 2], xlabel="θₘᵢₙ", ylabel="Count", title="Angle histogram", width=400, height=400, titlealign=:left) -hist!(ax, rad2deg.(angles), bins=20:2:60) -vlines!(ax, [30.0], color=:red) +ax = Axis(fig[1, 1], xlabel = "A/A(Ω)", ylabel = "Count", title = "Area histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, areas, bins = 0:0.0001:0.0005) +ax = Axis(fig[1, 2], xlabel = "θₘᵢₙ", ylabel = "Count", title = "Angle histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, rad2deg.(angles), bins = 20:2:60) +vlines!(ax, [30.0], color = :red) resize_to_layout!(fig) fig ```` +```@raw html + +``` + We see that indeed many of the triangle areas are very small, and the angles are all greater than 30 degrees. @@ -122,7 +198,7 @@ case where the mesh refinement is needed. For this example, we consider an examp with holes, but note that any triangulation can be refined, regardless of the type. Here is the triangulation we consider. -````@example refinement +````julia n = 100 θ = LinRange(0, 2π, n + 1) θ = [θ[1:n]; 0] @@ -142,15 +218,23 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Let us now refine this triangulation. -````@example refinement +````julia A = get_area(tri) -refine!(tri; min_angle=27.3, max_area=0.01A, rng) +refine!(tri; min_angle = 27.3, max_area = 0.01A, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + We inspect the plot, and we might think that it's perhaps not fine enough. Let's use finer constraints and see what happens. Since `refine!` operates on `tri` in-place, refining it again @@ -158,12 +242,16 @@ with the constraints below is going to take roughly the same amount of time as if we had refined it with these constraints in the first place. -````@example refinement -refine!(tri; min_angle=33.9, max_area=0.001A, rng) +````julia +refine!(tri; min_angle = 33.9, max_area = 0.001A, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This is indeed much better, but notice that the inner hole is much more fine than the outer. This is because we are applying the same area constraint inside and outside, when really we should try and take note @@ -177,7 +265,7 @@ instead of applying constraints so that the triangles are limited to 1% of the t triangulation area, we do 0.5% or 0.1% of the area of the inner or outer domain, respectively. -````@example refinement +````julia outer_area = π * (r₁^2 - r₂^2) inner_area = π * r₃^2 function in_inner(p, q, r) @@ -196,24 +284,32 @@ function area_constraint(_tri, T) end ```` +```` +area_constraint (generic function with 1 method) +```` + Let's now refine. We recompute the triangulation so that we can see the new results. -````@example refinement +````julia boundary_nodes, points = convert_boundary_points_to_indices(x, y) rng = StableRNG(456) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=30.0, custom_constraint=area_constraint, rng) +refine!(tri; min_angle = 30.0, custom_constraint = area_constraint, rng) fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This is now much better, and the two parts of the domain are appropriately refined. Let us extend our custom constraint function to also require that any triangle has minimum angle less than 33 degrees inside the innermost domain, and less than 20 degrees outside the innermost domain. -````@example refinement +````julia function angle_constraint(_tri, T) i, j, k = triangle_vertices(T) p, q, r = get_point(_tri, i, j, k) @@ -231,6 +327,10 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Indeed, the inner domain is much finer. These examples could be extended to more complicated cases, for example using adaptive mesh refinement for a numerical PDE solution so that triangles are refined based on some *a posteriori* error estimate, implemented @@ -244,19 +344,5149 @@ algorithm will still try its best to refine in these locations. Let's consider a example with many small angles. We consider the boundary of Switzerland, as obtained in this [NaturalNeighbours.jl example](https://danielvandh.github.io/NaturalNeighbours.jl/stable/swiss/). -````@example refinement +````julia using Downloads using DelimitedFiles boundary_url = "https://gist.githubusercontent.com/DanielVandH/13687b0918e45a416a5c93cd52c91449/raw/a8da6cdc94859fd66bcff85a2307f0f9cd57a18c/boundary.txt" boundary_dir = Downloads.download(boundary_url) -boundary = readdlm(boundary_dir, skipstart=6) +boundary = readdlm(boundary_dir, skipstart = 6) boundary_points = [(boundary[i, 1], boundary[i, 2]) for i in axes(boundary, 1)] reverse!(boundary_points) ```` +```` +5126-element Vector{Tuple{Float64, Float64}}: + (7.133862520764, 45.871870678164) + (7.138563027059, 45.871870678164) + (7.138563027059, 45.876571184459) + (7.143263533355, 45.876571184459) + (7.14796403965, 45.876571184459) + (7.152664545945, 45.876571184459) + (7.15736505224, 45.876571184459) + (7.162065558535, 45.876571184459) + (7.162065558535, 45.871870678164) + (7.166766064831, 45.871870678164) + (7.166766064831, 45.867170171868) + (7.171466571126, 45.867170171868) + (7.171466571126, 45.862469665573) + (7.176167077421, 45.862469665573) + (7.180867583716, 45.862469665573) + (7.185568090011, 45.862469665573) + (7.185568090011, 45.857769159278) + (7.190268596307, 45.857769159278) + (7.194969102602, 45.857769159278) + (7.194969102602, 45.862469665573) + (7.199669608897, 45.862469665573) + (7.199669608897, 45.867170171868) + (7.199669608897, 45.871870678164) + (7.199669608897, 45.876571184459) + (7.204370115192, 45.876571184459) + (7.209070621488, 45.876571184459) + (7.209070621488, 45.881271690754) + (7.213771127783, 45.881271690754) + (7.213771127783, 45.885972197049) + (7.218471634078, 45.885972197049) + (7.218471634078, 45.890672703344) + (7.223172140373, 45.890672703344) + (7.227872646668, 45.890672703344) + (7.232573152964, 45.890672703344) + (7.237273659259, 45.890672703344) + (7.241974165554, 45.890672703344) + (7.246674671849, 45.890672703344) + (7.251375178144, 45.890672703344) + (7.25607568444, 45.890672703344) + (7.260776190735, 45.890672703344) + (7.260776190735, 45.89537320964) + (7.26547669703, 45.89537320964) + (7.270177203325, 45.89537320964) + (7.270177203325, 45.900073715935) + (7.274877709621, 45.900073715935) + (7.279578215916, 45.900073715935) + (7.279578215916, 45.90477422223) + (7.279578215916, 45.909474728525) + (7.284278722211, 45.909474728525) + (7.284278722211, 45.91417523482) + (7.288979228506, 45.91417523482) + (7.288979228506, 45.918875741116) + (7.293679734801, 45.918875741116) + (7.298380241097, 45.918875741116) + (7.303080747392, 45.918875741116) + (7.307781253687, 45.918875741116) + (7.312481759982, 45.918875741116) + (7.312481759982, 45.91417523482) + (7.317182266278, 45.91417523482) + (7.317182266278, 45.909474728525) + (7.321882772573, 45.909474728525) + (7.326583278868, 45.909474728525) + (7.331283785163, 45.909474728525) + (7.335984291458, 45.909474728525) + (7.335984291458, 45.91417523482) + (7.340684797754, 45.91417523482) + (7.345385304049, 45.91417523482) + (7.350085810344, 45.91417523482) + (7.350085810344, 45.909474728525) + (7.354786316639, 45.909474728525) + (7.354786316639, 45.90477422223) + (7.359486822934, 45.90477422223) + (7.36418732923, 45.90477422223) + (7.368887835525, 45.90477422223) + (7.37358834182, 45.90477422223) + (7.37358834182, 45.900073715935) + (7.378288848115, 45.900073715935) + (7.382989354411, 45.900073715935) + (7.382989354411, 45.89537320964) + (7.387689860706, 45.89537320964) + (7.387689860706, 45.900073715935) + (7.392390367001, 45.900073715935) + (7.397090873296, 45.900073715935) + (7.397090873296, 45.90477422223) + (7.397090873296, 45.909474728525) + (7.401791379591, 45.909474728525) + (7.406491885887, 45.909474728525) + (7.411192392182, 45.909474728525) + (7.415892898477, 45.909474728525) + (7.420593404772, 45.909474728525) + (7.420593404772, 45.91417523482) + (7.425293911067, 45.91417523482) + (7.429994417363, 45.91417523482) + (7.429994417363, 45.918875741116) + (7.434694923658, 45.918875741116) + (7.434694923658, 45.923576247411) + (7.439395429953, 45.923576247411) + (7.439395429953, 45.928276753706) + (7.444095936248, 45.928276753706) + (7.448796442544, 45.928276753706) + (7.448796442544, 45.932977260001) + (7.453496948839, 45.932977260001) + (7.458197455134, 45.932977260001) + (7.462897961429, 45.932977260001) + (7.462897961429, 45.937677766297) + (7.467598467724, 45.937677766297) + (7.467598467724, 45.932977260001) + (7.47229897402, 45.932977260001) + (7.47229897402, 45.937677766297) + (7.47229897402, 45.942378272592) + (7.47229897402, 45.947078778887) + (7.47229897402, 45.951779285182) + (7.476999480315, 45.951779285182) + (7.48169998661, 45.951779285182) + (7.48169998661, 45.956479791477) + (7.486400492905, 45.956479791477) + (7.4911009992, 45.956479791477) + (7.495801505496, 45.956479791477) + (7.495801505496, 45.961180297773) + (7.500502011791, 45.961180297773) + (7.505202518086, 45.961180297773) + (7.509903024381, 45.961180297773) + (7.514603530677, 45.961180297773) + (7.519304036972, 45.961180297773) + (7.524004543267, 45.961180297773) + (7.524004543267, 45.956479791477) + (7.528705049562, 45.956479791477) + (7.533405555857, 45.956479791477) + (7.538106062153, 45.956479791477) + (7.542806568448, 45.956479791477) + (7.542806568448, 45.961180297773) + (7.547507074743, 45.961180297773) + (7.547507074743, 45.965880804068) + (7.547507074743, 45.970581310363) + (7.542806568448, 45.970581310363) + (7.542806568448, 45.975281816658) + (7.542806568448, 45.979982322953) + (7.542806568448, 45.984682829249) + (7.547507074743, 45.984682829249) + (7.552207581038, 45.984682829249) + (7.556908087333, 45.984682829249) + (7.561608593629, 45.984682829249) + (7.566309099924, 45.984682829249) + (7.566309099924, 45.989383335544) + (7.571009606219, 45.989383335544) + (7.575710112514, 45.989383335544) + (7.575710112514, 45.984682829249) + (7.58041061881, 45.984682829249) + (7.58041061881, 45.979982322953) + (7.58041061881, 45.975281816658) + (7.585111125105, 45.975281816658) + (7.585111125105, 45.970581310363) + (7.5898116314, 45.970581310363) + (7.594512137695, 45.970581310363) + (7.59921264399, 45.970581310363) + (7.603913150286, 45.970581310363) + (7.608613656581, 45.970581310363) + (7.613314162876, 45.970581310363) + (7.618014669171, 45.970581310363) + (7.622715175467, 45.970581310363) + (7.627415681762, 45.970581310363) + (7.632116188057, 45.970581310363) + (7.636816694352, 45.970581310363) + (7.641517200647, 45.970581310363) + (7.646217706943, 45.970581310363) + (7.646217706943, 45.975281816658) + (7.650918213238, 45.975281816658) + (7.655618719533, 45.975281816658) + (7.660319225828, 45.975281816658) + (7.665019732123, 45.975281816658) + (7.669720238419, 45.975281816658) + (7.669720238419, 45.970581310363) + (7.674420744714, 45.970581310363) + (7.674420744714, 45.965880804068) + (7.679121251009, 45.965880804068) + (7.679121251009, 45.961180297773) + (7.679121251009, 45.956479791477) + (7.683821757304, 45.956479791477) + (7.6885222636, 45.956479791477) + (7.693222769895, 45.956479791477) + (7.69792327619, 45.956479791477) + (7.69792327619, 45.951779285182) + (7.702623782485, 45.951779285182) + (7.70732428878, 45.951779285182) + (7.70732428878, 45.947078778887) + (7.70732428878, 45.942378272592) + (7.70732428878, 45.937677766297) + (7.70732428878, 45.932977260001) + (7.712024795076, 45.932977260001) + (7.712024795076, 45.928276753706) + (7.716725301371, 45.928276753706) + (7.716725301371, 45.923576247411) + (7.721425807666, 45.923576247411) + (7.726126313961, 45.923576247411) + (7.730826820256, 45.923576247411) + (7.735527326552, 45.923576247411) + (7.735527326552, 45.928276753706) + (7.740227832847, 45.928276753706) + (7.740227832847, 45.932977260001) + (7.744928339142, 45.932977260001) + (7.744928339142, 45.937677766297) + (7.749628845437, 45.937677766297) + (7.749628845437, 45.942378272592) + (7.754329351733, 45.942378272592) + (7.754329351733, 45.937677766297) + (7.759029858028, 45.937677766297) + (7.763730364323, 45.937677766297) + (7.768430870618, 45.937677766297) + (7.768430870618, 45.932977260001) + (7.773131376913, 45.932977260001) + (7.777831883209, 45.932977260001) + (7.777831883209, 45.928276753706) + (7.782532389504, 45.928276753706) + (7.787232895799, 45.928276753706) + (7.787232895799, 45.923576247411) + (7.791933402094, 45.923576247411) + (7.796633908389, 45.923576247411) + (7.796633908389, 45.918875741116) + (7.801334414685, 45.918875741116) + (7.80603492098, 45.918875741116) + (7.80603492098, 45.923576247411) + (7.810735427275, 45.923576247411) + (7.81543593357, 45.923576247411) + (7.820136439866, 45.923576247411) + (7.824836946161, 45.923576247411) + (7.829537452456, 45.923576247411) + (7.834237958751, 45.923576247411) + (7.838938465046, 45.923576247411) + (7.843638971342, 45.923576247411) + (7.848339477637, 45.923576247411) + (7.848339477637, 45.918875741116) + (7.853039983932, 45.918875741116) + (7.857740490227, 45.918875741116) + (7.862440996522, 45.918875741116) + (7.867141502818, 45.918875741116) + (7.871842009113, 45.918875741116) + (7.871842009113, 45.923576247411) + (7.876542515408, 45.923576247411) + (7.876542515408, 45.928276753706) + (7.871842009113, 45.928276753706) + (7.871842009113, 45.932977260001) + (7.867141502818, 45.932977260001) + (7.867141502818, 45.937677766297) + (7.867141502818, 45.942378272592) + (7.871842009113, 45.942378272592) + (7.871842009113, 45.947078778887) + (7.871842009113, 45.951779285182) + (7.876542515408, 45.951779285182) + (7.876542515408, 45.956479791477) + (7.876542515408, 45.961180297773) + (7.881243021703, 45.961180297773) + (7.881243021703, 45.965880804068) + (7.881243021703, 45.970581310363) + (7.876542515408, 45.970581310363) + (7.876542515408, 45.975281816658) + (7.881243021703, 45.975281816658) + (7.885943527999, 45.975281816658) + (7.890644034294, 45.975281816658) + (7.890644034294, 45.979982322953) + (7.895344540589, 45.979982322953) + (7.895344540589, 45.984682829249) + (7.900045046884, 45.984682829249) + (7.900045046884, 45.989383335544) + (7.904745553179, 45.989383335544) + (7.904745553179, 45.994083841839) + (7.909446059475, 45.994083841839) + (7.909446059475, 45.998784348134) + (7.91414656577, 45.998784348134) + (7.918847072065, 45.998784348134) + (7.92354757836, 45.998784348134) + (7.928248084656, 45.998784348134) + (7.932948590951, 45.998784348134) + (7.937649097246, 45.998784348134) + (7.942349603541, 45.998784348134) + (7.947050109836, 45.998784348134) + (7.951750616132, 45.998784348134) + (7.956451122427, 45.998784348134) + (7.961151628722, 45.998784348134) + (7.965852135017, 45.998784348134) + (7.970552641312, 45.998784348134) + (7.975253147608, 45.998784348134) + (7.979953653903, 45.998784348134) + (7.984654160198, 45.998784348134) + (7.989354666493, 45.998784348134) + (7.994055172789, 45.998784348134) + (7.994055172789, 46.00348485443) + (7.998755679084, 46.00348485443) + (7.998755679084, 46.008185360725) + (7.998755679084, 46.01288586702) + (8.003456185379, 46.01288586702) + (8.008156691674, 46.01288586702) + (8.012857197969, 46.01288586702) + (8.012857197969, 46.017586373315) + (8.012857197969, 46.02228687961) + (8.017557704265, 46.02228687961) + (8.017557704265, 46.026987385906) + (8.017557704265, 46.031687892201) + (8.017557704265, 46.036388398496) + (8.02225821056, 46.036388398496) + (8.02225821056, 46.041088904791) + (8.026958716855, 46.041088904791) + (8.026958716855, 46.045789411086) + (8.03165922315, 46.045789411086) + (8.03165922315, 46.050489917382) + (8.026958716855, 46.050489917382) + (8.026958716855, 46.055190423677) + (8.026958716855, 46.059890929972) + (8.026958716855, 46.064591436267) + (8.02225821056, 46.064591436267) + (8.02225821056, 46.069291942563) + (8.02225821056, 46.073992448858) + (8.02225821056, 46.078692955153) + (8.026958716855, 46.078692955153) + (8.026958716855, 46.083393461448) + (8.03165922315, 46.083393461448) + (8.03165922315, 46.088093967743) + (8.03165922315, 46.092794474039) + (8.03165922315, 46.097494980334) + (8.036359729445, 46.097494980334) + (8.036359729445, 46.102195486629) + (8.041060235741, 46.102195486629) + (8.045760742036, 46.102195486629) + (8.050461248331, 46.102195486629) + (8.055161754626, 46.102195486629) + (8.059862260922, 46.102195486629) + (8.064562767217, 46.102195486629) + (8.064562767217, 46.106895992924) + (8.069263273512, 46.106895992924) + (8.073963779807, 46.106895992924) + (8.078664286102, 46.106895992924) + (8.083364792398, 46.106895992924) + (8.088065298693, 46.106895992924) + (8.092765804988, 46.106895992924) + (8.097466311283, 46.106895992924) + (8.097466311283, 46.111596499219) + (8.102166817578, 46.111596499219) + (8.106867323874, 46.111596499219) + (8.106867323874, 46.116297005515) + (8.111567830169, 46.116297005515) + (8.116268336464, 46.116297005515) + (8.116268336464, 46.12099751181) + (8.116268336464, 46.125698018105) + (8.116268336464, 46.1303985244) + (8.120968842759, 46.1303985244) + (8.120968842759, 46.135099030696) + (8.125669349055, 46.135099030696) + (8.13036985535, 46.135099030696) + (8.135070361645, 46.135099030696) + (8.13977086794, 46.135099030696) + (8.144471374235, 46.135099030696) + (8.149171880531, 46.135099030696) + (8.149171880531, 46.139799536991) + (8.153872386826, 46.139799536991) + (8.153872386826, 46.144500043286) + (8.153872386826, 46.149200549581) + (8.153872386826, 46.153901055876) + (8.149171880531, 46.153901055876) + (8.149171880531, 46.158601562172) + (8.149171880531, 46.163302068467) + (8.153872386826, 46.163302068467) + (8.153872386826, 46.168002574762) + (8.153872386826, 46.172703081057) + (8.158572893121, 46.172703081057) + (8.163273399416, 46.172703081057) + (8.163273399416, 46.177403587352) + (8.167973905711, 46.177403587352) + (8.167973905711, 46.182104093648) + (8.163273399416, 46.182104093648) + (8.163273399416, 46.186804599943) + (8.158572893121, 46.186804599943) + (8.158572893121, 46.191505106238) + (8.153872386826, 46.191505106238) + (8.153872386826, 46.196205612533) + (8.149171880531, 46.196205612533) + (8.149171880531, 46.200906118829) + (8.149171880531, 46.205606625124) + (8.144471374235, 46.205606625124) + (8.144471374235, 46.210307131419) + (8.144471374235, 46.215007637714) + (8.13977086794, 46.215007637714) + (8.13977086794, 46.219708144009) + (8.13977086794, 46.224408650305) + (8.135070361645, 46.224408650305) + (8.135070361645, 46.2291091566) + (8.13036985535, 46.2291091566) + (8.125669349055, 46.2291091566) + (8.120968842759, 46.2291091566) + (8.120968842759, 46.233809662895) + (8.116268336464, 46.233809662895) + (8.116268336464, 46.23851016919) + (8.116268336464, 46.243210675486) + (8.111567830169, 46.243210675486) + (8.111567830169, 46.247911181781) + (8.106867323874, 46.247911181781) + (8.106867323874, 46.252611688076) + (8.102166817578, 46.252611688076) + (8.097466311283, 46.252611688076) + (8.092765804988, 46.252611688076) + (8.088065298693, 46.252611688076) + (8.083364792398, 46.252611688076) + (8.083364792398, 46.257312194371) + (8.078664286102, 46.257312194371) + (8.078664286102, 46.262012700666) + (8.083364792398, 46.262012700666) + (8.083364792398, 46.266713206962) + (8.088065298693, 46.266713206962) + (8.092765804988, 46.266713206962) + (8.092765804988, 46.271413713257) + (8.097466311283, 46.271413713257) + (8.097466311283, 46.276114219552) + (8.102166817578, 46.276114219552) + (8.106867323874, 46.276114219552) + (8.106867323874, 46.280814725847) + (8.111567830169, 46.280814725847) + (8.116268336464, 46.280814725847) + (8.116268336464, 46.285515232142) + (8.116268336464, 46.290215738438) + (8.120968842759, 46.290215738438) + (8.120968842759, 46.294916244733) + (8.125669349055, 46.294916244733) + (8.125669349055, 46.299616751028) + (8.13036985535, 46.299616751028) + (8.135070361645, 46.299616751028) + (8.135070361645, 46.304317257323) + (8.13977086794, 46.304317257323) + (8.13977086794, 46.299616751028) + (8.144471374235, 46.299616751028) + (8.149171880531, 46.299616751028) + (8.153872386826, 46.299616751028) + (8.153872386826, 46.294916244733) + (8.158572893121, 46.294916244733) + (8.163273399416, 46.294916244733) + (8.167973905711, 46.294916244733) + (8.172674412007, 46.294916244733) + (8.177374918302, 46.294916244733) + (8.177374918302, 46.299616751028) + (8.182075424597, 46.299616751028) + (8.186775930892, 46.299616751028) + (8.191476437188, 46.299616751028) + (8.191476437188, 46.304317257323) + (8.196176943483, 46.304317257323) + (8.200877449778, 46.304317257323) + (8.205577956073, 46.304317257323) + (8.210278462368, 46.304317257323) + (8.210278462368, 46.309017763619) + (8.214978968664, 46.309017763619) + (8.214978968664, 46.313718269914) + (8.214978968664, 46.318418776209) + (8.219679474959, 46.318418776209) + (8.219679474959, 46.323119282504) + (8.224379981254, 46.323119282504) + (8.224379981254, 46.327819788799) + (8.224379981254, 46.332520295095) + (8.229080487549, 46.332520295095) + (8.229080487549, 46.33722080139) + (8.233780993844, 46.33722080139) + (8.23848150014, 46.33722080139) + (8.243182006435, 46.33722080139) + (8.243182006435, 46.341921307685) + (8.24788251273, 46.341921307685) + (8.252583019025, 46.341921307685) + (8.252583019025, 46.34662181398) + (8.257283525321, 46.34662181398) + (8.261984031616, 46.34662181398) + (8.261984031616, 46.351322320275) + (8.261984031616, 46.356022826571) + (8.261984031616, 46.360723332866) + (8.261984031616, 46.365423839161) + (8.266684537911, 46.365423839161) + (8.271385044206, 46.365423839161) + (8.276085550501, 46.365423839161) + (8.280786056797, 46.365423839161) + (8.285486563092, 46.365423839161) + (8.285486563092, 46.370124345456) + (8.290187069387, 46.370124345456) + (8.294887575682, 46.370124345456) + (8.294887575682, 46.374824851752) + (8.299588081978, 46.374824851752) + (8.304288588273, 46.374824851752) + (8.308989094568, 46.374824851752) + (8.308989094568, 46.379525358047) + (8.313689600863, 46.379525358047) + (8.313689600863, 46.384225864342) + (8.318390107158, 46.384225864342) + (8.318390107158, 46.388926370637) + (8.313689600863, 46.388926370637) + (8.313689600863, 46.393626876932) + (8.313689600863, 46.398327383228) + (8.313689600863, 46.403027889523) + (8.308989094568, 46.403027889523) + (8.304288588273, 46.403027889523) + (8.299588081978, 46.403027889523) + (8.294887575682, 46.403027889523) + (8.294887575682, 46.407728395818) + (8.290187069387, 46.407728395818) + (8.290187069387, 46.412428902113) + (8.294887575682, 46.412428902113) + (8.294887575682, 46.417129408408) + (8.299588081978, 46.417129408408) + (8.299588081978, 46.421829914704) + (8.304288588273, 46.421829914704) + (8.308989094568, 46.421829914704) + (8.308989094568, 46.426530420999) + (8.313689600863, 46.426530420999) + (8.318390107158, 46.426530420999) + (8.323090613454, 46.426530420999) + (8.327791119749, 46.426530420999) + (8.332491626044, 46.426530420999) + (8.332491626044, 46.431230927294) + (8.337192132339, 46.431230927294) + (8.341892638634, 46.431230927294) + (8.341892638634, 46.435931433589) + (8.34659314493, 46.435931433589) + (8.34659314493, 46.440631939885) + (8.351293651225, 46.440631939885) + (8.35599415752, 46.440631939885) + (8.35599415752, 46.44533244618) + (8.360694663815, 46.44533244618) + (8.360694663815, 46.450032952475) + (8.365395170111, 46.450032952475) + (8.370095676406, 46.450032952475) + (8.370095676406, 46.45473345877) + (8.374796182701, 46.45473345877) + (8.379496688996, 46.45473345877) + (8.384197195291, 46.45473345877) + (8.388897701587, 46.45473345877) + (8.393598207882, 46.45473345877) + (8.398298714177, 46.45473345877) + (8.402999220472, 46.45473345877) + (8.407699726767, 46.45473345877) + (8.407699726767, 46.459433965065) + (8.412400233063, 46.459433965065) + (8.417100739358, 46.459433965065) + (8.421801245653, 46.459433965065) + (8.426501751948, 46.459433965065) + (8.426501751948, 46.464134471361) + (8.431202258244, 46.464134471361) + (8.435902764539, 46.464134471361) + (8.440603270834, 46.464134471361) + (8.445303777129, 46.464134471361) + (8.450004283424, 46.464134471361) + (8.450004283424, 46.459433965065) + (8.45470478972, 46.459433965065) + (8.45470478972, 46.45473345877) + (8.459405296015, 46.45473345877) + (8.459405296015, 46.450032952475) + (8.46410580231, 46.450032952475) + (8.46410580231, 46.44533244618) + (8.46410580231, 46.440631939885) + (8.459405296015, 46.440631939885) + (8.459405296015, 46.435931433589) + (8.459405296015, 46.431230927294) + (8.459405296015, 46.426530420999) + (8.459405296015, 46.421829914704) + (8.459405296015, 46.417129408408) + (8.46410580231, 46.417129408408) + (8.46410580231, 46.412428902113) + (8.468806308605, 46.412428902113) + (8.468806308605, 46.407728395818) + (8.46410580231, 46.407728395818) + (8.46410580231, 46.403027889523) + (8.46410580231, 46.398327383228) + (8.468806308605, 46.398327383228) + (8.468806308605, 46.393626876932) + (8.46410580231, 46.393626876932) + (8.46410580231, 46.388926370637) + (8.46410580231, 46.384225864342) + (8.46410580231, 46.379525358047) + (8.46410580231, 46.374824851752) + (8.468806308605, 46.374824851752) + (8.468806308605, 46.370124345456) + (8.468806308605, 46.365423839161) + (8.468806308605, 46.360723332866) + (8.46410580231, 46.360723332866) + (8.46410580231, 46.356022826571) + (8.46410580231, 46.351322320275) + (8.46410580231, 46.34662181398) + (8.46410580231, 46.341921307685) + (8.46410580231, 46.33722080139) + (8.46410580231, 46.332520295095) + (8.46410580231, 46.327819788799) + (8.459405296015, 46.327819788799) + (8.45470478972, 46.327819788799) + (8.45470478972, 46.323119282504) + (8.450004283424, 46.323119282504) + (8.450004283424, 46.318418776209) + (8.445303777129, 46.318418776209) + (8.440603270834, 46.318418776209) + (8.440603270834, 46.313718269914) + (8.440603270834, 46.309017763619) + (8.440603270834, 46.304317257323) + (8.435902764539, 46.304317257323) + (8.431202258244, 46.304317257323) + (8.431202258244, 46.299616751028) + (8.431202258244, 46.294916244733) + (8.431202258244, 46.290215738438) + (8.435902764539, 46.290215738438) + (8.435902764539, 46.285515232142) + (8.440603270834, 46.285515232142) + (8.440603270834, 46.280814725847) + (8.445303777129, 46.280814725847) + (8.445303777129, 46.276114219552) + (8.450004283424, 46.276114219552) + (8.450004283424, 46.271413713257) + (8.450004283424, 46.266713206962) + (8.450004283424, 46.262012700666) + (8.450004283424, 46.257312194371) + (8.445303777129, 46.257312194371) + (8.445303777129, 46.252611688076) + (8.445303777129, 46.247911181781) + (8.450004283424, 46.247911181781) + (8.45470478972, 46.247911181781) + (8.45470478972, 46.243210675486) + (8.459405296015, 46.243210675486) + (8.46410580231, 46.243210675486) + (8.46410580231, 46.23851016919) + (8.468806308605, 46.23851016919) + (8.468806308605, 46.233809662895) + (8.4735068149, 46.233809662895) + (8.4735068149, 46.2291091566) + (8.478207321196, 46.2291091566) + (8.482907827491, 46.2291091566) + (8.487608333786, 46.2291091566) + (8.492308840081, 46.2291091566) + (8.497009346377, 46.2291091566) + (8.497009346377, 46.224408650305) + (8.501709852672, 46.224408650305) + (8.506410358967, 46.224408650305) + (8.511110865262, 46.224408650305) + (8.515811371557, 46.224408650305) + (8.515811371557, 46.219708144009) + (8.520511877853, 46.219708144009) + (8.525212384148, 46.219708144009) + (8.529912890443, 46.219708144009) + (8.534613396738, 46.219708144009) + (8.534613396738, 46.215007637714) + (8.534613396738, 46.210307131419) + (8.534613396738, 46.205606625124) + (8.539313903033, 46.205606625124) + (8.539313903033, 46.200906118829) + (8.539313903033, 46.196205612533) + (8.544014409329, 46.196205612533) + (8.548714915624, 46.196205612533) + (8.548714915624, 46.191505106238) + (8.553415421919, 46.191505106238) + (8.553415421919, 46.186804599943) + (8.558115928214, 46.186804599943) + (8.558115928214, 46.182104093648) + (8.56281643451, 46.182104093648) + (8.567516940805, 46.182104093648) + (8.567516940805, 46.177403587352) + (8.5722174471, 46.177403587352) + (8.5722174471, 46.172703081057) + (8.5722174471, 46.168002574762) + (8.576917953395, 46.168002574762) + (8.576917953395, 46.163302068467) + (8.58161845969, 46.163302068467) + (8.586318965986, 46.163302068467) + (8.586318965986, 46.158601562172) + (8.591019472281, 46.158601562172) + (8.595719978576, 46.158601562172) + (8.595719978576, 46.153901055876) + (8.600420484871, 46.153901055876) + (8.600420484871, 46.149200549581) + (8.595719978576, 46.149200549581) + (8.595719978576, 46.144500043286) + (8.595719978576, 46.139799536991) + (8.600420484871, 46.139799536991) + (8.605120991167, 46.139799536991) + (8.605120991167, 46.135099030696) + (8.609821497462, 46.135099030696) + (8.609821497462, 46.1303985244) + (8.609821497462, 46.125698018105) + (8.614522003757, 46.125698018105) + (8.614522003757, 46.12099751181) + (8.619222510052, 46.12099751181) + (8.623923016347, 46.12099751181) + (8.628623522643, 46.12099751181) + (8.633324028938, 46.12099751181) + (8.638024535233, 46.12099751181) + (8.642725041528, 46.12099751181) + (8.647425547823, 46.12099751181) + (8.652126054119, 46.12099751181) + (8.652126054119, 46.116297005515) + (8.656826560414, 46.116297005515) + (8.656826560414, 46.111596499219) + (8.661527066709, 46.111596499219) + (8.666227573004, 46.111596499219) + (8.666227573004, 46.106895992924) + (8.6709280793, 46.106895992924) + (8.675628585595, 46.106895992924) + (8.675628585595, 46.111596499219) + (8.68032909189, 46.111596499219) + (8.68032909189, 46.106895992924) + (8.685029598185, 46.106895992924) + (8.685029598185, 46.102195486629) + (8.68973010448, 46.102195486629) + (8.694430610776, 46.102195486629) + (8.699131117071, 46.102195486629) + (8.703831623366, 46.102195486629) + (8.703831623366, 46.097494980334) + (8.708532129661, 46.097494980334) + (8.713232635956, 46.097494980334) + (8.717933142252, 46.097494980334) + (8.717933142252, 46.102195486629) + (8.717933142252, 46.106895992924) + (8.722633648547, 46.106895992924) + (8.722633648547, 46.111596499219) + (8.727334154842, 46.111596499219) + (8.732034661137, 46.111596499219) + (8.732034661137, 46.116297005515) + (8.736735167433, 46.116297005515) + (8.736735167433, 46.12099751181) + (8.741435673728, 46.12099751181) + (8.746136180023, 46.12099751181) + (8.746136180023, 46.116297005515) + (8.750836686318, 46.116297005515) + (8.750836686318, 46.111596499219) + (8.755537192613, 46.111596499219) + (8.755537192613, 46.106895992924) + (8.755537192613, 46.102195486629) + (8.760237698909, 46.102195486629) + (8.764938205204, 46.102195486629) + (8.764938205204, 46.097494980334) + (8.769638711499, 46.097494980334) + (8.774339217794, 46.097494980334) + (8.779039724089, 46.097494980334) + (8.783740230385, 46.097494980334) + (8.78844073668, 46.097494980334) + (8.793141242975, 46.097494980334) + (8.79784174927, 46.097494980334) + (8.802542255566, 46.097494980334) + (8.802542255566, 46.102195486629) + (8.807242761861, 46.102195486629) + (8.811943268156, 46.102195486629) + (8.811943268156, 46.097494980334) + (8.816643774451, 46.097494980334) + (8.821344280746, 46.097494980334) + (8.821344280746, 46.092794474039) + (8.826044787042, 46.092794474039) + (8.830745293337, 46.092794474039) + (8.830745293337, 46.088093967743) + (8.835445799632, 46.088093967743) + (8.835445799632, 46.083393461448) + (8.840146305927, 46.083393461448) + (8.840146305927, 46.078692955153) + (8.844846812222, 46.078692955153) + (8.849547318518, 46.078692955153) + (8.849547318518, 46.073992448858) + (8.854247824813, 46.073992448858) + (8.854247824813, 46.069291942563) + (8.854247824813, 46.064591436267) + (8.854247824813, 46.059890929972) + (8.849547318518, 46.059890929972) + (8.849547318518, 46.055190423677) + (8.849547318518, 46.050489917382) + (8.844846812222, 46.050489917382) + (8.840146305927, 46.050489917382) + (8.835445799632, 46.050489917382) + (8.830745293337, 46.050489917382) + (8.830745293337, 46.045789411086) + (8.830745293337, 46.041088904791) + (8.830745293337, 46.036388398496) + (8.826044787042, 46.036388398496) + (8.826044787042, 46.031687892201) + (8.826044787042, 46.026987385906) + (8.821344280746, 46.026987385906) + (8.816643774451, 46.026987385906) + (8.811943268156, 46.026987385906) + (8.811943268156, 46.02228687961) + (8.807242761861, 46.02228687961) + (8.802542255566, 46.02228687961) + (8.802542255566, 46.017586373315) + (8.79784174927, 46.017586373315) + (8.79784174927, 46.01288586702) + (8.79784174927, 46.008185360725) + (8.793141242975, 46.008185360725) + (8.793141242975, 46.00348485443) + (8.793141242975, 45.998784348134) + (8.78844073668, 45.998784348134) + (8.78844073668, 45.994083841839) + (8.78844073668, 45.989383335544) + (8.793141242975, 45.989383335544) + (8.793141242975, 45.994083841839) + (8.79784174927, 45.994083841839) + (8.802542255566, 45.994083841839) + (8.807242761861, 45.994083841839) + (8.807242761861, 45.989383335544) + (8.811943268156, 45.989383335544) + (8.816643774451, 45.989383335544) + (8.821344280746, 45.989383335544) + (8.826044787042, 45.989383335544) + (8.830745293337, 45.989383335544) + (8.830745293337, 45.984682829249) + (8.835445799632, 45.984682829249) + (8.840146305927, 45.984682829249) + (8.840146305927, 45.979982322953) + (8.844846812222, 45.979982322953) + (8.844846812222, 45.975281816658) + (8.849547318518, 45.975281816658) + (8.849547318518, 45.970581310363) + (8.854247824813, 45.970581310363) + (8.858948331108, 45.970581310363) + (8.858948331108, 45.965880804068) + (8.863648837403, 45.965880804068) + (8.868349343699, 45.965880804068) + (8.868349343699, 45.961180297773) + (8.873049849994, 45.961180297773) + (8.873049849994, 45.956479791477) + (8.877750356289, 45.956479791477) + (8.882450862584, 45.956479791477) + (8.887151368879, 45.956479791477) + (8.891851875175, 45.956479791477) + (8.89655238147, 45.956479791477) + (8.89655238147, 45.951779285182) + (8.89655238147, 45.947078778887) + (8.89655238147, 45.942378272592) + (8.89655238147, 45.937677766297) + (8.89655238147, 45.932977260001) + (8.89655238147, 45.928276753706) + (8.89655238147, 45.923576247411) + (8.901252887765, 45.923576247411) + (8.901252887765, 45.918875741116) + (8.90595339406, 45.918875741116) + (8.910653900356, 45.918875741116) + (8.915354406651, 45.918875741116) + (8.915354406651, 45.91417523482) + (8.920054912946, 45.91417523482) + (8.920054912946, 45.909474728525) + (8.920054912946, 45.90477422223) + (8.924755419241, 45.90477422223) + (8.924755419241, 45.900073715935) + (8.924755419241, 45.89537320964) + (8.924755419241, 45.890672703344) + (8.929455925536, 45.890672703344) + (8.929455925536, 45.885972197049) + (8.934156431832, 45.885972197049) + (8.934156431832, 45.881271690754) + (8.934156431832, 45.876571184459) + (8.934156431832, 45.871870678164) + (8.934156431832, 45.867170171868) + (8.938856938127, 45.867170171868) + (8.943557444422, 45.867170171868) + (8.943557444422, 45.862469665573) + (8.938856938127, 45.862469665573) + (8.934156431832, 45.862469665573) + (8.934156431832, 45.857769159278) + (8.929455925536, 45.857769159278) + (8.929455925536, 45.853068652983) + (8.924755419241, 45.853068652983) + (8.920054912946, 45.853068652983) + (8.920054912946, 45.848368146687) + (8.915354406651, 45.848368146687) + (8.915354406651, 45.843667640392) + (8.915354406651, 45.838967134097) + (8.910653900356, 45.838967134097) + (8.910653900356, 45.834266627802) + (8.915354406651, 45.834266627802) + (8.915354406651, 45.829566121507) + (8.920054912946, 45.829566121507) + (8.924755419241, 45.829566121507) + (8.924755419241, 45.834266627802) + (8.929455925536, 45.834266627802) + (8.934156431832, 45.834266627802) + (8.934156431832, 45.838967134097) + (8.938856938127, 45.838967134097) + (8.943557444422, 45.838967134097) + (8.943557444422, 45.843667640392) + (8.948257950717, 45.843667640392) + (8.952958457012, 45.843667640392) + (8.957658963308, 45.843667640392) + (8.957658963308, 45.838967134097) + (8.962359469603, 45.838967134097) + (8.962359469603, 45.834266627802) + (8.967059975898, 45.834266627802) + (8.971760482193, 45.834266627802) + (8.976460988489, 45.834266627802) + (8.981161494784, 45.834266627802) + (8.985862001079, 45.834266627802) + (8.990562507374, 45.834266627802) + (8.995263013669, 45.834266627802) + (8.995263013669, 45.829566121507) + (8.995263013669, 45.824865615211) + (8.995263013669, 45.820165108916) + (8.999963519965, 45.820165108916) + (9.00466402626, 45.820165108916) + (9.009364532555, 45.820165108916) + (9.01406503885, 45.820165108916) + (9.018765545145, 45.820165108916) + (9.023466051441, 45.820165108916) + (9.028166557736, 45.820165108916) + (9.032867064031, 45.820165108916) + (9.032867064031, 45.824865615211) + (9.032867064031, 45.829566121507) + (9.037567570326, 45.829566121507) + (9.037567570326, 45.834266627802) + (9.037567570326, 45.838967134097) + (9.037567570326, 45.843667640392) + (9.042268076622, 45.843667640392) + (9.042268076622, 45.848368146687) + (9.046968582917, 45.848368146687) + (9.046968582917, 45.853068652983) + (9.051669089212, 45.853068652983) + (9.051669089212, 45.857769159278) + (9.051669089212, 45.862469665573) + (9.051669089212, 45.867170171868) + (9.051669089212, 45.871870678164) + (9.056369595507, 45.871870678164) + (9.056369595507, 45.876571184459) + (9.061070101802, 45.876571184459) + (9.065770608098, 45.876571184459) + (9.070471114393, 45.876571184459) + (9.070471114393, 45.881271690754) + (9.075171620688, 45.881271690754) + (9.075171620688, 45.885972197049) + (9.079872126983, 45.885972197049) + (9.079872126983, 45.890672703344) + (9.084572633278, 45.890672703344) + (9.084572633278, 45.89537320964) + (9.089273139574, 45.89537320964) + (9.089273139574, 45.900073715935) + (9.084572633278, 45.900073715935) + (9.079872126983, 45.900073715935) + (9.075171620688, 45.900073715935) + (9.075171620688, 45.90477422223) + (9.075171620688, 45.909474728525) + (9.075171620688, 45.91417523482) + (9.070471114393, 45.91417523482) + (9.065770608098, 45.91417523482) + (9.061070101802, 45.91417523482) + (9.061070101802, 45.918875741116) + (9.061070101802, 45.923576247411) + (9.056369595507, 45.923576247411) + (9.056369595507, 45.918875741116) + (9.051669089212, 45.918875741116) + (9.051669089212, 45.923576247411) + (9.046968582917, 45.923576247411) + (9.046968582917, 45.928276753706) + (9.042268076622, 45.928276753706) + (9.037567570326, 45.928276753706) + (9.032867064031, 45.928276753706) + (9.028166557736, 45.928276753706) + (9.023466051441, 45.928276753706) + (9.018765545145, 45.928276753706) + (9.018765545145, 45.932977260001) + (9.023466051441, 45.932977260001) + (9.023466051441, 45.937677766297) + (9.018765545145, 45.937677766297) + (9.018765545145, 45.942378272592) + (9.01406503885, 45.942378272592) + (9.01406503885, 45.947078778887) + (9.018765545145, 45.947078778887) + (9.018765545145, 45.951779285182) + (9.01406503885, 45.951779285182) + (9.01406503885, 45.956479791477) + (9.01406503885, 45.961180297773) + (9.009364532555, 45.961180297773) + (9.00466402626, 45.961180297773) + (9.00466402626, 45.965880804068) + (8.999963519965, 45.965880804068) + (8.995263013669, 45.965880804068) + (8.990562507374, 45.965880804068) + (8.990562507374, 45.970581310363) + (8.995263013669, 45.970581310363) + (8.995263013669, 45.975281816658) + (8.995263013669, 45.979982322953) + (8.999963519965, 45.979982322953) + (9.00466402626, 45.979982322953) + (9.009364532555, 45.979982322953) + (9.009364532555, 45.984682829249) + (9.009364532555, 45.989383335544) + (9.01406503885, 45.989383335544) + (9.018765545145, 45.989383335544) + (9.023466051441, 45.989383335544) + (9.023466051441, 45.994083841839) + (9.028166557736, 45.994083841839) + (9.028166557736, 45.998784348134) + (9.023466051441, 45.998784348134) + (9.023466051441, 46.00348485443) + (9.023466051441, 46.008185360725) + (9.023466051441, 46.01288586702) + (9.023466051441, 46.017586373315) + (9.018765545145, 46.017586373315) + (9.018765545145, 46.02228687961) + (9.01406503885, 46.02228687961) + (9.01406503885, 46.026987385906) + (9.009364532555, 46.026987385906) + (9.009364532555, 46.031687892201) + (9.009364532555, 46.036388398496) + (9.009364532555, 46.041088904791) + (9.01406503885, 46.041088904791) + (9.018765545145, 46.041088904791) + (9.018765545145, 46.045789411086) + (9.018765545145, 46.050489917382) + (9.023466051441, 46.050489917382) + (9.023466051441, 46.055190423677) + (9.028166557736, 46.055190423677) + (9.032867064031, 46.055190423677) + (9.037567570326, 46.055190423677) + (9.037567570326, 46.059890929972) + (9.042268076622, 46.059890929972) + (9.046968582917, 46.059890929972) + (9.051669089212, 46.059890929972) + (9.056369595507, 46.059890929972) + (9.061070101802, 46.059890929972) + (9.065770608098, 46.059890929972) + (9.070471114393, 46.059890929972) + (9.070471114393, 46.064591436267) + (9.075171620688, 46.064591436267) + (9.079872126983, 46.064591436267) + (9.079872126983, 46.069291942563) + (9.079872126983, 46.073992448858) + (9.079872126983, 46.078692955153) + (9.084572633278, 46.078692955153) + (9.084572633278, 46.083393461448) + (9.089273139574, 46.083393461448) + (9.089273139574, 46.088093967743) + (9.084572633278, 46.088093967743) + (9.084572633278, 46.092794474039) + (9.084572633278, 46.097494980334) + (9.079872126983, 46.097494980334) + (9.079872126983, 46.102195486629) + (9.079872126983, 46.106895992924) + (9.075171620688, 46.106895992924) + (9.075171620688, 46.111596499219) + (9.075171620688, 46.116297005515) + (9.075171620688, 46.12099751181) + (9.079872126983, 46.12099751181) + (9.084572633278, 46.12099751181) + (9.084572633278, 46.125698018105) + (9.089273139574, 46.125698018105) + (9.093973645869, 46.125698018105) + (9.098674152164, 46.125698018105) + (9.098674152164, 46.1303985244) + (9.103374658459, 46.1303985244) + (9.108075164755, 46.1303985244) + (9.108075164755, 46.135099030696) + (9.11277567105, 46.135099030696) + (9.117476177345, 46.135099030696) + (9.12217668364, 46.135099030696) + (9.12217668364, 46.139799536991) + (9.126877189935, 46.139799536991) + (9.126877189935, 46.144500043286) + (9.131577696231, 46.144500043286) + (9.131577696231, 46.149200549581) + (9.136278202526, 46.149200549581) + (9.136278202526, 46.153901055876) + (9.140978708821, 46.153901055876) + (9.145679215116, 46.153901055876) + (9.145679215116, 46.158601562172) + (9.150379721411, 46.158601562172) + (9.155080227707, 46.158601562172) + (9.155080227707, 46.163302068467) + (9.159780734002, 46.163302068467) + (9.159780734002, 46.168002574762) + (9.164481240297, 46.168002574762) + (9.164481240297, 46.172703081057) + (9.169181746592, 46.172703081057) + (9.173882252888, 46.172703081057) + (9.178582759183, 46.172703081057) + (9.183283265478, 46.172703081057) + (9.187983771773, 46.172703081057) + (9.187983771773, 46.177403587352) + (9.192684278068, 46.177403587352) + (9.192684278068, 46.182104093648) + (9.197384784364, 46.182104093648) + (9.197384784364, 46.186804599943) + (9.197384784364, 46.191505106238) + (9.192684278068, 46.191505106238) + (9.192684278068, 46.196205612533) + (9.197384784364, 46.196205612533) + (9.197384784364, 46.200906118829) + (9.202085290659, 46.200906118829) + (9.202085290659, 46.205606625124) + (9.202085290659, 46.210307131419) + (9.206785796954, 46.210307131419) + (9.211486303249, 46.210307131419) + (9.216186809544, 46.210307131419) + (9.216186809544, 46.215007637714) + (9.22088731584, 46.215007637714) + (9.22088731584, 46.219708144009) + (9.22088731584, 46.224408650305) + (9.22088731584, 46.2291091566) + (9.225587822135, 46.2291091566) + (9.225587822135, 46.233809662895) + (9.23028832843, 46.233809662895) + (9.234988834725, 46.233809662895) + (9.239689341021, 46.233809662895) + (9.244389847316, 46.233809662895) + (9.249090353611, 46.233809662895) + (9.249090353611, 46.23851016919) + (9.249090353611, 46.243210675486) + (9.249090353611, 46.247911181781) + (9.249090353611, 46.252611688076) + (9.249090353611, 46.257312194371) + (9.249090353611, 46.262012700666) + (9.253790859906, 46.262012700666) + (9.253790859906, 46.266713206962) + (9.253790859906, 46.271413713257) + (9.258491366201, 46.271413713257) + (9.258491366201, 46.276114219552) + (9.258491366201, 46.280814725847) + (9.263191872497, 46.280814725847) + (9.267892378792, 46.280814725847) + (9.267892378792, 46.285515232142) + (9.272592885087, 46.285515232142) + (9.272592885087, 46.290215738438) + (9.277293391382, 46.290215738438) + (9.277293391382, 46.294916244733) + (9.281993897678, 46.294916244733) + (9.281993897678, 46.299616751028) + (9.281993897678, 46.304317257323) + (9.281993897678, 46.309017763619) + (9.286694403973, 46.309017763619) + (9.286694403973, 46.313718269914) + (9.291394910268, 46.313718269914) + (9.291394910268, 46.318418776209) + (9.296095416563, 46.318418776209) + (9.296095416563, 46.323119282504) + (9.296095416563, 46.327819788799) + (9.296095416563, 46.332520295095) + (9.291394910268, 46.332520295095) + (9.291394910268, 46.33722080139) + (9.296095416563, 46.33722080139) + (9.296095416563, 46.341921307685) + (9.300795922858, 46.341921307685) + (9.300795922858, 46.34662181398) + (9.300795922858, 46.351322320275) + (9.296095416563, 46.351322320275) + (9.296095416563, 46.356022826571) + (9.291394910268, 46.356022826571) + (9.286694403973, 46.356022826571) + (9.281993897678, 46.356022826571) + (9.281993897678, 46.360723332866) + (9.277293391382, 46.360723332866) + (9.277293391382, 46.365423839161) + (9.277293391382, 46.370124345456) + (9.277293391382, 46.374824851752) + (9.277293391382, 46.379525358047) + (9.281993897678, 46.379525358047) + (9.281993897678, 46.384225864342) + (9.281993897678, 46.388926370637) + (9.277293391382, 46.388926370637) + (9.277293391382, 46.393626876932) + (9.277293391382, 46.398327383228) + (9.281993897678, 46.398327383228) + (9.281993897678, 46.403027889523) + (9.281993897678, 46.407728395818) + (9.281993897678, 46.412428902113) + (9.277293391382, 46.412428902113) + (9.277293391382, 46.417129408408) + (9.272592885087, 46.417129408408) + (9.272592885087, 46.421829914704) + (9.267892378792, 46.421829914704) + (9.263191872497, 46.421829914704) + (9.258491366201, 46.421829914704) + (9.258491366201, 46.426530420999) + (9.253790859906, 46.426530420999) + (9.253790859906, 46.431230927294) + (9.249090353611, 46.431230927294) + (9.249090353611, 46.435931433589) + (9.249090353611, 46.440631939885) + (9.249090353611, 46.44533244618) + (9.249090353611, 46.450032952475) + (9.253790859906, 46.450032952475) + (9.258491366201, 46.450032952475) + (9.263191872497, 46.450032952475) + (9.263191872497, 46.45473345877) + (9.267892378792, 46.45473345877) + (9.272592885087, 46.45473345877) + (9.272592885087, 46.459433965065) + (9.277293391382, 46.459433965065) + (9.277293391382, 46.464134471361) + (9.272592885087, 46.464134471361) + (9.272592885087, 46.468834977656) + (9.277293391382, 46.468834977656) + (9.277293391382, 46.473535483951) + (9.277293391382, 46.478235990246) + (9.277293391382, 46.482936496541) + (9.277293391382, 46.482936496542) + (9.277293391382, 46.487637002837) + (9.281993897678, 46.487637002837) + (9.281993897678, 46.492337509132) + (9.286694403973, 46.492337509132) + (9.286694403973, 46.497038015427) + (9.291394910268, 46.497038015427) + (9.296095416563, 46.497038015427) + (9.300795922858, 46.497038015427) + (9.300795922858, 46.501738521722) + (9.305496429154, 46.501738521722) + (9.310196935449, 46.501738521722) + (9.314897441744, 46.501738521722) + (9.314897441744, 46.506439028018) + (9.319597948039, 46.506439028018) + (9.324298454334, 46.506439028018) + (9.32899896063, 46.506439028018) + (9.333699466925, 46.506439028018) + (9.33839997322, 46.506439028018) + (9.343100479515, 46.506439028018) + (9.347800985811, 46.506439028018) + (9.352501492106, 46.506439028018) + (9.357201998401, 46.506439028018) + (9.361902504696, 46.506439028018) + (9.366603010991, 46.506439028018) + (9.371303517287, 46.506439028018) + (9.371303517287, 46.501738521722) + (9.371303517287, 46.497038015427) + (9.371303517287, 46.492337509132) + (9.371303517287, 46.487637002837) + (9.376004023582, 46.487637002837) + (9.380704529877, 46.487637002837) + (9.380704529877, 46.482936496541) + (9.385405036172, 46.482936496541) + (9.385405036172, 46.478235990246) + (9.390105542467, 46.478235990246) + (9.390105542467, 46.473535483951) + (9.394806048763, 46.473535483951) + (9.394806048763, 46.468834977656) + (9.399506555058, 46.468834977656) + (9.404207061353, 46.468834977656) + (9.408907567648, 46.468834977656) + (9.413608073944, 46.468834977656) + (9.418308580239, 46.468834977656) + (9.418308580239, 46.473535483951) + (9.423009086534, 46.473535483951) + (9.423009086534, 46.478235990246) + (9.423009086534, 46.482936496541) + (9.423009086534, 46.482936496542) + (9.423009086534, 46.487637002837) + (9.427709592829, 46.487637002837) + (9.427709592829, 46.492337509132) + (9.432410099124, 46.492337509132) + (9.432410099124, 46.497038015427) + (9.43711060542, 46.497038015427) + (9.43711060542, 46.501738521722) + (9.441811111715, 46.501738521722) + (9.44651161801, 46.501738521722) + (9.451212124305, 46.501738521722) + (9.451212124305, 46.506439028018) + (9.4559126306, 46.506439028018) + (9.460613136896, 46.506439028018) + (9.460613136896, 46.501738521722) + (9.460613136896, 46.497038015427) + (9.460613136896, 46.492337509132) + (9.460613136896, 46.487637002837) + (9.460613136896, 46.482936496542) + (9.4559126306, 46.482936496542) + (9.451212124305, 46.482936496542) + (9.451212124305, 46.478235990246) + (9.4559126306, 46.478235990246) + (9.460613136896, 46.478235990246) + (9.465313643191, 46.478235990246) + (9.465313643191, 46.473535483951) + (9.465313643191, 46.468834977656) + (9.465313643191, 46.464134471361) + (9.460613136896, 46.464134471361) + (9.460613136896, 46.459433965065) + (9.460613136896, 46.45473345877) + (9.460613136896, 46.450032952475) + (9.460613136896, 46.44533244618) + (9.460613136896, 46.440631939885) + (9.4559126306, 46.440631939885) + (9.4559126306, 46.435931433589) + (9.4559126306, 46.431230927294) + (9.4559126306, 46.426530420999) + (9.4559126306, 46.421829914704) + (9.4559126306, 46.417129408408) + (9.4559126306, 46.412428902113) + (9.460613136896, 46.412428902113) + (9.460613136896, 46.407728395818) + (9.465313643191, 46.407728395818) + (9.465313643191, 46.403027889523) + (9.465313643191, 46.398327383228) + (9.465313643191, 46.393626876932) + (9.465313643191, 46.388926370637) + (9.465313643191, 46.384225864342) + (9.465313643191, 46.379525358047) + (9.465313643191, 46.374824851752) + (9.465313643191, 46.370124345456) + (9.470014149486, 46.370124345456) + (9.474714655781, 46.370124345456) + (9.479415162077, 46.370124345456) + (9.479415162077, 46.365423839161) + (9.484115668372, 46.365423839161) + (9.488816174667, 46.365423839161) + (9.493516680962, 46.365423839161) + (9.493516680962, 46.360723332866) + (9.498217187257, 46.360723332866) + (9.498217187257, 46.356022826571) + (9.502917693553, 46.356022826571) + (9.502917693553, 46.351322320275) + (9.507618199848, 46.351322320275) + (9.507618199848, 46.34662181398) + (9.507618199848, 46.341921307685) + (9.512318706143, 46.341921307685) + (9.512318706143, 46.33722080139) + (9.512318706143, 46.332520295095) + (9.517019212438, 46.332520295095) + (9.517019212438, 46.327819788799) + (9.521719718733, 46.327819788799) + (9.521719718733, 46.323119282504) + (9.526420225029, 46.323119282504) + (9.526420225029, 46.318418776209) + (9.531120731324, 46.318418776209) + (9.531120731324, 46.313718269914) + (9.535821237619, 46.313718269914) + (9.535821237619, 46.309017763619) + (9.540521743914, 46.309017763619) + (9.540521743914, 46.304317257323) + (9.54522225021, 46.304317257323) + (9.549922756505, 46.304317257323) + (9.5546232628, 46.304317257323) + (9.559323769095, 46.304317257323) + (9.56402427539, 46.304317257323) + (9.56402427539, 46.299616751028) + (9.568724781686, 46.299616751028) + (9.573425287981, 46.299616751028) + (9.573425287981, 46.294916244733) + (9.578125794276, 46.294916244733) + (9.582826300571, 46.294916244733) + (9.587526806867, 46.294916244733) + (9.592227313162, 46.294916244733) + (9.596927819457, 46.294916244733) + (9.601628325752, 46.294916244733) + (9.606328832047, 46.294916244733) + (9.611029338343, 46.294916244733) + (9.615729844638, 46.294916244733) + (9.615729844638, 46.290215738438) + (9.620430350933, 46.290215738438) + (9.620430350933, 46.285515232142) + (9.625130857228, 46.285515232142) + (9.629831363523, 46.285515232142) + (9.634531869819, 46.285515232142) + (9.639232376114, 46.285515232142) + (9.643932882409, 46.285515232142) + (9.643932882409, 46.290215738438) + (9.648633388704, 46.290215738438) + (9.653333895, 46.290215738438) + (9.653333895, 46.294916244733) + (9.658034401295, 46.294916244733) + (9.66273490759, 46.294916244733) + (9.667435413885, 46.294916244733) + (9.667435413885, 46.299616751028) + (9.67213592018, 46.299616751028) + (9.676836426476, 46.299616751028) + (9.681536932771, 46.299616751028) + (9.686237439066, 46.299616751028) + (9.686237439066, 46.294916244733) + (9.690937945361, 46.294916244733) + (9.695638451656, 46.294916244733) + (9.695638451656, 46.290215738438) + (9.700338957952, 46.290215738438) + (9.705039464247, 46.290215738438) + (9.709739970542, 46.290215738438) + (9.709739970542, 46.294916244733) + (9.714440476837, 46.294916244733) + (9.714440476837, 46.299616751028) + (9.719140983133, 46.299616751028) + (9.719140983133, 46.304317257323) + (9.719140983133, 46.309017763619) + (9.723841489428, 46.309017763619) + (9.723841489428, 46.313718269914) + (9.728541995723, 46.313718269914) + (9.728541995723, 46.318418776209) + (9.723841489428, 46.318418776209) + (9.723841489428, 46.323119282504) + (9.719140983133, 46.323119282504) + (9.719140983133, 46.327819788799) + (9.723841489428, 46.327819788799) + (9.723841489428, 46.332520295095) + (9.728541995723, 46.332520295095) + (9.728541995723, 46.33722080139) + (9.723841489428, 46.33722080139) + (9.723841489428, 46.341921307685) + (9.728541995723, 46.341921307685) + (9.728541995723, 46.34662181398) + (9.733242502018, 46.34662181398) + (9.733242502018, 46.351322320275) + (9.737943008313, 46.351322320275) + (9.742643514609, 46.351322320275) + (9.747344020904, 46.351322320275) + (9.747344020904, 46.34662181398) + (9.752044527199, 46.34662181398) + (9.756745033494, 46.34662181398) + (9.756745033494, 46.341921307685) + (9.761445539789, 46.341921307685) + (9.761445539789, 46.33722080139) + (9.766146046085, 46.33722080139) + (9.77084655238, 46.33722080139) + (9.77084655238, 46.332520295095) + (9.775547058675, 46.332520295095) + (9.78024756497, 46.332520295095) + (9.78024756497, 46.33722080139) + (9.784948071266, 46.33722080139) + (9.789648577561, 46.33722080139) + (9.789648577561, 46.341921307685) + (9.794349083856, 46.341921307685) + (9.799049590151, 46.341921307685) + (9.803750096446, 46.341921307685) + (9.803750096446, 46.34662181398) + (9.808450602742, 46.34662181398) + (9.813151109037, 46.34662181398) + (9.817851615332, 46.34662181398) + (9.817851615332, 46.351322320275) + (9.822552121627, 46.351322320275) + (9.822552121627, 46.356022826571) + (9.827252627922, 46.356022826571) + (9.831953134218, 46.356022826571) + (9.831953134218, 46.360723332866) + (9.836653640513, 46.360723332866) + (9.841354146808, 46.360723332866) + (9.846054653103, 46.360723332866) + (9.850755159399, 46.360723332866) + (9.850755159399, 46.365423839161) + (9.855455665694, 46.365423839161) + (9.860156171989, 46.365423839161) + (9.864856678284, 46.365423839161) + (9.869557184579, 46.365423839161) + (9.874257690875, 46.365423839161) + (9.87895819717, 46.365423839161) + (9.87895819717, 46.370124345456) + (9.883658703465, 46.370124345456) + (9.883658703465, 46.374824851752) + (9.88835920976, 46.374824851752) + (9.893059716056, 46.374824851752) + (9.897760222351, 46.374824851752) + (9.897760222351, 46.379525358047) + (9.902460728646, 46.379525358047) + (9.907161234941, 46.379525358047) + (9.911861741236, 46.379525358047) + (9.911861741236, 46.374824851752) + (9.916562247532, 46.374824851752) + (9.916562247532, 46.370124345456) + (9.921262753827, 46.370124345456) + (9.925963260122, 46.370124345456) + (9.925963260122, 46.365423839161) + (9.930663766417, 46.365423839161) + (9.930663766417, 46.370124345456) + (9.935364272712, 46.370124345456) + (9.935364272712, 46.374824851752) + (9.940064779008, 46.374824851752) + (9.940064779008, 46.379525358047) + (9.944765285303, 46.379525358047) + (9.949465791598, 46.379525358047) + (9.954166297893, 46.379525358047) + (9.958866804189, 46.379525358047) + (9.958866804189, 46.374824851752) + (9.958866804189, 46.370124345456) + (9.963567310484, 46.370124345456) + (9.963567310484, 46.365423839161) + (9.968267816779, 46.365423839161) + (9.968267816779, 46.360723332866) + (9.972968323074, 46.360723332866) + (9.977668829369, 46.360723332866) + (9.977668829369, 46.356022826571) + (9.982369335665, 46.356022826571) + (9.98706984196, 46.356022826571) + (9.98706984196, 46.351322320275) + (9.991770348255, 46.351322320275) + (9.99647085455, 46.351322320275) + (9.99647085455, 46.34662181398) + (9.99647085455, 46.341921307685) + (9.991770348255, 46.341921307685) + (9.991770348255, 46.33722080139) + (9.98706984196, 46.33722080139) + (9.98706984196, 46.332520295095) + (9.98706984196, 46.327819788799) + (9.982369335665, 46.327819788799) + (9.982369335665, 46.323119282504) + (9.98706984196, 46.323119282504) + (9.98706984196, 46.318418776209) + (9.991770348255, 46.318418776209) + (9.991770348255, 46.313718269914) + (9.99647085455, 46.313718269914) + (10.001171360845, 46.313718269914) + (10.001171360845, 46.309017763619) + (10.001171360845, 46.304317257323) + (9.99647085455, 46.304317257323) + (9.99647085455, 46.299616751028) + (9.99647085455, 46.294916244733) + (9.991770348255, 46.294916244733) + (9.991770348255, 46.290215738438) + (9.99647085455, 46.290215738438) + (9.99647085455, 46.285515232142) + (10.001171360845, 46.285515232142) + (10.001171360845, 46.280814725847) + (10.005871867141, 46.280814725847) + (10.010572373436, 46.280814725847) + (10.015272879731, 46.280814725847) + (10.019973386026, 46.280814725847) + (10.019973386026, 46.276114219552) + (10.024673892322, 46.276114219552) + (10.029374398617, 46.276114219552) + (10.034074904912, 46.276114219552) + (10.038775411207, 46.276114219552) + (10.038775411207, 46.271413713257) + (10.043475917502, 46.271413713257) + (10.048176423798, 46.271413713257) + (10.048176423798, 46.266713206962) + (10.052876930093, 46.266713206962) + (10.052876930093, 46.262012700666) + (10.057577436388, 46.262012700666) + (10.057577436388, 46.257312194371) + (10.057577436388, 46.252611688076) + (10.057577436388, 46.247911181781) + (10.057577436388, 46.243210675486) + (10.057577436388, 46.23851016919) + (10.052876930093, 46.23851016919) + (10.052876930093, 46.233809662895) + (10.048176423798, 46.233809662895) + (10.043475917502, 46.233809662895) + (10.043475917502, 46.2291091566) + (10.048176423798, 46.2291091566) + (10.048176423798, 46.224408650305) + (10.052876930093, 46.224408650305) + (10.057577436388, 46.224408650305) + (10.057577436388, 46.219708144009) + (10.062277942683, 46.219708144009) + (10.066978448978, 46.219708144009) + (10.071678955274, 46.219708144009) + (10.076379461569, 46.219708144009) + (10.076379461569, 46.224408650305) + (10.081079967864, 46.224408650305) + (10.085780474159, 46.224408650305) + (10.090480980455, 46.224408650305) + (10.09518148675, 46.224408650305) + (10.09518148675, 46.2291091566) + (10.099881993045, 46.2291091566) + (10.10458249934, 46.2291091566) + (10.10458249934, 46.224408650305) + (10.109283005635, 46.224408650305) + (10.113983511931, 46.224408650305) + (10.118684018226, 46.224408650305) + (10.123384524521, 46.224408650305) + (10.128085030816, 46.224408650305) + (10.132785537111, 46.224408650305) + (10.137486043407, 46.224408650305) + (10.137486043407, 46.2291091566) + (10.142186549702, 46.2291091566) + (10.146887055997, 46.2291091566) + (10.146887055997, 46.233809662895) + (10.146887055997, 46.23851016919) + (10.151587562292, 46.23851016919) + (10.156288068588, 46.23851016919) + (10.156288068588, 46.243210675486) + (10.160988574883, 46.243210675486) + (10.160988574883, 46.247911181781) + (10.165689081178, 46.247911181781) + (10.170389587473, 46.247911181781) + (10.170389587473, 46.252611688076) + (10.175090093768, 46.252611688076) + (10.175090093768, 46.257312194371) + (10.175090093768, 46.262012700666) + (10.175090093768, 46.266713206962) + (10.170389587473, 46.266713206962) + (10.170389587473, 46.271413713257) + (10.165689081178, 46.271413713257) + (10.160988574883, 46.271413713257) + (10.160988574883, 46.276114219552) + (10.160988574883, 46.280814725847) + (10.160988574883, 46.285515232142) + (10.156288068588, 46.285515232142) + (10.156288068588, 46.290215738438) + (10.156288068588, 46.294916244733) + (10.151587562292, 46.294916244733) + (10.146887055997, 46.294916244733) + (10.142186549702, 46.294916244733) + (10.142186549702, 46.299616751028) + (10.137486043407, 46.299616751028) + (10.137486043407, 46.304317257323) + (10.137486043407, 46.309017763619) + (10.132785537111, 46.309017763619) + (10.128085030816, 46.309017763619) + (10.128085030816, 46.313718269914) + (10.123384524521, 46.313718269914) + (10.118684018226, 46.313718269914) + (10.118684018226, 46.318418776209) + (10.113983511931, 46.318418776209) + (10.113983511931, 46.323119282504) + (10.113983511931, 46.327819788799) + (10.109283005635, 46.327819788799) + (10.109283005635, 46.332520295095) + (10.10458249934, 46.332520295095) + (10.10458249934, 46.33722080139) + (10.10458249934, 46.341921307685) + (10.10458249934, 46.34662181398) + (10.109283005635, 46.34662181398) + (10.109283005635, 46.351322320275) + (10.113983511931, 46.351322320275) + (10.113983511931, 46.356022826571) + (10.118684018226, 46.356022826571) + (10.118684018226, 46.360723332866) + (10.123384524521, 46.360723332866) + (10.128085030816, 46.360723332866) + (10.132785537111, 46.360723332866) + (10.132785537111, 46.365423839161) + (10.128085030816, 46.365423839161) + (10.128085030816, 46.370124345456) + (10.128085030816, 46.374824851752) + (10.128085030816, 46.379525358047) + (10.132785537111, 46.379525358047) + (10.132785537111, 46.384225864342) + (10.137486043407, 46.384225864342) + (10.142186549702, 46.384225864342) + (10.146887055997, 46.384225864342) + (10.151587562292, 46.384225864342) + (10.156288068588, 46.384225864342) + (10.160988574883, 46.384225864342) + (10.160988574883, 46.388926370637) + (10.160988574883, 46.393626876932) + (10.165689081178, 46.393626876932) + (10.165689081178, 46.398327383228) + (10.165689081178, 46.403027889523) + (10.165689081178, 46.407728395818) + (10.165689081178, 46.412428902113) + (10.160988574883, 46.412428902113) + (10.156288068588, 46.412428902113) + (10.151587562292, 46.412428902113) + (10.146887055997, 46.412428902113) + (10.146887055997, 46.417129408408) + (10.146887055997, 46.421829914704) + (10.142186549702, 46.421829914704) + (10.142186549702, 46.426530420999) + (10.137486043407, 46.426530420999) + (10.132785537111, 46.426530420999) + (10.132785537111, 46.431230927294) + (10.128085030816, 46.431230927294) + (10.123384524521, 46.431230927294) + (10.123384524521, 46.426530420999) + (10.118684018226, 46.426530420999) + (10.113983511931, 46.426530420999) + (10.109283005635, 46.426530420999) + (10.10458249934, 46.426530420999) + (10.10458249934, 46.421829914704) + (10.099881993045, 46.421829914704) + (10.09518148675, 46.421829914704) + (10.090480980455, 46.421829914704) + (10.085780474159, 46.421829914704) + (10.081079967864, 46.421829914704) + (10.076379461569, 46.421829914704) + (10.076379461569, 46.426530420999) + (10.071678955274, 46.426530420999) + (10.066978448978, 46.426530420999) + (10.062277942683, 46.426530420999) + (10.057577436388, 46.426530420999) + (10.057577436388, 46.431230927294) + (10.057577436388, 46.435931433589) + (10.052876930093, 46.435931433589) + (10.052876930093, 46.440631939885) + (10.048176423798, 46.440631939885) + (10.043475917502, 46.440631939885) + (10.043475917502, 46.44533244618) + (10.038775411207, 46.44533244618) + (10.038775411207, 46.450032952475) + (10.043475917502, 46.450032952475) + (10.043475917502, 46.45473345877) + (10.048176423798, 46.45473345877) + (10.048176423798, 46.459433965065) + (10.052876930093, 46.459433965065) + (10.052876930093, 46.464134471361) + (10.052876930093, 46.468834977656) + (10.052876930093, 46.473535483951) + (10.048176423798, 46.473535483951) + (10.048176423798, 46.478235990246) + (10.043475917502, 46.478235990246) + (10.043475917502, 46.482936496541) + (10.043475917502, 46.482936496542) + (10.043475917502, 46.487637002837) + (10.048176423798, 46.487637002837) + (10.048176423798, 46.492337509132) + (10.048176423798, 46.497038015427) + (10.048176423798, 46.501738521722) + (10.048176423798, 46.506439028018) + (10.043475917502, 46.506439028018) + (10.043475917502, 46.511139534313) + (10.048176423798, 46.511139534313) + (10.048176423798, 46.515840040608) + (10.052876930093, 46.515840040608) + (10.052876930093, 46.520540546903) + (10.052876930093, 46.525241053198) + (10.052876930093, 46.529941559494) + (10.048176423798, 46.529941559494) + (10.048176423798, 46.534642065789) + (10.048176423798, 46.539342572084) + (10.048176423798, 46.544043078379) + (10.052876930093, 46.544043078379) + (10.057577436388, 46.544043078379) + (10.062277942683, 46.544043078379) + (10.062277942683, 46.548743584675) + (10.066978448978, 46.548743584675) + (10.066978448978, 46.55344409097) + (10.071678955274, 46.55344409097) + (10.071678955274, 46.558144597265) + (10.076379461569, 46.558144597265) + (10.076379461569, 46.56284510356) + (10.081079967864, 46.56284510356) + (10.085780474159, 46.56284510356) + (10.085780474159, 46.567545609855) + (10.081079967864, 46.567545609855) + (10.081079967864, 46.572246116151) + (10.081079967864, 46.576946622446) + (10.085780474159, 46.576946622446) + (10.090480980455, 46.576946622446) + (10.09518148675, 46.576946622446) + (10.09518148675, 46.581647128741) + (10.099881993045, 46.581647128741) + (10.099881993045, 46.586347635036) + (10.099881993045, 46.591048141331) + (10.099881993045, 46.595748647627) + (10.099881993045, 46.600449153922) + (10.099881993045, 46.605149660217) + (10.099881993045, 46.609850166512) + (10.10458249934, 46.609850166512) + (10.109283005635, 46.609850166512) + (10.113983511931, 46.609850166512) + (10.118684018226, 46.609850166512) + (10.123384524521, 46.609850166512) + (10.128085030816, 46.609850166512) + (10.132785537111, 46.609850166512) + (10.137486043407, 46.609850166512) + (10.142186549702, 46.609850166512) + (10.146887055997, 46.609850166512) + (10.151587562292, 46.609850166512) + (10.151587562292, 46.614550672808) + (10.156288068588, 46.614550672808) + (10.160988574883, 46.614550672808) + (10.165689081178, 46.614550672808) + (10.165689081178, 46.619251179103) + (10.170389587473, 46.619251179103) + (10.175090093768, 46.619251179103) + (10.175090093768, 46.623951685398) + (10.179790600064, 46.623951685398) + (10.184491106359, 46.623951685398) + (10.189191612654, 46.623951685398) + (10.193892118949, 46.623951685398) + (10.198592625244, 46.623951685398) + (10.20329313154, 46.623951685398) + (10.20329313154, 46.619251179103) + (10.207993637835, 46.619251179103) + (10.21269414413, 46.619251179103) + (10.217394650425, 46.619251179103) + (10.217394650425, 46.623951685398) + (10.222095156721, 46.623951685398) + (10.222095156721, 46.628652191693) + (10.226795663016, 46.628652191693) + (10.231496169311, 46.628652191693) + (10.231496169311, 46.633352697988) + (10.236196675606, 46.633352697988) + (10.240897181901, 46.633352697988) + (10.240897181901, 46.628652191693) + (10.240897181901, 46.623951685398) + (10.245597688197, 46.623951685398) + (10.245597688197, 46.619251179103) + (10.250298194492, 46.619251179103) + (10.250298194492, 46.614550672808) + (10.254998700787, 46.614550672808) + (10.254998700787, 46.609850166512) + (10.254998700787, 46.605149660217) + (10.254998700787, 46.600449153922) + (10.250298194492, 46.600449153922) + (10.245597688197, 46.600449153922) + (10.245597688197, 46.595748647627) + (10.245597688197, 46.591048141331) + (10.245597688197, 46.586347635036) + (10.245597688197, 46.581647128741) + (10.245597688197, 46.576946622446) + (10.245597688197, 46.572246116151) + (10.250298194492, 46.572246116151) + (10.254998700787, 46.572246116151) + (10.259699207082, 46.572246116151) + (10.259699207082, 46.576946622446) + (10.264399713378, 46.576946622446) + (10.269100219673, 46.576946622446) + (10.273800725968, 46.576946622446) + (10.273800725968, 46.572246116151) + (10.278501232263, 46.572246116151) + (10.283201738558, 46.572246116151) + (10.283201738558, 46.567545609855) + (10.287902244854, 46.567545609855) + (10.287902244854, 46.56284510356) + (10.292602751149, 46.56284510356) + (10.292602751149, 46.558144597265) + (10.297303257444, 46.558144597265) + (10.297303257444, 46.55344409097) + (10.297303257444, 46.548743584675) + (10.302003763739, 46.548743584675) + (10.306704270034, 46.548743584675) + (10.31140477633, 46.548743584675) + (10.316105282625, 46.548743584675) + (10.32080578892, 46.548743584675) + (10.325506295215, 46.548743584675) + (10.330206801511, 46.548743584675) + (10.334907307806, 46.548743584675) + (10.334907307806, 46.544043078379) + (10.339607814101, 46.544043078379) + (10.344308320396, 46.544043078379) + (10.344308320396, 46.548743584675) + (10.349008826691, 46.548743584675) + (10.349008826691, 46.55344409097) + (10.353709332987, 46.55344409097) + (10.358409839282, 46.55344409097) + (10.363110345577, 46.55344409097) + (10.367810851872, 46.55344409097) + (10.372511358167, 46.55344409097) + (10.377211864463, 46.55344409097) + (10.377211864463, 46.548743584675) + (10.381912370758, 46.548743584675) + (10.386612877053, 46.548743584675) + (10.391313383348, 46.548743584675) + (10.391313383348, 46.544043078379) + (10.396013889644, 46.544043078379) + (10.400714395939, 46.544043078379) + (10.405414902234, 46.544043078379) + (10.405414902234, 46.548743584675) + (10.410115408529, 46.548743584675) + (10.414815914824, 46.548743584675) + (10.41951642112, 46.548743584675) + (10.424216927415, 46.548743584675) + (10.424216927415, 46.544043078379) + (10.42891743371, 46.544043078379) + (10.42891743371, 46.539342572084) + (10.433617940005, 46.539342572084) + (10.4383184463, 46.539342572084) + (10.4383184463, 46.534642065789) + (10.443018952596, 46.534642065789) + (10.447719458891, 46.534642065789) + (10.452419965186, 46.534642065789) + (10.457120471481, 46.534642065789) + (10.461820977777, 46.534642065789) + (10.461820977777, 46.539342572084) + (10.461820977777, 46.544043078379) + (10.466521484072, 46.544043078379) + (10.471221990367, 46.544043078379) + (10.471221990367, 46.548743584675) + (10.471221990367, 46.55344409097) + (10.475922496662, 46.55344409097) + (10.475922496662, 46.558144597265) + (10.475922496662, 46.56284510356) + (10.475922496662, 46.567545609855) + (10.475922496662, 46.572246116151) + (10.480623002957, 46.572246116151) + (10.480623002957, 46.576946622446) + (10.485323509253, 46.576946622446) + (10.485323509253, 46.581647128741) + (10.485323509253, 46.586347635036) + (10.485323509253, 46.591048141331) + (10.485323509253, 46.595748647627) + (10.485323509253, 46.600449153922) + (10.485323509253, 46.605149660217) + (10.490024015548, 46.605149660217) + (10.490024015548, 46.609850166512) + (10.490024015548, 46.614550672808) + (10.485323509253, 46.614550672808) + (10.485323509253, 46.619251179103) + (10.480623002957, 46.619251179103) + (10.480623002957, 46.623951685398) + (10.475922496662, 46.623951685398) + (10.471221990367, 46.623951685398) + (10.471221990367, 46.628652191693) + (10.466521484072, 46.628652191693) + (10.461820977777, 46.628652191693) + (10.461820977777, 46.633352697988) + (10.457120471481, 46.633352697988) + (10.452419965186, 46.633352697988) + (10.452419965186, 46.638053204284) + (10.447719458891, 46.638053204284) + (10.443018952596, 46.638053204284) + (10.4383184463, 46.638053204284) + (10.433617940005, 46.638053204284) + (10.42891743371, 46.638053204284) + (10.424216927415, 46.638053204284) + (10.41951642112, 46.638053204284) + (10.414815914824, 46.638053204284) + (10.410115408529, 46.638053204284) + (10.405414902234, 46.638053204284) + (10.400714395939, 46.638053204284) + (10.400714395939, 46.642753710579) + (10.396013889644, 46.642753710579) + (10.396013889644, 46.647454216874) + (10.396013889644, 46.652154723169) + (10.391313383348, 46.652154723169) + (10.391313383348, 46.656855229464) + (10.391313383348, 46.66155573576) + (10.391313383348, 46.666256242055) + (10.391313383348, 46.67095674835) + (10.386612877053, 46.67095674835) + (10.386612877053, 46.675657254645) + (10.386612877053, 46.680357760941) + (10.381912370758, 46.680357760941) + (10.381912370758, 46.685058267236) + (10.386612877053, 46.685058267236) + (10.386612877053, 46.689758773531) + (10.391313383348, 46.689758773531) + (10.396013889644, 46.689758773531) + (10.396013889644, 46.694459279826) + (10.396013889644, 46.699159786121) + (10.400714395939, 46.699159786121) + (10.400714395939, 46.703860292417) + (10.405414902234, 46.703860292417) + (10.405414902234, 46.708560798712) + (10.410115408529, 46.708560798712) + (10.414815914824, 46.708560798712) + (10.414815914824, 46.713261305007) + (10.414815914824, 46.717961811302) + (10.414815914824, 46.722662317597) + (10.410115408529, 46.722662317597) + (10.410115408529, 46.727362823893) + (10.405414902234, 46.727362823893) + (10.405414902234, 46.732063330188) + (10.400714395939, 46.732063330188) + (10.400714395939, 46.736763836483) + (10.405414902234, 46.736763836483) + (10.405414902234, 46.741464342778) + (10.410115408529, 46.741464342778) + (10.414815914824, 46.741464342778) + (10.41951642112, 46.741464342778) + (10.41951642112, 46.746164849074) + (10.424216927415, 46.746164849074) + (10.424216927415, 46.750865355369) + (10.42891743371, 46.750865355369) + (10.433617940005, 46.750865355369) + (10.4383184463, 46.750865355369) + (10.4383184463, 46.755565861664) + (10.443018952596, 46.755565861664) + (10.443018952596, 46.760266367959) + (10.443018952596, 46.764966874254) + (10.443018952596, 46.76966738055) + (10.4383184463, 46.76966738055) + (10.4383184463, 46.774367886845) + (10.433617940005, 46.774367886845) + (10.433617940005, 46.77906839314) + (10.42891743371, 46.77906839314) + (10.42891743371, 46.783768899435) + (10.424216927415, 46.783768899435) + (10.424216927415, 46.78846940573) + (10.424216927415, 46.788469405731) + (10.424216927415, 46.793169912026) + (10.42891743371, 46.793169912026) + (10.42891743371, 46.797870418321) + (10.433617940005, 46.797870418321) + (10.4383184463, 46.797870418321) + (10.443018952596, 46.797870418321) + (10.447719458891, 46.797870418321) + (10.447719458891, 46.802570924616) + (10.447719458891, 46.807271430911) + (10.452419965186, 46.807271430911) + (10.452419965186, 46.811971937207) + (10.457120471481, 46.811971937207) + (10.457120471481, 46.816672443502) + (10.457120471481, 46.821372949797) + (10.457120471481, 46.826073456092) + (10.457120471481, 46.830773962387) + (10.461820977777, 46.830773962387) + (10.461820977777, 46.835474468683) + (10.466521484072, 46.835474468683) + (10.466521484072, 46.840174974978) + (10.466521484072, 46.844875481273) + (10.471221990367, 46.844875481273) + (10.471221990367, 46.849575987568) + (10.471221990367, 46.854276493864) + (10.471221990367, 46.858977000159) + (10.466521484072, 46.858977000159) + (10.466521484072, 46.863677506454) + (10.471221990367, 46.863677506454) + (10.471221990367, 46.868378012749) + (10.471221990367, 46.873078519044) + (10.471221990367, 46.87777902534) + (10.471221990367, 46.882479531635) + (10.466521484072, 46.882479531635) + (10.466521484072, 46.88718003793) + (10.471221990367, 46.88718003793) + (10.471221990367, 46.891880544225) + (10.475922496662, 46.891880544225) + (10.475922496662, 46.89658105052) + (10.475922496662, 46.901281556816) + (10.475922496662, 46.905982063111) + (10.480623002957, 46.905982063111) + (10.480623002957, 46.910682569406) + (10.485323509253, 46.910682569406) + (10.485323509253, 46.915383075701) + (10.485323509253, 46.920083581997) + (10.485323509253, 46.924784088292) + (10.490024015548, 46.924784088292) + (10.490024015548, 46.929484594587) + (10.485323509253, 46.929484594587) + (10.485323509253, 46.934185100882) + (10.490024015548, 46.934185100882) + (10.490024015548, 46.938885607177) + (10.485323509253, 46.938885607177) + (10.480623002957, 46.938885607177) + (10.475922496662, 46.938885607177) + (10.475922496662, 46.943586113473) + (10.471221990367, 46.943586113473) + (10.471221990367, 46.948286619768) + (10.466521484072, 46.948286619768) + (10.461820977777, 46.948286619768) + (10.457120471481, 46.948286619768) + (10.457120471481, 46.952987126063) + (10.452419965186, 46.952987126063) + (10.447719458891, 46.952987126063) + (10.443018952596, 46.952987126063) + (10.4383184463, 46.952987126063) + (10.4383184463, 46.957687632358) + (10.433617940005, 46.957687632358) + (10.42891743371, 46.957687632358) + (10.424216927415, 46.957687632358) + (10.424216927415, 46.962388138653) + (10.424216927415, 46.967088644949) + (10.424216927415, 46.971789151244) + (10.42891743371, 46.971789151244) + (10.42891743371, 46.976489657539) + (10.424216927415, 46.976489657539) + (10.424216927415, 46.981190163834) + (10.41951642112, 46.981190163834) + (10.414815914824, 46.981190163834) + (10.410115408529, 46.981190163834) + (10.410115408529, 46.98589067013) + (10.405414902234, 46.98589067013) + (10.405414902234, 46.990591176425) + (10.400714395939, 46.990591176425) + (10.400714395939, 46.99529168272) + (10.396013889644, 46.99529168272) + (10.396013889644, 46.999992189015) + (10.391313383348, 46.999992189015) + (10.386612877053, 46.999992189015) + (10.381912370758, 46.999992189015) + (10.381912370758, 46.99529168272) + (10.377211864463, 46.99529168272) + (10.377211864463, 46.990591176425) + (10.372511358167, 46.990591176425) + (10.367810851872, 46.990591176425) + (10.363110345577, 46.990591176425) + (10.358409839282, 46.990591176425) + (10.353709332987, 46.990591176425) + (10.349008826691, 46.990591176425) + (10.344308320396, 46.990591176425) + (10.344308320396, 46.98589067013) + (10.344308320396, 46.981190163834) + (10.339607814101, 46.981190163834) + (10.339607814101, 46.976489657539) + (10.334907307806, 46.976489657539) + (10.334907307806, 46.971789151244) + (10.334907307806, 46.967088644949) + (10.330206801511, 46.967088644949) + (10.330206801511, 46.962388138653) + (10.330206801511, 46.957687632358) + (10.330206801511, 46.952987126063) + (10.325506295215, 46.952987126063) + (10.32080578892, 46.952987126063) + (10.316105282625, 46.952987126063) + (10.31140477633, 46.952987126063) + (10.31140477633, 46.948286619768) + (10.306704270034, 46.948286619768) + (10.306704270034, 46.943586113473) + (10.306704270034, 46.938885607177) + (10.31140477633, 46.938885607177) + (10.31140477633, 46.934185100882) + (10.316105282625, 46.934185100882) + (10.316105282625, 46.929484594587) + (10.316105282625, 46.924784088292) + (10.31140477633, 46.924784088292) + (10.306704270034, 46.924784088292) + (10.302003763739, 46.924784088292) + (10.297303257444, 46.924784088292) + (10.297303257444, 46.920083581997) + (10.292602751149, 46.920083581997) + (10.292602751149, 46.924784088292) + (10.287902244854, 46.924784088292) + (10.283201738558, 46.924784088292) + (10.278501232263, 46.924784088292) + (10.273800725968, 46.924784088292) + (10.273800725968, 46.929484594587) + (10.269100219673, 46.929484594587) + (10.264399713378, 46.929484594587) + (10.259699207082, 46.929484594587) + (10.254998700787, 46.929484594587) + (10.250298194492, 46.929484594587) + (10.245597688197, 46.929484594587) + (10.240897181901, 46.929484594587) + (10.240897181901, 46.924784088292) + (10.240897181901, 46.920083581997) + (10.240897181901, 46.915383075701) + (10.236196675606, 46.915383075701) + (10.236196675606, 46.910682569406) + (10.236196675606, 46.905982063111) + (10.236196675606, 46.901281556816) + (10.231496169311, 46.901281556816) + (10.231496169311, 46.89658105052) + (10.226795663016, 46.89658105052) + (10.226795663016, 46.891880544225) + (10.226795663016, 46.88718003793) + (10.231496169311, 46.88718003793) + (10.236196675606, 46.88718003793) + (10.236196675606, 46.882479531635) + (10.236196675606, 46.87777902534) + (10.231496169311, 46.87777902534) + (10.231496169311, 46.873078519044) + (10.231496169311, 46.868378012749) + (10.226795663016, 46.868378012749) + (10.222095156721, 46.868378012749) + (10.217394650425, 46.868378012749) + (10.217394650425, 46.863677506454) + (10.21269414413, 46.863677506454) + (10.207993637835, 46.863677506454) + (10.20329313154, 46.863677506454) + (10.198592625244, 46.863677506454) + (10.198592625244, 46.868378012749) + (10.193892118949, 46.868378012749) + (10.193892118949, 46.863677506454) + (10.189191612654, 46.863677506454) + (10.189191612654, 46.858977000159) + (10.184491106359, 46.858977000159) + (10.184491106359, 46.854276493864) + (10.179790600064, 46.854276493864) + (10.175090093768, 46.854276493864) + (10.170389587473, 46.854276493864) + (10.170389587473, 46.849575987568) + (10.165689081178, 46.849575987568) + (10.160988574883, 46.849575987568) + (10.156288068588, 46.849575987568) + (10.151587562292, 46.849575987568) + (10.146887055997, 46.849575987568) + (10.142186549702, 46.849575987568) + (10.137486043407, 46.849575987568) + (10.132785537111, 46.849575987568) + (10.128085030816, 46.849575987568) + (10.123384524521, 46.849575987568) + (10.123384524521, 46.844875481273) + (10.118684018226, 46.844875481273) + (10.113983511931, 46.844875481273) + (10.113983511931, 46.840174974978) + (10.109283005635, 46.840174974978) + (10.10458249934, 46.840174974978) + (10.10458249934, 46.844875481273) + (10.099881993045, 46.844875481273) + (10.099881993045, 46.849575987568) + (10.09518148675, 46.849575987568) + (10.090480980455, 46.849575987568) + (10.090480980455, 46.854276493864) + (10.090480980455, 46.858977000159) + (10.085780474159, 46.858977000159) + (10.081079967864, 46.858977000159) + (10.076379461569, 46.858977000159) + (10.076379461569, 46.863677506454) + (10.071678955274, 46.863677506454) + (10.071678955274, 46.858977000159) + (10.066978448978, 46.858977000159) + (10.066978448978, 46.863677506454) + (10.062277942683, 46.863677506454) + (10.062277942683, 46.858977000159) + (10.057577436388, 46.858977000159) + (10.057577436388, 46.863677506454) + (10.052876930093, 46.863677506454) + (10.052876930093, 46.868378012749) + (10.052876930093, 46.873078519044) + (10.052876930093, 46.87777902534) + (10.048176423798, 46.87777902534) + (10.043475917502, 46.87777902534) + (10.043475917502, 46.882479531635) + (10.038775411207, 46.882479531635) + (10.038775411207, 46.88718003793) + (10.034074904912, 46.88718003793) + (10.029374398617, 46.88718003793) + (10.029374398617, 46.891880544225) + (10.029374398617, 46.89658105052) + (10.024673892322, 46.89658105052) + (10.019973386026, 46.89658105052) + (10.019973386026, 46.901281556816) + (10.015272879731, 46.901281556816) + (10.010572373436, 46.901281556816) + (10.005871867141, 46.901281556816) + (10.001171360845, 46.901281556816) + (9.99647085455, 46.901281556816) + (9.991770348255, 46.901281556816) + (9.98706984196, 46.901281556816) + (9.98706984196, 46.905982063111) + (9.982369335665, 46.905982063111) + (9.982369335665, 46.910682569406) + (9.982369335665, 46.915383075701) + (9.977668829369, 46.915383075701) + (9.972968323074, 46.915383075701) + (9.968267816779, 46.915383075701) + (9.968267816779, 46.910682569406) + (9.963567310484, 46.910682569406) + (9.963567310484, 46.915383075701) + (9.958866804189, 46.915383075701) + (9.954166297893, 46.915383075701) + (9.949465791598, 46.915383075701) + (9.949465791598, 46.910682569406) + (9.944765285303, 46.910682569406) + (9.944765285303, 46.915383075701) + (9.940064779008, 46.915383075701) + (9.935364272712, 46.915383075701) + (9.930663766417, 46.915383075701) + (9.925963260122, 46.915383075701) + (9.925963260122, 46.920083581997) + (9.921262753827, 46.920083581997) + (9.916562247532, 46.920083581997) + (9.916562247532, 46.924784088292) + (9.911861741236, 46.924784088292) + (9.907161234941, 46.924784088292) + (9.902460728646, 46.924784088292) + (9.902460728646, 46.929484594587) + (9.897760222351, 46.929484594587) + (9.893059716056, 46.929484594587) + (9.893059716056, 46.934185100882) + (9.88835920976, 46.934185100882) + (9.883658703465, 46.934185100882) + (9.87895819717, 46.934185100882) + (9.87895819717, 46.938885607177) + (9.87895819717, 46.943586113473) + (9.87895819717, 46.948286619768) + (9.874257690875, 46.948286619768) + (9.874257690875, 46.952987126063) + (9.87895819717, 46.952987126063) + (9.87895819717, 46.957687632358) + (9.874257690875, 46.957687632358) + (9.874257690875, 46.962388138653) + (9.874257690875, 46.967088644949) + (9.874257690875, 46.971789151244) + (9.874257690875, 46.976489657539) + (9.87895819717, 46.976489657539) + (9.883658703465, 46.976489657539) + (9.883658703465, 46.981190163834) + (9.883658703465, 46.98589067013) + (9.88835920976, 46.98589067013) + (9.893059716056, 46.98589067013) + (9.893059716056, 46.990591176425) + (9.88835920976, 46.990591176425) + (9.88835920976, 46.99529168272) + (9.88835920976, 46.999992189015) + (9.883658703465, 46.999992189015) + (9.883658703465, 47.00469269531) + (9.87895819717, 47.00469269531) + (9.874257690875, 47.00469269531) + (9.874257690875, 47.009393201606) + (9.869557184579, 47.009393201606) + (9.869557184579, 47.014093707901) + (9.874257690875, 47.014093707901) + (9.87895819717, 47.014093707901) + (9.87895819717, 47.018794214196) + (9.874257690875, 47.018794214196) + (9.874257690875, 47.023494720491) + (9.869557184579, 47.023494720491) + (9.864856678284, 47.023494720491) + (9.860156171989, 47.023494720491) + (9.860156171989, 47.018794214196) + (9.855455665694, 47.018794214196) + (9.850755159399, 47.018794214196) + (9.850755159399, 47.014093707901) + (9.846054653103, 47.014093707901) + (9.841354146808, 47.014093707901) + (9.836653640513, 47.014093707901) + (9.831953134218, 47.014093707901) + (9.827252627922, 47.014093707901) + (9.827252627922, 47.018794214196) + (9.822552121627, 47.018794214196) + (9.817851615332, 47.018794214196) + (9.817851615332, 47.023494720491) + (9.813151109037, 47.023494720491) + (9.808450602742, 47.023494720491) + (9.803750096446, 47.023494720491) + (9.803750096446, 47.028195226786) + (9.799049590151, 47.028195226786) + (9.794349083856, 47.028195226786) + (9.794349083856, 47.032895733082) + (9.789648577561, 47.032895733082) + (9.789648577561, 47.037596239377) + (9.784948071266, 47.037596239377) + (9.78024756497, 47.037596239377) + (9.775547058675, 47.037596239377) + (9.77084655238, 47.037596239377) + (9.766146046085, 47.037596239377) + (9.761445539789, 47.037596239377) + (9.756745033494, 47.037596239377) + (9.752044527199, 47.037596239377) + (9.747344020904, 47.037596239377) + (9.747344020904, 47.042296745672) + (9.742643514609, 47.042296745672) + (9.737943008313, 47.042296745672) + (9.733242502018, 47.042296745672) + (9.728541995723, 47.042296745672) + (9.723841489428, 47.042296745672) + (9.719140983133, 47.042296745672) + (9.719140983133, 47.046997251967) + (9.714440476837, 47.046997251967) + (9.709739970542, 47.046997251967) + (9.705039464247, 47.046997251967) + (9.705039464247, 47.051697758263) + (9.700338957952, 47.051697758263) + (9.695638451656, 47.051697758263) + (9.690937945361, 47.051697758263) + (9.690937945361, 47.056398264558) + (9.686237439066, 47.056398264558) + (9.681536932771, 47.056398264558) + (9.681536932771, 47.061098770853) + (9.676836426476, 47.061098770853) + (9.67213592018, 47.061098770853) + (9.667435413885, 47.061098770853) + (9.66273490759, 47.061098770853) + (9.66273490759, 47.056398264558) + (9.658034401295, 47.056398264558) + (9.653333895, 47.056398264558) + (9.653333895, 47.061098770853) + (9.648633388704, 47.061098770853) + (9.643932882409, 47.061098770853) + (9.643932882409, 47.056398264558) + (9.639232376114, 47.056398264558) + (9.639232376114, 47.051697758263) + (9.634531869819, 47.051697758263) + (9.629831363523, 47.051697758263) + (9.625130857228, 47.051697758263) + (9.620430350933, 47.051697758263) + (9.615729844638, 47.051697758263) + (9.615729844638, 47.056398264558) + (9.611029338343, 47.056398264558) + (9.611029338343, 47.061098770853) + (9.606328832047, 47.061098770853) + (9.601628325752, 47.061098770853) + (9.596927819457, 47.061098770853) + (9.596927819457, 47.056398264558) + (9.592227313162, 47.056398264558) + (9.587526806867, 47.056398264558) + (9.582826300571, 47.056398264558) + (9.582826300571, 47.051697758263) + (9.578125794276, 47.051697758263) + (9.573425287981, 47.051697758263) + (9.568724781686, 47.051697758263) + (9.56402427539, 47.051697758263) + (9.559323769095, 47.051697758263) + (9.559323769095, 47.046997251967) + (9.5546232628, 47.046997251967) + (9.5546232628, 47.051697758263) + (9.5546232628, 47.056398264558) + (9.549922756505, 47.056398264558) + (9.549922756505, 47.061098770853) + (9.54522225021, 47.061098770853) + (9.54522225021, 47.065799277148) + (9.540521743914, 47.065799277148) + (9.535821237619, 47.065799277148) + (9.531120731324, 47.065799277148) + (9.531120731324, 47.061098770853) + (9.526420225029, 47.061098770853) + (9.521719718733, 47.061098770853) + (9.517019212438, 47.061098770853) + (9.517019212438, 47.056398264558) + (9.512318706143, 47.056398264558) + (9.507618199848, 47.056398264558) + (9.502917693553, 47.056398264558) + (9.498217187257, 47.056398264558) + (9.493516680962, 47.056398264558) + (9.488816174667, 47.056398264558) + (9.488816174667, 47.051697758263) + (9.484115668372, 47.051697758263) + (9.484115668372, 47.056398264558) + (9.479415162077, 47.056398264558) + (9.474714655781, 47.056398264558) + (9.474714655781, 47.061098770853) + (9.474714655781, 47.065799277148) + (9.479415162077, 47.065799277148) + (9.479415162077, 47.070499783443) + (9.484115668372, 47.070499783443) + (9.488816174667, 47.070499783443) + (9.488816174667, 47.075200289739) + (9.493516680962, 47.075200289739) + (9.498217187257, 47.075200289739) + (9.498217187257, 47.079900796034) + (9.502917693553, 47.079900796034) + (9.507618199848, 47.079900796034) + (9.507618199848, 47.084601302329) + (9.512318706143, 47.084601302329) + (9.517019212438, 47.084601302329) + (9.517019212438, 47.089301808624) + (9.517019212438, 47.094002314919) + (9.517019212438, 47.09400231492) + (9.517019212438, 47.098702821215) + (9.521719718733, 47.098702821215) + (9.521719718733, 47.10340332751) + (9.521719718733, 47.108103833805) + (9.517019212438, 47.108103833805) + (9.517019212438, 47.1128043401) + (9.517019212438, 47.117504846396) + (9.517019212438, 47.122205352691) + (9.512318706143, 47.122205352691) + (9.512318706143, 47.126905858986) + (9.512318706143, 47.131606365281) + (9.512318706143, 47.136306871576) + (9.507618199848, 47.136306871576) + (9.507618199848, 47.141007377872) + (9.507618199848, 47.145707884167) + (9.502917693553, 47.145707884167) + (9.502917693553, 47.150408390462) + (9.498217187257, 47.150408390462) + (9.498217187257, 47.155108896757) + (9.493516680962, 47.155108896757) + (9.493516680962, 47.159809403053) + (9.493516680962, 47.164509909348) + (9.488816174667, 47.164509909348) + (9.488816174667, 47.169210415643) + (9.488816174667, 47.173910921938) + (9.488816174667, 47.178611428233) + (9.484115668372, 47.178611428233) + (9.484115668372, 47.183311934529) + (9.488816174667, 47.183311934529) + (9.488816174667, 47.188012440824) + (9.488816174667, 47.192712947119) + (9.488816174667, 47.197413453414) + (9.493516680962, 47.197413453414) + (9.493516680962, 47.202113959709) + (9.493516680962, 47.206814466005) + (9.498217187257, 47.206814466005) + (9.498217187257, 47.2115149723) + (9.498217187257, 47.216215478595) + (9.502917693553, 47.216215478595) + (9.502917693553, 47.22091598489) + (9.502917693553, 47.225616491186) + (9.507618199848, 47.225616491186) + (9.507618199848, 47.230316997481) + (9.512318706143, 47.230316997481) + (9.512318706143, 47.235017503776) + (9.517019212438, 47.235017503776) + (9.517019212438, 47.239718010071) + (9.517019212438, 47.244418516366) + (9.521719718733, 47.244418516366) + (9.521719718733, 47.249119022662) + (9.521719718733, 47.253819528957) + (9.526420225029, 47.253819528957) + (9.526420225029, 47.258520035252) + (9.526420225029, 47.263220541547) + (9.531120731324, 47.263220541547) + (9.531120731324, 47.267921047842) + (9.531120731324, 47.272621554138) + (9.535821237619, 47.272621554138) + (9.535821237619, 47.277322060433) + (9.540521743914, 47.277322060433) + (9.54522225021, 47.277322060433) + (9.54522225021, 47.282022566728) + (9.549922756505, 47.282022566728) + (9.549922756505, 47.286723073023) + (9.5546232628, 47.286723073023) + (9.5546232628, 47.291423579319) + (9.5546232628, 47.296124085614) + (9.5546232628, 47.300824591909) + (9.559323769095, 47.300824591909) + (9.56402427539, 47.300824591909) + (9.56402427539, 47.305525098204) + (9.568724781686, 47.305525098204) + (9.573425287981, 47.305525098204) + (9.573425287981, 47.310225604499) + (9.578125794276, 47.310225604499) + (9.582826300571, 47.310225604499) + (9.582826300571, 47.314926110795) + (9.587526806867, 47.314926110795) + (9.587526806867, 47.31962661709) + (9.592227313162, 47.31962661709) + (9.592227313162, 47.324327123385) + (9.592227313162, 47.32902762968) + (9.592227313162, 47.333728135975) + (9.596927819457, 47.333728135975) + (9.596927819457, 47.338428642271) + (9.596927819457, 47.343129148566) + (9.601628325752, 47.343129148566) + (9.601628325752, 47.347829654861) + (9.606328832047, 47.347829654861) + (9.606328832047, 47.352530161156) + (9.611029338343, 47.352530161156) + (9.611029338343, 47.357230667452) + (9.615729844638, 47.357230667452) + (9.615729844638, 47.361931173747) + (9.620430350933, 47.361931173747) + (9.620430350933, 47.366631680042) + (9.625130857228, 47.366631680042) + (9.629831363523, 47.366631680042) + (9.634531869819, 47.366631680042) + (9.639232376114, 47.366631680042) + (9.643932882409, 47.366631680042) + (9.648633388704, 47.366631680042) + (9.653333895, 47.366631680042) + (9.658034401295, 47.366631680042) + (9.658034401295, 47.371332186337) + (9.66273490759, 47.371332186337) + (9.667435413885, 47.371332186337) + (9.667435413885, 47.376032692632) + (9.67213592018, 47.376032692632) + (9.67213592018, 47.380733198928) + (9.67213592018, 47.385433705223) + (9.67213592018, 47.390134211518) + (9.67213592018, 47.394834717813) + (9.667435413885, 47.394834717813) + (9.66273490759, 47.394834717813) + (9.66273490759, 47.399535224108) + (9.658034401295, 47.399535224108) + (9.658034401295, 47.404235730404) + (9.653333895, 47.404235730404) + (9.653333895, 47.408936236699) + (9.653333895, 47.413636742994) + (9.653333895, 47.418337249289) + (9.648633388704, 47.418337249289) + (9.648633388704, 47.423037755585) + (9.648633388704, 47.42773826188) + (9.643932882409, 47.42773826188) + (9.643932882409, 47.432438768175) + (9.643932882409, 47.43713927447) + (9.648633388704, 47.43713927447) + (9.648633388704, 47.441839780765) + (9.653333895, 47.441839780765) + (9.653333895, 47.446540287061) + (9.658034401295, 47.446540287061) + (9.658034401295, 47.451240793356) + (9.658034401295, 47.455941299651) + (9.653333895, 47.455941299651) + (9.648633388704, 47.455941299651) + (9.643932882409, 47.455941299651) + (9.639232376114, 47.455941299651) + (9.634531869819, 47.455941299651) + (9.629831363523, 47.455941299651) + (9.625130857228, 47.455941299651) + (9.620430350933, 47.455941299651) + (9.620430350933, 47.460641805946) + (9.615729844638, 47.460641805946) + (9.615729844638, 47.465342312242) + (9.611029338343, 47.465342312242) + (9.611029338343, 47.470042818537) + (9.606328832047, 47.470042818537) + (9.606328832047, 47.465342312242) + (9.606328832047, 47.460641805946) + (9.601628325752, 47.460641805946) + (9.596927819457, 47.460641805946) + (9.596927819457, 47.465342312242) + (9.592227313162, 47.465342312242) + (9.592227313162, 47.470042818537) + (9.587526806867, 47.470042818537) + (9.587526806867, 47.474743324832) + (9.587526806867, 47.479443831127) + (9.582826300571, 47.479443831127) + (9.582826300571, 47.484144337422) + (9.578125794276, 47.484144337422) + (9.578125794276, 47.488844843718) + (9.573425287981, 47.488844843718) + (9.568724781686, 47.488844843718) + (9.568724781686, 47.493545350013) + (9.56402427539, 47.493545350013) + (9.56402427539, 47.498245856308) + (9.559323769095, 47.498245856308) + (9.559323769095, 47.502946362603) + (9.559323769095, 47.507646868898) + (9.559323769095, 47.512347375194) + (9.559323769095, 47.517047881489) + (9.5546232628, 47.517047881489) + (9.5546232628, 47.521748387784) + (9.5546232628, 47.526448894079) + (9.5546232628, 47.531149400375) + (9.549922756505, 47.531149400375) + (9.549922756505, 47.53584990667) + (9.54522225021, 47.53584990667) + (9.540521743914, 47.53584990667) + (9.535821237619, 47.53584990667) + (9.531120731324, 47.53584990667) + (9.526420225029, 47.53584990667) + (9.521719718733, 47.53584990667) + (9.517019212438, 47.53584990667) + (9.512318706143, 47.53584990667) + (9.512318706143, 47.540550412965) + (9.507618199848, 47.540550412965) + (9.507618199848, 47.54525091926) + (9.502917693553, 47.54525091926) + (9.502917693553, 47.549951425555) + (9.498217187257, 47.549951425555) + (9.498217187257, 47.554651931851) + (9.493516680962, 47.554651931851) + (9.493516680962, 47.559352438146) + (9.488816174667, 47.559352438146) + (9.484115668372, 47.559352438146) + (9.484115668372, 47.564052944441) + (9.479415162077, 47.564052944441) + (9.479415162077, 47.568753450736) + (9.474714655781, 47.568753450736) + (9.474714655781, 47.573453957031) + (9.470014149486, 47.573453957031) + (9.470014149486, 47.578154463327) + (9.465313643191, 47.578154463327) + (9.465313643191, 47.582854969622) + (9.460613136896, 47.582854969622) + (9.460613136896, 47.587555475917) + (9.4559126306, 47.587555475917) + (9.451212124305, 47.587555475917) + (9.451212124305, 47.592255982212) + (9.44651161801, 47.592255982212) + (9.44651161801, 47.596956488508) + (9.441811111715, 47.596956488508) + (9.43711060542, 47.596956488508) + (9.432410099124, 47.596956488508) + (9.432410099124, 47.601656994803) + (9.427709592829, 47.601656994803) + (9.423009086534, 47.601656994803) + (9.418308580239, 47.601656994803) + (9.418308580239, 47.606357501098) + (9.413608073944, 47.606357501098) + (9.408907567648, 47.606357501098) + (9.404207061353, 47.606357501098) + (9.404207061353, 47.611058007393) + (9.399506555058, 47.611058007393) + (9.394806048763, 47.611058007393) + (9.390105542467, 47.611058007393) + (9.390105542467, 47.615758513688) + (9.385405036172, 47.615758513688) + (9.380704529877, 47.615758513688) + (9.376004023582, 47.615758513688) + (9.376004023582, 47.620459019984) + (9.371303517287, 47.620459019984) + (9.366603010991, 47.620459019984) + (9.366603010991, 47.625159526279) + (9.361902504696, 47.625159526279) + (9.357201998401, 47.625159526279) + (9.352501492106, 47.625159526279) + (9.352501492106, 47.629860032574) + (9.347800985811, 47.629860032574) + (9.343100479515, 47.629860032574) + (9.33839997322, 47.629860032574) + (9.33839997322, 47.634560538869) + (9.333699466925, 47.634560538869) + (9.32899896063, 47.634560538869) + (9.324298454334, 47.634560538869) + (9.324298454334, 47.639261045164) + (9.319597948039, 47.639261045164) + (9.314897441744, 47.639261045164) + (9.310196935449, 47.639261045164) + (9.310196935449, 47.64396155146) + (9.305496429154, 47.64396155146) + (9.300795922858, 47.64396155146) + (9.296095416563, 47.64396155146) + (9.296095416563, 47.648662057755) + (9.291394910268, 47.648662057755) + (9.286694403973, 47.648662057755) + (9.281993897678, 47.648662057755) + (9.281993897678, 47.65336256405) + (9.277293391382, 47.65336256405) + (9.272592885087, 47.65336256405) + (9.267892378792, 47.65336256405) + (9.267892378792, 47.658063070345) + (9.263191872497, 47.658063070345) + (9.258491366201, 47.658063070345) + (9.253790859906, 47.658063070345) + (9.249090353611, 47.658063070345) + (9.244389847316, 47.658063070345) + (9.239689341021, 47.658063070345) + (9.234988834725, 47.658063070345) + (9.23028832843, 47.658063070345) + (9.225587822135, 47.658063070345) + (9.22088731584, 47.658063070345) + (9.216186809544, 47.658063070345) + (9.211486303249, 47.658063070345) + (9.206785796954, 47.658063070345) + (9.206785796954, 47.65336256405) + (9.202085290659, 47.65336256405) + (9.202085290659, 47.658063070345) + (9.197384784364, 47.658063070345) + (9.192684278068, 47.658063070345) + (9.187983771773, 47.658063070345) + (9.183283265478, 47.658063070345) + (9.178582759183, 47.658063070345) + (9.178582759183, 47.65336256405) + (9.173882252888, 47.65336256405) + (9.169181746592, 47.65336256405) + (9.169181746592, 47.658063070345) + (9.164481240297, 47.658063070345) + (9.164481240297, 47.662763576641) + (9.159780734002, 47.662763576641) + (9.159780734002, 47.667464082936) + (9.155080227707, 47.667464082936) + (9.150379721411, 47.667464082936) + (9.145679215116, 47.667464082936) + (9.145679215116, 47.662763576641) + (9.140978708821, 47.662763576641) + (9.136278202526, 47.662763576641) + (9.136278202526, 47.667464082936) + (9.131577696231, 47.667464082936) + (9.126877189935, 47.667464082936) + (9.12217668364, 47.667464082936) + (9.117476177345, 47.667464082936) + (9.117476177345, 47.672164589231) + (9.11277567105, 47.672164589231) + (9.108075164755, 47.672164589231) + (9.108075164755, 47.676865095526) + (9.103374658459, 47.676865095526) + (9.098674152164, 47.676865095526) + (9.093973645869, 47.676865095526) + (9.089273139574, 47.676865095526) + (9.089273139574, 47.681565601821) + (9.084572633278, 47.681565601821) + (9.084572633278, 47.676865095526) + (9.079872126983, 47.676865095526) + (9.075171620688, 47.676865095526) + (9.075171620688, 47.681565601821) + (9.070471114393, 47.681565601821) + (9.065770608098, 47.681565601821) + (9.061070101802, 47.681565601821) + (9.056369595507, 47.681565601821) + (9.056369595507, 47.686266108117) + (9.051669089212, 47.686266108117) + (9.046968582917, 47.686266108117) + (9.042268076622, 47.686266108117) + (9.037567570326, 47.686266108117) + (9.032867064031, 47.686266108117) + (9.028166557736, 47.686266108117) + (9.023466051441, 47.686266108117) + (9.018765545145, 47.686266108117) + (9.01406503885, 47.686266108117) + (9.009364532555, 47.686266108117) + (9.009364532555, 47.681565601821) + (9.00466402626, 47.681565601821) + (8.999963519965, 47.681565601821) + (8.995263013669, 47.681565601821) + (8.995263013669, 47.676865095526) + (8.990562507374, 47.676865095526) + (8.985862001079, 47.676865095526) + (8.981161494784, 47.676865095526) + (8.981161494784, 47.672164589231) + (8.976460988489, 47.672164589231) + (8.971760482193, 47.672164589231) + (8.971760482193, 47.667464082936) + (8.967059975898, 47.667464082936) + (8.962359469603, 47.667464082936) + (8.962359469603, 47.662763576641) + (8.957658963308, 47.662763576641) + (8.952958457012, 47.662763576641) + (8.952958457012, 47.658063070345) + (8.948257950717, 47.658063070345) + (8.943557444422, 47.658063070345) + (8.938856938127, 47.658063070345) + (8.934156431832, 47.658063070345) + (8.929455925536, 47.658063070345) + (8.929455925536, 47.65336256405) + (8.924755419241, 47.65336256405) + (8.920054912946, 47.65336256405) + (8.915354406651, 47.65336256405) + (8.910653900356, 47.65336256405) + (8.910653900356, 47.648662057755) + (8.90595339406, 47.648662057755) + (8.901252887765, 47.648662057755) + (8.89655238147, 47.648662057755) + (8.891851875175, 47.648662057755) + (8.887151368879, 47.648662057755) + (8.887151368879, 47.65336256405) + (8.882450862584, 47.65336256405) + (8.877750356289, 47.65336256405) + (8.873049849994, 47.65336256405) + (8.873049849994, 47.658063070345) + (8.873049849994, 47.662763576641) + (8.873049849994, 47.667464082936) + (8.873049849994, 47.672164589231) + (8.868349343699, 47.672164589231) + (8.868349343699, 47.676865095526) + (8.863648837403, 47.676865095526) + (8.863648837403, 47.681565601821) + (8.858948331108, 47.681565601821) + (8.854247824813, 47.681565601821) + (8.849547318518, 47.681565601821) + (8.849547318518, 47.686266108117) + (8.854247824813, 47.686266108117) + (8.854247824813, 47.690966614412) + (8.858948331108, 47.690966614412) + (8.858948331108, 47.695667120707) + (8.863648837403, 47.695667120707) + (8.868349343699, 47.695667120707) + (8.873049849994, 47.695667120707) + (8.873049849994, 47.700367627002) + (8.873049849994, 47.705068133297) + (8.868349343699, 47.705068133297) + (8.863648837403, 47.705068133297) + (8.858948331108, 47.705068133297) + (8.854247824813, 47.705068133297) + (8.849547318518, 47.705068133297) + (8.844846812222, 47.705068133297) + (8.844846812222, 47.709768639593) + (8.844846812222, 47.714469145888) + (8.840146305927, 47.714469145888) + (8.835445799632, 47.714469145888) + (8.830745293337, 47.714469145888) + (8.830745293337, 47.709768639593) + (8.826044787042, 47.709768639593) + (8.821344280746, 47.709768639593) + (8.821344280746, 47.714469145888) + (8.826044787042, 47.714469145888) + (8.826044787042, 47.719169652183) + (8.821344280746, 47.719169652183) + (8.816643774451, 47.719169652183) + (8.816643774451, 47.723870158478) + (8.811943268156, 47.723870158478) + (8.807242761861, 47.723870158478) + (8.807242761861, 47.728570664774) + (8.811943268156, 47.728570664774) + (8.811943268156, 47.733271171069) + (8.807242761861, 47.733271171069) + (8.807242761861, 47.737971677364) + (8.802542255566, 47.737971677364) + (8.79784174927, 47.737971677364) + (8.79784174927, 47.733271171069) + (8.79784174927, 47.728570664774) + (8.793141242975, 47.728570664774) + (8.78844073668, 47.728570664774) + (8.783740230385, 47.728570664774) + (8.783740230385, 47.723870158478) + (8.779039724089, 47.723870158478) + (8.774339217794, 47.723870158478) + (8.774339217794, 47.719169652183) + (8.769638711499, 47.719169652183) + (8.769638711499, 47.714469145888) + (8.769638711499, 47.709768639593) + (8.769638711499, 47.705068133297) + (8.774339217794, 47.705068133297) + (8.779039724089, 47.705068133297) + (8.783740230385, 47.705068133297) + (8.78844073668, 47.705068133297) + (8.793141242975, 47.705068133297) + (8.79784174927, 47.705068133297) + (8.79784174927, 47.700367627002) + (8.79784174927, 47.695667120707) + (8.802542255566, 47.695667120707) + (8.807242761861, 47.695667120707) + (8.811943268156, 47.695667120707) + (8.811943268156, 47.690966614412) + (8.807242761861, 47.690966614412) + (8.802542255566, 47.690966614412) + (8.79784174927, 47.690966614412) + (8.79784174927, 47.686266108117) + (8.793141242975, 47.686266108117) + (8.793141242975, 47.681565601821) + (8.793141242975, 47.676865095526) + (8.78844073668, 47.676865095526) + (8.783740230385, 47.676865095526) + (8.779039724089, 47.676865095526) + (8.779039724089, 47.681565601821) + (8.774339217794, 47.681565601821) + (8.769638711499, 47.681565601821) + (8.769638711499, 47.686266108117) + (8.764938205204, 47.686266108117) + (8.760237698909, 47.686266108117) + (8.760237698909, 47.690966614412) + (8.755537192613, 47.690966614412) + (8.750836686318, 47.690966614412) + (8.746136180023, 47.690966614412) + (8.741435673728, 47.690966614412) + (8.736735167433, 47.690966614412) + (8.732034661137, 47.690966614412) + (8.727334154842, 47.690966614412) + (8.727334154842, 47.695667120707) + (8.727334154842, 47.700367627002) + (8.727334154842, 47.705068133297) + (8.732034661137, 47.705068133297) + (8.732034661137, 47.709768639593) + (8.732034661137, 47.714469145888) + (8.736735167433, 47.714469145888) + (8.736735167433, 47.719169652183) + (8.732034661137, 47.719169652183) + (8.727334154842, 47.719169652183) + (8.722633648547, 47.719169652183) + (8.722633648547, 47.723870158478) + (8.717933142252, 47.723870158478) + (8.713232635956, 47.723870158478) + (8.713232635956, 47.728570664774) + (8.713232635956, 47.733271171069) + (8.713232635956, 47.737971677364) + (8.717933142252, 47.737971677364) + (8.717933142252, 47.742672183659) + (8.722633648547, 47.742672183659) + (8.722633648547, 47.747372689954) + (8.727334154842, 47.747372689954) + (8.732034661137, 47.747372689954) + (8.736735167433, 47.747372689954) + (8.741435673728, 47.747372689954) + (8.741435673728, 47.75207319625) + (8.736735167433, 47.75207319625) + (8.736735167433, 47.756773702545) + (8.732034661137, 47.756773702545) + (8.732034661137, 47.76147420884) + (8.727334154842, 47.76147420884) + (8.722633648547, 47.76147420884) + (8.717933142252, 47.76147420884) + (8.717933142252, 47.766174715135) + (8.713232635956, 47.766174715135) + (8.708532129661, 47.766174715135) + (8.708532129661, 47.76147420884) + (8.703831623366, 47.76147420884) + (8.699131117071, 47.76147420884) + (8.699131117071, 47.756773702545) + (8.694430610776, 47.756773702545) + (8.68973010448, 47.756773702545) + (8.68973010448, 47.76147420884) + (8.685029598185, 47.76147420884) + (8.685029598185, 47.766174715135) + (8.685029598185, 47.77087522143) + (8.68973010448, 47.77087522143) + (8.68973010448, 47.775575727726) + (8.685029598185, 47.775575727726) + (8.685029598185, 47.780276234021) + (8.68032909189, 47.780276234021) + (8.68032909189, 47.784976740316) + (8.675628585595, 47.784976740316) + (8.6709280793, 47.784976740316) + (8.6709280793, 47.789677246611) + (8.666227573004, 47.789677246611) + (8.661527066709, 47.789677246611) + (8.656826560414, 47.789677246611) + (8.656826560414, 47.794377752907) + (8.661527066709, 47.794377752907) + (8.661527066709, 47.799078259202) + (8.656826560414, 47.799078259202) + (8.652126054119, 47.799078259202) + (8.647425547823, 47.799078259202) + (8.647425547823, 47.794377752907) + (8.647425547823, 47.789677246611) + (8.647425547823, 47.784976740316) + (8.647425547823, 47.780276234021) + (8.647425547823, 47.775575727726) + (8.652126054119, 47.775575727726) + (8.652126054119, 47.77087522143) + (8.647425547823, 47.77087522143) + (8.647425547823, 47.766174715135) + (8.642725041528, 47.766174715135) + (8.638024535233, 47.766174715135) + (8.638024535233, 47.76147420884) + (8.633324028938, 47.76147420884) + (8.628623522643, 47.76147420884) + (8.623923016347, 47.76147420884) + (8.623923016347, 47.766174715135) + (8.619222510052, 47.766174715135) + (8.619222510052, 47.77087522143) + (8.619222510052, 47.775575727726) + (8.623923016347, 47.775575727726) + (8.623923016347, 47.780276234021) + (8.619222510052, 47.780276234021) + (8.614522003757, 47.780276234021) + (8.614522003757, 47.784976740316) + (8.619222510052, 47.784976740316) + (8.619222510052, 47.789677246611) + (8.619222510052, 47.794377752907) + (8.619222510052, 47.799078259202) + (8.614522003757, 47.799078259202) + (8.609821497462, 47.799078259202) + (8.609821497462, 47.803778765497) + (8.605120991167, 47.803778765497) + (8.600420484871, 47.803778765497) + (8.595719978576, 47.803778765497) + (8.595719978576, 47.799078259202) + (8.591019472281, 47.799078259202) + (8.591019472281, 47.803778765497) + (8.586318965986, 47.803778765497) + (8.58161845969, 47.803778765497) + (8.58161845969, 47.799078259202) + (8.576917953395, 47.799078259202) + (8.5722174471, 47.799078259202) + (8.5722174471, 47.803778765497) + (8.5722174471, 47.808479271792) + (8.567516940805, 47.808479271792) + (8.567516940805, 47.803778765497) + (8.56281643451, 47.803778765497) + (8.56281643451, 47.799078259202) + (8.56281643451, 47.794377752907) + (8.567516940805, 47.794377752907) + (8.567516940805, 47.789677246611) + (8.5722174471, 47.789677246611) + (8.5722174471, 47.784976740316) + (8.576917953395, 47.784976740316) + (8.576917953395, 47.780276234021) + (8.5722174471, 47.780276234021) + (8.567516940805, 47.780276234021) + (8.56281643451, 47.780276234021) + (8.558115928214, 47.780276234021) + (8.558115928214, 47.784976740316) + (8.553415421919, 47.784976740316) + (8.548714915624, 47.784976740316) + (8.548714915624, 47.780276234021) + (8.544014409329, 47.780276234021) + (8.539313903033, 47.780276234021) + (8.534613396738, 47.780276234021) + (8.529912890443, 47.780276234021) + (8.529912890443, 47.775575727726) + (8.525212384148, 47.775575727726) + (8.520511877853, 47.775575727726) + (8.520511877853, 47.77087522143) + (8.515811371557, 47.77087522143) + (8.515811371557, 47.775575727726) + (8.511110865262, 47.775575727726) + (8.506410358967, 47.775575727726) + (8.501709852672, 47.775575727726) + (8.501709852672, 47.77087522143) + (8.497009346377, 47.77087522143) + (8.492308840081, 47.77087522143) + (8.487608333786, 47.77087522143) + (8.482907827491, 47.77087522143) + (8.482907827491, 47.766174715135) + (8.478207321196, 47.766174715135) + (8.4735068149, 47.766174715135) + (8.4735068149, 47.76147420884) + (8.468806308605, 47.76147420884) + (8.468806308605, 47.756773702545) + (8.468806308605, 47.75207319625) + (8.46410580231, 47.75207319625) + (8.459405296015, 47.75207319625) + (8.459405296015, 47.747372689954) + (8.45470478972, 47.747372689954) + (8.45470478972, 47.742672183659) + (8.45470478972, 47.737971677364) + (8.450004283424, 47.737971677364) + (8.450004283424, 47.733271171069) + (8.450004283424, 47.728570664774) + (8.45470478972, 47.728570664774) + (8.45470478972, 47.723870158478) + (8.450004283424, 47.723870158478) + (8.445303777129, 47.723870158478) + (8.440603270834, 47.723870158478) + (8.440603270834, 47.719169652183) + (8.435902764539, 47.719169652183) + (8.435902764539, 47.714469145888) + (8.431202258244, 47.714469145888) + (8.431202258244, 47.709768639593) + (8.426501751948, 47.709768639593) + (8.421801245653, 47.709768639593) + (8.417100739358, 47.709768639593) + (8.412400233063, 47.709768639593) + (8.412400233063, 47.705068133297) + (8.412400233063, 47.700367627002) + (8.407699726767, 47.700367627002) + (8.402999220472, 47.700367627002) + (8.402999220472, 47.695667120707) + (8.407699726767, 47.695667120707) + (8.412400233063, 47.695667120707) + (8.412400233063, 47.690966614412) + (8.417100739358, 47.690966614412) + (8.417100739358, 47.686266108117) + (8.421801245653, 47.686266108117) + (8.421801245653, 47.681565601821) + (8.417100739358, 47.681565601821) + (8.412400233063, 47.681565601821) + (8.412400233063, 47.676865095526) + (8.407699726767, 47.676865095526) + (8.407699726767, 47.672164589231) + (8.407699726767, 47.667464082936) + (8.412400233063, 47.667464082936) + (8.417100739358, 47.667464082936) + (8.421801245653, 47.667464082936) + (8.426501751948, 47.667464082936) + (8.426501751948, 47.662763576641) + (8.431202258244, 47.662763576641) + (8.431202258244, 47.658063070345) + (8.435902764539, 47.658063070345) + (8.440603270834, 47.658063070345) + (8.440603270834, 47.65336256405) + (8.445303777129, 47.65336256405) + (8.450004283424, 47.65336256405) + (8.45470478972, 47.65336256405) + (8.459405296015, 47.65336256405) + (8.46410580231, 47.65336256405) + (8.46410580231, 47.648662057755) + (8.46410580231, 47.64396155146) + (8.468806308605, 47.64396155146) + (8.468806308605, 47.639261045164) + (8.4735068149, 47.639261045164) + (8.478207321196, 47.639261045164) + (8.478207321196, 47.64396155146) + (8.478207321196, 47.648662057755) + (8.482907827491, 47.648662057755) + (8.482907827491, 47.64396155146) + (8.487608333786, 47.64396155146) + (8.492308840081, 47.64396155146) + (8.497009346377, 47.64396155146) + (8.497009346377, 47.648662057755) + (8.501709852672, 47.648662057755) + (8.506410358967, 47.648662057755) + (8.511110865262, 47.648662057755) + (8.515811371557, 47.648662057755) + (8.520511877853, 47.648662057755) + (8.520511877853, 47.64396155146) + (8.525212384148, 47.64396155146) + (8.529912890443, 47.64396155146) + (8.529912890443, 47.648662057755) + (8.529912890443, 47.65336256405) + (8.529912890443, 47.658063070345) + (8.525212384148, 47.658063070345) + (8.525212384148, 47.662763576641) + (8.529912890443, 47.662763576641) + (8.534613396738, 47.662763576641) + (8.534613396738, 47.658063070345) + (8.539313903033, 47.658063070345) + (8.539313903033, 47.662763576641) + (8.539313903033, 47.667464082936) + (8.544014409329, 47.667464082936) + (8.548714915624, 47.667464082936) + (8.553415421919, 47.667464082936) + (8.558115928214, 47.667464082936) + (8.56281643451, 47.667464082936) + (8.567516940805, 47.667464082936) + (8.567516940805, 47.662763576641) + (8.5722174471, 47.662763576641) + (8.576917953395, 47.662763576641) + (8.58161845969, 47.662763576641) + (8.586318965986, 47.662763576641) + (8.586318965986, 47.667464082936) + (8.591019472281, 47.667464082936) + (8.595719978576, 47.667464082936) + (8.595719978576, 47.672164589231) + (8.600420484871, 47.672164589231) + (8.605120991167, 47.672164589231) + (8.605120991167, 47.667464082936) + (8.609821497462, 47.667464082936) + (8.609821497462, 47.662763576641) + (8.614522003757, 47.662763576641) + (8.619222510052, 47.662763576641) + (8.619222510052, 47.658063070345) + (8.623923016347, 47.658063070345) + (8.628623522643, 47.658063070345) + (8.628623522643, 47.65336256405) + (8.628623522643, 47.648662057755) + (8.628623522643, 47.64396155146) + (8.623923016347, 47.64396155146) + (8.623923016347, 47.639261045164) + (8.619222510052, 47.639261045164) + (8.614522003757, 47.639261045164) + (8.609821497462, 47.639261045164) + (8.605120991167, 47.639261045164) + (8.605120991167, 47.64396155146) + (8.609821497462, 47.64396155146) + (8.614522003757, 47.64396155146) + (8.614522003757, 47.648662057755) + (8.609821497462, 47.648662057755) + (8.609821497462, 47.65336256405) + (8.605120991167, 47.65336256405) + (8.600420484871, 47.65336256405) + (8.600420484871, 47.648662057755) + (8.600420484871, 47.64396155146) + (8.595719978576, 47.64396155146) + (8.595719978576, 47.639261045164) + (8.595719978576, 47.634560538869) + (8.595719978576, 47.629860032574) + (8.600420484871, 47.629860032574) + (8.600420484871, 47.625159526279) + (8.600420484871, 47.620459019984) + (8.605120991167, 47.620459019984) + (8.605120991167, 47.615758513688) + (8.605120991167, 47.611058007393) + (8.600420484871, 47.611058007393) + (8.600420484871, 47.606357501098) + (8.595719978576, 47.606357501098) + (8.591019472281, 47.606357501098) + (8.591019472281, 47.601656994803) + (8.586318965986, 47.601656994803) + (8.586318965986, 47.596956488508) + (8.58161845969, 47.596956488508) + (8.576917953395, 47.596956488508) + (8.5722174471, 47.596956488508) + (8.567516940805, 47.596956488508) + (8.56281643451, 47.596956488508) + (8.56281643451, 47.601656994803) + (8.56281643451, 47.606357501098) + (8.567516940805, 47.606357501098) + (8.567516940805, 47.611058007393) + (8.5722174471, 47.611058007393) + (8.5722174471, 47.615758513688) + (8.567516940805, 47.615758513688) + (8.567516940805, 47.620459019984) + (8.56281643451, 47.620459019984) + (8.558115928214, 47.620459019984) + (8.558115928214, 47.625159526279) + (8.553415421919, 47.625159526279) + (8.548714915624, 47.625159526279) + (8.544014409329, 47.625159526279) + (8.544014409329, 47.629860032574) + (8.539313903033, 47.629860032574) + (8.534613396738, 47.629860032574) + (8.534613396738, 47.634560538869) + (8.529912890443, 47.634560538869) + (8.525212384148, 47.634560538869) + (8.520511877853, 47.634560538869) + (8.515811371557, 47.634560538869) + (8.515811371557, 47.629860032574) + (8.515811371557, 47.625159526279) + (8.511110865262, 47.625159526279) + (8.511110865262, 47.620459019984) + (8.506410358967, 47.620459019984) + (8.506410358967, 47.615758513688) + (8.501709852672, 47.615758513688) + (8.497009346377, 47.615758513688) + (8.492308840081, 47.615758513688) + (8.487608333786, 47.615758513688) + (8.482907827491, 47.615758513688) + (8.482907827491, 47.611058007393) + (8.478207321196, 47.611058007393) + (8.4735068149, 47.611058007393) + (8.4735068149, 47.606357501098) + (8.468806308605, 47.606357501098) + (8.468806308605, 47.601656994803) + (8.46410580231, 47.601656994803) + (8.459405296015, 47.601656994803) + (8.459405296015, 47.596956488508) + (8.459405296015, 47.592255982212) + (8.459405296015, 47.587555475917) + (8.46410580231, 47.587555475917) + (8.46410580231, 47.582854969622) + (8.468806308605, 47.582854969622) + (8.4735068149, 47.582854969622) + (8.478207321196, 47.582854969622) + (8.478207321196, 47.587555475917) + (8.482907827491, 47.587555475917) + (8.487608333786, 47.587555475917) + (8.492308840081, 47.587555475917) + (8.492308840081, 47.582854969622) + (8.492308840081, 47.578154463327) + (8.487608333786, 47.578154463327) + (8.482907827491, 47.578154463327) + (8.478207321196, 47.578154463327) + (8.478207321196, 47.573453957031) + (8.4735068149, 47.573453957031) + (8.468806308605, 47.573453957031) + (8.46410580231, 47.573453957031) + (8.459405296015, 47.573453957031) + (8.45470478972, 47.573453957031) + (8.45470478972, 47.568753450736) + (8.450004283424, 47.568753450736) + (8.445303777129, 47.568753450736) + (8.440603270834, 47.568753450736) + (8.440603270834, 47.564052944441) + (8.435902764539, 47.564052944441) + (8.431202258244, 47.564052944441) + (8.426501751948, 47.564052944441) + (8.426501751948, 47.568753450736) + (8.421801245653, 47.568753450736) + (8.417100739358, 47.568753450736) + (8.412400233063, 47.568753450736) + (8.412400233063, 47.573453957031) + (8.407699726767, 47.573453957031) + (8.402999220472, 47.573453957031) + (8.402999220472, 47.578154463327) + (8.398298714177, 47.578154463327) + (8.398298714177, 47.573453957031) + (8.393598207882, 47.573453957031) + (8.388897701587, 47.573453957031) + (8.388897701587, 47.568753450736) + (8.384197195291, 47.568753450736) + (8.384197195291, 47.564052944441) + (8.379496688996, 47.564052944441) + (8.379496688996, 47.568753450736) + (8.374796182701, 47.568753450736) + (8.370095676406, 47.568753450736) + (8.365395170111, 47.568753450736) + (8.360694663815, 47.568753450736) + (8.35599415752, 47.568753450736) + (8.351293651225, 47.568753450736) + (8.34659314493, 47.568753450736) + (8.341892638634, 47.568753450736) + (8.337192132339, 47.568753450736) + (8.332491626044, 47.568753450736) + (8.327791119749, 47.568753450736) + (8.327791119749, 47.573453957031) + (8.323090613454, 47.573453957031) + (8.318390107158, 47.573453957031) + (8.318390107158, 47.578154463327) + (8.313689600863, 47.578154463327) + (8.313689600863, 47.582854969622) + (8.308989094568, 47.582854969622) + (8.304288588273, 47.582854969622) + (8.304288588273, 47.587555475917) + (8.299588081978, 47.587555475917) + (8.294887575682, 47.587555475917) + (8.294887575682, 47.592255982212) + (8.294887575682, 47.596956488508) + (8.294887575682, 47.601656994803) + (8.294887575682, 47.606357501098) + (8.294887575682, 47.611058007393) + (8.290187069387, 47.611058007393) + (8.285486563092, 47.611058007393) + (8.280786056797, 47.611058007393) + (8.276085550501, 47.611058007393) + (8.271385044206, 47.611058007393) + (8.266684537911, 47.611058007393) + (8.261984031616, 47.611058007393) + (8.261984031616, 47.615758513688) + (8.257283525321, 47.615758513688) + (8.252583019025, 47.615758513688) + (8.24788251273, 47.615758513688) + (8.24788251273, 47.611058007393) + (8.243182006435, 47.611058007393) + (8.23848150014, 47.611058007393) + (8.233780993844, 47.611058007393) + (8.233780993844, 47.606357501098) + (8.229080487549, 47.606357501098) + (8.224379981254, 47.606357501098) + (8.224379981254, 47.611058007393) + (8.219679474959, 47.611058007393) + (8.219679474959, 47.615758513688) + (8.214978968664, 47.615758513688) + (8.214978968664, 47.620459019984) + (8.210278462368, 47.620459019984) + (8.205577956073, 47.620459019984) + (8.200877449778, 47.620459019984) + (8.196176943483, 47.620459019984) + (8.196176943483, 47.615758513688) + (8.191476437188, 47.615758513688) + (8.191476437188, 47.611058007393) + (8.186775930892, 47.611058007393) + (8.186775930892, 47.606357501098) + (8.182075424597, 47.606357501098) + (8.182075424597, 47.601656994803) + (8.177374918302, 47.601656994803) + (8.172674412007, 47.601656994803) + (8.172674412007, 47.596956488508) + (8.167973905711, 47.596956488508) + (8.167973905711, 47.592255982212) + (8.163273399416, 47.592255982212) + (8.158572893121, 47.592255982212) + (8.158572893121, 47.596956488508) + (8.153872386826, 47.596956488508) + (8.149171880531, 47.596956488508) + (8.144471374235, 47.596956488508) + (8.144471374235, 47.592255982212) + (8.13977086794, 47.592255982212) + (8.13977086794, 47.587555475917) + (8.135070361645, 47.587555475917) + (8.135070361645, 47.582854969622) + (8.13036985535, 47.582854969622) + (8.125669349055, 47.582854969622) + (8.120968842759, 47.582854969622) + (8.116268336464, 47.582854969622) + (8.111567830169, 47.582854969622) + (8.106867323874, 47.582854969622) + (8.106867323874, 47.578154463327) + (8.102166817578, 47.578154463327) + (8.102166817578, 47.573453957031) + (8.102166817578, 47.568753450736) + (8.102166817578, 47.564052944441) + (8.097466311283, 47.564052944441) + (8.097466311283, 47.559352438146) + (8.092765804988, 47.559352438146) + (8.088065298693, 47.559352438146) + (8.083364792398, 47.559352438146) + (8.078664286102, 47.559352438146) + (8.078664286102, 47.564052944441) + (8.073963779807, 47.564052944441) + (8.069263273512, 47.564052944441) + (8.064562767217, 47.564052944441) + (8.059862260922, 47.564052944441) + (8.055161754626, 47.564052944441) + (8.055161754626, 47.559352438146) + (8.050461248331, 47.559352438146) + (8.050461248331, 47.554651931851) + (8.045760742036, 47.554651931851) + (8.041060235741, 47.554651931851) + (8.036359729445, 47.554651931851) + (8.03165922315, 47.554651931851) + (8.03165922315, 47.549951425555) + (8.026958716855, 47.549951425555) + (8.02225821056, 47.549951425555) + (8.017557704265, 47.549951425555) + (8.012857197969, 47.549951425555) + (8.008156691674, 47.549951425555) + (8.008156691674, 47.554651931851) + (8.003456185379, 47.554651931851) + (7.998755679084, 47.554651931851) + (7.994055172789, 47.554651931851) + (7.989354666493, 47.554651931851) + (7.984654160198, 47.554651931851) + (7.979953653903, 47.554651931851) + (7.975253147608, 47.554651931851) + (7.970552641312, 47.554651931851) + (7.965852135017, 47.554651931851) + (7.965852135017, 47.559352438146) + (7.961151628722, 47.559352438146) + (7.961151628722, 47.554651931851) + (7.956451122427, 47.554651931851) + (7.951750616132, 47.554651931851) + (7.951750616132, 47.549951425555) + (7.951750616132, 47.54525091926) + (7.947050109836, 47.54525091926) + (7.942349603541, 47.54525091926) + (7.937649097246, 47.54525091926) + (7.932948590951, 47.54525091926) + (7.928248084656, 47.54525091926) + (7.92354757836, 47.54525091926) + (7.918847072065, 47.54525091926) + (7.918847072065, 47.549951425555) + (7.91414656577, 47.549951425555) + (7.909446059475, 47.549951425555) + (7.909446059475, 47.554651931851) + (7.909446059475, 47.559352438146) + (7.909446059475, 47.564052944441) + (7.909446059475, 47.568753450736) + (7.909446059475, 47.573453957031) + (7.904745553179, 47.573453957031) + (7.904745553179, 47.578154463327) + (7.900045046884, 47.578154463327) + (7.900045046884, 47.582854969622) + (7.895344540589, 47.582854969622) + (7.895344540589, 47.587555475917) + (7.890644034294, 47.587555475917) + (7.885943527999, 47.587555475917) + (7.881243021703, 47.587555475917) + (7.881243021703, 47.592255982212) + (7.876542515408, 47.592255982212) + (7.876542515408, 47.587555475917) + (7.871842009113, 47.587555475917) + (7.867141502818, 47.587555475917) + (7.862440996522, 47.587555475917) + (7.857740490227, 47.587555475917) + (7.857740490227, 47.582854969622) + (7.853039983932, 47.582854969622) + (7.848339477637, 47.582854969622) + (7.843638971342, 47.582854969622) + (7.838938465046, 47.582854969622) + (7.834237958751, 47.582854969622) + (7.834237958751, 47.587555475917) + (7.829537452456, 47.587555475917) + (7.824836946161, 47.587555475917) + (7.820136439866, 47.587555475917) + (7.81543593357, 47.587555475917) + (7.81543593357, 47.582854969622) + (7.81543593357, 47.578154463327) + (7.81543593357, 47.573453957031) + (7.810735427275, 47.573453957031) + (7.810735427275, 47.568753450736) + (7.80603492098, 47.568753450736) + (7.801334414685, 47.568753450736) + (7.801334414685, 47.564052944441) + (7.801334414685, 47.559352438146) + (7.796633908389, 47.559352438146) + (7.791933402094, 47.559352438146) + (7.791933402094, 47.554651931851) + (7.787232895799, 47.554651931851) + (7.782532389504, 47.554651931851) + (7.777831883209, 47.554651931851) + (7.777831883209, 47.549951425555) + (7.773131376913, 47.549951425555) + (7.768430870618, 47.549951425555) + (7.763730364323, 47.549951425555) + (7.759029858028, 47.549951425555) + (7.754329351733, 47.549951425555) + (7.754329351733, 47.54525091926) + (7.749628845437, 47.54525091926) + (7.744928339142, 47.54525091926) + (7.740227832847, 47.54525091926) + (7.735527326552, 47.54525091926) + (7.730826820256, 47.54525091926) + (7.726126313961, 47.54525091926) + (7.721425807666, 47.54525091926) + (7.721425807666, 47.540550412965) + (7.716725301371, 47.540550412965) + (7.712024795076, 47.540550412965) + (7.70732428878, 47.540550412965) + (7.70732428878, 47.53584990667) + (7.702623782485, 47.53584990667) + (7.69792327619, 47.53584990667) + (7.69792327619, 47.531149400375) + (7.693222769895, 47.531149400375) + (7.6885222636, 47.531149400375) + (7.683821757304, 47.531149400375) + (7.679121251009, 47.531149400375) + (7.674420744714, 47.531149400375) + (7.674420744714, 47.53584990667) + (7.669720238419, 47.53584990667) + (7.665019732123, 47.53584990667) + (7.665019732123, 47.540550412965) + (7.660319225828, 47.540550412965) + (7.660319225828, 47.54525091926) + (7.655618719533, 47.54525091926) + (7.650918213238, 47.54525091926) + (7.650918213238, 47.549951425555) + (7.646217706943, 47.549951425555) + (7.646217706943, 47.554651931851) + (7.641517200647, 47.554651931851) + (7.641517200647, 47.559352438146) + (7.636816694352, 47.559352438146) + (7.636816694352, 47.564052944441) + (7.641517200647, 47.564052944441) + (7.646217706943, 47.564052944441) + (7.650918213238, 47.564052944441) + (7.655618719533, 47.564052944441) + (7.660319225828, 47.564052944441) + (7.665019732123, 47.564052944441) + (7.669720238419, 47.564052944441) + (7.674420744714, 47.564052944441) + (7.679121251009, 47.564052944441) + (7.679121251009, 47.568753450736) + (7.683821757304, 47.568753450736) + (7.6885222636, 47.568753450736) + (7.6885222636, 47.573453957031) + (7.683821757304, 47.573453957031) + (7.683821757304, 47.578154463327) + (7.683821757304, 47.582854969622) + (7.679121251009, 47.582854969622) + (7.674420744714, 47.582854969622) + (7.674420744714, 47.587555475917) + (7.674420744714, 47.592255982212) + (7.669720238419, 47.592255982212) + (7.665019732123, 47.592255982212) + (7.660319225828, 47.592255982212) + (7.660319225828, 47.596956488508) + (7.655618719533, 47.596956488508) + (7.650918213238, 47.596956488508) + (7.646217706943, 47.596956488508) + (7.646217706943, 47.592255982212) + (7.641517200647, 47.592255982212) + (7.641517200647, 47.587555475917) + (7.636816694352, 47.587555475917) + (7.632116188057, 47.587555475917) + (7.632116188057, 47.582854969622) + (7.627415681762, 47.582854969622) + (7.627415681762, 47.578154463327) + (7.622715175467, 47.578154463327) + (7.618014669171, 47.578154463327) + (7.613314162876, 47.578154463327) + (7.608613656581, 47.578154463327) + (7.603913150286, 47.578154463327) + (7.603913150286, 47.582854969622) + (7.603913150286, 47.587555475917) + (7.59921264399, 47.587555475917) + (7.594512137695, 47.587555475917) + (7.5898116314, 47.587555475917) + (7.585111125105, 47.587555475917) + (7.585111125105, 47.582854969622) + (7.585111125105, 47.578154463327) + (7.58041061881, 47.578154463327) + (7.575710112514, 47.578154463327) + (7.571009606219, 47.578154463327) + (7.566309099924, 47.578154463327) + (7.561608593629, 47.578154463327) + (7.561608593629, 47.573453957031) + (7.556908087333, 47.573453957031) + (7.556908087333, 47.568753450736) + (7.556908087333, 47.564052944441) + (7.552207581038, 47.564052944441) + (7.547507074743, 47.564052944441) + (7.547507074743, 47.559352438146) + (7.542806568448, 47.559352438146) + (7.538106062153, 47.559352438146) + (7.538106062153, 47.554651931851) + (7.533405555857, 47.554651931851) + (7.528705049562, 47.554651931851) + (7.528705049562, 47.549951425555) + (7.524004543267, 47.549951425555) + (7.519304036972, 47.549951425555) + (7.514603530677, 47.549951425555) + (7.514603530677, 47.54525091926) + (7.509903024381, 47.54525091926) + (7.505202518086, 47.54525091926) + (7.505202518086, 47.540550412965) + (7.500502011791, 47.540550412965) + (7.500502011791, 47.53584990667) + (7.500502011791, 47.531149400375) + (7.505202518086, 47.531149400375) + (7.505202518086, 47.526448894079) + (7.509903024381, 47.526448894079) + (7.509903024381, 47.531149400375) + (7.514603530677, 47.531149400375) + (7.519304036972, 47.531149400375) + (7.524004543267, 47.531149400375) + (7.528705049562, 47.531149400375) + (7.528705049562, 47.526448894079) + (7.528705049562, 47.521748387784) + (7.524004543267, 47.521748387784) + (7.524004543267, 47.517047881489) + (7.519304036972, 47.517047881489) + (7.514603530677, 47.517047881489) + (7.509903024381, 47.517047881489) + (7.505202518086, 47.517047881489) + (7.500502011791, 47.517047881489) + (7.500502011791, 47.512347375194) + (7.505202518086, 47.512347375194) + (7.505202518086, 47.507646868898) + (7.509903024381, 47.507646868898) + (7.509903024381, 47.502946362603) + (7.509903024381, 47.498245856308) + (7.509903024381, 47.493545350013) + (7.505202518086, 47.493545350013) + (7.500502011791, 47.493545350013) + (7.500502011791, 47.488844843718) + (7.495801505496, 47.488844843718) + (7.495801505496, 47.484144337422) + (7.4911009992, 47.484144337422) + (7.486400492905, 47.484144337422) + (7.48169998661, 47.484144337422) + (7.48169998661, 47.479443831127) + (7.476999480315, 47.479443831127) + (7.47229897402, 47.479443831127) + (7.47229897402, 47.484144337422) + (7.467598467724, 47.484144337422) + (7.462897961429, 47.484144337422) + (7.462897961429, 47.488844843718) + (7.458197455134, 47.488844843718) + (7.453496948839, 47.488844843718) + (7.453496948839, 47.493545350013) + (7.448796442544, 47.493545350013) + (7.444095936248, 47.493545350013) + (7.439395429953, 47.493545350013) + (7.439395429953, 47.498245856308) + (7.434694923658, 47.498245856308) + (7.429994417363, 47.498245856308) + (7.429994417363, 47.493545350013) + (7.429994417363, 47.488844843718) + (7.425293911067, 47.488844843718) + (7.425293911067, 47.484144337422) + (7.420593404772, 47.484144337422) + (7.420593404772, 47.479443831127) + (7.425293911067, 47.479443831127) + (7.429994417363, 47.479443831127) + (7.434694923658, 47.479443831127) + (7.439395429953, 47.479443831127) + (7.444095936248, 47.479443831127) + (7.448796442544, 47.479443831127) + (7.448796442544, 47.474743324832) + (7.453496948839, 47.474743324832) + (7.453496948839, 47.470042818537) + (7.453496948839, 47.465342312242) + (7.448796442544, 47.465342312242) + (7.448796442544, 47.460641805946) + (7.444095936248, 47.460641805946) + (7.439395429953, 47.460641805946) + (7.434694923658, 47.460641805946) + (7.429994417363, 47.460641805946) + (7.429994417363, 47.455941299651) + (7.429994417363, 47.451240793356) + (7.425293911067, 47.451240793356) + (7.425293911067, 47.446540287061) + (7.420593404772, 47.446540287061) + (7.415892898477, 47.446540287061) + (7.415892898477, 47.441839780765) + (7.411192392182, 47.441839780765) + (7.406491885887, 47.441839780765) + (7.406491885887, 47.43713927447) + (7.401791379591, 47.43713927447) + (7.397090873296, 47.43713927447) + (7.392390367001, 47.43713927447) + (7.392390367001, 47.432438768175) + (7.387689860706, 47.432438768175) + (7.382989354411, 47.432438768175) + (7.378288848115, 47.432438768175) + (7.37358834182, 47.432438768175) + (7.368887835525, 47.432438768175) + (7.36418732923, 47.432438768175) + (7.359486822934, 47.432438768175) + (7.354786316639, 47.432438768175) + (7.350085810344, 47.432438768175) + (7.350085810344, 47.43713927447) + (7.345385304049, 47.43713927447) + (7.340684797754, 47.43713927447) + (7.335984291458, 47.43713927447) + (7.331283785163, 47.43713927447) + (7.326583278868, 47.43713927447) + (7.321882772573, 47.43713927447) + (7.317182266278, 47.43713927447) + (7.312481759982, 47.43713927447) + (7.312481759982, 47.441839780765) + (7.307781253687, 47.441839780765) + (7.307781253687, 47.43713927447) + (7.303080747392, 47.43713927447) + (7.298380241097, 47.43713927447) + (7.298380241097, 47.432438768175) + (7.293679734801, 47.432438768175) + (7.288979228506, 47.432438768175) + (7.284278722211, 47.432438768175) + (7.279578215916, 47.432438768175) + (7.274877709621, 47.432438768175) + (7.270177203325, 47.432438768175) + (7.270177203325, 47.42773826188) + (7.26547669703, 47.42773826188) + (7.260776190735, 47.42773826188) + (7.260776190735, 47.423037755585) + (7.25607568444, 47.423037755585) + (7.251375178144, 47.423037755585) + (7.246674671849, 47.423037755585) + (7.241974165554, 47.423037755585) + (7.241974165554, 47.42773826188) + (7.241974165554, 47.432438768175) + (7.237273659259, 47.432438768175) + (7.237273659259, 47.43713927447) + (7.232573152964, 47.43713927447) + (7.227872646668, 47.43713927447) + (7.227872646668, 47.441839780765) + (7.223172140373, 47.441839780765) + (7.223172140373, 47.43713927447) + (7.218471634078, 47.43713927447) + (7.213771127783, 47.43713927447) + (7.209070621488, 47.43713927447) + (7.209070621488, 47.432438768175) + (7.204370115192, 47.432438768175) + (7.199669608897, 47.432438768175) + (7.199669608897, 47.43713927447) + (7.194969102602, 47.43713927447) + (7.190268596307, 47.43713927447) + (7.190268596307, 47.441839780765) + (7.185568090011, 47.441839780765) + (7.180867583716, 47.441839780765) + (7.176167077421, 47.441839780765) + (7.171466571126, 47.441839780765) + (7.171466571126, 47.446540287061) + (7.176167077421, 47.446540287061) + (7.176167077421, 47.451240793356) + (7.176167077421, 47.455941299651) + (7.176167077421, 47.460641805946) + (7.176167077421, 47.465342312242) + (7.176167077421, 47.470042818537) + (7.180867583716, 47.470042818537) + (7.180867583716, 47.474743324832) + (7.180867583716, 47.479443831127) + (7.185568090011, 47.479443831127) + (7.185568090011, 47.484144337422) + (7.190268596307, 47.484144337422) + (7.190268596307, 47.488844843718) + (7.194969102602, 47.488844843718) + (7.199669608897, 47.488844843718) + (7.199669608897, 47.493545350013) + (7.194969102602, 47.493545350013) + (7.190268596307, 47.493545350013) + (7.185568090011, 47.493545350013) + (7.180867583716, 47.493545350013) + (7.180867583716, 47.488844843718) + (7.176167077421, 47.488844843718) + (7.171466571126, 47.488844843718) + (7.166766064831, 47.488844843718) + (7.162065558535, 47.488844843718) + (7.162065558535, 47.493545350013) + (7.15736505224, 47.493545350013) + (7.15736505224, 47.498245856308) + (7.152664545945, 47.498245856308) + (7.14796403965, 47.498245856308) + (7.143263533355, 47.498245856308) + (7.143263533355, 47.502946362603) + (7.138563027059, 47.502946362603) + (7.133862520764, 47.502946362603) + (7.129162014469, 47.502946362603) + (7.124461508174, 47.502946362603) + (7.124461508174, 47.498245856308) + (7.119761001878, 47.498245856308) + (7.119761001878, 47.493545350013) + (7.115060495583, 47.493545350013) + (7.110359989288, 47.493545350013) + (7.105659482993, 47.493545350013) + (7.100958976698, 47.493545350013) + (7.096258470402, 47.493545350013) + (7.091557964107, 47.493545350013) + (7.091557964107, 47.488844843718) + (7.086857457812, 47.488844843718) + (7.082156951517, 47.488844843718) + (7.077456445222, 47.488844843718) + (7.072755938926, 47.488844843718) + (7.068055432631, 47.488844843718) + (7.068055432631, 47.493545350013) + (7.063354926336, 47.493545350013) + (7.058654420041, 47.493545350013) + (7.053953913745, 47.493545350013) + (7.04925340745, 47.493545350013) + (7.044552901155, 47.493545350013) + (7.044552901155, 47.498245856308) + (7.03985239486, 47.498245856308) + (7.035151888565, 47.498245856308) + (7.030451382269, 47.498245856308) + (7.030451382269, 47.502946362603) + (7.025750875974, 47.502946362603) + (7.021050369679, 47.502946362603) + (7.016349863384, 47.502946362603) + (7.011649357089, 47.502946362603) + (7.006948850793, 47.502946362603) + (7.002248344498, 47.502946362603) + (7.002248344498, 47.498245856308) + (6.997547838203, 47.498245856308) + (6.992847331908, 47.498245856308) + (6.992847331908, 47.493545350013) + (6.988146825612, 47.493545350013) + (6.988146825612, 47.488844843718) + (6.988146825612, 47.484144337422) + (6.988146825612, 47.479443831127) + (6.988146825612, 47.474743324832) + (6.992847331908, 47.474743324832) + (6.992847331908, 47.470042818537) + (6.992847331908, 47.465342312242) + (6.997547838203, 47.465342312242) + (6.997547838203, 47.470042818537) + (7.002248344498, 47.470042818537) + (7.002248344498, 47.465342312242) + (7.002248344498, 47.460641805946) + (6.997547838203, 47.460641805946) + (6.997547838203, 47.455941299651) + (7.002248344498, 47.455941299651) + (7.002248344498, 47.451240793356) + (6.997547838203, 47.451240793356) + (6.992847331908, 47.451240793356) + (6.988146825612, 47.451240793356) + (6.983446319317, 47.451240793356) + (6.983446319317, 47.446540287061) + (6.978745813022, 47.446540287061) + (6.974045306727, 47.446540287061) + (6.969344800432, 47.446540287061) + (6.969344800432, 47.441839780765) + (6.969344800432, 47.43713927447) + (6.964644294136, 47.43713927447) + (6.959943787841, 47.43713927447) + (6.959943787841, 47.432438768175) + (6.955243281546, 47.432438768175) + (6.955243281546, 47.43713927447) + (6.950542775251, 47.43713927447) + (6.945842268956, 47.43713927447) + (6.945842268956, 47.432438768175) + (6.94114176266, 47.432438768175) + (6.94114176266, 47.42773826188) + (6.94114176266, 47.423037755585) + (6.94114176266, 47.418337249289) + (6.94114176266, 47.413636742994) + (6.94114176266, 47.408936236699) + (6.94114176266, 47.404235730404) + (6.936441256365, 47.404235730404) + (6.93174075007, 47.404235730404) + (6.927040243775, 47.404235730404) + (6.922339737479, 47.404235730404) + (6.917639231184, 47.404235730404) + (6.917639231184, 47.399535224108) + (6.912938724889, 47.399535224108) + (6.912938724889, 47.394834717813) + (6.912938724889, 47.390134211518) + (6.912938724889, 47.385433705223) + (6.908238218594, 47.385433705223) + (6.903537712299, 47.385433705223) + (6.898837206003, 47.385433705223) + (6.898837206003, 47.380733198928) + (6.894136699708, 47.380733198928) + (6.889436193413, 47.380733198928) + (6.889436193413, 47.376032692632) + (6.884735687118, 47.376032692632) + (6.884735687118, 47.371332186337) + (6.884735687118, 47.366631680042) + (6.884735687118, 47.361931173747) + (6.880035180822, 47.361931173747) + (6.880035180822, 47.357230667452) + (6.880035180822, 47.352530161156) + (6.884735687118, 47.352530161156) + (6.889436193413, 47.352530161156) + (6.889436193413, 47.357230667452) + (6.894136699708, 47.357230667452) + (6.898837206003, 47.357230667452) + (6.903537712299, 47.357230667452) + (6.908238218594, 47.357230667452) + (6.912938724889, 47.357230667452) + (6.917639231184, 47.357230667452) + (6.922339737479, 47.357230667452) + (6.927040243775, 47.357230667452) + (6.93174075007, 47.357230667452) + (6.936441256365, 47.357230667452) + (6.94114176266, 47.357230667452) + (6.945842268956, 47.357230667452) + (6.950542775251, 47.357230667452) + (6.955243281546, 47.357230667452) + (6.959943787841, 47.357230667452) + (6.964644294136, 47.357230667452) + (6.964644294136, 47.361931173747) + (6.969344800432, 47.361931173747) + (6.974045306727, 47.361931173747) + (6.978745813022, 47.361931173747) + (6.983446319317, 47.361931173747) + (6.988146825612, 47.361931173747) + (6.992847331908, 47.361931173747) + (6.997547838203, 47.361931173747) + (6.997547838203, 47.366631680042) + (7.002248344498, 47.366631680042) + (7.006948850793, 47.366631680042) + (7.011649357089, 47.366631680042) + (7.011649357089, 47.371332186337) + (7.016349863384, 47.371332186337) + (7.021050369679, 47.371332186337) + (7.025750875974, 47.371332186337) + (7.030451382269, 47.371332186337) + (7.035151888565, 47.371332186337) + (7.035151888565, 47.366631680042) + (7.035151888565, 47.361931173747) + (7.03985239486, 47.361931173747) + (7.044552901155, 47.361931173747) + (7.04925340745, 47.361931173747) + (7.04925340745, 47.357230667452) + (7.04925340745, 47.352530161156) + (7.04925340745, 47.347829654861) + (7.053953913745, 47.347829654861) + (7.058654420041, 47.347829654861) + (7.058654420041, 47.343129148566) + (7.058654420041, 47.338428642271) + (7.053953913745, 47.338428642271) + (7.053953913745, 47.333728135975) + (7.04925340745, 47.333728135975) + (7.04925340745, 47.32902762968) + (7.044552901155, 47.32902762968) + (7.03985239486, 47.32902762968) + (7.035151888565, 47.32902762968) + (7.030451382269, 47.32902762968) + (7.025750875974, 47.32902762968) + (7.025750875974, 47.324327123385) + (7.021050369679, 47.324327123385) + (7.016349863384, 47.324327123385) + (7.011649357089, 47.324327123385) + (7.006948850793, 47.324327123385) + (7.006948850793, 47.31962661709) + (7.011649357089, 47.31962661709) + (7.016349863384, 47.31962661709) + (7.016349863384, 47.314926110795) + (7.016349863384, 47.310225604499) + (7.011649357089, 47.310225604499) + (7.011649357089, 47.305525098204) + (7.006948850793, 47.305525098204) + (7.006948850793, 47.300824591909) + (7.002248344498, 47.300824591909) + (6.997547838203, 47.300824591909) + (6.997547838203, 47.296124085614) + (6.992847331908, 47.296124085614) + (6.988146825612, 47.296124085614) + (6.983446319317, 47.296124085614) + (6.978745813022, 47.296124085614) + (6.974045306727, 47.296124085614) + (6.974045306727, 47.291423579319) + (6.969344800432, 47.291423579319) + (6.964644294136, 47.291423579319) + (6.959943787841, 47.291423579319) + (6.955243281546, 47.291423579319) + (6.950542775251, 47.291423579319) + (6.945842268956, 47.291423579319) + (6.945842268956, 47.286723073023) + (6.94114176266, 47.286723073023) + (6.94114176266, 47.282022566728) + (6.945842268956, 47.282022566728) + (6.945842268956, 47.277322060433) + (6.950542775251, 47.277322060433) + (6.950542775251, 47.272621554138) + (6.950542775251, 47.267921047842) + (6.950542775251, 47.263220541547) + (6.950542775251, 47.258520035252) + (6.950542775251, 47.253819528957) + (6.945842268956, 47.253819528957) + (6.945842268956, 47.249119022662) + (6.950542775251, 47.249119022662) + (6.950542775251, 47.244418516366) + (6.950542775251, 47.239718010071) + (6.945842268956, 47.239718010071) + (6.94114176266, 47.239718010071) + (6.94114176266, 47.235017503776) + (6.94114176266, 47.230316997481) + (6.936441256365, 47.230316997481) + (6.93174075007, 47.230316997481) + (6.927040243775, 47.230316997481) + (6.927040243775, 47.225616491186) + (6.922339737479, 47.225616491186) + (6.922339737479, 47.22091598489) + (6.917639231184, 47.22091598489) + (6.912938724889, 47.22091598489) + (6.912938724889, 47.216215478595) + (6.908238218594, 47.216215478595) + (6.903537712299, 47.216215478595) + (6.903537712299, 47.2115149723) + (6.898837206003, 47.2115149723) + (6.898837206003, 47.206814466005) + (6.894136699708, 47.206814466005) + (6.889436193413, 47.206814466005) + (6.889436193413, 47.202113959709) + (6.884735687118, 47.202113959709) + (6.880035180822, 47.202113959709) + (6.880035180822, 47.197413453414) + (6.875334674527, 47.197413453414) + (6.875334674527, 47.192712947119) + (6.875334674527, 47.188012440824) + (6.875334674527, 47.183311934529) + (6.870634168232, 47.183311934529) + (6.865933661937, 47.183311934529) + (6.865933661937, 47.178611428233) + (6.861233155642, 47.178611428233) + (6.856532649346, 47.178611428233) + (6.851832143051, 47.178611428233) + (6.851832143051, 47.173910921938) + (6.847131636756, 47.173910921938) + (6.842431130461, 47.173910921938) + (6.842431130461, 47.169210415643) + (6.842431130461, 47.164509909348) + (6.847131636756, 47.164509909348) + (6.851832143051, 47.164509909348) + (6.856532649346, 47.164509909348) + (6.856532649346, 47.159809403053) + (6.851832143051, 47.159809403053) + (6.851832143051, 47.155108896757) + (6.847131636756, 47.155108896757) + (6.842431130461, 47.155108896757) + (6.837730624166, 47.155108896757) + (6.837730624166, 47.150408390462) + (6.83303011787, 47.150408390462) + (6.83303011787, 47.145707884167) + (6.828329611575, 47.145707884167) + (6.82362910528, 47.145707884167) + (6.82362910528, 47.141007377872) + (6.818928598985, 47.141007377872) + (6.818928598985, 47.136306871576) + (6.814228092689, 47.136306871576) + (6.809527586394, 47.136306871576) + (6.804827080099, 47.136306871576) + (6.804827080099, 47.131606365281) + (6.800126573804, 47.131606365281) + (6.800126573804, 47.126905858986) + (6.795426067509, 47.126905858986) + (6.790725561213, 47.126905858986) + (6.786025054918, 47.126905858986) + (6.781324548623, 47.126905858986) + (6.781324548623, 47.122205352691) + (6.776624042328, 47.122205352691) + (6.771923536033, 47.122205352691) + (6.767223029737, 47.122205352691) + (6.762522523442, 47.122205352691) + (6.762522523442, 47.117504846396) + (6.757822017147, 47.117504846396) + (6.753121510852, 47.117504846396) + (6.753121510852, 47.1128043401) + (6.748421004556, 47.1128043401) + (6.748421004556, 47.108103833805) + (6.743720498261, 47.108103833805) + (6.739019991966, 47.108103833805) + (6.739019991966, 47.10340332751) + (6.743720498261, 47.10340332751) + (6.743720498261, 47.098702821215) + (6.743720498261, 47.09400231492) + (6.743720498261, 47.094002314919) + (6.743720498261, 47.089301808624) + (6.739019991966, 47.089301808624) + (6.734319485671, 47.089301808624) + (6.729618979376, 47.089301808624) + (6.72491847308, 47.089301808624) + (6.720217966785, 47.089301808624) + (6.71551746049, 47.089301808624) + (6.71551746049, 47.084601302329) + (6.710816954195, 47.084601302329) + (6.7061164479, 47.084601302329) + (6.7061164479, 47.079900796034) + (6.7061164479, 47.075200289739) + (6.7061164479, 47.070499783443) + (6.701415941604, 47.070499783443) + (6.696715435309, 47.070499783443) + (6.692014929014, 47.070499783443) + (6.692014929014, 47.065799277148) + (6.696715435309, 47.065799277148) + (6.696715435309, 47.061098770853) + (6.701415941604, 47.061098770853) + (6.7061164479, 47.061098770853) + (6.7061164479, 47.056398264558) + (6.710816954195, 47.056398264558) + (6.71551746049, 47.056398264558) + (6.71551746049, 47.051697758263) + (6.71551746049, 47.046997251967) + (6.710816954195, 47.046997251967) + (6.710816954195, 47.042296745672) + (6.7061164479, 47.042296745672) + (6.7061164479, 47.037596239377) + (6.701415941604, 47.037596239377) + (6.696715435309, 47.037596239377) + (6.692014929014, 47.037596239377) + (6.687314422719, 47.037596239377) + (6.687314422719, 47.032895733082) + (6.682613916423, 47.032895733082) + (6.677913410128, 47.032895733082) + (6.673212903833, 47.032895733082) + (6.668512397538, 47.032895733082) + (6.668512397538, 47.028195226786) + (6.663811891243, 47.028195226786) + (6.663811891243, 47.023494720491) + (6.659111384947, 47.023494720491) + (6.654410878652, 47.023494720491) + (6.654410878652, 47.018794214196) + (6.654410878652, 47.014093707901) + (6.649710372357, 47.014093707901) + (6.649710372357, 47.009393201606) + (6.645009866062, 47.009393201606) + (6.640309359767, 47.009393201606) + (6.640309359767, 47.00469269531) + (6.635608853471, 47.00469269531) + (6.635608853471, 46.999992189015) + (6.630908347176, 46.999992189015) + (6.630908347176, 46.99529168272) + (6.626207840881, 46.99529168272) + (6.621507334586, 46.99529168272) + (6.61680682829, 46.99529168272) + (6.612106321995, 46.99529168272) + (6.612106321995, 46.990591176425) + (6.6074058157, 46.990591176425) + (6.602705309405, 46.990591176425) + (6.59800480311, 46.990591176425) + (6.593304296814, 46.990591176425) + (6.588603790519, 46.990591176425) + (6.588603790519, 46.98589067013) + (6.583903284224, 46.98589067013) + (6.579202777929, 46.98589067013) + (6.579202777929, 46.981190163834) + (6.574502271633, 46.981190163834) + (6.569801765338, 46.981190163834) + (6.565101259043, 46.981190163834) + (6.560400752748, 46.981190163834) + (6.560400752748, 46.976489657539) + (6.555700246453, 46.976489657539) + (6.550999740157, 46.976489657539) + (6.546299233862, 46.976489657539) + (6.541598727567, 46.976489657539) + (6.536898221272, 46.976489657539) + (6.536898221272, 46.971789151244) + (6.532197714977, 46.971789151244) + (6.527497208681, 46.971789151244) + (6.522796702386, 46.971789151244) + (6.518096196091, 46.971789151244) + (6.513395689796, 46.971789151244) + (6.513395689796, 46.967088644949) + (6.5086951835, 46.967088644949) + (6.503994677205, 46.967088644949) + (6.49929417091, 46.967088644949) + (6.49929417091, 46.971789151244) + (6.494593664615, 46.971789151244) + (6.48989315832, 46.971789151244) + (6.48989315832, 46.967088644949) + (6.485192652024, 46.967088644949) + (6.485192652024, 46.962388138653) + (6.480492145729, 46.962388138653) + (6.475791639434, 46.962388138653) + (6.475791639434, 46.957687632358) + (6.471091133139, 46.957687632358) + (6.466390626844, 46.957687632358) + (6.466390626844, 46.952987126063) + (6.461690120548, 46.952987126063) + (6.461690120548, 46.948286619768) + (6.456989614253, 46.948286619768) + (6.456989614253, 46.943586113473) + (6.452289107958, 46.943586113473) + (6.452289107958, 46.938885607177) + (6.447588601663, 46.938885607177) + (6.442888095367, 46.938885607177) + (6.442888095367, 46.934185100882) + (6.438187589072, 46.934185100882) + (6.438187589072, 46.929484594587) + (6.433487082777, 46.929484594587) + (6.433487082777, 46.924784088292) + (6.438187589072, 46.924784088292) + (6.438187589072, 46.920083581997) + (6.442888095367, 46.920083581997) + (6.442888095367, 46.915383075701) + (6.447588601663, 46.915383075701) + (6.447588601663, 46.910682569406) + (6.452289107958, 46.910682569406) + (6.452289107958, 46.905982063111) + (6.456989614253, 46.905982063111) + (6.456989614253, 46.901281556816) + (6.456989614253, 46.89658105052) + (6.461690120548, 46.89658105052) + (6.461690120548, 46.891880544225) + (6.461690120548, 46.88718003793) + (6.466390626844, 46.88718003793) + (6.466390626844, 46.882479531635) + (6.466390626844, 46.87777902534) + (6.466390626844, 46.873078519044) + (6.466390626844, 46.868378012749) + (6.466390626844, 46.863677506454) + (6.461690120548, 46.863677506454) + (6.461690120548, 46.858977000159) + (6.461690120548, 46.854276493864) + (6.461690120548, 46.849575987568) + (6.456989614253, 46.849575987568) + (6.456989614253, 46.844875481273) + (6.452289107958, 46.844875481273) + (6.447588601663, 46.844875481273) + (6.447588601663, 46.840174974978) + (6.447588601663, 46.835474468683) + (6.442888095367, 46.835474468683) + (6.442888095367, 46.830773962387) + (6.442888095367, 46.826073456092) + (6.442888095367, 46.821372949797) + (6.442888095367, 46.816672443502) + (6.438187589072, 46.816672443502) + (6.438187589072, 46.811971937207) + (6.433487082777, 46.811971937207) + (6.433487082777, 46.807271430911) + (6.433487082777, 46.802570924616) + (6.438187589072, 46.802570924616) + (6.438187589072, 46.797870418321) + (6.442888095367, 46.797870418321) + (6.447588601663, 46.797870418321) + (6.447588601663, 46.793169912026) + (6.452289107958, 46.793169912026) + (6.452289107958, 46.78846940573) + (6.456989614253, 46.78846940573) + (6.456989614253, 46.783768899435) + (6.456989614253, 46.77906839314) + (6.452289107958, 46.77906839314) + (6.452289107958, 46.774367886845) + (6.447588601663, 46.774367886845) + (6.447588601663, 46.76966738055) + (6.442888095367, 46.76966738055) + (6.442888095367, 46.764966874254) + (6.438187589072, 46.764966874254) + (6.438187589072, 46.760266367959) + (6.433487082777, 46.760266367959) + (6.428786576482, 46.760266367959) + (6.428786576482, 46.755565861664) + (6.424086070187, 46.755565861664) + (6.419385563891, 46.755565861664) + (6.414685057596, 46.755565861664) + (6.409984551301, 46.755565861664) + (6.409984551301, 46.750865355369) + (6.405284045006, 46.750865355369) + (6.400583538711, 46.750865355369) + (6.400583538711, 46.746164849074) + (6.395883032415, 46.746164849074) + (6.39118252612, 46.746164849074) + (6.386482019825, 46.746164849074) + (6.386482019825, 46.741464342778) + (6.39118252612, 46.741464342778) + (6.39118252612, 46.736763836483) + (6.386482019825, 46.736763836483) + (6.386482019825, 46.732063330188) + (6.38178151353, 46.732063330188) + (6.377081007234, 46.732063330188) + (6.372380500939, 46.732063330188) + (6.367679994644, 46.732063330188) + (6.367679994644, 46.727362823893) + (6.372380500939, 46.727362823893) + (6.372380500939, 46.722662317597) + (6.367679994644, 46.722662317597) + (6.362979488349, 46.722662317597) + (6.358278982054, 46.722662317597) + (6.358278982054, 46.717961811302) + (6.353578475758, 46.717961811302) + (6.348877969463, 46.717961811302) + (6.348877969463, 46.713261305007) + (6.344177463168, 46.713261305007) + (6.339476956873, 46.713261305007) + (6.339476956873, 46.708560798712) + (6.334776450578, 46.708560798712) + (6.330075944282, 46.708560798712) + (6.330075944282, 46.703860292417) + (6.325375437987, 46.703860292417) + (6.320674931692, 46.703860292417) + (6.315974425397, 46.703860292417) + (6.315974425397, 46.699159786121) + (6.311273919101, 46.699159786121) + (6.306573412806, 46.699159786121) + (6.301872906511, 46.699159786121) + (6.301872906511, 46.694459279826) + (6.297172400216, 46.694459279826) + (6.292471893921, 46.694459279826) + (6.292471893921, 46.689758773531) + (6.287771387625, 46.689758773531) + (6.28307088133, 46.689758773531) + (6.28307088133, 46.685058267236) + (6.278370375035, 46.685058267236) + (6.27366986874, 46.685058267236) + (6.27366986874, 46.680357760941) + (6.268969362444, 46.680357760941) + (6.268969362444, 46.675657254645) + (6.264268856149, 46.675657254645) + (6.264268856149, 46.67095674835) + (6.259568349854, 46.67095674835) + (6.259568349854, 46.666256242055) + (6.254867843559, 46.666256242055) + (6.250167337264, 46.666256242055) + (6.250167337264, 46.66155573576) + (6.245466830968, 46.66155573576) + (6.245466830968, 46.656855229464) + (6.240766324673, 46.656855229464) + (6.236065818378, 46.656855229464) + (6.236065818378, 46.652154723169) + (6.231365312083, 46.652154723169) + (6.226664805788, 46.652154723169) + (6.226664805788, 46.647454216874) + (6.221964299492, 46.647454216874) + (6.221964299492, 46.642753710579) + (6.217263793197, 46.642753710579) + (6.212563286902, 46.642753710579) + (6.212563286902, 46.638053204284) + (6.207862780607, 46.638053204284) + (6.203162274311, 46.638053204284) + (6.203162274311, 46.633352697988) + (6.198461768016, 46.633352697988) + (6.198461768016, 46.628652191693) + (6.193761261721, 46.628652191693) + (6.193761261721, 46.623951685398) + (6.189060755426, 46.623951685398) + (6.184360249131, 46.623951685398) + (6.184360249131, 46.619251179103) + (6.179659742835, 46.619251179103) + (6.179659742835, 46.614550672808) + (6.17495923654, 46.614550672808) + (6.170258730245, 46.614550672808) + (6.170258730245, 46.609850166512) + (6.16555822395, 46.609850166512) + (6.160857717655, 46.609850166512) + (6.156157211359, 46.609850166512) + (6.156157211359, 46.605149660217) + (6.151456705064, 46.605149660217) + (6.146756198769, 46.605149660217) + (6.146756198769, 46.600449153922) + (6.142055692474, 46.600449153922) + (6.137355186178, 46.600449153922) + (6.137355186178, 46.595748647627) + (6.132654679883, 46.595748647627) + (6.127954173588, 46.595748647627) + (6.127954173588, 46.591048141331) + (6.127954173588, 46.586347635036) + (6.123253667293, 46.586347635036) + (6.123253667293, 46.581647128741) + (6.118553160998, 46.581647128741) + (6.118553160998, 46.576946622446) + (6.113852654702, 46.576946622446) + (6.113852654702, 46.572246116151) + (6.118553160998, 46.572246116151) + (6.123253667293, 46.572246116151) + (6.123253667293, 46.567545609855) + (6.127954173588, 46.567545609855) + (6.127954173588, 46.56284510356) + (6.132654679883, 46.56284510356) + (6.137355186178, 46.56284510356) + (6.137355186178, 46.558144597265) + (6.142055692474, 46.558144597265) + (6.142055692474, 46.55344409097) + (6.146756198769, 46.55344409097) + (6.146756198769, 46.548743584675) + (6.151456705064, 46.548743584675) + (6.156157211359, 46.548743584675) + (6.156157211359, 46.544043078379) + (6.151456705064, 46.544043078379) + (6.151456705064, 46.539342572084) + (6.151456705064, 46.534642065789) + (6.151456705064, 46.529941559494) + (6.146756198769, 46.529941559494) + (6.142055692474, 46.529941559494) + (6.142055692474, 46.534642065789) + (6.137355186178, 46.534642065789) + (6.137355186178, 46.529941559494) + (6.132654679883, 46.529941559494) + (6.132654679883, 46.525241053198) + (6.127954173588, 46.525241053198) + (6.127954173588, 46.520540546903) + (6.123253667293, 46.520540546903) + (6.123253667293, 46.515840040608) + (6.118553160998, 46.515840040608) + (6.118553160998, 46.511139534313) + (6.113852654702, 46.511139534313) + (6.113852654702, 46.506439028018) + (6.109152148407, 46.506439028018) + (6.109152148407, 46.501738521722) + (6.109152148407, 46.497038015427) + (6.104451642112, 46.497038015427) + (6.104451642112, 46.492337509132) + (6.104451642112, 46.487637002837) + (6.099751135817, 46.487637002837) + (6.099751135817, 46.482936496542) + (6.099751135817, 46.482936496541) + (6.099751135817, 46.478235990246) + (6.095050629522, 46.478235990246) + (6.090350123226, 46.478235990246) + (6.090350123226, 46.473535483951) + (6.085649616931, 46.473535483951) + (6.080949110636, 46.473535483951) + (6.080949110636, 46.468834977656) + (6.076248604341, 46.468834977656) + (6.076248604341, 46.464134471361) + (6.076248604341, 46.459433965065) + (6.076248604341, 46.45473345877) + (6.076248604341, 46.450032952475) + (6.080949110636, 46.450032952475) + (6.085649616931, 46.450032952475) + (6.085649616931, 46.44533244618) + (6.085649616931, 46.440631939885) + (6.085649616931, 46.435931433589) + (6.080949110636, 46.435931433589) + (6.080949110636, 46.431230927294) + (6.076248604341, 46.431230927294) + (6.071548098045, 46.431230927294) + (6.071548098045, 46.426530420999) + (6.071548098045, 46.421829914704) + (6.06684759175, 46.421829914704) + (6.06684759175, 46.417129408408) + (6.071548098045, 46.417129408408) + (6.071548098045, 46.412428902113) + (6.076248604341, 46.412428902113) + (6.080949110636, 46.412428902113) + (6.085649616931, 46.412428902113) + (6.085649616931, 46.407728395818) + (6.090350123226, 46.407728395818) + (6.095050629522, 46.407728395818) + (6.099751135817, 46.407728395818) + (6.099751135817, 46.403027889523) + (6.104451642112, 46.403027889523) + (6.104451642112, 46.398327383228) + (6.109152148407, 46.398327383228) + (6.113852654702, 46.398327383228) + (6.118553160998, 46.398327383228) + (6.118553160998, 46.393626876932) + (6.123253667293, 46.393626876932) + (6.127954173588, 46.393626876932) + (6.127954173588, 46.388926370637) + (6.132654679883, 46.388926370637) + (6.137355186178, 46.388926370637) + (6.137355186178, 46.384225864342) + (6.142055692474, 46.384225864342) + (6.146756198769, 46.384225864342) + (6.146756198769, 46.379525358047) + (6.151456705064, 46.379525358047) + (6.156157211359, 46.379525358047) + (6.160857717655, 46.379525358047) + (6.160857717655, 46.374824851752) + (6.16555822395, 46.374824851752) + (6.16555822395, 46.370124345456) + (6.170258730245, 46.370124345456) + (6.170258730245, 46.365423839161) + (6.16555822395, 46.365423839161) + (6.16555822395, 46.360723332866) + (6.160857717655, 46.360723332866) + (6.160857717655, 46.356022826571) + (6.160857717655, 46.351322320275) + (6.156157211359, 46.351322320275) + (6.156157211359, 46.34662181398) + (6.151456705064, 46.34662181398) + (6.146756198769, 46.34662181398) + (6.146756198769, 46.341921307685) + (6.142055692474, 46.341921307685) + (6.142055692474, 46.33722080139) + (6.137355186178, 46.33722080139) + (6.137355186178, 46.332520295095) + (6.137355186178, 46.327819788799) + (6.132654679883, 46.327819788799) + (6.132654679883, 46.323119282504) + (6.127954173588, 46.323119282504) + (6.127954173588, 46.318418776209) + (6.123253667293, 46.318418776209) + (6.123253667293, 46.313718269914) + (6.118553160998, 46.313718269914) + (6.118553160998, 46.309017763619) + (6.118553160998, 46.304317257323) + (6.123253667293, 46.304317257323) + (6.123253667293, 46.299616751028) + (6.118553160998, 46.299616751028) + (6.118553160998, 46.294916244733) + (6.113852654702, 46.294916244733) + (6.113852654702, 46.290215738438) + (6.109152148407, 46.290215738438) + (6.109152148407, 46.285515232142) + (6.104451642112, 46.285515232142) + (6.104451642112, 46.280814725847) + (6.104451642112, 46.276114219552) + (6.109152148407, 46.276114219552) + (6.109152148407, 46.271413713257) + (6.113852654702, 46.271413713257) + (6.113852654702, 46.266713206962) + (6.118553160998, 46.266713206962) + (6.118553160998, 46.262012700666) + (6.123253667293, 46.262012700666) + (6.123253667293, 46.257312194371) + (6.123253667293, 46.252611688076) + (6.123253667293, 46.247911181781) + (6.118553160998, 46.247911181781) + (6.118553160998, 46.243210675486) + (6.113852654702, 46.243210675486) + (6.109152148407, 46.243210675486) + (6.109152148407, 46.23851016919) + (6.104451642112, 46.23851016919) + (6.099751135817, 46.23851016919) + (6.099751135817, 46.243210675486) + (6.095050629522, 46.243210675486) + (6.090350123226, 46.243210675486) + (6.090350123226, 46.247911181781) + (6.085649616931, 46.247911181781) + (6.080949110636, 46.247911181781) + (6.080949110636, 46.243210675486) + (6.076248604341, 46.243210675486) + (6.071548098045, 46.243210675486) + (6.071548098045, 46.23851016919) + (6.06684759175, 46.23851016919) + (6.06684759175, 46.243210675486) + (6.062147085455, 46.243210675486) + (6.05744657916, 46.243210675486) + (6.05744657916, 46.23851016919) + (6.052746072865, 46.23851016919) + (6.052746072865, 46.233809662895) + (6.048045566569, 46.233809662895) + (6.043345060274, 46.233809662895) + (6.038644553979, 46.233809662895) + (6.038644553979, 46.23851016919) + (6.033944047684, 46.23851016919) + (6.029243541389, 46.23851016919) + (6.029243541389, 46.233809662895) + (6.024543035093, 46.233809662895) + (6.019842528798, 46.233809662895) + (6.015142022503, 46.233809662895) + (6.015142022503, 46.2291091566) + (6.010441516208, 46.2291091566) + (6.005741009912, 46.2291091566) + (6.005741009912, 46.224408650305) + (6.001040503617, 46.224408650305) + (5.996339997322, 46.224408650305) + (5.991639491027, 46.224408650305) + (5.991639491027, 46.219708144009) + (5.991639491027, 46.215007637714) + (5.986938984732, 46.215007637714) + (5.982238478436, 46.215007637714) + (5.977537972141, 46.215007637714) + (5.972837465846, 46.215007637714) + (5.972837465846, 46.210307131419) + (5.972837465846, 46.205606625124) + (5.972837465846, 46.200906118829) + (5.968136959551, 46.200906118829) + (5.968136959551, 46.196205612533) + (5.972837465846, 46.196205612533) + (5.972837465846, 46.191505106238) + (5.977537972141, 46.191505106238) + (5.982238478436, 46.191505106238) + (5.986938984732, 46.191505106238) + (5.986938984732, 46.186804599943) + (5.991639491027, 46.186804599943) + (5.991639491027, 46.182104093648) + (5.991639491027, 46.177403587353) + (5.991639491027, 46.177403587352) + (5.991639491027, 46.172703081057) + (5.986938984732, 46.172703081057) + (5.982238478436, 46.172703081057) + (5.982238478436, 46.168002574762) + (5.977537972141, 46.168002574762) + (5.977537972141, 46.163302068467) + (5.977537972141, 46.158601562172) + (5.972837465846, 46.158601562172) + (5.972837465846, 46.153901055876) + (5.968136959551, 46.153901055876) + (5.968136959551, 46.149200549581) + (5.968136959551, 46.144500043286) + (5.963436453256, 46.144500043286) + (5.963436453256, 46.139799536991) + (5.963436453256, 46.135099030696) + (5.95873594696, 46.135099030696) + (5.95873594696, 46.1303985244) + (5.95873594696, 46.125698018105) + (5.963436453256, 46.125698018105) + (5.963436453256, 46.1303985244) + (5.968136959551, 46.1303985244) + (5.972837465846, 46.1303985244) + (5.977537972141, 46.1303985244) + (5.977537972141, 46.135099030696) + (5.982238478436, 46.135099030696) + (5.982238478436, 46.139799536991) + (5.982238478436, 46.144500043286) + (5.986938984732, 46.144500043286) + (5.991639491027, 46.144500043286) + (5.996339997322, 46.144500043286) + (6.001040503617, 46.144500043286) + (6.005741009912, 46.144500043286) + (6.010441516208, 46.144500043286) + (6.015142022503, 46.144500043286) + (6.019842528798, 46.144500043286) + (6.024543035093, 46.144500043286) + (6.024543035093, 46.139799536991) + (6.029243541389, 46.139799536991) + (6.033944047684, 46.139799536991) + (6.038644553979, 46.139799536991) + (6.043345060274, 46.139799536991) + (6.048045566569, 46.139799536991) + (6.048045566569, 46.144500043286) + (6.048045566569, 46.149200549581) + (6.052746072865, 46.149200549581) + (6.05744657916, 46.149200549581) + (6.062147085455, 46.149200549581) + (6.06684759175, 46.149200549581) + (6.071548098045, 46.149200549581) + (6.076248604341, 46.149200549581) + (6.080949110636, 46.149200549581) + (6.085649616931, 46.149200549581) + (6.090350123226, 46.149200549581) + (6.095050629522, 46.149200549581) + (6.099751135817, 46.149200549581) + (6.099751135817, 46.144500043286) + (6.104451642112, 46.144500043286) + (6.109152148407, 46.144500043286) + (6.113852654702, 46.144500043286) + (6.118553160998, 46.144500043286) + (6.118553160998, 46.139799536991) + (6.123253667293, 46.139799536991) + (6.127954173588, 46.139799536991) + (6.132654679883, 46.139799536991) + (6.137355186178, 46.139799536991) + (6.137355186178, 46.144500043286) + (6.142055692474, 46.144500043286) + (6.146756198769, 46.144500043286) + (6.146756198769, 46.149200549581) + (6.151456705064, 46.149200549581) + (6.156157211359, 46.149200549581) + (6.156157211359, 46.153901055876) + (6.160857717655, 46.153901055876) + (6.16555822395, 46.153901055876) + (6.170258730245, 46.153901055876) + (6.170258730245, 46.158601562172) + (6.17495923654, 46.158601562172) + (6.179659742835, 46.158601562172) + (6.179659742835, 46.163302068467) + (6.184360249131, 46.163302068467) + (6.189060755426, 46.163302068467) + (6.189060755426, 46.168002574762) + (6.189060755426, 46.172703081057) + (6.184360249131, 46.172703081057) + (6.184360249131, 46.177403587352) + (6.189060755426, 46.177403587352) + (6.189060755426, 46.182104093648) + (6.193761261721, 46.182104093648) + (6.198461768016, 46.182104093648) + (6.198461768016, 46.186804599943) + (6.203162274311, 46.186804599943) + (6.203162274311, 46.191505106238) + (6.207862780607, 46.191505106238) + (6.212563286902, 46.191505106238) + (6.212563286902, 46.196205612533) + (6.217263793197, 46.196205612533) + (6.217263793197, 46.200906118829) + (6.221964299492, 46.200906118829) + (6.226664805788, 46.200906118829) + (6.226664805788, 46.205606625124) + (6.231365312083, 46.205606625124) + (6.236065818378, 46.205606625124) + (6.240766324673, 46.205606625124) + (6.245466830968, 46.205606625124) + (6.250167337264, 46.205606625124) + (6.254867843559, 46.205606625124) + (6.254867843559, 46.210307131419) + (6.259568349854, 46.210307131419) + (6.264268856149, 46.210307131419) + (6.268969362444, 46.210307131419) + (6.268969362444, 46.215007637714) + (6.27366986874, 46.215007637714) + (6.278370375035, 46.215007637714) + (6.28307088133, 46.215007637714) + (6.28307088133, 46.219708144009) + (6.287771387625, 46.219708144009) + (6.292471893921, 46.219708144009) + (6.292471893921, 46.224408650305) + (6.297172400216, 46.224408650305) + (6.297172400216, 46.2291091566) + (6.301872906511, 46.2291091566) + (6.301872906511, 46.233809662895) + (6.306573412806, 46.233809662895) + (6.306573412806, 46.23851016919) + (6.306573412806, 46.243210675486) + (6.311273919101, 46.243210675486) + (6.311273919101, 46.247911181781) + (6.311273919101, 46.252611688076) + (6.306573412806, 46.252611688076) + (6.301872906511, 46.252611688076) + (6.301872906511, 46.257312194371) + (6.297172400216, 46.257312194371) + (6.297172400216, 46.262012700666) + (6.297172400216, 46.266713206962) + (6.292471893921, 46.266713206962) + (6.292471893921, 46.262012700666) + (6.287771387625, 46.262012700666) + (6.287771387625, 46.257312194371) + (6.28307088133, 46.257312194371) + (6.28307088133, 46.252611688076) + (6.278370375035, 46.252611688076) + (6.27366986874, 46.252611688076) + (6.268969362444, 46.252611688076) + (6.268969362444, 46.247911181781) + (6.264268856149, 46.247911181781) + (6.264268856149, 46.252611688076) + (6.259568349854, 46.252611688076) + (6.259568349854, 46.257312194371) + (6.254867843559, 46.257312194371) + (6.254867843559, 46.262012700666) + (6.250167337264, 46.262012700666) + (6.250167337264, 46.266713206962) + (6.245466830968, 46.266713206962) + (6.245466830968, 46.271413713257) + (6.240766324673, 46.271413713257) + (6.240766324673, 46.276114219552) + (6.240766324673, 46.280814725847) + (6.240766324673, 46.285515232142) + (6.245466830968, 46.285515232142) + (6.250167337264, 46.285515232142) + (6.250167337264, 46.290215738438) + (6.250167337264, 46.294916244733) + (6.250167337264, 46.299616751028) + (6.250167337264, 46.304317257323) + (6.245466830968, 46.304317257323) + (6.240766324673, 46.304317257323) + (6.240766324673, 46.309017763619) + (6.236065818378, 46.309017763619) + (6.231365312083, 46.309017763619) + (6.226664805788, 46.309017763619) + (6.226664805788, 46.313718269914) + (6.221964299492, 46.313718269914) + (6.221964299492, 46.318418776209) + (6.226664805788, 46.318418776209) + (6.226664805788, 46.323119282504) + (6.231365312083, 46.323119282504) + (6.231365312083, 46.327819788799) + (6.236065818378, 46.327819788799) + (6.236065818378, 46.332520295095) + (6.236065818378, 46.33722080139) + (6.240766324673, 46.33722080139) + (6.240766324673, 46.341921307685) + (6.245466830968, 46.341921307685) + (6.245466830968, 46.34662181398) + (6.250167337264, 46.34662181398) + (6.250167337264, 46.351322320275) + (6.250167337264, 46.356022826571) + (6.254867843559, 46.356022826571) + (6.254867843559, 46.360723332866) + (6.259568349854, 46.360723332866) + (6.264268856149, 46.360723332866) + (6.264268856149, 46.365423839161) + (6.268969362444, 46.365423839161) + (6.268969362444, 46.370124345456) + (6.27366986874, 46.370124345456) + (6.278370375035, 46.370124345456) + (6.278370375035, 46.374824851752) + (6.28307088133, 46.374824851752) + (6.287771387625, 46.374824851752) + (6.287771387625, 46.379525358047) + (6.292471893921, 46.379525358047) + (6.292471893921, 46.384225864342) + (6.297172400216, 46.384225864342) + (6.301872906511, 46.384225864342) + (6.301872906511, 46.388926370637) + (6.306573412806, 46.388926370637) + (6.311273919101, 46.388926370637) + (6.311273919101, 46.393626876932) + (6.315974425397, 46.393626876932) + (6.315974425397, 46.398327383228) + (6.320674931692, 46.398327383228) + (6.325375437987, 46.398327383228) + (6.325375437987, 46.403027889523) + (6.330075944282, 46.403027889523) + (6.334776450578, 46.403027889523) + (6.339476956873, 46.403027889523) + (6.344177463168, 46.403027889523) + (6.344177463168, 46.407728395818) + (6.348877969463, 46.407728395818) + (6.353578475758, 46.407728395818) + (6.358278982054, 46.407728395818) + (6.362979488349, 46.407728395818) + (6.367679994644, 46.407728395818) + (6.372380500939, 46.407728395818) + (6.377081007234, 46.407728395818) + (6.38178151353, 46.407728395818) + (6.38178151353, 46.412428902113) + (6.386482019825, 46.412428902113) + (6.39118252612, 46.412428902113) + (6.395883032415, 46.412428902113) + (6.400583538711, 46.412428902113) + (6.405284045006, 46.412428902113) + (6.409984551301, 46.412428902113) + (6.414685057596, 46.412428902113) + (6.419385563891, 46.412428902113) + (6.419385563891, 46.417129408408) + (6.424086070187, 46.417129408408) + (6.428786576482, 46.417129408408) + (6.433487082777, 46.417129408408) + (6.433487082777, 46.421829914704) + (6.438187589072, 46.421829914704) + (6.442888095367, 46.421829914704) + (6.442888095367, 46.426530420999) + (6.447588601663, 46.426530420999) + (6.452289107958, 46.426530420999) + (6.456989614253, 46.426530420999) + (6.456989614253, 46.431230927294) + (6.461690120548, 46.431230927294) + (6.466390626844, 46.431230927294) + (6.466390626844, 46.435931433589) + (6.471091133139, 46.435931433589) + (6.475791639434, 46.435931433589) + (6.480492145729, 46.435931433589) + (6.480492145729, 46.440631939885) + (6.485192652024, 46.440631939885) + (6.48989315832, 46.440631939885) + (6.48989315832, 46.44533244618) + (6.494593664615, 46.44533244618) + (6.49929417091, 46.44533244618) + (6.49929417091, 46.450032952475) + (6.503994677205, 46.450032952475) + (6.5086951835, 46.450032952475) + (6.513395689796, 46.450032952475) + (6.513395689796, 46.45473345877) + (6.518096196091, 46.45473345877) + (6.522796702386, 46.45473345877) + (6.527497208681, 46.45473345877) + (6.532197714977, 46.45473345877) + (6.536898221272, 46.45473345877) + (6.541598727567, 46.45473345877) + (6.546299233862, 46.45473345877) + (6.550999740157, 46.45473345877) + (6.555700246453, 46.45473345877) + (6.560400752748, 46.45473345877) + (6.565101259043, 46.45473345877) + (6.569801765338, 46.45473345877) + (6.574502271633, 46.45473345877) + (6.579202777929, 46.45473345877) + (6.583903284224, 46.45473345877) + (6.588603790519, 46.45473345877) + (6.593304296814, 46.45473345877) + (6.59800480311, 46.45473345877) + (6.602705309405, 46.45473345877) + (6.6074058157, 46.45473345877) + (6.612106321995, 46.45473345877) + (6.61680682829, 46.45473345877) + (6.621507334586, 46.45473345877) + (6.626207840881, 46.45473345877) + (6.630908347176, 46.45473345877) + (6.635608853471, 46.45473345877) + (6.640309359767, 46.45473345877) + (6.645009866062, 46.45473345877) + (6.649710372357, 46.45473345877) + (6.654410878652, 46.45473345877) + (6.659111384947, 46.45473345877) + (6.663811891243, 46.45473345877) + (6.668512397538, 46.45473345877) + (6.673212903833, 46.45473345877) + (6.677913410128, 46.45473345877) + (6.677913410128, 46.450032952475) + (6.682613916423, 46.450032952475) + (6.687314422719, 46.450032952475) + (6.692014929014, 46.450032952475) + (6.696715435309, 46.450032952475) + (6.701415941604, 46.450032952475) + (6.7061164479, 46.450032952475) + (6.7061164479, 46.44533244618) + (6.710816954195, 46.44533244618) + (6.71551746049, 46.44533244618) + (6.720217966785, 46.44533244618) + (6.72491847308, 46.44533244618) + (6.729618979376, 46.44533244618) + (6.734319485671, 46.44533244618) + (6.734319485671, 46.440631939885) + (6.739019991966, 46.440631939885) + (6.743720498261, 46.440631939885) + (6.748421004556, 46.440631939885) + (6.753121510852, 46.440631939885) + (6.757822017147, 46.440631939885) + (6.762522523442, 46.440631939885) + (6.762522523442, 46.435931433589) + (6.767223029737, 46.435931433589) + (6.771923536033, 46.435931433589) + (6.776624042328, 46.435931433589) + (6.781324548623, 46.435931433589) + (6.786025054918, 46.435931433589) + (6.790725561213, 46.435931433589) + (6.790725561213, 46.431230927294) + (6.795426067509, 46.431230927294) + (6.800126573804, 46.431230927294) + (6.804827080099, 46.431230927294) + (6.809527586394, 46.431230927294) + (6.814228092689, 46.431230927294) + (6.818928598985, 46.431230927294) + (6.818928598985, 46.426530420999) + (6.818928598985, 46.421829914704) + (6.814228092689, 46.421829914704) + (6.814228092689, 46.417129408408) + (6.814228092689, 46.412428902113) + (6.809527586394, 46.412428902113) + (6.809527586394, 46.407728395818) + (6.809527586394, 46.403027889523) + (6.804827080099, 46.403027889523) + (6.804827080099, 46.398327383228) + (6.804827080099, 46.393626876932) + (6.804827080099, 46.388926370637) + (6.804827080099, 46.384225864342) + (6.804827080099, 46.379525358047) + (6.800126573804, 46.379525358047) + (6.800126573804, 46.374824851752) + (6.795426067509, 46.374824851752) + (6.795426067509, 46.370124345456) + (6.790725561213, 46.370124345456) + (6.790725561213, 46.365423839161) + (6.786025054918, 46.365423839161) + (6.781324548623, 46.365423839161) + (6.776624042328, 46.365423839161) + (6.776624042328, 46.360723332866) + (6.771923536033, 46.360723332866) + (6.771923536033, 46.356022826571) + (6.771923536033, 46.351322320275) + (6.771923536033, 46.34662181398) + (6.776624042328, 46.34662181398) + (6.781324548623, 46.34662181398) + (6.781324548623, 46.341921307685) + (6.781324548623, 46.33722080139) + (6.786025054918, 46.33722080139) + (6.786025054918, 46.332520295095) + (6.790725561213, 46.332520295095) + (6.795426067509, 46.332520295095) + (6.800126573804, 46.332520295095) + (6.800126573804, 46.327819788799) + (6.800126573804, 46.323119282504) + (6.800126573804, 46.318418776209) + (6.804827080099, 46.318418776209) + (6.809527586394, 46.318418776209) + (6.814228092689, 46.318418776209) + (6.814228092689, 46.313718269914) + (6.818928598985, 46.313718269914) + (6.82362910528, 46.313718269914) + (6.82362910528, 46.309017763619) + (6.828329611575, 46.309017763619) + (6.828329611575, 46.304317257323) + (6.828329611575, 46.299616751028) + (6.83303011787, 46.299616751028) + (6.837730624166, 46.299616751028) + (6.837730624166, 46.294916244733) + (6.842431130461, 46.294916244733) + (6.847131636756, 46.294916244733) + (6.847131636756, 46.290215738438) + (6.851832143051, 46.290215738438) + (6.851832143051, 46.294916244733) + (6.856532649346, 46.294916244733) + (6.856532649346, 46.290215738438) + (6.861233155642, 46.290215738438) + (6.861233155642, 46.285515232142) + (6.861233155642, 46.280814725847) + (6.861233155642, 46.276114219552) + (6.856532649346, 46.276114219552) + (6.856532649346, 46.271413713257) + (6.861233155642, 46.271413713257) + (6.861233155642, 46.266713206962) + (6.856532649346, 46.266713206962) + (6.856532649346, 46.262012700666) + (6.856532649346, 46.257312194371) + (6.856532649346, 46.252611688076) + (6.851832143051, 46.252611688076) + (6.847131636756, 46.252611688076) + (6.847131636756, 46.247911181781) + (6.842431130461, 46.247911181781) + (6.842431130461, 46.243210675486) + (6.837730624166, 46.243210675486) + (6.837730624166, 46.23851016919) + (6.83303011787, 46.23851016919) + (6.828329611575, 46.23851016919) + (6.828329611575, 46.233809662895) + (6.82362910528, 46.233809662895) + (6.82362910528, 46.2291091566) + (6.818928598985, 46.2291091566) + (6.818928598985, 46.224408650305) + (6.818928598985, 46.219708144009) + (6.814228092689, 46.219708144009) + (6.814228092689, 46.215007637714) + (6.809527586394, 46.215007637714) + (6.809527586394, 46.210307131419) + (6.804827080099, 46.210307131419) + (6.804827080099, 46.205606625124) + (6.804827080099, 46.200906118829) + (6.804827080099, 46.196205612533) + (6.809527586394, 46.196205612533) + (6.809527586394, 46.191505106238) + (6.809527586394, 46.186804599943) + (6.814228092689, 46.186804599943) + (6.814228092689, 46.182104093648) + (6.809527586394, 46.182104093648) + (6.809527586394, 46.177403587353) + (6.809527586394, 46.177403587352) + (6.809527586394, 46.172703081057) + (6.804827080099, 46.172703081057) + (6.804827080099, 46.168002574762) + (6.800126573804, 46.168002574762) + (6.800126573804, 46.163302068467) + (6.795426067509, 46.163302068467) + (6.795426067509, 46.158601562172) + (6.790725561213, 46.158601562172) + (6.790725561213, 46.153901055876) + (6.790725561213, 46.149200549581) + (6.795426067509, 46.149200549581) + (6.795426067509, 46.144500043286) + (6.795426067509, 46.139799536991) + (6.800126573804, 46.139799536991) + (6.800126573804, 46.135099030696) + (6.804827080099, 46.135099030696) + (6.809527586394, 46.135099030696) + (6.809527586394, 46.1303985244) + (6.814228092689, 46.1303985244) + (6.818928598985, 46.1303985244) + (6.82362910528, 46.1303985244) + (6.828329611575, 46.1303985244) + (6.83303011787, 46.1303985244) + (6.83303011787, 46.135099030696) + (6.837730624166, 46.135099030696) + (6.842431130461, 46.135099030696) + (6.842431130461, 46.1303985244) + (6.847131636756, 46.1303985244) + (6.847131636756, 46.125698018105) + (6.851832143051, 46.125698018105) + (6.856532649346, 46.125698018105) + (6.861233155642, 46.125698018105) + (6.865933661937, 46.125698018105) + (6.870634168232, 46.125698018105) + (6.875334674527, 46.125698018105) + (6.880035180822, 46.125698018105) + (6.884735687118, 46.125698018105) + (6.889436193413, 46.125698018105) + (6.894136699708, 46.125698018105) + (6.898837206003, 46.125698018105) + (6.898837206003, 46.12099751181) + (6.898837206003, 46.116297005515) + (6.894136699708, 46.116297005515) + (6.894136699708, 46.111596499219) + (6.894136699708, 46.106895992924) + (6.889436193413, 46.106895992924) + (6.889436193413, 46.102195486629) + (6.889436193413, 46.097494980334) + (6.884735687118, 46.097494980334) + (6.884735687118, 46.092794474039) + (6.884735687118, 46.088093967743) + (6.889436193413, 46.088093967743) + (6.889436193413, 46.083393461448) + (6.889436193413, 46.078692955153) + (6.889436193413, 46.073992448858) + (6.884735687118, 46.073992448858) + (6.884735687118, 46.069291942563) + (6.880035180822, 46.069291942563) + (6.880035180822, 46.064591436267) + (6.875334674527, 46.064591436267) + (6.875334674527, 46.059890929972) + (6.875334674527, 46.055190423677) + (6.870634168232, 46.055190423677) + (6.870634168232, 46.050489917382) + (6.875334674527, 46.050489917382) + (6.875334674527, 46.045789411086) + (6.880035180822, 46.045789411086) + (6.884735687118, 46.045789411086) + (6.884735687118, 46.041088904791) + (6.889436193413, 46.041088904791) + (6.889436193413, 46.045789411086) + (6.894136699708, 46.045789411086) + (6.894136699708, 46.050489917382) + (6.898837206003, 46.050489917382) + (6.903537712299, 46.050489917382) + (6.908238218594, 46.050489917382) + (6.912938724889, 46.050489917382) + (6.912938724889, 46.055190423677) + (6.917639231184, 46.055190423677) + (6.917639231184, 46.059890929972) + (6.922339737479, 46.059890929972) + (6.922339737479, 46.064591436267) + (6.927040243775, 46.064591436267) + (6.93174075007, 46.064591436267) + (6.936441256365, 46.064591436267) + (6.936441256365, 46.059890929972) + (6.936441256365, 46.055190423677) + (6.94114176266, 46.055190423677) + (6.94114176266, 46.050489917382) + (6.945842268956, 46.050489917382) + (6.950542775251, 46.050489917382) + (6.950542775251, 46.045789411086) + (6.955243281546, 46.045789411086) + (6.955243281546, 46.041088904791) + (6.955243281546, 46.036388398496) + (6.959943787841, 46.036388398496) + (6.959943787841, 46.031687892201) + (6.964644294136, 46.031687892201) + (6.969344800432, 46.031687892201) + (6.969344800432, 46.026987385906) + (6.974045306727, 46.026987385906) + (6.974045306727, 46.02228687961) + (6.978745813022, 46.02228687961) + (6.978745813022, 46.017586373315) + (6.983446319317, 46.017586373315) + (6.983446319317, 46.01288586702) + (6.983446319317, 46.008185360725) + (6.983446319317, 46.00348485443) + (6.988146825612, 46.00348485443) + (6.992847331908, 46.00348485443) + (6.992847331908, 45.998784348134) + (6.997547838203, 45.998784348134) + (7.002248344498, 45.998784348134) + (7.006948850793, 45.998784348134) + (7.011649357089, 45.998784348134) + (7.011649357089, 45.994083841839) + (7.011649357089, 45.989383335544) + (7.011649357089, 45.984682829249) + (7.016349863384, 45.984682829249) + (7.021050369679, 45.984682829249) + (7.021050369679, 45.979982322953) + (7.021050369679, 45.975281816658) + (7.016349863384, 45.975281816658) + (7.011649357089, 45.975281816658) + (7.011649357089, 45.970581310363) + (7.011649357089, 45.965880804068) + (7.016349863384, 45.965880804068) + (7.016349863384, 45.961180297773) + (7.021050369679, 45.961180297773) + (7.025750875974, 45.961180297773) + (7.025750875974, 45.956479791477) + (7.030451382269, 45.956479791477) + (7.035151888565, 45.956479791477) + (7.035151888565, 45.951779285182) + (7.035151888565, 45.947078778887) + (7.035151888565, 45.942378272592) + (7.035151888565, 45.937677766297) + (7.03985239486, 45.937677766297) + (7.03985239486, 45.932977260001) + (7.03985239486, 45.928276753706) + (7.044552901155, 45.928276753706) + (7.044552901155, 45.923576247411) + (7.044552901155, 45.918875741116) + (7.04925340745, 45.918875741116) + (7.04925340745, 45.91417523482) + (7.053953913745, 45.91417523482) + (7.058654420041, 45.91417523482) + (7.063354926336, 45.91417523482) + (7.063354926336, 45.909474728525) + (7.063354926336, 45.90477422223) + (7.063354926336, 45.900073715935) + (7.068055432631, 45.900073715935) + (7.068055432631, 45.89537320964) + (7.072755938926, 45.89537320964) + (7.077456445222, 45.89537320964) + (7.077456445222, 45.890672703344) + (7.077456445222, 45.885972197049) + (7.082156951517, 45.885972197049) + (7.082156951517, 45.881271690754) + (7.086857457812, 45.881271690754) + (7.091557964107, 45.881271690754) + (7.091557964107, 45.876571184459) + (7.091557964107, 45.871870678164) + (7.096258470402, 45.871870678164) + (7.096258470402, 45.867170171868) + (7.096258470402, 45.862469665573) + (7.100958976698, 45.862469665573) + (7.100958976698, 45.857769159278) + (7.105659482993, 45.857769159278) + (7.110359989288, 45.857769159278) + (7.115060495583, 45.857769159278) + (7.119761001878, 45.857769159278) + (7.119761001878, 45.862469665573) + (7.124461508174, 45.862469665573) + (7.129162014469, 45.862469665573) + (7.129162014469, 45.867170171868) + (7.133862520764, 45.867170171868) + (7.133862520764, 45.871870678164) +```` + Here is the boundary. -````@example refinement +````julia boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) rng = StableRNG(789) tri = triangulate(points; boundary_nodes, rng) @@ -264,25 +5494,45 @@ fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + Now let's refine. -````@example refinement +````julia A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.001A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) +```` + +```` +Delaunay Triangulation. + Number of vertices: 14165 + Number of triangles: 23178 + Number of edges: 37342 + Has boundary nodes: true + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: true ```` -````@example refinement +````julia fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + We see that the triangulation is now adequately refined. There are still triangles near the boundaries whose minimum angle is less than 30 degrees, though, because of the angles that boundary edges meet at in some places. Most of the triangles will satisfy the constraint, though, as we show below. -````@example refinement +````julia stats = statistics(tri) angles = first.(get_all_stat(stats, :angles)) # the first is the smallest fig, ax, sc = scatter(rad2deg.(angles)) @@ -290,14 +5540,18 @@ hlines!(ax, [30.0], color = :red, linewidth = 4) fig ```` +```@raw html + +``` + As we can see, the vast majority of the triangles satisfy the constraint, but there are still some that do not. Here is another set of results with a lower minimum angle constraint. -````@example refinement +````julia boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) rng = StableRNG(789) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=18.73, max_area=0.001A, rng) +refine!(tri; min_angle = 18.73, max_area = 0.001A, rng) fig = Figure(fontsize = 43) ax = Axis(fig[1, 1], width = 600, height = 400) triplot!(tri) @@ -310,8 +5564,13 @@ resize_to_layout!(fig) fig ```` +```@raw html + +``` + In this case, all the triangles satisfy the constraint, of course at the expense of some other triangles having lesser quality. + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/refinement.jl). @@ -328,35 +5587,35 @@ points = tuple.(x, y) tri = triangulate(points; rng) orig_tri = deepcopy(tri) A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.01A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.01A, rng) statistics(tri) -fig, ax, sc = triplot(orig_tri, axis=(title="Pre-refinement",)) -ax = Axis(fig[1, 2], title="Post-refinement") +fig, ax, sc = triplot(orig_tri, axis = (title = "Pre-refinement",)) +ax = Axis(fig[1, 2], title = "Post-refinement") triplot!(ax, tri) fig -refine!(tri; min_angle=30.0, max_area=0.001A, rng) # 0.1% instead of 1% +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) # 0.1% instead of 1% fig, ax, sc = triplot(tri) fig test_tri = deepcopy(tri) -refine!(test_tri; min_angle=35.0, max_area=0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going +refine!(test_tri; min_angle = 35.0, max_area = 0.001A, max_points = 5_000, rng) # 20_000 so that it doesn't just keep going statistics(test_tri) fig, ax, sc = triplot(test_tri) fig stats = statistics(tri) -fig = Figure(fontsize=33) +fig = Figure(fontsize = 33) areas = get_all_stat(stats, :area) ./ A angles = first.(get_all_stat(stats, :angles)) # the first is the smallest -ax = Axis(fig[1, 1], xlabel="A/A(Ω)", ylabel="Count", title="Area histogram", width=400, height=400, titlealign=:left) -hist!(ax, areas, bins=0:0.0001:0.0005) -ax = Axis(fig[1, 2], xlabel="θₘᵢₙ", ylabel="Count", title="Angle histogram", width=400, height=400, titlealign=:left) -hist!(ax, rad2deg.(angles), bins=20:2:60) -vlines!(ax, [30.0], color=:red) +ax = Axis(fig[1, 1], xlabel = "A/A(Ω)", ylabel = "Count", title = "Area histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, areas, bins = 0:0.0001:0.0005) +ax = Axis(fig[1, 2], xlabel = "θₘᵢₙ", ylabel = "Count", title = "Angle histogram", width = 400, height = 400, titlealign = :left) +hist!(ax, rad2deg.(angles), bins = 20:2:60) +vlines!(ax, [30.0], color = :red) resize_to_layout!(fig) fig @@ -379,11 +5638,11 @@ fig, ax, sc = triplot(tri) fig A = get_area(tri) -refine!(tri; min_angle=27.3, max_area=0.01A, rng) +refine!(tri; min_angle = 27.3, max_area = 0.01A, rng) fig, ax, sc = triplot(tri) fig -refine!(tri; min_angle=33.9, max_area=0.001A, rng) +refine!(tri; min_angle = 33.9, max_area = 0.001A, rng) fig, ax, sc = triplot(tri) fig @@ -407,7 +5666,7 @@ end boundary_nodes, points = convert_boundary_points_to_indices(x, y) rng = StableRNG(456) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=30.0, custom_constraint=area_constraint, rng) +refine!(tri; min_angle = 30.0, custom_constraint = area_constraint, rng) fig, ax, sc = triplot(tri) fig @@ -431,7 +5690,7 @@ using Downloads using DelimitedFiles boundary_url = "https://gist.githubusercontent.com/DanielVandH/13687b0918e45a416a5c93cd52c91449/raw/a8da6cdc94859fd66bcff85a2307f0f9cd57a18c/boundary.txt" boundary_dir = Downloads.download(boundary_url) -boundary = readdlm(boundary_dir, skipstart=6) +boundary = readdlm(boundary_dir, skipstart = 6) boundary_points = [(boundary[i, 1], boundary[i, 2]) for i in axes(boundary, 1)] reverse!(boundary_points) @@ -442,7 +5701,7 @@ fig, ax, sc = triplot(tri) fig A = get_area(tri) -refine!(tri; min_angle=30.0, max_area=0.001A, rng) +refine!(tri; min_angle = 30.0, max_area = 0.001A, rng) fig, ax, sc = triplot(tri) fig @@ -456,7 +5715,7 @@ fig boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) rng = StableRNG(789) tri = triangulate(points; boundary_nodes, rng) -refine!(tri; min_angle=18.73, max_area=0.001A, rng) +refine!(tri; min_angle = 18.73, max_area = 0.001A, rng) fig = Figure(fontsize = 43) ax = Axis(fig[1, 1], width = 600, height = 400) triplot!(tri) diff --git a/docs/src/tutorials/unconstrained.md b/docs/src/tutorials/unconstrained.md index 0a4ccb3ee..5bf7b0b7b 100644 --- a/docs/src/tutorials/unconstrained.md +++ b/docs/src/tutorials/unconstrained.md @@ -8,7 +8,7 @@ Our first example considers constructing unconstrained Delaunay triangulations. To start, let us load in the packages we will need. -````@example unconstrained +````julia using DelaunayTriangulation using CairoMakie # for plotting using StableRNGs # for reproducibility @@ -18,31 +18,53 @@ using LinearAlgebra # used for computing norms later We consider just triangulating a random set of points. First, generating the points: -````@example unconstrained +````julia rng = StableRNG(123) points = rand(rng, 2, 500) # just do rand(2, 500) if you are not concerned about the RNG ```` +```` +2×500 Matrix{Float64}: + 0.181026 0.669058 0.437991 0.763974 0.515045 0.70134 0.876273 0.739213 0.506876 0.266373 0.351618 0.721093 0.637996 0.363447 0.455205 0.348518 0.809794 0.223906 0.61295 0.329471 0.540632 0.223046 0.539128 0.419776 0.458012 0.687042 0.15147 0.785806 0.336894 0.343754 0.418788 0.256693 0.0639703 0.331352 0.244427 0.425703 0.491863 0.776779 0.360371 0.00263946 0.340133 0.270424 0.115997 0.813952 0.421372 0.722946 0.552395 0.797896 0.523122 0.288461 0.545081 0.437921 0.304731 0.89046 0.637476 0.813697 0.69858 0.151131 0.793309 0.329285 0.562948 0.0815702 0.279641 0.817653 0.801687 0.695043 0.307854 0.377544 0.558266 0.824428 0.796442 0.154541 0.0800997 0.691939 0.167874 0.933698 0.93185 0.791387 0.82006 0.708238 0.95372 0.753526 0.74857 0.659175 0.209896 0.196745 0.127467 0.524392 0.0829614 0.700979 0.134585 0.00688858 0.51353 0.24561 0.163308 0.435777 0.918945 0.166482 0.0568971 0.406672 0.527439 0.4354 0.21018 0.43972 0.301404 0.583691 0.874586 0.387704 0.350605 0.502661 0.582974 0.151539 0.276187 0.880838 0.152898 0.277676 0.549405 0.163404 0.129285 0.131234 0.196663 0.80264 0.869203 0.112288 0.110314 0.458535 0.784782 0.250383 0.917494 0.488987 0.54606 0.185561 0.995848 0.762547 0.308271 0.510413 0.178851 0.634063 0.931508 0.213869 0.183094 0.532255 0.625907 0.65799 0.628808 0.799758 0.481242 0.940936 0.881986 0.374775 0.374894 0.69412 0.932955 0.764663 0.101373 0.74717 0.905268 0.646034 0.230818 0.736922 0.327148 0.624086 0.978315 0.676679 0.675824 0.76549 0.310209 0.0560602 0.977099 0.400777 0.385446 0.153937 0.628224 0.0259813 0.556082 0.00130711 0.587556 0.521749 0.362642 0.517127 0.755883 0.153261 0.199942 0.301887 0.828024 0.0927618 0.622874 0.207796 0.022725 0.234718 0.1874 0.559458 0.402361 0.737495 0.100388 0.394142 0.796617 0.491243 0.435373 0.676698 0.601822 0.912472 0.65373 0.800586 0.665684 0.656845 0.925526 0.733754 0.106838 0.828335 0.431333 0.00736147 0.921623 0.507653 0.971479 0.269747 0.817207 0.215851 0.609782 0.711618 0.226012 0.539521 0.261726 0.66208 0.899939 0.876967 0.284227 0.351236 0.965389 0.949363 0.237952 0.998855 0.315107 0.0404263 0.675675 0.310525 0.791587 0.0233863 0.0955889 0.896359 0.762741 0.828236 0.769262 0.47533 0.063996 0.755876 0.973318 0.146077 0.770016 0.61136 0.263433 0.94654 0.906265 0.827459 0.966827 0.489265 0.987065 0.824262 0.288757 0.30942 0.195225 0.324369 0.529757 0.212361 0.900904 0.88208 0.511181 0.751019 0.420527 0.883097 0.219401 0.323676 0.637138 0.118389 0.868121 0.409298 0.270215 0.453449 0.123123 0.811252 0.389822 0.145426 0.820001 0.257654 0.135927 0.709894 0.462429 0.446925 0.856169 0.806983 0.881146 0.974744 0.167324 0.955413 0.967742 0.341459 0.958273 0.858018 0.621369 0.456395 0.503465 0.323223 0.0752862 0.955472 0.52896 0.902039 0.357986 0.237799 0.571431 0.834022 0.176041 0.788659 0.29665 0.554148 0.644947 0.954224 0.776911 0.620958 0.00291754 0.095197 0.0210285 0.664658 0.762682 0.484171 0.921929 0.901151 0.668319 0.262004 0.386269 0.436472 0.824224 0.683262 0.340386 0.117477 0.733987 0.442351 0.989014 0.978268 0.1671 0.330902 0.741137 0.554488 0.548208 0.616783 0.972508 0.266814 0.170246 0.410809 0.262931 0.755769 0.422182 0.604407 0.817767 0.974785 0.955647 0.739929 0.320489 0.62935 0.21621 0.272473 0.601508 0.414413 0.804268 0.196294 0.974554 0.583934 0.335481 0.539881 0.300205 0.337433 0.0202547 0.296958 0.494453 0.11217 0.0715926 0.564346 0.571969 0.53193 0.157119 0.289274 0.388633 0.779599 0.911604 0.117072 0.898052 0.462633 0.761786 0.505131 0.467784 0.0493592 0.0923198 0.0449557 0.135861 0.635555 0.909697 0.613948 0.279111 0.857699 0.00524744 0.120045 0.429042 0.0882701 0.193549 0.398813 0.610383 0.401103 0.53577 0.170252 0.872609 0.438583 0.750883 0.865202 0.266392 0.711303 0.637627 0.089177 0.410576 0.303547 0.894829 0.125559 0.473098 0.464572 0.806659 0.221016 0.0280905 0.810146 0.00827066 0.804782 0.0616697 0.941801 0.250919 0.237675 0.823915 0.541156 0.720895 0.803985 0.0786536 0.236702 0.956706 0.640619 0.958435 0.82819 0.882578 0.597655 0.564413 0.837944 0.418879 0.53278 0.818377 0.975019 0.382218 0.0698097 0.459689 0.236278 0.235126 0.0313331 0.537227 0.263279 0.460627 0.473966 0.944432 0.623716 0.785133 0.0120468 0.603183 0.0428481 0.145068 0.989866 0.413146 0.47412 0.762582 0.761679 0.968606 0.667712 0.253657 0.713645 0.181444 0.521983 0.0227201 0.0828667 0.259405 0.959931 0.42234 0.875965 0.353899 0.927026 0.62526 0.596537 0.973425 0.941601 0.0438116 0.911062 0.739358 0.864538 0.699831 0.400533 0.337066 0.459817 0.312727 0.0634304 + 0.36749 0.0427306 0.48329 0.924483 0.495042 0.693569 0.944219 0.559545 0.646024 0.253141 0.527389 0.188512 0.427843 0.577647 0.16582 0.737079 0.171167 0.848205 0.952542 0.918373 0.820474 0.598776 0.619535 0.453259 0.836069 0.353959 0.703671 0.551635 0.710355 0.405438 0.346188 0.157176 0.596071 0.0965347 0.128071 0.926538 0.134549 0.597526 0.034642 0.604342 0.0888438 0.290691 0.847073 0.0601803 0.679816 0.737598 0.970875 0.683298 0.855341 0.431233 0.638433 0.775729 0.745173 0.139747 0.856516 0.777063 0.152194 0.324202 0.0924124 0.00563978 0.579165 0.450706 0.0560835 0.50384 0.65171 0.389672 0.381893 0.7932 0.707537 0.515592 0.327837 0.817693 0.0475871 0.819659 0.125727 0.493807 0.311002 0.765118 0.521854 0.0734049 0.17116 0.90863 0.66635 0.63634 0.221245 0.241482 0.478185 0.390411 0.0617778 0.648669 0.308804 0.541835 0.428168 0.496737 0.545666 0.911066 0.0662768 0.649396 0.760846 0.248483 0.401041 0.0396139 0.900348 0.939905 0.873122 0.80144 0.0770524 0.506864 0.428658 0.121242 0.638559 0.974467 0.639326 0.835716 0.207941 0.592121 0.506314 0.186599 0.794883 0.802221 0.160557 0.191487 0.481045 0.0205251 0.751321 0.692231 0.0247294 0.521179 0.42381 0.890044 0.341701 0.48763 0.457178 0.452692 0.724959 0.192477 0.55463 0.513373 0.739426 0.00516507 0.42228 0.409429 0.843826 0.829954 0.53278 0.345138 0.571183 0.509987 0.33359 0.358201 0.0316704 0.686877 0.0452453 0.633021 0.100261 0.801601 0.203674 0.930138 0.222399 0.889327 0.93828 0.387938 0.0555843 0.348795 0.339641 0.294326 0.362177 0.876946 0.569376 0.550425 0.561675 0.154164 0.152203 0.36556 0.111442 0.735052 0.389202 0.886379 0.15633 0.144373 0.237032 0.145793 0.45279 0.0372542 0.440216 0.18769 0.692835 0.808651 0.622941 0.854403 0.373967 0.186052 0.246232 0.579073 0.1812 0.852832 0.999781 0.989092 0.776308 0.423385 0.843372 0.674218 0.1239 0.313695 0.38427 0.559683 0.207026 0.745099 0.331923 0.138651 0.0398031 0.391087 0.840941 0.487405 0.140799 0.904586 0.210664 0.543117 0.999184 0.260491 0.637879 0.154327 0.428806 0.533854 0.584642 0.63172 0.205341 0.473755 0.813529 0.46243 0.534511 0.361381 0.158313 0.151782 0.189559 0.036348 0.645382 0.865508 0.857054 0.529265 0.726127 0.417632 0.103866 0.97594 0.00780044 0.2739 0.930787 0.410755 0.676963 0.0768056 0.762454 0.868867 0.558984 0.736597 0.114093 0.867234 0.482919 0.0028658 0.309163 0.904961 0.828557 0.986628 0.199129 0.567569 0.977771 0.575212 0.401379 0.831577 0.0412443 0.459265 0.82129 0.0788373 0.0171894 0.853996 0.154636 0.062491 0.165524 0.091407 0.448646 0.0171893 0.0980491 0.855286 0.214436 0.1485 0.151223 0.751848 0.239441 0.27903 0.48538 0.00820996 0.560848 0.669526 0.014872 0.133648 0.057047 0.8933 0.401493 0.53216 0.800628 0.380869 0.507253 0.308986 0.952318 0.634803 0.262183 0.826332 0.132768 0.325102 0.407019 0.901277 0.0935133 0.835246 0.069461 0.122496 0.283896 0.486517 0.719179 0.0950475 0.0327314 0.0761925 0.433444 0.0667151 0.0517945 0.194546 0.0116186 0.633291 0.319646 0.455837 0.0323374 0.39123 0.72488 0.366719 0.930497 0.840097 0.560529 0.462569 0.374708 0.683058 0.150342 0.728512 0.0959656 0.286593 0.903991 0.196968 0.989066 0.199721 0.502435 0.14738 0.265107 0.0416473 0.114756 0.0747264 0.170444 0.747839 0.311876 0.497515 0.970706 0.429969 0.940689 0.0109684 0.674098 0.889181 0.642075 0.132777 0.103044 0.00559392 0.917282 0.645921 0.181392 0.76393 0.936732 0.388988 0.56209 0.929056 0.498177 0.707023 0.344282 0.919879 0.284647 0.632842 0.910668 0.0279172 0.328333 0.455078 0.370364 0.58211 0.803457 0.082038 0.861727 0.640028 0.705404 0.15266 0.896605 0.391123 0.420594 0.115443 0.43585 0.00436228 0.152666 0.933136 0.858691 0.0127729 0.964708 0.610086 0.136407 0.892495 0.815915 0.0629032 0.761915 0.17202 0.528866 0.537323 0.0417917 0.20407 0.705418 0.954324 0.576491 0.642704 0.800022 0.564916 0.195492 0.485029 0.0980802 0.0581283 0.960441 0.0577736 0.738122 0.604437 0.0428863 0.894244 0.96158 0.262416 0.573678 0.831426 0.32834 0.494434 0.375363 0.308775 0.964644 0.092962 0.534357 0.230757 0.811912 0.300044 0.614219 0.986509 0.770094 0.321493 0.549143 0.277844 0.929055 0.88323 0.0785272 0.872782 0.303657 0.962391 0.310815 0.47404 0.865449 0.815715 0.934553 0.534671 0.535503 0.458238 0.66025 0.206327 0.349035 0.980125 0.415568 0.171304 0.683687 0.414906 0.317704 0.818032 0.235651 0.0368418 0.0666789 0.813251 0.860372 0.189548 0.222904 0.550917 0.271007 0.0716159 0.188967 0.862459 0.933695 0.554072 0.827465 0.0370543 0.836151 0.0143462 0.494221 0.638122 0.395067 0.175565 0.942264 0.0794176 0.892313 0.606559 +```` + We now triangulate these points by using [`triangulate`](@ref). We pass the `rng` as a keyword argument, but again if you are not concerned about the RNG (or set the seed using `Random.seed!`) then you can ignore this. -````@example unconstrained -tri = triangulate(points; rng=rng) +````julia +tri = triangulate(points; rng = rng) +```` + +```` +Delaunay Triangulation. + Number of vertices: 500 + Number of triangles: 980 + Number of edges: 1479 + Has boundary nodes: false + Has ghost triangles: true + Curve-bounded: false + Weighted: false + Constrained: false ```` -````@example unconstrained +````julia fig, ax, sc = triplot(tri) fig ```` +```@raw html + +``` + This `tri` object is our [`Triangulation`](@ref), and we can interact with it in many ways. ## Iterating over vertices For example, we can iterate over the points in the triangulation using [`each_solid_vertex`](@ref). Here we compute the centroid of the point cloud: -````@example unconstrained +````julia function compute_centroid(tri) s = [0.0, 0.0] for i in each_solid_vertex(tri) @@ -55,35 +77,572 @@ end s = compute_centroid(tri) ```` +```` +2-element Vector{Float64}: + 0.5106629621450203 + 0.477077379328767 +```` + We need to use the `solid` identifier because triangulations are made up of both _solid_ and _ghost_ vertices/edges/triangles, for reasons described in the [manual](../manual/ghost_triangles.md). If we just use [`each_vertex(tri)`](@ref each_vertex), then we also find a vertex `-1` that corresponds to the boundary. For example, the points on the boundary can be obtained using: -````@example unconstrained +````julia get_neighbours(tri, -1) ```` +```` +Set{Int64} with 18 elements: + 456 + 176 + 425 + 258 + 325 + 398 + 197 + 219 + 319 + 262 + 112 + 345 + 371 + 232 + 245 + 163 + 468 + 140 +```` + One reason to be careful with this especially is that `get_point(tri, -1)` does actually correspond to a coordinate, -````@example unconstrained +````julia get_point(tri, -1) ```` +```` +(0.500547641525688, 0.497711096515429) +```` + (This is the pole of inaccessibility for the domain; see [here](../tutorials/pole_of_inaccessibility.md) for more details.) You can use [`each_vertex`](@ref) or [`each_ghost_vertex`](@ref) to consider all types of vertices or only the ghost vertices. If you just want the vertices, use `each_vertex(tri)`, which will also include the ghost vertex. -````@example unconstrained +````julia each_vertex(tri) ```` +```` +Set{Int64} with 501 elements: + 319 + 185 + 420 + 365 + 422 + 263 + 242 + 183 + 224 + 177 + 77 + 172 + 103 + 59 + 211 + 358 + 366 + 414 + 116 + 79 + 279 + 485 + 46 + 152 + 250 + 448 + 438 + 436 + 454 + 154 + 206 + 500 + 40 + 245 + 325 + 145 + 444 + 342 + 457 + 460 + 351 + 158 + 92 + 118 + 162 + 494 + 93 + 304 + 18 + 349 + 368 + 217 + 61 + 412 + 212 + 474 + 223 + 285 + 198 + 331 + 80 + 51 + 490 + 143 + 330 + 284 + 419 + 367 + 186 + 90 + 456 + 316 + 179 + 52 + 369 + 356 + 487 + 85 + 406 + 10 + 261 + 484 + 340 + 329 + 466 + 241 + 236 + 190 + 14 + 357 + 403 + 123 + 305 + 197 + 233 + 196 + 408 + 324 + 54 + 327 + 62 + 205 + 483 + 122 + 58 + 385 + 321 + 318 + 87 + 317 + 248 + 202 + 455 + 160 + 289 + 49 + 396 + 131 + 373 + 53 + 492 + 286 + 181 + 446 + 56 + 429 + 425 + 60 + 220 + 308 + 67 + 215 + 404 + 168 + 431 + 364 + 479 + 75 + 111 + 66 + 280 + 374 + 141 + 278 + 477 + 450 + 135 + 138 + 107 + 170 + 238 + 22 + 391 + 288 + 400 + 113 + 283 + 309 + 55 + 265 + 136 + 117 + 218 + 28 + 84 + 203 + 353 + 292 + 232 + 240 + 147 + 415 + 146 + 390 + 380 + 424 + 193 + 226 + 488 + 17 + 271 + 335 + 426 + 89 + 214 + 48 + 493 + 134 + 473 + 253 + 64 + 394 + 410 + 486 + 300 + 171 + 478 + 216 + 108 + 382 + 2 + 27 + 124 + 273 + 312 + 290 + 20 + 81 + 398 + 9 + 189 + 409 + 249 + 395 + 372 + 88 + 260 + 37 + 121 + 311 + 281 + 174 + 496 + 322 + 269 + 262 + 320 + 151 + 244 + 434 + 277 + 377 + 34 + 50 + 243 + 194 + 301 + 458 + -1 + 106 + 102 + 259 + 379 + 21 + 440 + 192 + 362 + 47 + 407 + 178 + 387 + 306 + 472 + 155 + 293 + 499 + 73 + 251 + 115 + 112 + 86 + 207 + 465 + 430 + 23 + 264 + 41 + 68 + 130 + 125 + 339 + 336 + 343 + 468 + 100 + 230 + 195 + 388 + 222 + 276 + 381 + 247 + 184 + 1 + 435 + 137 + 427 + 237 + 270 + 33 + 254 + 482 + 165 + 142 + 416 + 5 + 45 + 418 + 449 + 282 + 393 + 437 + 148 + 36 + 7 + 95 + 25 + 296 + 476 + 341 + 287 + 19 + 44 + 266 + 31 + 29 + 303 + 159 + 463 + 101 + 360 + 462 + 246 + 97 + 402 + 413 + 110 + 30 + 234 + 272 + 182 + 164 + 470 + 267 + 4 + 359 + 328 + 69 + 11 + 119 + 495 + 307 + 144 + 257 + 352 + 200 + 187 + 213 + 227 + 109 + 445 + 453 + 498 + 120 + 297 + 24 + 464 + 433 + 447 + 314 + 480 + 315 + 268 + 497 + 32 + 471 + 239 + 191 + 150 + 199 + 361 + 98 + 411 + 310 + 169 + 180 + 428 + 347 + 375 + 332 + 229 + 163 + 467 + 338 + 3 + 96 + 35 + 348 + 417 + 333 + 376 + 12 + 82 + 71 + 208 + 26 + 127 + 389 + 295 + 57 + 475 + 397 + 129 + 78 + 133 + 72 + 258 + 252 + 313 + 354 + 299 + 345 + 231 + 432 + 114 + 337 + 275 + 363 + 378 + 176 + 469 + 451 + 157 + 392 + 16 + 370 + 489 + 74 + 228 + 105 + 399 + 421 + 166 + 274 + 15 + 6 + 219 + 153 + 139 + 13 + 405 + 104 + 302 + 43 + 39 + 443 + 126 + 441 + 156 + 439 + 346 + 344 + 294 + 481 + 161 + 383 + 401 + 209 + 323 + 8 + 83 + 201 + 99 + 491 + 386 + 461 + 334 + 423 + 210 + 63 + 91 + 173 + 256 + 188 + 355 + 235 + 204 + 384 + 371 + 76 + 167 + 42 + 132 + 140 + 442 + 255 + 291 + 452 + 94 + 225 + 128 + 70 + 350 + 38 + 326 + 221 + 175 + 459 + 149 + 65 + 298 +```` + ## Iterating over edges We can also iterate over the edges of the triangulation using [`each_solid_edge`](@ref), or [`each_edge`](@ref) for both solid and ghost edges and [`each_ghost_edge`](@ref) for only the ghost edges. To give an example, here we compute the average length of an edge. -````@example unconstrained +````julia function compute_mean_edge_length(tri) ℓ = 0.0 for e in each_solid_edge(tri) @@ -97,12 +656,1517 @@ end ℓ = compute_mean_edge_length(tri) ```` +```` +0.05645693808033534 +```` + By default, the triangulation has ghost edges, so [`each_edge`](@ref) and [`each_solid_edge`](@ref) are not the same. -````@example unconstrained +````julia each_edge(tri) ```` +```` +Set{Tuple{Int64, Int64}} with 1497 elements: + (453, 388) + (276, 329) + (17, 12) + (382, 127) + (4, 197) + (366, 352) + (34, 313) + (407, 106) + (114, 56) + (194, 90) + (263, 136) + (498, 388) + (345, 446) + (343, 47) + (375, 33) + (412, 433) + (292, 304) + (290, 127) + (274, 334) + (427, 176) + (29, 16) + (435, 472) + (124, 320) + (424, 311) + (272, 41) + (63, 413) + (458, 50) + (208, 156) + (404, 171) + (94, 132) + (261, 103) + (229, 139) + (250, 352) + (358, 117) + (412, 240) + (237, 363) + (196, 199) + (55, 158) + (11, 228) + (149, 442) + (299, 286) + (451, 36) + (217, 353) + (241, 471) + (338, 139) + (379, 186) + (410, 496) + (167, 30) + (359, 403) + (452, 371) + (112, -1) + (372, 223) + (480, 195) + (322, 80) + (138, 145) + (277, 284) + (219, 19) + (243, 57) + (24, 336) + (271, 18) + (262, 244) + (140, 413) + (116, 128) + (183, 328) + (312, 82) + (296, 499) + (235, 173) + (239, 274) + (43, 334) + (78, 156) + (150, 483) + (34, 284) + (26, 165) + (494, 65) + (273, 322) + (234, 392) + (356, 224) + (346, 159) + (381, 406) + (262, 198) + (481, 159) + (345, 439) + (423, 210) + (6, 83) + (255, 97) + (154, 38) + (82, 160) + (282, 261) + (147, 9) + (402, 73) + (170, 171) + (445, 23) + (468, -1) + (230, 316) + (11, 14) + (115, 186) + (175, 110) + (24, 228) + (442, 246) + (466, 480) + (248, 191) + (122, 17) + (292, 338) + (430, 252) + (447, 68) + (410, 348) + (48, 249) + (272, 236) + (20, 333) + (174, 212) + (71, 435) + (452, 374) + (300, 93) + (491, 334) + (221, 135) + (279, 132) + (26, 435) + (74, 286) + (44, 484) + (370, 53) + (402, 293) + (19, 47) + (422, 170) + (129, 270) + (483, 193) + (317, 471) + (216, 260) + (195, 186) + (448, 288) + (300, 88) + (36, 406) + (230, 133) + (93, 117) + (104, 36) + (99, 491) + (327, 315) + (474, 144) + (140, 360) + (199, 68) + (279, 384) + (497, 357) + (247, 252) + (423, 44) + (202, 226) + (78, 317) + (296, 406) + (450, 473) + (184, 313) + (438, 42) + (74, 156) + (294, 215) + (447, 16) + (338, 468) + (443, 56) + (354, 139) + (381, 367) + (61, 117) + (480, 392) + (308, 191) + (97, 484) + (160, 268) + (386, 404) + (136, 180) + (369, 227) + (143, 144) + (245, 140) + (89, 124) + (181, 414) + (3, 336) + (6, 286) + (130, 389) + (148, 316) + (155, 320) + (336, 330) + (183, 141) + (151, 281) + (243, 12) + (496, 348) + (60, 366) + (457, 288) + (109, 469) + (452, 303) + (62, 464) + (10, 227) + (371, 479) + (130, 244) + (495, 472) + (254, 78) + (121, 118) + (282, 72) + (461, 7) + (316, 257) + (24, 469) + (478, 460) + (371, 168) + (108, 3) + (291, 266) + (321, 464) + (84, 206) + (279, 141) + (481, 346) + (179, 307) + (106, 376) + (225, 266) + (292, 169) + (412, 291) + (213, 306) + (74, 160) + (280, 426) + (245, 402) + (273, 290) + (390, 500) + (122, 353) + (452, 168) + (220, 315) + (162, 164) + (91, 209) + (385, 297) + (405, 396) + (28, 411) + (273, 2) + (256, 25) + (240, 253) + (126, 45) + (373, 422) + (296, 367) + (129, 230) + (138, 358) + (260, 20) + (206, 462) + (167, 67) + (150, 469) + (488, 206) + (377, 162) + (235, 220) + (335, 206) + (255, 215) + (59, 423) + (350, 476) + (133, 468) + (487, 55) + (22, 116) + (155, 311) + (167, 308) + (42, 308) + (450, 77) + (354, 468) + (166, 435) + (345, 468) + (398, 325) + (350, 323) + (69, 106) + (113, 116) + (145, 462) + (441, 482) + (213, 114) + (215, 365) + (351, 278) + (309, 358) + (25, 389) + (493, 436) + (453, 102) + (322, 2) + (386, 45) + (461, 439) + (272, 313) + (385, 149) + (335, 411) + (345, 197) + (59, 44) + (233, 307) + (205, 200) + (255, 294) + (429, 319) + (499, 260) + (41, 281) + (459, 401) + (215, 232) + (64, 436) + (138, 224) + (11, 458) + (480, 379) + (324, 136) + (318, 352) + (189, 500) + (97, 295) + (493, 134) + (420, 95) + (113, 380) + (316, 76) + (231, 264) + (344, 405) + (476, 127) + (456, 371) + (377, 342) + (119, 72) + (115, 118) + (354, 489) + (447, 52) + (428, 363) + (276, 281) + (486, 310) + (452, 393) + (160, 144) + (377, 444) + (223, 141) + (378, 130) + (489, 468) + (309, 177) + (213, 252) + (370, 105) + (59, 323) + (434, 478) + (437, 212) + (450, 232) + (312, 310) + (109, 50) + (273, 250) + (339, 118) + (432, 86) + (208, 241) + (154, 83) + (414, 220) + (310, 114) + (120, 72) + (96, 362) + (195, 118) + (466, 234) + (499, 20) + (289, 70) + (16, 68) + (370, 68) + (261, 188) + (160, 55) + (23, 9) + (15, 421) + (383, 385) + (373, 117) + (48, 471) + (302, 483) + (480, 186) + (256, 49) + (64, 79) + (494, 266) + (43, 274) + (313, 236) + (438, 308) + (368, 111) + (28, 433) + (173, 405) + (298, 449) + (283, 353) + (175, 396) + (130, 96) + (225, 482) + (306, 229) + (182, 285) + (105, 68) + (279, 437) + (324, 470) + (322, 250) + (340, 135) + (63, 184) + (76, 270) + (499, 216) + (84, 415) + (237, 249) + (147, 422) + (157, 207) + (219, 197) + (461, 247) + (42, 455) + (446, 265) + (103, 393) + (245, 429) + (205, 164) + (382, 426) + (33, 92) + (194, 206) + (328, 223) + (439, 468) + (51, 111) + (163, -1) + (370, 16) + (181, 283) + (466, 91) + (62, 384) + (445, 51) + (194, 154) + (132, 87) + (335, 224) + (254, 409) + (273, 366) + (177, 131) + (46, 286) + (216, 103) + (104, 130) + (78, 387) + (410, 193) + (493, 224) + (330, 31) + (370, 251) + (214, 422) + (116, 418) + (79, 449) + (175, 405) + (54, 107) + (87, 384) + (1, 467) + (456, 303) + (326, 202) + (105, 190) + (298, 289) + (80, 341) + (45, 9) + (85, 159) + (54, 97) + (181, 442) + (150, 330) + (138, 117) + (312, 268) + (91, 58) + (201, 343) + (133, 337) + (185, 289) + (408, 477) + (22, 221) + (105, 251) + (420, 33) + (80, 476) + (185, 270) + (17, 353) + (35, 313) + (60, 140) + (55, 144) + (69, 368) + (448, 131) + (432, 10) + (113, 221) + (378, 178) + (69, 376) + (242, 270) + (100, 410) + (80, 323) + (189, 390) + (340, 29) + (488, 84) + (487, 19) + (437, 467) + (84, 187) + (163, 295) + (470, 37) + (90, 83) + (420, 87) + (420, 137) + (99, 125) + (378, 47) + (309, 117) + (445, 61) + (137, 347) + (54, 210) + (425, 371) + (473, 232) + (429, 234) + (473, 297) + (19, 158) + (415, 187) + (237, 428) + (248, 141) + (267, 93) + (496, 193) + (25, 460) + (487, 201) + (464, 212) + (358, 13) + (307, 281) + (333, 367) + (191, 223) + (472, 134) + (301, 214) + (296, 20) + (476, 290) + (262, 497) + (67, 30) + (205, 66) + (22, 113) + (194, 335) + (457, 131) + (75, 182) + (222, 180) + (267, 88) + (299, 106) + (258, -1) + (279, 248) + (243, 17) + (53, 135) + (279, 87) + (436, 289) + (35, 284) + (307, 348) + (476, 2) + (461, 430) + (175, 388) + (48, 65) + (277, 32) + (243, 59) + (474, 286) + (242, 385) + (157, 275) + (28, 38) + (345, -1) + (438, 455) + (181, 246) + (208, 78) + (104, 451) + (456, 425) + (256, 130) + (397, 458) + (33, 500) + (40, 33) + (357, 431) + (332, 26) + (220, 246) + (465, 361) + (403, 431) + (95, 347) + (310, 82) + (263, 222) + (397, 50) + (76, 123) + (237, 154) + (250, 318) + (395, 297) + (283, 442) + (493, 200) + (93, 5) + (162, 165) + (4, 158) + (93, 142) + (238, 371) + (497, 333) + (278, 110) + (466, 209) + (211, 276) + (176, -1) + (369, 346) + (450, 355) + (32, 121) + (324, 287) + (377, 177) + (69, 9) + (361, 368) + (488, 117) + (361, 376) + (486, 213) + (219, 47) + (482, 253) + (287, 410) + (136, 470) + (240, 291) + (196, 296) + (387, 268) + (366, 388) + (443, 306) + (60, 360) + (322, 203) + (279, 62) + (301, 422) + (264, 116) + (419, 443) + (432, 475) + (494, 202) + (464, 92) + (302, 10) + (331, 254) + (298, 123) + (438, 58) + (148, 253) + (273, 352) + (357, 161) + (188, 251) + (138, 462) + (196, 401) + (359, 216) + (316, 441) + (451, 367) + (207, 77) + (64, 70) + (57, 80) + (27, 221) + (472, 146) + (471, 249) + (299, 143) + (11, 108) + (58, 209) + (169, 304) + (180, 37) + (340, 53) + (390, 391) + (58, 308) + (263, 305) + (172, 339) + (267, 300) + (113, 135) + (228, 458) + (197, 446) + (24, 3) + (489, 252) + (424, 140) + (107, 210) + (401, 362) + (351, 276) + (266, 253) + (481, 10) + (302, 259) + (456, 416) + (485, 233) + (400, 374) + (194, 84) + (228, 50) + (219, -1) + (478, 69) + (11, 171) + (344, 192) + (27, 119) + (100, 193) + (443, 114) + (147, 170) + (331, 202) + (54, 294) + (444, 327) + (463, 436) + (397, 223) + (331, 317) + (213, 229) + (376, 368) + (221, 251) + (35, 121) + (62, 437) + (470, 180) + (203, 173) + (378, 244) + (107, 423) + (454, 105) + (440, 203) + (25, 199) + (348, 281) + (419, 139) + (126, 52) + (140, 293) + (103, 403) + (490, 153) + (24, 108) + (236, 39) + (168, 491) + (14, 418) + (40, 399) + (463, 411) + (6, 90) + (424, 413) + (479, 168) + (89, 234) + (479, 491) + (371, 176) + (75, 364) + (321, 437) + (280, 44) + (162, 327) + (256, 178) + (199, 460) + (309, 101) + (375, 92) + (300, 288) + (248, 437) + (464, 375) + (446, 7) + (181, 220) + (336, 422) + (282, 103) + (394, 164) + (57, 12) + (299, 474) + (271, 188) + (222, 314) + (427, 390) + (107, 44) + (116, 14) + (27, 391) + (169, 338) + (98, 27) + (201, 106) + (353, 210) + (424, 477) + (238, 479) + (435, 146) + (158, 197) + (473, 355) + (34, 307) + (424, 63) + (93, 336) + (342, 305) + (288, 31) + (44, 426) + (153, 295) + (42, 10) + (238, 168) + (457, 305) + (465, 84) + (91, 379) + (299, 376) + (488, 462) + (285, 195) + (463, 79) + (230, 297) + (301, 117) + (241, 317) + (431, 161) + (327, 165) + (314, 180) + (432, 349) + (108, 170) + (450, 215) + (194, 38) + (454, 190) + (318, 396) + (17, 210) + (65, 363) + (266, 226) + (495, 134) + (185, 472) + (459, 362) + (167, 259) + (42, 259) + (124, 402) + (458, 128) + (84, 111) + (27, 188) + (200, 134) + (242, 472) + (104, 244) + (219, 198) + (74, 474) + (372, 30) + (264, 218) + (286, 156) + (481, 475) + (465, 187) + (82, 158) + (166, 71) + (42, 432) + (205, 13) + (368, 23) + (371, -1) + (58, 455) + (98, 500) + (284, 233) + (129, 395) + (61, 23) + (458, 328) + (63, 313) + (37, 110) + (140, -1) + (130, 459) + (211, 329) + (451, 333) + (399, 212) + (62, 87) + (407, 69) + (81, 450) + (58, 1) + (147, 386) + (11, 116) + (488, 111) + (404, 418) + (182, 172) + (60, 39) + (404, 45) + (148, 240) + (359, 103) + (41, 307) + (487, 343) + (289, 270) + (51, 23) + (266, 433) + (179, 233) + (188, 72) + (18, 190) + (369, 233) + (263, 192) + (202, 139) + (237, 65) + (230, 257) + (424, 364) + (201, 143) + (137, 218) + (248, 1) + (447, 199) + (258, 398) + (34, 272) + (94, 458) + (140, 258) + (311, 477) + (40, 176) + (417, 171) + (133, 338) + (428, 154) + (258, 290) + (125, 119) + (445, 488) + (235, 57) + (135, 418) + (466, 399) + (354, 338) + (50, 30) + (319, -1) + (400, 393) + (97, 365) + (211, 102) + (366, 102) + (335, 8) + (88, 101) + (492, 153) + (256, 389) + (15, 37) + (300, 31) + (250, 440) + (15, 348) + (220, 435) + (308, 1) + (60, 184) + (113, 418) + (155, 234) + (321, 62) + (200, 224) + (324, 421) + (485, 369) + (85, 86) + (354, 229) + (216, 431) + (485, 179) + (234, 319) + (25, 459) + (121, 159) + (89, 429) + (196, 105) + (398, 44) + (494, 363) + (39, 281) + (436, 356) + (125, 391) + (463, 28) + (342, 192) + (456, 112) + (330, 469) + (415, 286) + (400, 416) + (66, 435) + (243, 210) + (28, 449) + (340, 370) + (309, 142) + (340, 16) + (382, 476) + (85, 115) + (138, 13) + (147, 373) + (18, 261) + (285, 155) + (117, 5) + (350, 80) + (196, 68) + (273, 476) + (181, 122) + (466, 392) + (486, 7) + (49, 343) + (349, 10) + (382, 323) + (245, -1) + (152, 90) + (249, 83) + (230, 76) + (198, 378) + (81, 215) + (133, 169) + (15, 351) + (293, 477) + (325, -1) + (203, 396) + (243, 423) + (427, 391) + (287, 136) + (7, 265) + (154, 90) + (386, 417) + (220, 327) + (219, 158) + (137, 22) + (380, 418) + (198, 47) + (98, 390) + (419, 306) + (372, 67) + (453, 498) + (216, 161) + (208, 46) + (489, 229) + (262, 431) + (312, 56) + (235, 12) + (190, 251) + (388, 110) + (289, 123) + (20, 161) + (278, 276) + (403, 112) + (104, 96) + (409, 56) + (126, 9) + (462, 117) + (165, 164) + (81, 294) + (54, 157) + (184, 413) + (434, 201) + (203, 405) + (174, 209) + (35, 32) + (260, 161) + (42, 349) + (214, 5) + (243, 341) + (373, 23) + (388, 278) + (24, 109) + (455, 86) + (183, 223) + (421, 410) + (292, 202) + (287, 288) + (364, 339) + (153, 325) + (35, 424) + (352, 175) + (148, 76) + (298, 412) + (457, 377) + (428, 433) + (75, 339) + (194, 8) + (435, 246) + (15, 410) + (386, 9) + (288, 483) + (398, 492) + (478, 126) + (86, 159) + (209, 467) + (163, 365) + (408, 293) + (243, 323) + (3, 422) + (136, 222) + (174, 437) + (344, 342) + (225, 304) + (11, 128) + (344, 444) + (200, 495) + (465, 111) + (258, 366) + (416, 374) + (326, 304) + (408, 155) + (303, 371) + (163, 232) + (167, 372) + (409, 443) + (223, 50) + (64, 289) + (231, 116) + (211, 269) + (48, 317) + (53, 251) + (284, 313) + (456, -1) + (402, 140) + (277, 346) + (393, 374) + (184, 360) + (394, 13) + (404, 14) + (331, 78) + (71, 146) + (414, 12) + (120, 119) + (361, 187) + (478, 49) + (196, 362) + (485, 496) + (429, 73) + (142, 101) + (256, 460) + (343, 19) + (362, 36) + (288, 305) + (312, 160) + (387, 56) + (54, 275) + (60, 236) + (22, 264) + (29, 135) + (441, 169) + (490, 295) + (450, 207) + (189, 33) + (65, 249) + (347, 218) + (40, 212) + (232, 468) + (196, 406) + (49, 178) + (98, 221) + (416, 303) + (97, 107) + (6, 152) + (169, 257) + (151, 39) + (136, 305) + (303, 374) + (301, 373) + (395, 270) + (441, 253) + (427, 479) + (400, 403) + (6, 46) + (430, 7) + (261, 72) + (295, 365) + (177, 88) + (409, 139) + (409, 202) + (198, 244) + (451, 497) + (377, 131) + (242, 395) + (427, 491) + (11, 170) + (282, 334) + (96, 459) + (135, 251) + (318, 440) + (492, 484) + (427, 99) + (172, 118) + (60, 329) + (381, 296) + (197, -1) + (157, 77) + (299, 415) + (10, 475) + (119, 188) + (454, 18) + (350, 382) + (383, 473) + (240, 123) + (132, 347) + (241, 78) + (129, 297) + (262, 104) + (301, 5) + (133, 232) + (283, 157) + (74, 268) + (57, 203) + (133, 297) + (302, 485) + (109, 30) + (428, 38) + (147, 23) + (376, 187) + (75, 155) + (400, 112) + (434, 49) + (395, 385) + (302, 150) + (387, 156) + (448, 88) + (440, 396) + (8, 411) + (137, 95) + (200, 138) + (351, 281) + (455, 432) + (381, 36) + (6, 471) + (413, 360) + (154, 249) + (351, 37) + (310, 4) + (98, 391) + (337, 297) + (262, 219) + (351, 348) + (314, 110) + (275, 353) + (98, 22) + (267, 101) + (254, 56) + (300, 336) + (176, 319) + (40, 92) + (308, 259) + (389, 459) + (453, 278) + (60, 102) + (269, 276) + (420, 375) + (498, 278) + (216, 105) + (437, 209) + (379, 455) + (51, 368) + (40, 189) + (150, 30) + (107, 484) + (495, 66) + (192, 405) + (225, 169) + (151, 276) + (41, 39) + (231, 218) + (302, 193) + (29, 404) + (448, 457) + (323, 426) + (291, 253) + (200, 66) + (133, 257) + (425, -1) + (25, 401) + (341, 323) + (271, 190) + (225, 253) + (179, 496) + (27, 125) + (332, 164) + (108, 228) + (247, 439) + (299, 144) + (420, 500) + (180, 110) + (486, 430) + (399, 319) + (271, 251) + (383, 77) + (119, 334) + (6, 415) + (191, 141) + (359, 431) + (89, 73) + (282, 393) + (344, 315) + (121, 339) + (174, 399) + (283, 275) + (454, 216) + (60, 258) + (285, 118) + (212, 92) + (102, 276) + (444, 342) + (167, 150) + (331, 494) + (445, 111) + (424, 293) + (119, 491) + (3, 170) + (82, 4) + (408, 320) + (448, 300) + (466, 174) + (228, 109) + (368, 9) + (457, 342) + (85, 121) + (345, 265) + (434, 343) + (435, 165) + (81, 207) + (379, 58) + (325, 163) + (390, 176) + (192, 222) + (120, 334) + (179, 348) + (489, 213) + (230, 270) + (231, 128) + (235, 414) + (397, 328) + (402, 429) + (331, 409) + (102, 388) + (277, 233) + (358, 394) + (222, 405) + (32, 159) + (81, 157) + (231, 94) + (417, 170) + (232, 337) + (280, 258) + (148, 441) + (162, 444) + (452, 239) + (420, 98) + (89, 155) + (97, 294) + (185, 134) + (26, 164) + (27, 251) + (34, 233) + (74, 144) + (124, 73) + (70, 79) + (355, 77) + (85, 118) + (262, 403) + (4, 446) + (239, 334) + (262, 357) + (155, 195) + (71, 204) + (235, 315) + (494, 428) + (442, 77) + (29, 418) + (29, 45) + (361, 111) + (383, 297) + (271, 261) + (122, 12) + (35, 63) + (321, 212) + (91, 480) + (332, 66) + (298, 79) + (463, 449) + (150, 31) + (225, 226) + (34, 41) + (122, 217) + (80, 2) + (302, 227) + (97, 492) + (124, 293) + (115, 195) + (145, 206) + (204, 146) + (239, 168) + (239, 491) + (408, 311) + (60, 151) + (326, 226) + (436, 411) + (487, 158) + (471, 83) + (232, -1) + (499, 105) + (192, 305) + (52, 460) + (473, 337) + (308, 223) + (149, 77) + (262, 112) + (100, 483) + (490, 163) + (346, 227) + (132, 183) + (436, 134) + (490, 325) + (481, 227) + (189, 176) + (177, 358) + (478, 407) + (335, 356) + (84, 90) + (441, 257) + (312, 387) + (373, 61) + (157, 442) + (8, 28) + (94, 183) + (162, 394) + (419, 229) + (75, 285) + (59, 426) + (95, 87) + (291, 433) + (383, 149) + (272, 39) + (280, 127) + (255, 365) + (66, 26) + (493, 356) + (76, 240) + (398, 484) + (181, 12) + (175, 314) + (379, 86) + (38, 433) + (262, 451) + (149, 146) + (202, 304) + (435, 327) + (497, 161) + (181, 217) + (235, 203) + (199, 401) + (267, 142) + (247, 468) + (469, 30) + (55, 143) + (310, 7) + (436, 79) + (166, 442) + (269, 329) + (32, 346) + (486, 114) + (46, 471) + (379, 115) + (298, 433) + (439, 265) + (155, 392) + (35, 364) + (282, 274) + (352, 396) + (126, 69) + (242, 146) + (421, 470) + (151, 329) + (312, 114) + (393, 274) + (485, 193) + (115, 86) + (478, 52) + (116, 380) + (310, 446) + (454, 103) + (494, 48) + (298, 240) + (131, 88) + (15, 470) + (433, 449) + (404, 417) + (97, 153) + (204, 149) + (475, 159) + (239, 393) + (8, 38) + (364, 311) + (447, 45) + (54, 81) + (275, 210) + (364, 121) + (447, 126) + (58, 467) + (99, 119) + (132, 218) + (408, 124) + (75, 311) + (268, 156) + (166, 204) + (287, 483) + (203, 80) + (201, 55) + (279, 183) + (434, 407) + (398, -1) + (160, 158) + (322, 440) + (270, 123) + (31, 483) + (247, 430) + (137, 264) + (242, 185) + (461, 265) + (96, 36) + (93, 214) + (14, 171) + (365, 232) + (247, 489) + (94, 218) + (302, 42) + (302, 167) + (432, 159) + (486, 252) + (200, 13) + (72, 334) + (248, 467) + (202, 338) + (495, 435) + (162, 358) + (102, 329) + (195, 392) + (308, 372) + (49, 460) + (287, 100) + (331, 48) + (206, 224) + (444, 315) + (57, 341) + (166, 246) + (62, 375) + (287, 421) + (278, 37) + (356, 411) + (152, 415) + (273, 258) + (296, 105) + (205, 332) + (434, 21) + (494, 226) + (239, 43) + (18, 103) + (283, 217) + (20, 367) + (333, 161) + (145, 224) + (314, 405) + (99, 391) + (393, 403) + (372, 50) + (426, 127) + (262, -1) + (87, 375) + (299, 201) + (436, 185) + (434, 106) + (87, 347) + (52, 199) + (300, 330) + (336, 469) + (277, 369) + (409, 419) + (287, 305) + (176, 479) + (89, 320) + (242, 149) + (344, 235) + (162, 177) + (45, 16) + (152, 84) + (285, 172) + (169, 482) + (94, 128) + (184, 236) + (416, 112) + (383, 355) + (40, 319) + (309, 93) + (381, 451) + (245, 319) + (362, 406) + (453, 276) + (492, 325) + (344, 173) + (407, 21) + (241, 46) + (234, 399) + (78, 56) + (326, 225) + (494, 433) + (280, 398) + (130, 178) + (386, 170) + (204, 442) + (284, 32) + (352, 388) + (191, 1) + (485, 227) + (415, 376) + (93, 422) + (205, 394) + (309, 88) + (21, 106) + (306, 114) + (94, 328) + (343, 378) + (343, 178) + (182, 339) + (488, 61) + (208, 286) + (280, 290) + (298, 70) + (98, 137) +```` + Note also that the edges are all given as unordered, so the set of edges only includes one of `(i, j)` and `(j, i)` for each edge `(i, j)`. @@ -111,7 +2175,7 @@ Similarly, we can iterate over the triangles using [`each_solid_triangle`](@ref) or [`each_triangle`](@ref). By default, ghost triangles are included in the output. Here we compute the area of the domain by getting the area of each triangle. -````@example unconstrained +````julia area(p, q, r) = 0.5 * ((getx(q) - getx(p)) * (gety(r) - gety(p)) - (gety(q) - gety(p)) * (getx(r) - getx(p))) function compute_triangulation_area(tri) A = 0.0 @@ -125,13 +2189,1019 @@ end A = compute_triangulation_area(tri) ```` +```` +0.9683345161527972 +```` + (You can compute areas like this using [`get_area(tri)`](@ref get_area).) You can access the set of `triangles` using [`get_triangles(tri)`](@ref get_triangles): -````@example unconstrained +````julia get_triangles(tri) ```` +```` +Set{Tuple{Int64, Int64, Int64}} with 998 elements: + (59, 426, 44) + (163, 365, 295) + (383, 473, 297) + (499, 260, 216) + (185, 134, 472) + (239, 43, 274) + (300, 31, 288) + (113, 135, 221) + (461, 7, 430) + (230, 257, 316) + (57, 203, 80) + (277, 284, 233) + (74, 144, 474) + (398, 484, 44) + (288, 31, 483) + (361, 368, 111) + (450, 77, 207) + (220, 327, 315) + (151, 329, 276) + (196, 401, 362) + (255, 294, 97) + (35, 121, 364) + (485, 227, 369) + (452, 303, 371) + (150, 330, 469) + (395, 385, 297) + (296, 499, 105) + (335, 356, 411) + (344, 444, 342) + (407, 69, 106) + (382, 127, 426) + (412, 240, 291) + (287, 136, 305) + (354, 489, 229) + (211, 276, 269) + (400, 112, 416) + (420, 500, 33) + (479, 491, 168) + (262, 104, 244) + (282, 261, 103) + (448, 88, 300) + (97, 492, 153) + (3, 422, 170) + (470, 37, 180) + (97, 295, 365) + (196, 199, 401) + (318, 440, 396) + (292, 169, 338) + (99, 119, 491) + (243, 59, 423) + (381, 406, 36) + (332, 164, 26) + (55, 143, 144) + (150, 469, 30) + (335, 206, 224) + (185, 270, 289) + (91, 379, 58) + (220, 246, 435) + (138, 224, 145) + (245, -1, 140) + (75, 311, 364) + (485, 369, 233) + (434, 49, 478) + (344, 405, 173) + (74, 156, 268) + (192, 222, 405) + (29, 135, 418) + (177, 88, 131) + (6, 83, 471) + (20, 333, 161) + (457, 288, 305) + (377, 162, 177) + (408, 311, 155) + (354, 338, 468) + (267, 88, 101) + (478, 69, 407) + (358, 394, 13) + (245, 429, 319) + (107, 423, 44) + (113, 380, 418) + (342, 305, 192) + (398, 325, 492) + (137, 95, 347) + (256, 25, 460) + (369, 227, 346) + (296, 367, 20) + (453, 276, 102) + (27, 188, 119) + (267, 101, 142) + (377, 342, 444) + (352, 396, 175) + (419, 229, 306) + (397, 328, 223) + (354, 468, 489) + (238, 479, 168) + (104, 96, 130) + (454, 18, 190) + (163, -1, 232) + (211, 329, 102) + (402, 73, 429) + (464, 92, 212) + (371, 176, 479) + (434, 106, 201) + (296, 20, 499) + (326, 225, 304) + (216, 260, 161) + (20, 367, 333) + (282, 274, 334) + (248, 1, 191) + (133, 468, 338) + (11, 116, 128) + (261, 72, 188) + (301, 373, 422) + (434, 343, 49) + (174, 212, 399) + (75, 339, 182) + (174, 209, 437) + (345, 439, 468) + (302, 42, 10) + (262, 497, 451) + (466, 234, 392) + (256, 389, 25) + (219, 158, 197) + (332, 26, 66) + (167, 30, 67) + (25, 459, 401) + (497, 357, 161) + (420, 98, 500) + (75, 182, 285) + (463, 449, 28) + (300, 93, 336) + (75, 285, 155) + (98, 221, 27) + (456, 112, -1) + (225, 253, 482) + (366, 352, 388) + (456, 303, 416) + (201, 143, 55) + (312, 114, 310) + (11, 14, 116) + (129, 270, 395) + (299, 474, 144) + (205, 164, 332) + (104, 130, 244) + (96, 36, 362) + (243, 210, 17) + (345, 446, 265) + (76, 123, 270) + (105, 190, 251) + (235, 220, 315) + (94, 458, 128) + (85, 115, 118) + (407, 106, 21) + (478, 49, 460) + (489, 252, 213) + (476, 290, 127) + (133, 337, 232) + (66, 26, 435) + (231, 116, 264) + (113, 116, 380) + (486, 114, 213) + (428, 38, 433) + (18, 103, 261) + (298, 240, 412) + (487, 343, 201) + (302, 10, 227) + (322, 440, 250) + (58, 308, 1) + (32, 346, 159) + (121, 118, 339) + (441, 257, 169) + (107, 44, 484) + (115, 186, 195) + (410, 496, 348) + (126, 45, 9) + (465, 187, 361) + (181, 442, 246) + (487, 55, 158) + (263, 136, 222) + (136, 470, 180) + (43, 334, 274) + (40, 399, 212) + (42, 432, 349) + (242, 146, 149) + (488, 61, 117) + (300, 336, 330) + (463, 411, 436) + (409, 139, 419) + (445, 111, 51) + (109, 50, 30) + (120, 119, 72) + (220, 435, 327) + (429, 234, 319) + (107, 210, 423) + (428, 154, 38) + (438, 42, 308) + (424, 364, 311) + (331, 409, 254) + (438, 58, 455) + (242, 270, 185) + (267, 93, 300) + (420, 33, 375) + (461, 247, 439) + (11, 128, 458) + (255, 215, 294) + (6, 46, 286) + (299, 144, 143) + (404, 171, 417) + (448, 457, 131) + (300, 330, 31) + (235, 12, 414) + (189, 500, 390) + (242, 149, 385) + (208, 286, 46) + (191, 223, 141) + (379, 86, 455) + (318, 396, 352) + (54, 107, 97) + (24, 469, 336) + (219, 198, 47) + (11, 458, 228) + (301, 214, 5) + (175, 110, 388) + (29, 404, 45) + (271, 251, 190) + (194, 84, 206) + (26, 164, 165) + (228, 50, 109) + (242, 185, 472) + (78, 387, 156) + (279, 248, 141) + (299, 415, 286) + (260, 20, 161) + (280, 398, 44) + (434, 201, 343) + (494, 433, 266) + (485, 496, 193) + (262, 451, 104) + (495, 435, 472) + (283, 275, 157) + (494, 48, 65) + (480, 392, 195) + (147, 422, 373) + (245, 402, 429) + (243, 57, 341) + (85, 159, 86) + (435, 146, 472) + (208, 241, 78) + (277, 346, 32) + (344, 192, 405) + (179, 233, 307) + (312, 160, 268) + (243, 323, 59) + (465, 84, 187) + (248, 467, 1) + (452, 371, 168) + (340, 29, 16) + (350, 80, 476) + (239, 334, 43) + (282, 334, 72) + (183, 223, 328) + (478, 460, 52) + (203, 173, 405) + (489, 213, 229) + (345, 197, 446) + (148, 76, 316) + (35, 313, 284) + (211, 102, 276) + (240, 253, 291) + (81, 207, 157) + (279, 384, 62) + (383, 355, 473) + (145, 206, 462) + (176, -1, 319) + (488, 117, 462) + (167, 67, 372) + (344, 315, 444) + (285, 195, 155) + (6, 152, 90) + (237, 154, 428) + (119, 188, 72) + (175, 405, 314) + (202, 338, 139) + (81, 294, 215) + (166, 204, 71) + (455, 86, 432) + (408, 124, 293) + (409, 443, 56) + (15, 351, 37) + (370, 251, 53) + (381, 367, 296) + (78, 56, 387) + (452, 168, 239) + (473, 337, 297) + (147, 9, 386) + (48, 317, 471) + (243, 341, 323) + (312, 56, 114) + (126, 9, 69) + (196, 68, 199) + (271, 18, 261) + (383, 77, 355) + (494, 226, 202) + (345, 468, -1) + (54, 210, 107) + (222, 314, 405) + (194, 38, 154) + (343, 378, 178) + (256, 130, 389) + (456, -1, 425) + (89, 73, 124) + (98, 391, 390) + (89, 320, 155) + (492, 325, 153) + (481, 475, 159) + (345, 265, 439) + (424, 477, 293) + (254, 56, 78) + (60, 366, 102) + (437, 209, 467) + (167, 372, 308) + (445, 51, 23) + (488, 462, 206) + (154, 83, 90) + (40, 212, 92) + (150, 483, 31) + (22, 116, 113) + (415, 376, 187) + (343, 47, 378) + (302, 150, 167) + (427, 391, 99) + (408, 320, 124) + (235, 57, 12) + (51, 368, 23) + (302, 485, 193) + (147, 23, 9) + (205, 332, 66) + (277, 32, 284) + (308, 372, 223) + (436, 134, 185) + (34, 233, 284) + (204, 442, 149) + (166, 71, 435) + (145, 224, 206) + (155, 195, 392) + (371, -1, 176) + (100, 193, 410) + (60, 151, 39) + (27, 251, 188) + (29, 45, 16) + (370, 16, 68) + (179, 307, 348) + (208, 78, 156) + (136, 180, 222) + (205, 13, 394) + (425, -1, 371) + (27, 221, 251) + (386, 404, 417) + (445, 488, 111) + (167, 150, 30) + (157, 77, 442) + (292, 202, 304) + (273, 366, 258) + (95, 87, 347) + (359, 431, 403) + (150, 31, 330) + (377, 177, 131) + (478, 126, 69) + (116, 418, 380) + (273, 322, 250) + (273, 290, 476) + (298, 123, 240) + (352, 175, 388) + (124, 402, 293) + (15, 410, 348) + (124, 73, 402) + (148, 253, 240) + (287, 288, 483) + (494, 266, 226) + (222, 180, 314) + (457, 342, 377) + (63, 184, 313) + (494, 428, 433) + (283, 157, 442) + (351, 276, 278) + (271, 261, 188) + (490, 325, 163) + (372, 50, 223) + (22, 264, 116) + (494, 65, 363) + (63, 413, 184) + (157, 207, 77) + (216, 161, 431) + (262, 198, 219) + (456, 416, 112) + (463, 28, 411) + (298, 289, 123) + (340, 53, 135) + (309, 177, 358) + (35, 32, 121) + (493, 436, 356) + (445, 23, 61) + (370, 68, 105) + (424, 413, 63) + (181, 122, 217) + (194, 154, 90) + (377, 444, 162) + (299, 286, 474) + (436, 185, 289) + (162, 327, 165) + (194, 8, 38) + (167, 308, 259) + (152, 415, 84) + (485, 179, 496) + (250, 440, 318) + (292, 304, 169) + (387, 268, 156) + (368, 9, 23) + (60, 140, 258) + (48, 471, 249) + (198, 378, 47) + (82, 158, 160) + (495, 472, 134) + (287, 100, 410) + (64, 289, 70) + (230, 133, 257) + (452, 239, 393) + (241, 471, 317) + (59, 323, 426) + (181, 283, 442) + (133, 338, 169) + (71, 204, 146) + (133, 169, 257) + (499, 216, 105) + (279, 87, 384) + (54, 157, 275) + (453, 102, 388) + (89, 155, 234) + (490, 163, 295) + (351, 278, 37) + (237, 363, 65) + (271, 188, 251) + (54, 97, 294) + (335, 411, 8) + (440, 203, 396) + (26, 165, 435) + (461, 439, 265) + (24, 3, 108) + (486, 7, 310) + (326, 202, 226) + (132, 218, 347) + (133, 232, 468) + (27, 125, 391) + (490, 153, 325) + (386, 45, 404) + (344, 342, 192) + (419, 139, 229) + (49, 343, 178) + (456, 425, 371) + (282, 72, 261) + (82, 4, 158) + (42, 349, 10) + (182, 172, 285) + (283, 217, 353) + (452, 374, 303) + (298, 70, 289) + (129, 297, 230) + (454, 105, 216) + (181, 414, 12) + (196, 406, 296) + (11, 171, 14) + (262, 219, -1) + (219, 197, -1) + (350, 382, 323) + (196, 362, 406) + (247, 468, 439) + (54, 81, 157) + (478, 52, 126) + (254, 409, 56) + (17, 210, 353) + (280, 258, 398) + (398, -1, 325) + (379, 115, 86) + (424, 293, 140) + (486, 310, 114) + (450, 215, 232) + (298, 433, 449) + (499, 20, 260) + (362, 36, 406) + (175, 314, 110) + (354, 229, 139) + (309, 358, 117) + (298, 449, 79) + (447, 45, 126) + (235, 203, 57) + (262, 112, 403) + (74, 160, 144) + (180, 37, 110) + (200, 495, 134) + (147, 170, 422) + (292, 338, 202) + (493, 356, 224) + (424, 140, 413) + (122, 353, 217) + (279, 132, 87) + (194, 206, 335) + (24, 228, 109) + (60, 184, 360) + (194, 90, 84) + (162, 165, 164) + (60, 39, 236) + (11, 108, 170) + (466, 91, 209) + (262, -1, 112) + (48, 249, 65) + (166, 442, 204) + (42, 455, 432) + (454, 216, 103) + (312, 82, 160) + (481, 10, 475) + (438, 455, 42) + (129, 395, 297) + (448, 300, 288) + (453, 388, 498) + (309, 93, 142) + (280, 127, 290) + (382, 426, 323) + (234, 399, 319) + (447, 52, 199) + (321, 212, 437) + (138, 117, 358) + (97, 153, 295) + (40, 33, 189) + (35, 284, 32) + (398, 492, 484) + (373, 61, 23) + (308, 191, 1) + (116, 14, 418) + (331, 254, 78) + (324, 136, 287) + (381, 296, 406) + (309, 142, 101) + (321, 464, 212) + (93, 214, 422) + (299, 376, 415) + (466, 174, 399) + (480, 186, 379) + (361, 187, 376) + (35, 63, 313) + (302, 483, 150) + (486, 213, 252) + (445, 61, 488) + (397, 50, 458) + (345, -1, 197) + (262, 357, 497) + (335, 224, 356) + (91, 58, 209) + (272, 39, 41) + (400, 374, 393) + (225, 266, 253) + (451, 497, 333) + (487, 19, 343) + (231, 218, 94) + (62, 375, 464) + (41, 281, 307) + (322, 80, 203) + (60, 258, 366) + (486, 430, 7) + (448, 131, 88) + (498, 388, 278) + (450, 355, 77) + (235, 173, 203) + (4, 446, 197) + (273, 2, 322) + (54, 294, 81) + (279, 62, 437) + (155, 392, 234) + (204, 149, 146) + (40, 176, 319) + (463, 79, 449) + (230, 76, 270) + (62, 87, 375) + (262, 244, 198) + (357, 431, 161) + (336, 469, 330) + (28, 433, 38) + (409, 419, 443) + (438, 308, 58) + (432, 159, 475) + (76, 240, 123) + (100, 483, 193) + (154, 249, 83) + (427, 99, 491) + (103, 403, 393) + (343, 19, 47) + (301, 5, 117) + (424, 311, 477) + (228, 458, 50) + (69, 376, 106) + (130, 459, 389) + (138, 145, 462) + (25, 199, 460) + (104, 451, 36) + (457, 305, 342) + (242, 385, 395) + (60, 360, 140) + (420, 87, 95) + (235, 414, 220) + (174, 437, 212) + (75, 155, 311) + (225, 169, 304) + (231, 128, 116) + (481, 346, 227) + (379, 186, 115) + (98, 390, 500) + (35, 364, 424) + (282, 103, 393) + (285, 118, 195) + (248, 437, 467) + (162, 164, 394) + (382, 476, 127) + (25, 389, 459) + (397, 223, 50) + (383, 149, 77) + (213, 114, 306) + (324, 470, 136) + (359, 103, 216) + (162, 358, 177) + (441, 482, 253) + (486, 252, 430) + (302, 193, 483) + (427, 491, 479) + (314, 180, 110) + (181, 246, 220) + (184, 413, 360) + (183, 141, 223) + (271, 190, 18) + (301, 117, 373) + (89, 124, 320) + (258, 140, -1) + (351, 348, 281) + (133, 297, 337) + (379, 455, 58) + (351, 281, 276) + (97, 107, 484) + (397, 458, 328) + (302, 259, 42) + (404, 418, 14) + (277, 233, 369) + (211, 269, 329) + (122, 12, 17) + (243, 423, 210) + (24, 108, 228) + (282, 393, 274) + (122, 17, 353) + (27, 119, 125) + (196, 296, 105) + (434, 478, 407) + (89, 429, 73) + (6, 471, 46) + (471, 83, 249) + (309, 117, 93) + (324, 287, 421) + (208, 46, 241) + (273, 258, 290) + (81, 450, 207) + (85, 86, 115) + (283, 353, 275) + (200, 66, 495) + (378, 244, 130) + (248, 191, 141) + (115, 195, 118) + (25, 401, 199) + (273, 250, 352) + (494, 363, 428) + (326, 304, 202) + (400, 416, 374) + (344, 173, 235) + (287, 410, 421) + (238, 168, 371) + (160, 55, 144) + (151, 276, 281) + (466, 480, 91) + (41, 39, 281) + (310, 7, 446) + (453, 278, 276) + (490, 295, 153) + (378, 130, 178) + (71, 146, 435) + (120, 72, 334) + (24, 109, 469) + (242, 472, 146) + (435, 165, 327) + (113, 418, 135) + (487, 201, 55) + (138, 358, 13) + (11, 228, 108) + (331, 78, 317) + (256, 178, 130) + (221, 135, 251) + (312, 387, 56) + (198, 244, 378) + (493, 134, 436) + (98, 22, 221) + (450, 232, 473) + (456, 371, 303) + (307, 281, 348) + (60, 236, 184) + (241, 317, 78) + (129, 230, 270) + (99, 125, 119) + (247, 430, 252) + (408, 477, 311) + (331, 202, 409) + (232, -1, 468) + (59, 44, 423) + (231, 94, 128) + (194, 335, 8) + (93, 5, 214) + (162, 394, 358) + (162, 444, 327) + (147, 386, 170) + (120, 334, 119) + (137, 264, 22) + (230, 297, 133) + (279, 183, 132) + (74, 474, 286) + (231, 264, 218) + (93, 117, 5) + (420, 95, 137) + (51, 111, 368) + (96, 362, 459) + (373, 117, 61) + (94, 183, 328) + (402, 140, 293) + (310, 446, 4) + (94, 218, 132) + (200, 224, 138) + (255, 97, 365) + (273, 352, 366) + (94, 132, 183) + (81, 215, 450) + (309, 88, 177) + (272, 236, 39) + (280, 426, 127) + (80, 323, 341) + (75, 364, 339) + (119, 334, 491) + (427, 479, 176) + (364, 121, 339) + (256, 49, 178) + (436, 411, 356) + (427, 390, 391) + (443, 114, 56) + (312, 310, 82) + (408, 155, 320) + (453, 498, 278) + (205, 200, 13) + (172, 339, 118) + (432, 86, 159) + (388, 110, 278) + (58, 1, 467) + (447, 68, 16) + (98, 27, 391) + (417, 171, 170) + (432, 10, 349) + (340, 135, 29) + (321, 62, 464) + (381, 451, 367) + (344, 235, 315) + (291, 253, 266) + (301, 422, 214) + (372, 30, 50) + (130, 96, 459) + (326, 226, 225) + (32, 159, 121) + (267, 300, 88) + (64, 70, 79) + (99, 391, 125) + (308, 223, 191) + (91, 480, 379) + (64, 79, 436) + (451, 333, 367) + (464, 375, 92) + (488, 206, 84) + (409, 202, 139) + (340, 16, 370) + (29, 418, 404) + (80, 2, 476) + (298, 79, 70) + (383, 385, 149) + (148, 240, 76) + (278, 110, 37) + (69, 368, 376) + (493, 224, 200) + (6, 415, 152) + (465, 111, 84) + (132, 347, 87) + (205, 394, 164) + (255, 365, 215) + (15, 470, 421) + (277, 369, 346) + (485, 233, 179) + (89, 234, 429) + (420, 137, 98) + (208, 156, 286) + (473, 232, 337) + (35, 424, 63) + (85, 118, 121) + (166, 246, 442) + (443, 306, 114) + (64, 436, 289) + (28, 449, 433) + (366, 388, 102) + (74, 286, 156) + (84, 415, 187) + (256, 460, 49) + (34, 313, 272) + (189, 33, 500) + (181, 217, 283) + (280, 290, 258) + (410, 193, 496) + (427, 176, 390) + (400, 393, 403) + (137, 218, 264) + (34, 307, 233) + (463, 436, 79) + (302, 227, 485) + (466, 399, 234) + (310, 4, 82) + (152, 84, 90) + (151, 281, 39) + (184, 236, 313) + (419, 306, 443) + (242, 395, 270) + (34, 272, 41) + (289, 270, 123) + (239, 274, 393) + (263, 222, 192) + (22, 113, 221) + (203, 405, 396) + (181, 220, 414) + (447, 199, 68) + (447, 16, 45) + (263, 192, 305) + (60, 102, 329) + (269, 276, 329) + (309, 101, 88) + (148, 316, 441) + (279, 437, 248) + (4, 197, 158) + (237, 249, 154) + (272, 313, 236) + (58, 467, 209) + (280, 44, 426) + (312, 268, 387) + (6, 286, 415) + (262, 403, 431) + (299, 106, 376) + (447, 126, 52) + (54, 275, 210) + (273, 476, 2) + (24, 336, 3) + (287, 305, 288) + (267, 142, 93) + (287, 483, 100) + (454, 190, 105) + (52, 460, 199) + (8, 411, 28) + (408, 293, 477) + (350, 323, 80) + (98, 137, 22) + (225, 482, 169) + (247, 489, 468) + (461, 430, 247) + (94, 328, 458) + (62, 384, 87) + (213, 306, 229) + (340, 370, 53) + (322, 203, 440) + (8, 28, 38) + (420, 375, 87) + (316, 257, 441) + (461, 265, 7) + (140, 360, 413) + (239, 168, 491) + (493, 200, 134) + (40, 189, 176) + (200, 138, 13) + (480, 195, 186) + (488, 84, 111) + (3, 336, 422) + (322, 2, 80) + (450, 473, 355) + (215, 365, 232) + (495, 66, 435) + (398, 258, -1) + (181, 12, 122) + (331, 48, 494) + (245, 140, 402) + (175, 396, 405) + (404, 14, 171) + (74, 268, 160) + (109, 30, 469) + (182, 339, 172) + (205, 66, 200) + (466, 392, 480) + (230, 316, 76) + (237, 428, 363) + (299, 143, 201) + (166, 435, 246) + (15, 348, 351) + (219, 19, 158) + (243, 17, 12) + (15, 37, 470) + (457, 377, 131) + (34, 41, 307) + (386, 417, 170) + (40, 319, 399) + (487, 158, 19) + (441, 169, 482) + (291, 266, 433) + (179, 348, 496) + (219, 47, 19) + (383, 297, 385) + (243, 12, 57) + (459, 362, 401) + (138, 462, 117) + (454, 103, 18) + (60, 329, 151) + (238, 371, 479) + (247, 252, 489) + (321, 437, 62) + (434, 21, 106) + (53, 251, 135) + (225, 226, 266) + (42, 259, 308) + (97, 484, 492) + (57, 80, 341) + (412, 291, 433) + (381, 36, 451) + (372, 67, 30) + (149, 442, 77) + (241, 46, 471) + (448, 288, 457) + (262, 431, 357) + (196, 105, 68) + (324, 421, 470) + (386, 9, 45) + (147, 373, 23) + (163, 325, -1) + (263, 305, 136) + (497, 161, 333) + (285, 172, 118) + (69, 9, 368) + (331, 317, 48) + (416, 303, 374) + (361, 376, 368) + (375, 33, 92) + (93, 422, 336) + (245, 319, -1) + (160, 158, 55) + (34, 284, 313) + (189, 390, 176) + (250, 318, 352) + (481, 159, 346) + (6, 90, 83) + (298, 412, 433) + (359, 216, 431) + (481, 227, 10) + (85, 121, 159) + (299, 201, 106) + (452, 393, 374) + (40, 92, 33) + (446, 7, 265) + (279, 141, 183) + (137, 347, 218) + (432, 475, 10) + (163, 232, 365) + (354, 139, 338) + (237, 65, 249) + (302, 167, 259) + (465, 361, 111) + (104, 36, 96) + (350, 476, 382) + (148, 441, 253) + (239, 491, 334) + (108, 3, 170) + (434, 407, 21) + (15, 421, 410) + (466, 209, 174) + (444, 315, 327) + (370, 105, 251) + (400, 403, 112) + (359, 403, 103) + (11, 170, 171) + (275, 353, 210) + (331, 494, 202) +```` + The triangles are all positively oriented, meaning the triangles are given such that the corresponding points are traversed in counter-clockwise order. @@ -143,75 +3213,163 @@ For a given point, there are two type of neighbours: The neighbouring vertices, and the neighbouring triangles. The neighbours can be obtained using [`get_neighbours`](@ref). For example, the set of vertices that share an edge with the fifth vertex is: -````@example unconstrained +````julia get_neighbours(tri, 5) ```` +```` +Set{Int64} with 4 elements: + 93 + 117 + 301 + 214 +```` + The set of triangles that share an edge with the fifth vertex is obtained using [`get_adjacent2vertex`](@ref). This returns a set of edges `(v, w)` such that, for a given vertex `u`, `(u, v, w)` is a positively oriented triangle in the triangulation. For example, -````@example unconstrained +````julia get_adjacent2vertex(tri, 5) ```` +```` +Set{Tuple{Int64, Int64}} with 4 elements: + (93, 117) + (301, 214) + (117, 301) + (214, 93) +```` + means that the triangles that contain `5` as a vertex are `(5, 93, 117)`, `(5, 117, 301)`, `(5, 301, 214)`, and `(5, 214, 93)`. We can verify this: -````@example unconstrained +````julia filter(T -> 5 ∈ triangle_vertices(T), get_triangles(tri)) ```` +```` +Set{Tuple{Int64, Int64, Int64}} with 4 elements: + (93, 5, 214) + (301, 5, 117) + (93, 117, 5) + (301, 214, 5) +```` + These queries can also be applied to the ghost vertices, in which information about the boundary is provided. -````@example unconstrained +````julia get_neighbours(tri, -1) ```` -````@example unconstrained +```` +Set{Int64} with 18 elements: + 456 + 176 + 425 + 258 + 325 + 398 + 197 + 219 + 319 + 262 + 112 + 345 + 371 + 232 + 245 + 163 + 468 + 140 +```` + +````julia get_adjacent2vertex(tri, -1) ```` +```` +Set{Tuple{Int64, Int64}} with 18 elements: + (468, 232) + (398, 258) + (176, 371) + (425, 456) + (232, 163) + (112, 262) + (258, 140) + (319, 176) + (262, 219) + (163, 325) + (371, 425) + (219, 197) + (140, 245) + (325, 398) + (456, 112) + (197, 345) + (245, 319) + (345, 468) +```` + ### Edges For a given edge `(u, v)`, the relevant neighbours are the vertices that are next to it so that a triangle is formed. We can find the vertex `w` such that `(u, v, w)` is a positively oriented triangle in the triangulation using `get_adjacent(tri, u, v)`. For example, -````@example unconstrained +````julia get_adjacent(tri, 163, 365) ```` +```` +295 +```` + means that `(163, 365, 295)` is a positively oriented triangle, as we can verify: -````@example unconstrained +````julia DelaunayTriangulation.triangle_orientation(tri, 163, 365, 295) ```` +```` +Certificate.PositivelyOriented = 6 +```` + (The representation of this predicate using a [`DelaunayTriangulation.Certificate`](@ref) is described in more detail in the [manual](../manual/predicates.md).) The other triangle adjoining the unordered edge `(u, v)`, meaning the oriented edge `(v, u)`, is obtained similarly: -````@example unconstrained +````julia get_adjacent(tri, 365, 163) ```` +```` +232 +```` + If an edge `(u, v)` is on the boundary, oriented so that there is no solid vertex `w` such that `(u, v, w)` is a triangle in the triangulation, then `get_adjacent(tri, u, v)` returns the ghost vertex. For example, -````@example unconstrained +````julia get_adjacent(tri, 398, 258) ```` +```` +-1 +```` + means that `(398, 258)` is a boundary edge and `(398, 258, -1)` is a ghost triangle. You can test for this case using [`DelaunayTriangulation.is_boundary_edge`](@ref): -````@example unconstrained +````julia DelaunayTriangulation.is_boundary_edge(tri, 258, 398) ```` +```` +true +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/unconstrained.jl). @@ -225,7 +3383,7 @@ using LinearAlgebra # used for computing norms later rng = StableRNG(123) points = rand(rng, 2, 500) # just do rand(2, 500) if you are not concerned about the RNG -tri = triangulate(points; rng=rng) +tri = triangulate(points; rng = rng) fig, ax, sc = triplot(tri) fig diff --git a/docs/src/tutorials/voronoi.md b/docs/src/tutorials/voronoi.md index bff13b686..8254255dc 100644 --- a/docs/src/tutorials/voronoi.md +++ b/docs/src/tutorials/voronoi.md @@ -9,7 +9,7 @@ tessellations and work with them. Voronoi tessellations are built from a dual Delaunay triangulation using [`voronoi`](@ref). To start, let us load in the packages. -````@example voronoi +````julia using DelaunayTriangulation using CairoMakie using StableRNGs @@ -18,26 +18,37 @@ using StableRNGs We build the tessellation by constructing the triangulation, and then passing that triangulation into `voronoi`. -````@example voronoi +````julia points = [ (-3.0, 7.0), (1.0, 6.0), (-1.0, 3.0), (-2.0, 4.0), (3.0, -2.0), (5.0, 5.0), - (-4.0, -3.0), (3.0, 8.0) + (-4.0, -3.0), (3.0, 8.0), ] rng = StableRNG(123) tri = triangulate(points; rng) vorn = voronoi(tri) ```` +```` +Voronoi Tessellation. + Number of generators: 8 + Number of polygon vertices: 9 + Number of polygons: 8 +```` + To visualise the tessellation, you can use `voronoiplot`. Here, we also compare the tessellation with its dual triangulation. -````@example voronoi -fig, ax, sc = voronoiplot(vorn, markersize=13, colormap=:matter, strokecolor=:white, strokewidth=5) +````julia +fig, ax, sc = voronoiplot(vorn, markersize = 13, colormap = :matter, strokecolor = :white, strokewidth = 5) triplot!(ax, tri) fig ```` +```@raw html + +``` + The polygons each correspond to a *generator*, which is the black point inside it coming from `points`, i.e. the vertices of the triangulation. The polygons are all convex. Note also that the unbounded polygons, @@ -56,27 +67,55 @@ version of `get_points(tri)`. (A separate field is needed so that clipped and ce tessellations can add new generators without affecting the points in `tri`.) These generators can be accessed using `get_generators(vorn)`: -````@example voronoi +````julia DelaunayTriangulation.get_generators(vorn) ```` +```` +Dict{Int64, Tuple{Float64, Float64}} with 8 entries: + 5 => (3.0, -2.0) + 4 => (-2.0, 4.0) + 6 => (5.0, 5.0) + 7 => (-4.0, -3.0) + 2 => (1.0, 6.0) + 8 => (3.0, 8.0) + 3 => (-1.0, 3.0) + 1 => (-3.0, 7.0) +```` + It is preferred that you use [`each_generator(vorn)`](@ref each_generator), though, which is an iterator over the generators: -````@example voronoi +````julia each_generator(vorn) ```` +```` +KeySet for a Dict{Int64, Tuple{Float64, Float64}} with 8 entries. Keys: + 5 + 4 + 6 + 7 + 2 + 8 + 3 + 1 +```` + Note that this is just the keys of the above `Dict`. To access specific generators, you use [`get_generator`](@ref). For example, -````@example voronoi +````julia get_generator(vorn, 3) ```` +```` +(-1.0, 3.0) +```` + To give an example, here is how we can compute the average generator position. -````@example voronoi +````julia function average_generator(vorn) cx, cy = 0.0, 0.0 for i in each_generator(vorn) @@ -93,85 +132,172 @@ end cx, cy = average_generator(vorn) ```` +```` +(0.25, 3.5) +```` + ## Iterating over polygon and polygon vertices You can also look at the individual polygons, and all their vertices. These polygons and their vertices are stored as below: -````@example voronoi +````julia DelaunayTriangulation.get_polygons(vorn) ```` -````@example voronoi +```` +Dict{Int64, Vector{Int64}} with 8 entries: + 5 => [4, 8, -2, -1, 4] + 4 => [1, 9, 3, 7, 1] + 6 => [-1, -3, 6, 5, 4, -1] + 7 => [8, 1, 7, -5, -2, 8] + 2 => [9, 5, 6, 2, 3, 9] + 8 => [-3, -4, 2, 6, -3] + 3 => [4, 5, 9, 1, 8, 4] + 1 => [3, 2, -4, -5, 7, 3] +```` + +````julia DelaunayTriangulation.get_polygon_points(vorn) ```` +```` +9-element Vector{Tuple{Float64, Float64}}: + (-4.166666666666666, 0.8333333333333335) + (-0.2999999999999998, 9.3) + (-1.1363636363636365, 5.954545454545455) + (2.710526315789474, 1.868421052631579) + (2.357142857142857, 2.9285714285714284) + (3.1, 5.9) + (-10.807692307692307, 2.730769230769231) + (-0.7307692307692308, -0.8846153846153846) + (-0.30000000000000004, 4.7) +```` + You should not work with these fields directly, though. If you want to look at a specific polygon, you should use [`get_polygon`](@ref). For example, -````@example voronoi +````julia get_polygon(vorn, 1) ```` +```` +6-element Vector{Int64}: + 3 + 2 + -4 + -5 + 7 + 3 +```` + This is a `Vector` of the vertices of the polygon, in counter-clockwise order, and such that the first and last vertices are the same. The vertices refer to points in the `polygon_points` field, which you could then obtain using [`get_polygon_point`](@ref). For example, the first vertex corresponds to the coordinates: -````@example voronoi +````julia get_polygon_point(vorn, 1) ```` +```` +(-4.166666666666666, 0.8333333333333335) +```` + In `get_polygon(vorn, 1)`, notice that there are two negative indices. These negative indices correspond to vertices out at infinity; their actual values do not matter, just that they are negative. Thus, this polygon is actually an unbounded polygon. This can be checked in two ways: -````@example voronoi +````julia 1 ∈ DelaunayTriangulation.get_unbounded_polygons(vorn) ```` -````@example voronoi +```` +true +```` + +````julia get_area(vorn, 1) == Inf ```` +```` +true +```` + There are several ways that you can iterate over the polygons. If you want each polygon, then you can use [`each_polygon`](@ref): -````@example voronoi +````julia each_polygon(vorn) ```` +```` +ValueIterator for a Dict{Int64, Vector{Int64}} with 8 entries. Values: + [4, 8, -2, -1, 4] + [1, 9, 3, 7, 1] + [-1, -3, 6, 5, 4, -1] + [8, 1, 7, -5, -2, 8] + [9, 5, 6, 2, 3, 9] + [-3, -4, 2, 6, -3] + [4, 5, 9, 1, 8, 4] + [3, 2, -4, -5, 7, 3] +```` + This is an iterator over all the polygon vertices, but you do not get the associated polygon index. If you want an iterator that is over the polygon indices, you use [`each_polygon_index`](@ref): -````@example voronoi +````julia each_polygon_index(vorn) ```` +```` +KeySet for a Dict{Int64, Vector{Int64}} with 8 entries. Keys: + 5 + 4 + 6 + 7 + 2 + 8 + 3 + 1 +```` + If you did want to have both the indices and the vertices together, you can use `zip` on these two iterators. This would be the same as iterating over the internal `polygons` field, but this could be subject to change in the future. To get an iterator over the polygon vertices rather than caring about a specific polygon, you use [`each_polygon_vertex`](@ref): -````@example voronoi +````julia each_polygon_vertex(vorn) ```` +```` +Base.OneTo(9) +```` + This is just an iterator of the indices to pass into `get_polygon_point`. You can also query the number of polygons and polygon vertices as follows: -````@example voronoi +````julia num_polygons(vorn) ```` -````@example voronoi +```` +8 +```` + +````julia num_polygon_vertices(vorn) ```` +```` +9 +```` + To give an example of how we might use these iterators, here we compute the area of all polygons. -````@example voronoi +````julia function get_polygon_area(vorn, i) i ∈ DelaunayTriangulation.get_unbounded_polygons(vorn) && return Inf area = 0.0 @@ -179,7 +305,7 @@ function get_polygon_area(vorn, i) vⱼ = vertices[begin] pⱼ = get_polygon_point(vorn, vⱼ) xⱼ, yⱼ = getxy(pⱼ) - for j in (firstindex(vertices)+1):lastindex(vertices) # same as 2:length(vertices) + for j in (firstindex(vertices) + 1):lastindex(vertices) # same as 2:length(vertices) vⱼ₊₁ = vertices[j] pⱼ₊₁ = get_polygon_point(vorn, vⱼ₊₁) xⱼ₊₁, yⱼ₊₁ = getxy(pⱼ₊₁) @@ -198,9 +324,21 @@ end vorn_areas = get_polygon_areas(vorn) ```` +```` +8-element Vector{Float64}: + Inf + 14.34935064935065 + 20.07578561789088 + 23.92237762237762 + Inf + Inf + Inf + Inf +```` + Note that this could have also been obtained using [`get_area`](@ref): -````@example voronoi +````julia function direct_polygon_areas(vorn) areas = zeros(num_polygons(vorn)) for i in each_polygon_index(vorn) @@ -211,12 +349,20 @@ end vorn_areas ≈ direct_polygon_areas(vorn) ```` +```` +true +```` + Moreover, note that the following is false: -````@example voronoi +````julia vorn_areas ≈ [get_area(vorn, i) for i in each_polygon_index(vorn)] ```` +```` +false +```` + because `each_polygon_index` does not return the polygons in a sorted order. Before we move on, we emphasise that it is not guaranteed that the values of the vertices @@ -228,28 +374,56 @@ of the polygons will be the same, though, as they are derived from the point ind Given an edge in the tessellation, you can use [`get_adjacent`](@ref) to get the polygon that it is a part of (taking care of order). For example, -````@example voronoi +````julia get_adjacent(vorn, 1, 8) ```` +```` +3 +```` + means that the edge `(1, 8)` belongs to the third polygon, as we can easily verify: -````@example voronoi +````julia get_polygon(vorn, 3) ```` +```` +6-element Vector{Int64}: + 4 + 5 + 9 + 1 + 8 + 4 +```` + see that `(1, 8)` at the end. The order is important here, since -````@example voronoi +````julia get_adjacent(vorn, 8, 1) ```` +```` +7 +```` + means that the edge `(8, 1)` belongs to the seventh polygon: -````@example voronoi +````julia get_polygon(vorn, 7) ```` +```` +6-element Vector{Int64}: + 8 + 1 + 7 + -5 + -2 + 8 +```` + ## Just the code An uncommented version of this example is given below. You can view the source code for this file [here](https://github.com/JuliaGeometry/DelaunayTriangulation.jl/tree/main/docs/src/literate_tutorials/voronoi.jl). @@ -262,13 +436,13 @@ using StableRNGs points = [ (-3.0, 7.0), (1.0, 6.0), (-1.0, 3.0), (-2.0, 4.0), (3.0, -2.0), (5.0, 5.0), - (-4.0, -3.0), (3.0, 8.0) + (-4.0, -3.0), (3.0, 8.0), ] rng = StableRNG(123) tri = triangulate(points; rng) vorn = voronoi(tri) -fig, ax, sc = voronoiplot(vorn, markersize=13, colormap=:matter, strokecolor=:white, strokewidth=5) +fig, ax, sc = voronoiplot(vorn, markersize = 13, colormap = :matter, strokecolor = :white, strokewidth = 5) triplot!(ax, tri) fig @@ -322,7 +496,7 @@ function get_polygon_area(vorn, i) vⱼ = vertices[begin] pⱼ = get_polygon_point(vorn, vⱼ) xⱼ, yⱼ = getxy(pⱼ) - for j in (firstindex(vertices)+1):lastindex(vertices) # same as 2:length(vertices) + for j in (firstindex(vertices) + 1):lastindex(vertices) # same as 2:length(vertices) vⱼ₊₁ = vertices[j] pⱼ₊₁ = get_polygon_point(vorn, vⱼ₊₁) xⱼ₊₁, yⱼ₊₁ = getxy(pⱼ₊₁) diff --git a/src/DelaunayTriangulation.jl b/src/DelaunayTriangulation.jl index 4c83f2383..9313f139b 100644 --- a/src/DelaunayTriangulation.jl +++ b/src/DelaunayTriangulation.jl @@ -17,4 +17,4 @@ include("validation.jl") include("exports.jl") -end \ No newline at end of file +end diff --git a/src/algorithms.jl b/src/algorithms.jl index cad5be78d..2524922ff 100644 --- a/src/algorithms.jl +++ b/src/algorithms.jl @@ -35,4 +35,4 @@ include("algorithms/voronoi/centroidal.jl") include("algorithms/voronoi/clipped_coordinates.jl") include("algorithms/voronoi/clipped.jl") include("algorithms/voronoi/main.jl") -include("algorithms/voronoi/unbounded.jl") \ No newline at end of file +include("algorithms/voronoi/unbounded.jl") diff --git a/src/algorithms/convex_hull.jl b/src/algorithms/convex_hull.jl index 4f922c3b7..6b8ce048c 100644 --- a/src/algorithms/convex_hull.jl +++ b/src/algorithms/convex_hull.jl @@ -9,7 +9,7 @@ Computes the convex hull of `points`. The monotone chain algorithm is used. # Output - `ch`: The [`ConvexHull`](@ref). """ -function convex_hull(points; IntegerType::Type{I}=Int) where {I} +function convex_hull(points; IntegerType::Type{I} = Int) where {I} ch = ConvexHull(points, I[]) sizehint!(ch, num_points(points)) return convex_hull!(ch) @@ -22,7 +22,7 @@ Using the points in `ch`, computes the convex hull in-place. See also [`convex_hull`](@ref). """ -function convex_hull!(ch::ConvexHull{P,I}) where {P,I} +function convex_hull!(ch::ConvexHull{P, I}) where {P, I} indices = get_vertices(ch) points = get_points(ch) empty!(indices) @@ -34,10 +34,10 @@ function convex_hull!(ch::ConvexHull{P,I}) where {P,I} push!(indices, insertion_order[begin]) return ch elseif n == 2 - push!(indices, insertion_order[begin], insertion_order[begin+1], insertion_order[begin]) + push!(indices, insertion_order[begin], insertion_order[begin + 1], insertion_order[begin]) return ch elseif n == 3 - i, j, k = construct_positively_oriented_triangle(NTuple{3,I}, insertion_order[begin], insertion_order[begin+1], insertion_order[begin+2], points) + i, j, k = construct_positively_oriented_triangle(NTuple{3, I}, insertion_order[begin], insertion_order[begin + 1], insertion_order[begin + 2], points) push!(indices, i, j, k, i) return ch end @@ -46,13 +46,13 @@ function convex_hull!(ch::ConvexHull{P,I}) where {P,I} sizehint!(lower, max(4, floor(I, cbrt(n)))) sizehint!(upper, max(4, floor(I, cbrt(n)))) for i in eachindex(insertion_order) - while length(upper) ≥ 2 && is_left(point_position_relative_to_line(get_point(points, upper[end-1]), get_point(points, upper[end]), get_point(points, insertion_order[i]))) + while length(upper) ≥ 2 && is_left(point_position_relative_to_line(get_point(points, upper[end - 1]), get_point(points, upper[end]), get_point(points, insertion_order[i]))) pop!(upper) end push!(upper, insertion_order[i]) end for i in lastindex(insertion_order):-1:firstindex(insertion_order) - while length(lower) ≥ 2 && is_left(point_position_relative_to_line(get_point(points, lower[end-1]), get_point(points, lower[end]), get_point(points, insertion_order[i]))) + while length(lower) ≥ 2 && is_left(point_position_relative_to_line(get_point(points, lower[end - 1]), get_point(points, lower[end]), get_point(points, insertion_order[i]))) pop!(lower) end push!(lower, insertion_order[i]) @@ -64,4 +64,4 @@ function convex_hull!(ch::ConvexHull{P,I}) where {P,I} unique!(indices) push!(indices, indices[begin]) return ch -end \ No newline at end of file +end diff --git a/src/algorithms/intersections/rtree.jl b/src/algorithms/intersections/rtree.jl index 5a511233f..ff022d560 100644 --- a/src/algorithms/intersections/rtree.jl +++ b/src/algorithms/intersections/rtree.jl @@ -80,10 +80,10 @@ end Returns the subtree of `tree` at `level` that `bounding_box` should be inserted into. """ function find_subtree(tree, bounding_box, level) - node = get_root(tree)::Union{Branch,Leaf{Branch}} + node = get_root(tree)::Union{Branch, Leaf{Branch}} while get_level(node) > level min_enlargement = minimise_enlargement(node, bounding_box) - node = get_child(node, min_enlargement.idx)::Union{Branch,Leaf{Branch}} + node = get_child(node, min_enlargement.idx)::Union{Branch, Leaf{Branch}} end return node end @@ -350,7 +350,7 @@ end Returns the leaf node and the index in the leaf node's children that `id_bounding_box` is associated with. """ function find_bounding_box(tree::RTree, id_bounding_box::DiametralBoundingBox) - idx_leaf = find_bounding_box(get_root(tree), id_bounding_box)::Tuple{Leaf{Branch},Int} + idx_leaf = find_bounding_box(get_root(tree), id_bounding_box)::Tuple{Leaf{Branch}, Int} return idx_leaf[1]::Leaf{Branch}, idx_leaf[2]::Int end function find_bounding_box(branch::Branch, id_bounding_box::DiametralBoundingBox) @@ -450,7 +450,7 @@ Given the `detached` nodes from [`collapse_after_deletion!`](@ref), inserts them """ function insert_detached!(tree::RTree, detached) isempty(detached) && return tree - sort!(detached, by=get_level, rev=true) + sort!(detached, by = get_level, rev = true) for node in detached for child in get_children(node) insert!(tree, child, get_level(node)) @@ -467,7 +467,7 @@ end Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that intersect with `bounding_box`. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::RTree, bounding_box::BoundingBox; cache_id=1) +function get_intersections(tree::RTree, bounding_box::BoundingBox; cache_id = 1) return RTreeIntersectionIterator(tree, bounding_box, cache_id) end @@ -478,7 +478,7 @@ Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that as a [`BoundingBox`](@ref) with zero width and height centered at `point`. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::RTree, point::NTuple{2,<:Number}; cache_id=1) +function get_intersections(tree::RTree, point::NTuple{2, <:Number}; cache_id = 1) return RTreeIntersectionIterator(tree, BoundingBox(point), cache_id) end @@ -586,4 +586,4 @@ function _iterate(itr::RTreeIntersectionIterator, node, node_indices, need_tests end end end -end \ No newline at end of file +end diff --git a/src/algorithms/point_location/brute_force.jl b/src/algorithms/point_location/brute_force.jl index d42a90cad..bf349f45f 100644 --- a/src/algorithms/point_location/brute_force.jl +++ b/src/algorithms/point_location/brute_force.jl @@ -1,4 +1,4 @@ -struct PointNotFoundError{T,P} <: Exception +struct PointNotFoundError{T, P} <: Exception tri::T q::P end @@ -28,7 +28,7 @@ See also [`find_triangle`](@ref). # Output - `V`: The triangle containing the point `q`. """ -function brute_force_search(tri::Triangulation, q; itr=each_triangle(tri)) +function brute_force_search(tri::Triangulation, q; itr = each_triangle(tri)) for V in itr cert = point_position_relative_to_triangle(tri, V, q) !is_outside(cert) && return V @@ -48,7 +48,7 @@ function brute_force_search_enclosing_circumcircle(tri::Triangulation, i) cert = point_position_relative_to_circumcircle(tri, V, i) !is_outside(cert) && return V end - tri_type=triangle_type(tri) + tri_type = triangle_type(tri) V = construct_triangle(tri_type, ∅, ∅, ∅) return V -end \ No newline at end of file +end diff --git a/src/algorithms/point_location/find_polygon.jl b/src/algorithms/point_location/find_polygon.jl index 57edd6d13..5b1be37a9 100644 --- a/src/algorithms/point_location/find_polygon.jl +++ b/src/algorithms/point_location/find_polygon.jl @@ -21,4 +21,4 @@ end function find_polygon(hierarchy::PolygonHierarchy, points, boundary_nodes, q) tree = find_tree(hierarchy, points, boundary_nodes, q) return isnothing(tree) ? 0 : get_index(tree) -end \ No newline at end of file +end diff --git a/src/algorithms/point_location/jump_and_march.jl b/src/algorithms/point_location/jump_and_march.jl index f35a7da67..41e93c1eb 100644 --- a/src/algorithms/point_location/jump_and_march.jl +++ b/src/algorithms/point_location/jump_and_march.jl @@ -53,12 +53,14 @@ Selects the initial point for [`find_triangle`](@ref) to start from. - `i`: The index of the point closest to `q` out of those queried. """ select_initial_point -function select_initial_point(tri::Triangulation, _q; - point_indices=each_solid_vertex(tri), - m=default_num_samples(num_vertices(point_indices)), - try_points=(), - allow_boundary_points=!is_disjoint(tri), - rng::AbstractRNG=Random.default_rng()) +function select_initial_point( + tri::Triangulation, _q; + point_indices = each_solid_vertex(tri), + m = default_num_samples(num_vertices(point_indices)), + try_points = (), + allow_boundary_points = !is_disjoint(tri), + rng::AbstractRNG = Random.default_rng(), + ) F = number_type(tri) I = integer_type(tri) current_dist = typemax(F) @@ -77,12 +79,14 @@ function select_initial_point(tri::Triangulation, _q; end return I(current_idx) end -function select_initial_point(tri::Triangulation, q::Integer; - point_indices=each_solid_vertex(tri), - m=default_num_samples(num_vertices(tri)), - allow_boundary_points=!is_disjoint(tri), - try_points=(), - rng::AbstractRNG=Random.default_rng()) +function select_initial_point( + tri::Triangulation, q::Integer; + point_indices = each_solid_vertex(tri), + m = default_num_samples(num_vertices(tri)), + allow_boundary_points = !is_disjoint(tri), + try_points = (), + rng::AbstractRNG = Random.default_rng(), + ) return select_initial_point(tri, get_point(tri, q); point_indices, m, try_points, allow_boundary_points, rng) end @@ -102,7 +106,7 @@ Selects a random edge from the set of edges `edges`. - `pᵢ`: The point corresponding to `i`. - `pⱼ`: The point corresponding to `j`. """ -function select_random_edge(tri::Triangulation, edges, rng::AbstractRNG=Random.default_rng()) +function select_random_edge(tri::Triangulation, edges, rng::AbstractRNG = Random.default_rng()) edge = random_edge(rng, edges) i, j = edge_vertices(edge) pᵢ, pⱼ = get_point(tri, i, j) @@ -129,7 +133,7 @@ Selects a random edge from the set of edges `edges` and computes the certificate - `line_cert_i`: The [`Certificate`](@ref) for `pᵢ`'s position relative to the oriented line `pq`. - `line_cert_j`: The [`Certificate`](@ref) for `pⱼ`'s position relative to the oriented line `pq`. """ -function prepare_initial_edge(tri::Triangulation, edges, p, q, rng::AbstractRNG=Random.default_rng()) +function prepare_initial_edge(tri::Triangulation, edges, p, q, rng::AbstractRNG = Random.default_rng()) i, j, pᵢ, pⱼ = select_random_edge(tri, edges, rng) line_cert_i = point_position_relative_to_line(p, q, pᵢ) line_cert_j = point_position_relative_to_line(p, q, pⱼ) @@ -172,7 +176,7 @@ respectively. In case the initial edge is collinear with the line `pq`, where `p = get_point(tri, q)`, then `fix_initial_collinear_edge_for_interior_vertex` to find a non-collinear edge resample more edges from [`prepare_initial_edge`](@ref) if necessary. """ -function select_initial_triangle_interior_vertex(tri::Triangulation, k, q, store_history::F=Val(false), history=nothing, rng::AbstractRNG=Random.default_rng()) where {F} +function select_initial_triangle_interior_vertex(tri::Triangulation, k, q, store_history::F = Val(false), history = nothing, rng::AbstractRNG = Random.default_rng()) where {F} p = get_point(tri, k) ## Select the initial edge to rotate about neighbouring_edges = get_adjacent2vertex(tri, k) @@ -192,7 +196,7 @@ function select_initial_triangle_interior_vertex(tri::Triangulation, k, q, store pᵢ, pⱼ = pⱼ, pᵢ # pᵢ is left of pq, pⱼ is right of pq return p, i, j, pᵢ, pⱼ end -function select_initial_triangle_clockwise(tri::Triangulation, p, q, pᵢ, pⱼ, i, j, k, store_history::F=Val(false), history=nothing) where {F} +function select_initial_triangle_clockwise(tri::Triangulation, p, q, pᵢ, pⱼ, i, j, k, store_history::F = Val(false), history = nothing) where {F} line_cert_i = point_position_relative_to_line(p, q, pᵢ) if is_true(store_history) && is_collinear(line_cert_i) add_edge!(history, k, i) @@ -217,7 +221,7 @@ function select_initial_triangle_clockwise(tri::Triangulation, p, q, pᵢ, pⱼ, return i, j, pᵢ, pⱼ end end -function select_initial_triangle_counterclockwise(tri::Triangulation, line_cert_j, p, q, pᵢ, pⱼ, i, j, k, store_history::F=Val(false), history=nothing) where {F} +function select_initial_triangle_counterclockwise(tri::Triangulation, line_cert_j, p, q, pᵢ, pⱼ, i, j, k, store_history::F = Val(false), history = nothing) where {F} if is_true(store_history) && is_collinear(line_cert_j) add_edge!(history, k, j) end @@ -307,7 +311,7 @@ straight boundary in case `q` is collinear with it. - `right_cert`: The [`Certificate`](@ref) for the position of `q` relative to the boundary edge right of `k`. - `left_cert`: The [`Certificate`](@ref) for the position of `q` relative to the boundary edge left of `k`. """ -function check_for_intersections_with_adjacent_boundary_edges(tri::Triangulation{P,T,BN,W,I}, k, q, ghost_vertex=I(𝒢)) where {P,T,BN,W,I} +function check_for_intersections_with_adjacent_boundary_edges(tri::Triangulation{P, T, BN, W, I}, k, q, ghost_vertex = I(𝒢)) where {P, T, BN, W, I} p = get_point(tri, k) right = get_right_boundary_node(tri, k, ghost_vertex) left = get_left_boundary_node(tri, k, ghost_vertex) @@ -368,7 +372,7 @@ This function works by stepping along vertices on the boundaries in the directio if `is_right(direction_cert)` and `search_left_down_adjacent_boundary_edges` otherwise. In these functions, a `while` loop is used to keep stepping until `q_pos_cert`, which is updated at each iteration, changes value. """ -function search_down_adjacent_boundary_edges(tri::Triangulation, k, q, direction, q_pos, next_vertex, store_history::F=Val(false), history=nothing, ghost_vertex=integer_type(tri)(𝒢)) where {F} +function search_down_adjacent_boundary_edges(tri::Triangulation, k, q, direction, q_pos, next_vertex, store_history::F = Val(false), history = nothing, ghost_vertex = integer_type(tri)(𝒢)) where {F} i = k j = next_vertex pⱼ = get_point(tri, j) @@ -467,7 +471,7 @@ the vertex `k`, rotating counter-clockwise until we find an intersection or reac the vertex `k`. By keeping track of the positions of `pq` relative to the current vertex and the previous, we can identify when an intersection is found. If no intersection is found before reaching the boundary edge left of `k`, then `check_for_intersections_with_triangle_left_to_boundary_vertex` is used to check the remaining triangle. """ -function check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri::Triangulation, k, q, right_cert, left_cert, store_history::F=Val(false), history=nothing, ghost_vertex=integer_type(tri)(𝒢)) where {F} +function check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri::Triangulation, k, q, right_cert, left_cert, store_history::F = Val(false), history = nothing, ghost_vertex = integer_type(tri)(𝒢)) where {F} I = integer_type(tri) p = get_point(tri, k) other_boundary_node = get_left_boundary_node(tri, k, ghost_vertex) @@ -614,7 +618,7 @@ left of the line using `exterior_find_triangle_rotate_left` and clockwise otherw By keeping track of the current position of `q` and its position relative to the next ghost edge, we can identify when `q` resides inside a ghost triangle. """ -function exterior_find_triangle(tri::Triangulation, k, q, ghost_vertex=integer_type(tri)(𝒢)) +function exterior_find_triangle(tri::Triangulation, k, q, ghost_vertex = integer_type(tri)(𝒢)) pₘ, pᵢ = get_point(tri, ghost_vertex, k) i = k q_position = point_position_relative_to_line(pₘ, pᵢ, q) @@ -726,17 +730,19 @@ The algorithm underlying this function is complicated and broken into many parts 4. If we have not yet returned and the triangle is no longer positively oriented, we check if the triangle is degenerate using [`find_triangle_degenerate_arrangement`](@ref) and reinitialise the algorithm if needed. Otherwise, we have found the triangle containing `q` and return the triangle. """ -function find_triangle(tri::Triangulation, _q; - point_indices=each_solid_vertex(tri), - m=default_num_samples(num_vertices(point_indices)), - try_points=(), - rng::AbstractRNG=Random.default_rng(), - k=select_initial_point(tri, _q; point_indices, m, try_points, rng), - store_history::F=Val(false), - history=nothing, - maxiters=2 + num_exterior_curves(tri) - num_solid_vertices(tri) + num_solid_edges(tri), - concavity_protection=false, - use_barriers::Val{U}=Val(false)) where {F,U} +function find_triangle( + tri::Triangulation, _q; + point_indices = each_solid_vertex(tri), + m = default_num_samples(num_vertices(point_indices)), + try_points = (), + rng::AbstractRNG = Random.default_rng(), + k = select_initial_point(tri, _q; point_indices, m, try_points, rng), + store_history::F = Val(false), + history = nothing, + maxiters = 2 + num_exterior_curves(tri) - num_solid_vertices(tri) + num_solid_edges(tri), + concavity_protection = false, + use_barriers::Val{U} = Val(false), + ) where {F, U} I = integer_type(tri) maxiters = Int(maxiters) G = number_type(tri) @@ -892,8 +898,8 @@ function find_triangle_return_on_vertex(tri::Triangulation, q, k, p, pᵢ, pⱼ, # vertices, but without meaning that it is actually in that triangle. So, # we need to also check for the type of indices we have. safety_check = (q == p && !is_ghost_vertex(k)) || - (q == pᵢ && !is_ghost_vertex(i)) || - (q == pⱼ && !is_ghost_vertex(j)) + (q == pᵢ && !is_ghost_vertex(i)) || + (q == pⱼ && !is_ghost_vertex(j)) if safety_check orientation = triangle_orientation(pᵢ, pⱼ, p) if is_positively_oriented(orientation) @@ -1100,7 +1106,7 @@ function find_triangle_degenerate_arrangement(tri::Triangulation, q, k, store_hi return is_outside(in_cert) # if outside, we need to reinitialise. Otherwise, we're all good. end -function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng::AbstractRNG, maxiters, cur_iter, concavity_protection, num_restarts, use_barriers::Val{U}) where {F,U} +function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng::AbstractRNG, maxiters, cur_iter, concavity_protection, num_restarts, use_barriers::Val{U}) where {F, U} is_bnd, ghost_vertex = is_boundary_node(tri, k) I = integer_type(tri) trit = triangle_type(tri) @@ -1114,7 +1120,7 @@ function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng end else restart_flag, return_flag, V, p, i, j, pᵢ, pⱼ = initialise_find_triangle_boundary_vertex(tri, q, k, store_history, history, ghost_vertex, concavity_protection) - if restart_flag && !is_true(use_barriers) + if restart_flag && !is_true(use_barriers) return restart_find_triangle(tri, q, store_history, history, rng, maxiters, cur_iter, concavity_protection, num_restarts + 1, use_barriers) elseif restart_flag && is_true(use_barriers) return V, true @@ -1123,7 +1129,7 @@ function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng end if q == p || q == pᵢ || q == pⱼ restart_flag, return_flag, V = find_triangle_return_on_vertex(tri, q, k, p, pᵢ, pⱼ, i, j) - if restart_flag && !is_true(use_barriers) + if restart_flag && !is_true(use_barriers) return restart_find_triangle(tri, q, store_history, history, rng, maxiters, cur_iter, concavity_protection, num_restarts + 1, use_barriers) elseif restart_flag && is_true(use_barriers) return V, true @@ -1148,7 +1154,7 @@ function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng end while is_positively_oriented(arrangement) && !reached_barrier restart_flag, return_flag, reinitialise_flag, V, cur_iter, arrangement, k, last_changed, original_k, pᵢ, pⱼ, i, j = find_triangle_across_triangle(tri, q, k, store_history, history, maxiters, cur_iter, concavity_protection, arrangement, original_k, last_changed, p, i, j, pᵢ, pⱼ) - if restart_flag && !is_true(use_barriers) + if restart_flag && !is_true(use_barriers) return restart_find_triangle(tri, q, store_history, history, rng, maxiters, cur_iter, concavity_protection, num_restarts + 1, use_barriers) elseif restart_flag && is_true(use_barriers) return V, true @@ -1161,7 +1167,7 @@ function _find_triangle(tri::Triangulation, q, k, store_history::F, history, rng # To clear this up, let us just restart. if is_degenerate(arrangement) reinitialise_flag = find_triangle_degenerate_arrangement(tri, q, k, store_history, history, pᵢ, pⱼ, i, j) - if reinitialise_flag && !is_true(use_barriers) + if reinitialise_flag && !is_true(use_barriers) return _find_triangle(tri, q, last_changed == I(∅) ? i : last_changed, store_history, history, rng, maxiters, cur_iter, concavity_protection, num_restarts + 1, use_barriers) elseif reinitialise_flag && is_true(use_barriers) return V, true @@ -1237,16 +1243,16 @@ function restart_find_triangle(tri, q, store_history, history, rng, maxiters, cu if num_restarts < RESTART_LIMIT m = num_solid_vertices(tri) point_indices = each_solid_vertex(tri) - k = select_initial_point(tri, q; m=(m >> 1) + 1, point_indices, rng) # don't want to try all points, still want to give the algorithm a chance + k = select_initial_point(tri, q; m = (m >> 1) + 1, point_indices, rng) # don't want to try all points, still want to give the algorithm a chance return _find_triangle(tri, q, k, store_history, history, rng, maxiters, zero(cur_iter), concavity_protection, num_restarts, use_barriers) else V = brute_force_search(tri, q) V_is_bad = concavity_protection_check(tri, concavity_protection, V, q) if V_is_bad if is_ghost_triangle(V) - V = brute_force_search(tri, q; itr=each_solid_triangle(tri)) + V = brute_force_search(tri, q; itr = each_solid_triangle(tri)) else - V = brute_force_search(tri, q; itr=each_ghost_triangle(tri)) + V = brute_force_search(tri, q; itr = each_ghost_triangle(tri)) end end if is_true(use_barriers) @@ -1255,4 +1261,4 @@ function restart_find_triangle(tri, q, store_history, history, rng, maxiters, cu return V end end -end \ No newline at end of file +end diff --git a/src/algorithms/point_location/nearest_neighbour.jl b/src/algorithms/point_location/nearest_neighbour.jl index 1737a1fb0..955d22ae9 100644 --- a/src/algorithms/point_location/nearest_neighbour.jl +++ b/src/algorithms/point_location/nearest_neighbour.jl @@ -59,4 +59,4 @@ function jump_to_voronoi_polygon(tri::Triangulation, q; kwargs...) end end return current_idx -end \ No newline at end of file +end diff --git a/src/algorithms/pole_of_inaccessibility.jl b/src/algorithms/pole_of_inaccessibility.jl index e38b2a891..becf48d5a 100644 --- a/src/algorithms/pole_of_inaccessibility.jl +++ b/src/algorithms/pole_of_inaccessibility.jl @@ -22,7 +22,7 @@ a centroid which is not always inside the polygon. Some useful links are [this b and the [the original repo](https://github.com/mapbox/polylabel). Our implementation is partially based on on [the python implementation](https://github.com/Twista/python-polylabel) and [this other Julia implementation](https://github.com/asinghvi17/Polylabel.jl). """ -function pole_of_inaccessibility(points, boundary_nodes; precision=one(number_type(points))) +function pole_of_inaccessibility(points, boundary_nodes; precision = one(number_type(points))) ## Initiate xmin, xmax, ymin, ymax = polygon_bounds(points, boundary_nodes) width = xmax - xmin @@ -67,8 +67,10 @@ function pole_of_inaccessibility(points, boundary_nodes; precision=one(number_ty ## We are done, and the last best_cell is the solution return best_cell.x, best_cell.y end -function process_cell!(queue::CellQueue{F}, best_cell::Cell{F}, points, boundary_nodes, - precision) where {F} +function process_cell!( + queue::CellQueue{F}, best_cell::Cell{F}, points, boundary_nodes, + precision, + ) where {F} next_cell = get_next_cell!(queue) if next_cell.dist > best_cell.dist best_cell = next_cell # This cell will have a large circle, so let's choose it @@ -89,4 +91,4 @@ function process_cell!(queue::CellQueue{F}, best_cell::Cell{F}, points, boundary insert_cell!(queue, cell_3) insert_cell!(queue, cell_4) return best_cell -end \ No newline at end of file +end diff --git a/src/algorithms/polygon_clipping/sutherland_hodgman.jl b/src/algorithms/polygon_clipping/sutherland_hodgman.jl index f067ad8da..d550e5623 100644 --- a/src/algorithms/polygon_clipping/sutherland_hodgman.jl +++ b/src/algorithms/polygon_clipping/sutherland_hodgman.jl @@ -56,11 +56,11 @@ function clip_polygon(poly::Polygon{T}, clip_poly::Polygon) where {T} output_list = poly q = clip_poly[end] for p in clip_poly - input_list = output_list + input_list = output_list isempty(output_list) && break output_list = clip_polygon_to_edge(input_list, q, p) q = p end !isempty(output_list) && push!(output_list, output_list[begin]) return output_list::Vector{T} -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/add_boundary_information.jl b/src/algorithms/triangulation/basic_operations/add_boundary_information.jl index e63e0fb7b..07a7c83da 100644 --- a/src/algorithms/triangulation/basic_operations/add_boundary_information.jl +++ b/src/algorithms/triangulation/basic_operations/add_boundary_information.jl @@ -5,7 +5,7 @@ Updates `tri` so that the ghost triangle information defined by the boundary nod """ function add_boundary_information!(tri::Triangulation) I = integer_type(tri) - ghost_vertex= I(𝒢) + ghost_vertex = I(𝒢) bn = get_boundary_nodes(tri) if has_multiple_curves(tri) add_boundary_curve_information!(tri, bn, ghost_vertex) diff --git a/src/algorithms/triangulation/basic_operations/add_point.jl b/src/algorithms/triangulation/basic_operations/add_point.jl index 095296855..86967c9d9 100644 --- a/src/algorithms/triangulation/basic_operations/add_point.jl +++ b/src/algorithms/triangulation/basic_operations/add_point.jl @@ -34,27 +34,29 @@ The triangulation is updated in-place, but we do return In cases where `(x, y)` is outside of the triangulation, it will be added successfully but note that the `convex_hull` field of `tri` will no longer be accurate. You can use [`convex_hull!`](@ref) to fix it. """ -function add_point!(tri::Triangulation, new_point; - point_indices=each_solid_vertex(tri), - m=default_num_samples(length(point_indices)), - try_points=(), - rng::AbstractRNG=Random.default_rng(), - initial_search_point=integer_type(tri)(select_initial_point(tri, new_point; point_indices, m, try_points, rng)), - update_representative_point=false, - store_event_history=Val(false), - event_history=nothing, - concavity_protection=false, - V=find_triangle( - tri, - get_point(tri, new_point); - m=nothing, - point_indices=nothing, - try_points=nothing, - k=initial_search_point, - concavity_protection, - rng - ), - peek::P=Val(false)) where {P} +function add_point!( + tri::Triangulation, new_point; + point_indices = each_solid_vertex(tri), + m = default_num_samples(length(point_indices)), + try_points = (), + rng::AbstractRNG = Random.default_rng(), + initial_search_point = integer_type(tri)(select_initial_point(tri, new_point; point_indices, m, try_points, rng)), + update_representative_point = false, + store_event_history = Val(false), + event_history = nothing, + concavity_protection = false, + V = find_triangle( + tri, + get_point(tri, new_point); + m = nothing, + point_indices = nothing, + try_points = nothing, + k = initial_search_point, + concavity_protection, + rng, + ), + peek::P = Val(false), + ) where {P} int_flag = new_point isa Integer if !int_flag && !is_true(peek) push_point!(tri, new_point) @@ -70,41 +72,44 @@ function add_point!(tri::Triangulation, new_point; return V end -function add_point!(tri::Triangulation, new_point_x, new_point_y; - point_indices=get_vertices(tri), - m=default_num_samples(length(point_indices)), - try_points=(), - rng::AbstractRNG=Random.default_rng(), - initial_search_point=integer_type(tri)(select_initial_point(tri, (new_point_x, new_point_y); point_indices, m, try_points, rng)), - update_representative_point=false, - store_event_history=Val(false), - event_history=nothing, - concavity_protection=false, - V=find_triangle( - tri, - (new_point_x, new_point_y); - m=nothing, - point_indices=nothing, - try_points=nothing, - k=initial_search_point, - concavity_protection, - rng - ), - peek::P=Val(false)) where {P} +function add_point!( + tri::Triangulation, new_point_x, new_point_y; + point_indices = get_vertices(tri), + m = default_num_samples(length(point_indices)), + try_points = (), + rng::AbstractRNG = Random.default_rng(), + initial_search_point = integer_type(tri)(select_initial_point(tri, (new_point_x, new_point_y); point_indices, m, try_points, rng)), + update_representative_point = false, + store_event_history = Val(false), + event_history = nothing, + concavity_protection = false, + V = find_triangle( + tri, + (new_point_x, new_point_y); + m = nothing, + point_indices = nothing, + try_points = nothing, + k = initial_search_point, + concavity_protection, + rng, + ), + peek::P = Val(false), + ) where {P} !is_true(peek) && push_point!(tri, new_point_x, new_point_y) VV = add_point!( tri, is_true(peek) ? (new_point_x, new_point_y) : num_points(tri); - point_indices=point_indices, - m=m, - try_points=try_points, - rng=rng, - initial_search_point=initial_search_point, - update_representative_point=update_representative_point, - store_event_history=store_event_history, - event_history=event_history, + point_indices = point_indices, + m = m, + try_points = try_points, + rng = rng, + initial_search_point = initial_search_point, + update_representative_point = update_representative_point, + store_event_history = store_event_history, + event_history = event_history, V, - peek) + peek, + ) return VV end @@ -117,4 +122,4 @@ is defined on the weights stored in `tri`. The `kwargs` match those from [`add_p function add_point!(tri::Triangulation, x, y, w; kwargs...) add_weight!(tri, w) return add_point!(tri, x, y; kwargs...) -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/add_segment.jl b/src/algorithms/triangulation/basic_operations/add_segment.jl index b439ffc3e..23d7bd963 100644 --- a/src/algorithms/triangulation/basic_operations/add_segment.jl +++ b/src/algorithms/triangulation/basic_operations/add_segment.jl @@ -71,7 +71,7 @@ Adds `segment = (i, j)` to `tri`. # Outputs There is no output, but `tri` will be updated so that it now contains `segment`. """ -function add_segment!(tri::Triangulation, segment; rng::AbstractRNG=Random.default_rng()) +function add_segment!(tri::Triangulation, segment; rng::AbstractRNG = Random.default_rng()) e = optimise_edge_order(tri, segment) fix_edge_order_after_rotation!(tri, segment, e) add_segment_to_list!(tri, e) @@ -92,4 +92,4 @@ function add_segment!(tri::Triangulation, segment; rng::AbstractRNG=Random.defau end return tri end -add_segment!(tri::Triangulation, i, j; rng=Random.default_rng()) = add_segment!(tri, construct_edge(edge_type(tri), i, j); rng) \ No newline at end of file +add_segment!(tri::Triangulation, i, j; rng = Random.default_rng()) = add_segment!(tri, construct_edge(edge_type(tri), i, j); rng) diff --git a/src/algorithms/triangulation/basic_operations/add_triangle.jl b/src/algorithms/triangulation/basic_operations/add_triangle.jl index 3c53bdf65..7c391ccb4 100644 --- a/src/algorithms/triangulation/basic_operations/add_triangle.jl +++ b/src/algorithms/triangulation/basic_operations/add_triangle.jl @@ -16,8 +16,10 @@ so that its existence in the triangulation is known. # Outputs There are no outputs as `tri` is updated in-place. """ -function add_triangle!(tri::Ts, u::Integer, v::Integer, w::Integer; - protect_boundary=false, update_ghost_edges=false) where {Ts<:Triangulation} +function add_triangle!( + tri::Ts, u::Integer, v::Integer, w::Integer; + protect_boundary = false, update_ghost_edges = false, + ) where {Ts <: Triangulation} ## Add the necessary triangles adj = get_adjacent(tri) adj2v = get_adjacent2vertex(tri) @@ -43,13 +45,13 @@ function add_triangle!(tri::Ts, u::Integer, v::Integer, w::Integer; end return tri end -function add_triangle!(tri::Triangulation, T; protect_boundary=false, update_ghost_edges=false) +function add_triangle!(tri::Triangulation, T; protect_boundary = false, update_ghost_edges = false) u, v, w = triangle_vertices(T) add_triangle!(tri, u, v, w; protect_boundary, update_ghost_edges) return tri end -function add_boundary_edges_single!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function add_boundary_edges_single!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) # Here, we are adding two ghost triangles uwg and wvg, where g is the ghost vertex, coming from # the two new boundary edges uw and wv. @@ -79,7 +81,7 @@ function add_boundary_edges_single!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, return nothing end -function add_boundary_edges_double!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function add_boundary_edges_double!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) # Here, we are only adding a single ghost triangle vug, where g is the ghost vertex, # coming from the new boundary edge vu. @@ -109,7 +111,7 @@ function add_boundary_edges_double!(u, v, w, uv_bnd, vw_bnd, wu_bnd, triangles, return nothing end -function add_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function add_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) # Here, we are adding three ghost triangles uwg, wvg, and vug, where g is the ghost vertex. add_adjacent!(adj, v, u, g) @@ -138,4 +140,4 @@ function add_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I,E}, adj2 add_triangle!(triangles, w, v, g) end return nothing -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/delete_holes.jl b/src/algorithms/triangulation/basic_operations/delete_holes.jl index 2d401c6ad..5b4844bef 100644 --- a/src/algorithms/triangulation/basic_operations/delete_holes.jl +++ b/src/algorithms/triangulation/basic_operations/delete_holes.jl @@ -30,7 +30,7 @@ Deletes all the triangles in the set `triangles` from the triangulation `tri`. """ function delete_all_exterior_triangles!(tri::Triangulation, triangles) for T in each_triangle(triangles) - delete_triangle!(tri, T; protect_boundary=true) + delete_triangle!(tri, T; protect_boundary = true) end return tri end @@ -186,4 +186,4 @@ function find_all_triangles_to_delete(tri::Triangulation, points_to_process) end end return triangles_to_delete -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/delete_point.jl b/src/algorithms/triangulation/basic_operations/delete_point.jl index 197fb410e..865742aa4 100644 --- a/src/algorithms/triangulation/basic_operations/delete_point.jl +++ b/src/algorithms/triangulation/basic_operations/delete_point.jl @@ -16,11 +16,11 @@ Returns the counter-clockwise sequence of neighbours of `u` in `tri`. the associated boundary curve. If you do not have ghost triangles and you try to get the surrounding polygon of a boundary vertex, then this function may return an invalid polygon. """ -function get_surrounding_polygon(tri::Triangulation, u; skip_ghost_vertices=false) +function get_surrounding_polygon(tri::Triangulation, u; skip_ghost_vertices = false) return copy(get_surrounding_polygon!(tri, u; skip_ghost_vertices)) end -function get_surrounding_polygon!(tri::Triangulation, u; skip_ghost_vertices=false) +function get_surrounding_polygon!(tri::Triangulation, u; skip_ghost_vertices = false) cache = get_cache(tri) S = get_surrounding_polygon(cache) neighbouring_vertices = get_neighbours(tri, u) @@ -96,9 +96,9 @@ end Ensures that the edges in `S` surrounding a deleted vertex of `tri` are correctly updated. """ function fix_edges_after_deletion!(tri, S) - for i in firstindex(S):(lastindex(S)-1) + for i in firstindex(S):(lastindex(S) - 1) u = S[i] - v = S[i+1] + v = S[i + 1] w = get_adjacent(tri, v, u) if edge_exists(w) add_adjacent!(tri, u, w, v) @@ -132,10 +132,12 @@ See also [`check_delete_point_args`](@ref). - `event_history=nothing`: The event history of the triangulation from deleting the point. Only updated if `store_event_history` is true, in which case it needs to be an [`InsertionEventHistory`](@ref) object. - `rng::AbstractRNG=Random.default_rng()`: The random number generator to use for the triangulation. """ -function delete_point!(tri::Triangulation, vertex; - store_event_history=Val(false), - event_history=nothing, - rng::AbstractRNG=Random.default_rng()) +function delete_point!( + tri::Triangulation, vertex; + store_event_history = Val(false), + event_history = nothing, + rng::AbstractRNG = Random.default_rng(), + ) cache = get_cache(tri) empty!(cache) convex_tri = get_triangulation(cache) @@ -145,13 +147,13 @@ function delete_point!(tri::Triangulation, vertex; trit = triangle_type(tri) for uv in each_edge(neighbouring_edges) # note that we are mutating this iterator during iteration u, v = edge_vertices(uv) - delete_triangle!(tri, vertex, u, v; protect_boundary=true) + delete_triangle!(tri, vertex, u, v; protect_boundary = true) is_true(store_event_history) && delete_triangle!(event_history, construct_triangle(trit, vertex, u, v)) end triangulate_convex!(convex_tri, S; rng) # fill in the cavity for T in each_solid_triangle(convex_tri) u, v, w = triangle_vertices(T) - add_triangle!(tri, u, v, w; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, u, v, w; protect_boundary = true, update_ghost_edges = false) is_true(store_event_history) && add_triangle!(event_history, T) end delete_adjacent2vertex!(tri, vertex) diff --git a/src/algorithms/triangulation/basic_operations/delete_triangle.jl b/src/algorithms/triangulation/basic_operations/delete_triangle.jl index 5fb832b43..c5d89bdb2 100644 --- a/src/algorithms/triangulation/basic_operations/delete_triangle.jl +++ b/src/algorithms/triangulation/basic_operations/delete_triangle.jl @@ -16,8 +16,10 @@ so that its non-existence in the triangulation is known. # Outputs There are no outputs as `tri` is updated in-place. """ -function delete_triangle!(tri::Ts, u::Integer, v::Integer, w::Integer; - protect_boundary=false, update_ghost_edges=false) where {Ts<:Triangulation} +function delete_triangle!( + tri::Ts, u::Integer, v::Integer, w::Integer; + protect_boundary = false, update_ghost_edges = false, + ) where {Ts <: Triangulation} adj = get_adjacent(tri) adj2v = get_adjacent2vertex(tri) graph = get_graph(tri) @@ -48,13 +50,13 @@ function delete_triangle!(tri::Ts, u::Integer, v::Integer, w::Integer; end return nothing end -function delete_triangle!(tri::Triangulation, T; protect_boundary=false, update_ghost_edges=false) +function delete_triangle!(tri::Triangulation, T; protect_boundary = false, update_ghost_edges = false) u, v, w = triangle_vertices(T) delete_triangle!(tri, u, v, w; protect_boundary, update_ghost_edges) return nothing end -function delete_boundary_edges_single!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function delete_boundary_edges_single!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) u, v, w = choose_uvw(vu_bnd, wv_bnd, uw_bnd, u, v, w) delete_adjacent!(adj, v, u) @@ -85,7 +87,7 @@ function delete_boundary_edges_single!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangle return nothing end -function delete_boundary_edges_double!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function delete_boundary_edges_double!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) u, v, w = choose_uvw(!vu_bnd, !wv_bnd, !uw_bnd, u, v, w) delete_adjacent!(adj, u, w) @@ -116,7 +118,7 @@ function delete_boundary_edges_double!(u, v, w, vu_bnd, uw_bnd, wv_bnd, triangle return nothing end -function delete_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I,E}, adj2v, graph, update_ghost_edges) where {I,E} +function delete_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I, E}, adj2v, graph, update_ghost_edges) where {I, E} g = I(𝒢) delete_adjacent!(adj, w, v) delete_adjacent!(adj, v, u) @@ -146,4 +148,4 @@ function delete_boundary_edges_triple!(u, v, w, triangles, adj::Adjacent{I,E}, a delete_triangle!(triangles, u, w, g) end return nothing -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/flip_edge.jl b/src/algorithms/triangulation/basic_operations/flip_edge.jl index 5b676ba0e..7a4a4d6b7 100644 --- a/src/algorithms/triangulation/basic_operations/flip_edge.jl +++ b/src/algorithms/triangulation/basic_operations/flip_edge.jl @@ -20,17 +20,17 @@ There is no output, as `tri` is updated in-place. If `(i, j, k, ℓ)`, where `ℓ = get_adjacent(tri, i, j)` and `k = get_adjacent(tri, j, i)`, is not a convex quadrilateral, then this edge flip will make the triangulation non-planar. """ -function flip_edge!(tri::Triangulation, i::I, j::I, store_event_history::Val{B}=Val(false), event_history=nothing) where {I<:Integer,B} +function flip_edge!(tri::Triangulation, i::I, j::I, store_event_history::Val{B} = Val(false), event_history = nothing) where {I <: Integer, B} ℓ = get_adjacent(tri, i, j) k = get_adjacent(tri, j, i) flip_edge!(tri, i, j, k, ℓ, store_event_history, event_history) return tri end -function flip_edge!(tri::Triangulation, i::I, j::I, k::I, ℓ::I, store_event_history::Val{B}=Val(false), event_history=nothing) where {I<:Integer,B} - delete_triangle!(tri, i, k, j; protect_boundary=true, update_ghost_edges=false) - delete_triangle!(tri, i, j, ℓ; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, ℓ, k, j; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, ℓ, i, k; protect_boundary=true, update_ghost_edges=false) +function flip_edge!(tri::Triangulation, i::I, j::I, k::I, ℓ::I, store_event_history::Val{B} = Val(false), event_history = nothing) where {I <: Integer, B} + delete_triangle!(tri, i, k, j; protect_boundary = true, update_ghost_edges = false) + delete_triangle!(tri, i, j, ℓ; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, ℓ, k, j; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, ℓ, i, k; protect_boundary = true, update_ghost_edges = false) is_true(store_event_history) && store_flip_edge_history!(event_history, i, j, k, ℓ) return tri end @@ -51,4 +51,4 @@ function store_flip_edge_history!(event_history, i, j, k, ℓ) delete_triangle!(event_history.deleted_triangles, Tℓkj) delete_triangle!(event_history.deleted_triangles, Tℓik) return event_history -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/legalise_edge.jl b/src/algorithms/triangulation/basic_operations/legalise_edge.jl index 6f9ebac45..83199a653 100644 --- a/src/algorithms/triangulation/basic_operations/legalise_edge.jl +++ b/src/algorithms/triangulation/basic_operations/legalise_edge.jl @@ -23,13 +23,13 @@ There is no output, as `tri` is updated in-place. To get around this, we only store in these fields the triangles necessary to allow [`undo_insertion!`](@ref) to work, so that at a triangle that might have appeared in both will only appear in one. """ -function legalise_edge!(tri::Triangulation, i, j, r, store_event_history=Val(false), event_history=nothing) +function legalise_edge!(tri::Triangulation, i, j, r, store_event_history = Val(false), event_history = nothing) cert = is_legal(tri, i, j) - if is_illegal(cert) + if is_illegal(cert) e = get_adjacent(tri, j, i) flip_edge!(tri, i, j, e, r, store_event_history, event_history) legalise_edge!(tri, i, e, r, store_event_history, event_history) legalise_edge!(tri, e, j, r, store_event_history, event_history) end return tri -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/lock_convex_hull.jl b/src/algorithms/triangulation/basic_operations/lock_convex_hull.jl index a81821f0c..7a565540c 100644 --- a/src/algorithms/triangulation/basic_operations/lock_convex_hull.jl +++ b/src/algorithms/triangulation/basic_operations/lock_convex_hull.jl @@ -41,4 +41,4 @@ function lock_convex_hull!(tri::Triangulation) add_segment!(tri, e) end return tri -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/split_edge.jl b/src/algorithms/triangulation/basic_operations/split_edge.jl index b12796575..c02ca3db6 100644 --- a/src/algorithms/triangulation/basic_operations/split_edge.jl +++ b/src/algorithms/triangulation/basic_operations/split_edge.jl @@ -37,7 +37,7 @@ There is no output, as `tri` is updated in-place. The triangulation will only be updated as if `(i, j)` has been split rather than also `(j, i)`. You will need to call `split_edge!` again with `(j, i)` if you want to split that edge as well. """ -function split_edge!(tri::Triangulation, i, j, r, store_event_history=Val(false), event_history=nothing) +function split_edge!(tri::Triangulation, i, j, r, store_event_history = Val(false), event_history = nothing) if is_constrained(tri) && contains_segment(tri, i, j) is_bnd = contains_boundary_edge(tri, i, j) || contains_boundary_edge(tri, j, i) eᵢⱼ, eⱼᵢ, eᵢᵣ, eᵣᵢ, eᵣⱼ, eⱼᵣ = get_edges_for_split_edge(tri, i, j, r) @@ -79,9 +79,9 @@ function split_edge!(tri::Triangulation, i, j, r, store_event_history=Val(false) end end k = get_adjacent(tri, i, j) - delete_triangle!(tri, i, j, k; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, i, r, k; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, r, j, k; protect_boundary=true, update_ghost_edges=false) + delete_triangle!(tri, i, j, k; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, i, r, k; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, r, j, k; protect_boundary = true, update_ghost_edges = false) if is_true(store_event_history) trit = triangle_type(tri) Tᵢⱼₖ = construct_triangle(trit, i, j, k) @@ -113,7 +113,7 @@ See also [`complete_split_edge_and_legalise!`](@ref). # Outputs There is no output, as `tri` is updated in-place. """ -function legalise_split_edge!(tri::Triangulation, i, j, k, r, store_event_history=Val(false), event_history=nothing) +function legalise_split_edge!(tri::Triangulation, i, j, k, r, store_event_history = Val(false), event_history = nothing) legalise_edge!(tri, j, k, r, store_event_history, event_history) legalise_edge!(tri, k, i, r, store_event_history, event_history) return tri @@ -135,7 +135,7 @@ Given a triangulation `tri`, an edge `(i, j)`, and a point `r`, splits both `(i, # Outputs There is no output, as `tri` is updated in-place. """ -function complete_split_edge_and_legalise!(tri::Triangulation, i, j, r, store_event_history=Val(false), event_history=nothing) +function complete_split_edge_and_legalise!(tri::Triangulation, i, j, r, store_event_history = Val(false), event_history = nothing) k = get_adjacent(tri, i, j) ℓ = get_adjacent(tri, j, i) split_edge!(tri, i, j, r, store_event_history, event_history) @@ -145,9 +145,11 @@ function complete_split_edge_and_legalise!(tri::Triangulation, i, j, r, store_ev if is_true(store_event_history) # The deleted_triangles in event_history will contain triangles with the vertex r, which didn't actually appear # initially. So, we need to deal any triangles with r as a vertex from event_history.deleted_triangles. - filter!(T -> let r = r - r ∉ triangle_vertices(T) - end, event_history.deleted_triangles) + filter!( + T -> let r = r + r ∉ triangle_vertices(T) + end, event_history.deleted_triangles, + ) end return tri -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/basic_operations/split_triangle.jl b/src/algorithms/triangulation/basic_operations/split_triangle.jl index 2347da6ab..43e8e39bc 100644 --- a/src/algorithms/triangulation/basic_operations/split_triangle.jl +++ b/src/algorithms/triangulation/basic_operations/split_triangle.jl @@ -16,10 +16,10 @@ See also [`legalise_split_triangle!`](@ref) and [`complete_split_triangle_and_le There is no output, but `tri` will be updated so that it now contains the triangles `(i, j, r)`, `(j, k, r)`, and `(k, i, r)`. """ function split_triangle!(tri::Triangulation, i, j, k, r) - delete_triangle!(tri, i, j, k; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, i, j, r; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, j, k, r; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, k, i, r; protect_boundary=true, update_ghost_edges=false) + delete_triangle!(tri, i, j, k; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, i, j, r; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, j, k, r; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, k, i, r; protect_boundary = true, update_ghost_edges = false) return tri end diff --git a/src/algorithms/triangulation/basic_operations/unlock_convex_hull.jl b/src/algorithms/triangulation/basic_operations/unlock_convex_hull.jl index 356e5541f..a8ec74930 100644 --- a/src/algorithms/triangulation/basic_operations/unlock_convex_hull.jl +++ b/src/algorithms/triangulation/basic_operations/unlock_convex_hull.jl @@ -6,7 +6,7 @@ assuming that it was locked using [`lock_convex_hull!`](@ref). If `reconstruct = convex hull of `tri` will be reconstructed from the boundary nodes of `tri`. This is useful if, for example, you have split some of the boundary edges during mesh refinement. """ -function unlock_convex_hull!(tri::Triangulation; reconstruct=false) +function unlock_convex_hull!(tri::Triangulation; reconstruct = false) if !has_boundary_nodes(tri) throw(ArgumentError("Cannot unlock the convex hull of a triangulation without boundary nodes.")) end @@ -43,7 +43,7 @@ function unlock_convex_hull!(tri::Triangulation; reconstruct=false) chain = get_boundary_chain(tri, u, v, I(𝒢)) ne = length(chain) - 1 for ℓ in 1:ne - i, j = chain[ℓ], chain[ℓ+1] + i, j = chain[ℓ], chain[ℓ + 1] e_int = construct_edge(E, i, j) add_edge!(all_segments, e_int) add_edge!(interior_segments, e_int) @@ -51,4 +51,4 @@ function unlock_convex_hull!(tri::Triangulation; reconstruct=false) end empty!(interior_segments_on_hull) return tri -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/check_args.jl b/src/algorithms/triangulation/check_args.jl index beb1413de..6e45667eb 100644 --- a/src/algorithms/triangulation/check_args.jl +++ b/src/algorithms/triangulation/check_args.jl @@ -37,7 +37,7 @@ end struct InsufficientPointsError{P} <: Exception points::P end -struct InconsistentConnectionError{I,J} <: Exception +struct InconsistentConnectionError{I, J} <: Exception curve_index::I segment_index₁::I segment_index₂::I @@ -69,7 +69,7 @@ function Base.showerror(io::IO, err::InsufficientPointsError) print(io, "InsufficientPointsError: The provided point set has ", num_points(points), " points, but triangulations require at least three points.") return io end -function Base.showerror(io::IO, err::InconsistentConnectionError) +function Base.showerror(io::IO, err::InconsistentConnectionError) print(io, "InconsistentConnectionError: ") if !iszero(err.segment_index₁) && !(isone(err.segment_index₁) && isone(err.segment_index₂)) print(io, "Segment ", err.segment_index₁) @@ -145,7 +145,7 @@ function has_consistent_connections_multiple_curves(boundary_nodes) end return true end -function has_consistent_connections_multiple_sections(boundary_nodes, curve_index=0) +function has_consistent_connections_multiple_sections(boundary_nodes, curve_index = 0) ns = num_sections(boundary_nodes) segmentⱼ₋₁ = get_boundary_nodes(boundary_nodes, 1) nn = num_boundary_edges(segmentⱼ₋₁) + 1 @@ -169,4 +169,4 @@ function has_consistent_connections_contiguous(boundary_nodes) vₙ = get_boundary_nodes(boundary_nodes, nn) v₁ ≠ vₙ && throw(InconsistentConnectionError(0, 0, 0, v₁, vₙ)) return true -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/constrained_triangulation.jl b/src/algorithms/triangulation/constrained_triangulation.jl index 5a2ccec01..b2d779254 100644 --- a/src/algorithms/triangulation/constrained_triangulation.jl +++ b/src/algorithms/triangulation/constrained_triangulation.jl @@ -52,7 +52,7 @@ function fix_segments!(segments::AbstractVector{E}, bad_indices) where {E} if i == firstindex(segments) # If it starts with a bad index, then no problem, it connects two valid indices. continue else - prev = segments[i-1] + prev = segments[i - 1] cur = segments[i] segments[i] = construct_edge(E, terminal(prev), terminal(cur)) end @@ -86,11 +86,11 @@ function connect_segments!(segments::AbstractVector{E}) where {E} f = firstindex(segments) ℓ = lastindex(segments) I = number_type(E) - insert_idxs = Tuple{Int,I,I}[] + insert_idxs = Tuple{Int, I, I}[] shift_idx = 0 - for i in f:(ℓ-1) + for i in f:(ℓ - 1) eᵢ = segments[i] - eᵢ₊₁ = segments[i+1] + eᵢ₊₁ = segments[i + 1] if terminal(eᵢ) ≠ initial(eᵢ₊₁) push!(insert_idxs, (i + 1 + shift_idx, terminal(eᵢ), initial(eᵢ₊₁))) shift_idx += 1 @@ -221,39 +221,39 @@ into a set of boundary nodes for use in [`triangulate`](@ref). - `points`: The point set, which is the same as `existing_points` but with the boundary points appended to it. """ convert_boundary_points_to_indices -function convert_boundary_points_to_indices(x::AAA, y::AAA; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F<:Number,A<:AbstractVector{F},AA<:AbstractVector{A},AAA<:AbstractVector{AA}} +function convert_boundary_points_to_indices(x::AAA, y::AAA; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F <: Number, A <: AbstractVector{F}, AA <: AbstractVector{A}, AAA <: AbstractVector{AA}} check_args && @assert length(x) == length(y) nodes = [[Int[] for _ in eachindex(x[i])] for i in eachindex(x)] for i in eachindex(x) - _nodes, _ = convert_boundary_points_to_indices(x[i], y[i]; existing_points=existing_points, check_args=true) + _nodes, _ = convert_boundary_points_to_indices(x[i], y[i]; existing_points = existing_points, check_args = true) copyto!(nodes[i], _nodes) end return nodes, existing_points end -function convert_boundary_points_to_indices(x::AA, y::AA; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F<:Number,A<:AbstractVector{F},AA<:AbstractVector{A}} +function convert_boundary_points_to_indices(x::AA, y::AA; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F <: Number, A <: AbstractVector{F}, AA <: AbstractVector{A}} if check_args @assert length(x) == length(y) @assert all(i -> length(x[i]) == length(y[i]), eachindex(x, y)) @assert x[begin][begin] ≈ x[end][end] @assert y[begin][begin] ≈ y[end][end] - @assert all(i -> x[i][end] ≈ x[i+1][begin], firstindex(x):(lastindex(x)-1)) - @assert all(i -> y[i][end] ≈ y[i+1][begin], firstindex(y):(lastindex(y)-1)) + @assert all(i -> x[i][end] ≈ x[i + 1][begin], firstindex(x):(lastindex(x) - 1)) + @assert all(i -> y[i][end] ≈ y[i + 1][begin], firstindex(y):(lastindex(y) - 1)) end nodes = [Int[] for _ in eachindex(x)] for i in eachindex(x) - _nodes, _ = convert_boundary_points_to_indices(x[i], y[i]; existing_points=existing_points, check_args=false, adjust=false) + _nodes, _ = convert_boundary_points_to_indices(x[i], y[i]; existing_points = existing_points, check_args = false, adjust = false) resize!(nodes[i], length(_nodes)) copyto!(nodes[i], _nodes) end if adjust # needed so that the different segments connect - for i in firstindex(nodes):(lastindex(nodes)-1) - push!(nodes[i], nodes[i+1][begin]) + for i in firstindex(nodes):(lastindex(nodes) - 1) + push!(nodes[i], nodes[i + 1][begin]) end push!(nodes[end], nodes[begin][begin]) end return nodes, existing_points end -function convert_boundary_points_to_indices(x::A, y::A; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F<:Number,A<:AbstractVector{F}} +function convert_boundary_points_to_indices(x::A, y::A; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F <: Number, A <: AbstractVector{F}} if check_args @assert length(x) == length(y) @assert x[begin] ≈ x[end] @@ -261,7 +261,7 @@ function convert_boundary_points_to_indices(x::A, y::A; existing_points=NTuple{2 end nodes = Int[] init = num_points(existing_points) + 1 - for i in firstindex(x):(lastindex(x)-1) + for i in firstindex(x):(lastindex(x) - 1) push!(nodes, init) push_point!(existing_points, x[i], y[i]) init += 1 @@ -269,20 +269,20 @@ function convert_boundary_points_to_indices(x::A, y::A; existing_points=NTuple{2 adjust && push!(nodes, nodes[begin]) return nodes, existing_points end -function convert_boundary_points_to_indices(xy::A; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F,A<:AbstractVector{F}} +function convert_boundary_points_to_indices(xy::A; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F, A <: AbstractVector{F}} x = [getx(xy[i]) for i in eachindex(xy)] y = [gety(xy[i]) for i in eachindex(xy)] - return convert_boundary_points_to_indices(x, y; existing_points=existing_points, check_args=check_args, adjust=adjust) + return convert_boundary_points_to_indices(x, y; existing_points = existing_points, check_args = check_args, adjust = adjust) end -function convert_boundary_points_to_indices(xy::AA; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F,A<:AbstractVector{F},AA<:AbstractVector{A}} +function convert_boundary_points_to_indices(xy::AA; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F, A <: AbstractVector{F}, AA <: AbstractVector{A}} x = [[getx(xy[i][j]) for j in eachindex(xy[i])] for i in eachindex(xy)] y = [[gety(xy[i][j]) for j in eachindex(xy[i])] for i in eachindex(xy)] - return convert_boundary_points_to_indices(x, y; existing_points=existing_points, check_args=check_args, adjust=adjust) + return convert_boundary_points_to_indices(x, y; existing_points = existing_points, check_args = check_args, adjust = adjust) end -function convert_boundary_points_to_indices(xy::AAA; existing_points=NTuple{2,Float64}[], check_args=true, adjust=true) where {F,A<:AbstractVector{F},AA<:AbstractVector{A},AAA<:AbstractVector{AA}} +function convert_boundary_points_to_indices(xy::AAA; existing_points = NTuple{2, Float64}[], check_args = true, adjust = true) where {F, A <: AbstractVector{F}, AA <: AbstractVector{A}, AAA <: AbstractVector{AA}} x = [[[getx(xy[i][j][k]) for k in eachindex(xy[i][j])] for j in eachindex(xy[i])] for i in eachindex(xy)] y = [[[gety(xy[i][j][k]) for k in eachindex(xy[i][j])] for j in eachindex(xy[i])] for i in eachindex(xy)] - return convert_boundary_points_to_indices(x, y; existing_points=existing_points, check_args=check_args, adjust=adjust) + return convert_boundary_points_to_indices(x, y; existing_points = existing_points, check_args = check_args, adjust = adjust) end """ @@ -326,24 +326,25 @@ function remake_triangulation_with_constraints(tri::Triangulation, segments, bou boundary_enricher = get_boundary_enricher(tri) cache = get_cache(tri) return new_ghost_vertex_map, new_ghost_vertex_ranges, Triangulation( - points, - triangles, - boundary_nodes, - interior_segments, - all_segments, - weights, - adjacent, - adjacent2vertex, - graph, - boundary_curves, - boundary_edge_map, - ghost_vertex_map, # Delay putting these in until we are done with the triangulation - ghost_vertex_ranges, # Delay putting these in until we are done with the triangulation - ch, - representative_point_list, - polygon_hierarchy, - boundary_enricher, - cache) + points, + triangles, + boundary_nodes, + interior_segments, + all_segments, + weights, + adjacent, + adjacent2vertex, + graph, + boundary_curves, + boundary_edge_map, + ghost_vertex_map, # Delay putting these in until we are done with the triangulation + ghost_vertex_ranges, # Delay putting these in until we are done with the triangulation + ch, + representative_point_list, + polygon_hierarchy, + boundary_enricher, + cache, + ) end """ @@ -395,7 +396,8 @@ function replace_ghost_vertex_information(tri::Triangulation, ghost_vertex_map, representative_point_list, polygon_hierarchy, boundary_enricher, - cache) + cache, + ) end """ @@ -470,7 +472,7 @@ function prepare_vertex_linked_list(V::AbstractArray{I}) where {I} next = zeros(I, m) prev = zeros(I, m) shuffled_indices = zeros(I, m) - for i = 2:(m-1) + for i in 2:(m - 1) next[i] = i + 1 prev[i] = i - 1 shuffled_indices[i] = i @@ -494,7 +496,7 @@ There is no output, but `list` is updated in-place. """ function delete_polygon_vertices_in_random_order!(list::ShuffledPolygonLinkedList, tri::Triangulation, u, v, rng::AbstractRNG) m = list.k - for i in (m-1):-1:3 + for i in (m - 1):-1:3 j = select_random_vertex(tri, list, u, v, 2:i, rng) delete_vertex!(list, j) swap_permutation!(list, i, j) @@ -519,7 +521,7 @@ See also [`prepare_vertex_linked_list`](@ref) and [`delete_polygon_vertices_in_r # Outputs - `list::ShuffledPolygonLinkedList`: The linked list of polygon vertices representing the cavity. """ -function setup_cavity_cdt(tri::Triangulation, V; rng::AbstractRNG=Random.default_rng()) +function setup_cavity_cdt(tri::Triangulation, V; rng::AbstractRNG = Random.default_rng()) v = V[begin] u = V[end] list = prepare_vertex_linked_list(V) @@ -545,10 +547,10 @@ Triangulates the cavity `V` left behind when deleting triangles intersected in a # Outputs There is no output, but `tri` is updated in-place. """ -function triangulate_cavity_cdt!(tri::Triangulation, V, tri_fan::Triangulation, marked_vertices, fan_triangles; rng::AbstractRNG=Random.default_rng()) +function triangulate_cavity_cdt!(tri::Triangulation, V, tri_fan::Triangulation, marked_vertices, fan_triangles; rng::AbstractRNG = Random.default_rng()) list = setup_cavity_cdt(tri, V; rng) - add_triangle!(tri, V[begin], V[list.shuffled_indices[2]], V[end]; protect_boundary=true, update_ghost_edges=false) - for i in 3:(list.k-1) + add_triangle!(tri, V[begin], V[list.shuffled_indices[2]], V[end]; protect_boundary = true, update_ghost_edges = false) + for i in 3:(list.k - 1) a, b, c = get_triplet(list, i) add_point_cavity_cdt!(tri, a, b, c, marked_vertices) if !isempty(marked_vertices) && (last(marked_vertices) == a) || (a ∈ marked_vertices) # We try and insert a last, so the first check will sometimes be a nice boost @@ -571,15 +573,15 @@ end Given a sorted set of vertices `fan` in a fan of triangles associated with `fan_triangles`, retriangulates the fan, updating `tri` to do so and using `tri_fan` as a temporary triangulation. (This implements Lines 17--19 and Line 28 of the algorithms in [this paper](http://dx.doi.org/10.1016/j.comgeo.2015.04.006).) """ -function retriangulate_fan!(tri::Triangulation, tri_fan::Triangulation, fan, fan_triangles; rng::AbstractRNG=Random.default_rng()) +function retriangulate_fan!(tri::Triangulation, tri_fan::Triangulation, fan, fan_triangles; rng::AbstractRNG = Random.default_rng()) for T in each_triangle(fan_triangles) u, v, w = triangle_vertices(T) - delete_triangle!(tri, u, v, w; protect_boundary=true) + delete_triangle!(tri, u, v, w; protect_boundary = true) end triangulate_convex!(tri_fan, fan; rng) for T in each_solid_triangle(tri_fan) u, v, w = triangle_vertices(T) - add_triangle!(tri, u, v, w; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, u, v, w; protect_boundary = true, update_ghost_edges = false) end return tri end @@ -645,9 +647,9 @@ function add_point_cavity_cdt!(tri::Triangulation, u, v, w, marked_vertices) insert_flag = !is_inside(incircle_test) && is_positively_oriented(orient_test) end if insert_flag - add_triangle!(tri, u, v, w; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, u, v, w; protect_boundary = true, update_ghost_edges = false) else - delete_triangle!(tri, w, v, x; protect_boundary=true, update_ghost_edges=false) + delete_triangle!(tri, w, v, x; protect_boundary = true, update_ghost_edges = false) add_point_cavity_cdt!(tri, u, v, x, marked_vertices) add_point_cavity_cdt!(tri, u, x, w, marked_vertices) if !is_inside(incircle_test) @@ -664,7 +666,7 @@ Adds the triangles from `tris` to `tri_original`. """ function add_new_triangles!(tri_original::Triangulation, tris) for tri in each_triangle(tris) - add_triangle!(tri_original, tri; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri_original, tri; protect_boundary = true, update_ghost_edges = false) end return tri_original end @@ -688,16 +690,17 @@ See also [`find_triangle`](@ref). - `left_vertices`: The vertices of the intersected triangles that are left of `e`. - `right_vertices`: The vertices of the intersected triangles that are right of `e`. """ -function locate_intersecting_triangles(tri::Triangulation, e, rotate=Val(true), rng::AbstractRNG=Random.default_rng()) +function locate_intersecting_triangles(tri::Triangulation, e, rotate = Val(true), rng::AbstractRNG = Random.default_rng()) V = triangle_type(tri) E = edge_type(tri) I = integer_type(tri) e = is_true(rotate) ? sort_edge_by_degree(tri, e) : e # faster to start at the minimum degree vertex of the edge - history = PointLocationHistory{V,E,I}() + history = PointLocationHistory{V, E, I}() add_left_vertex!(history, initial(e)) add_right_vertex!(history, initial(e)) - find_triangle(tri, get_point(tri, terminal(e)); - m=nothing, k=initial(e), store_history=Val(true), history, rng + find_triangle( + tri, get_point(tri, terminal(e)); + m = nothing, k = initial(e), store_history = Val(true), history, rng, ) add_left_vertex!(history, terminal(e)) add_right_vertex!(history, terminal(e)) @@ -722,7 +725,7 @@ Deletes the triangles in `triangles` from `tri`. """ function delete_intersected_triangles!(tri, triangles) # don't really _need_ this method, but maybe it makes the code a bit clearer? for τ in each_triangle(triangles) - delete_triangle!(tri, τ; protect_boundary=true) + delete_triangle!(tri, τ; protect_boundary = true) end return tri end @@ -736,7 +739,7 @@ split so that it is instead represented by `collinear_segments`. These new segme See also [`connect_segments!`](@ref), [`extend_segments!`](@ref), [`split_segment!`](@ref) and [`split_boundary_edge_at_collinear_segments!`](@ref). """ -function process_collinear_segments!(tri::Triangulation, e, collinear_segments; rng::AbstractRNG=Random.default_rng()) +function process_collinear_segments!(tri::Triangulation, e, collinear_segments; rng::AbstractRNG = Random.default_rng()) isempty(collinear_segments) && return false all_segments = get_all_segments(tri) # the difference between all_segments and segments is important since we need to be careful about what segments are already in the triangulation delete_edge!(all_segments, e) @@ -805,7 +808,7 @@ to accommodate the changed types. # Outputs - `new_tri`: The new triangulation, now containing `segments` in the `interior_segments` field and `boundary_nodes` in the `boundary_nodes` field, and with the updated [`PolygonHierarchy`](@ref). See also [`remake_triangulation_with_constraints`](@ref) and [`replace_ghost_vertex_information`](@ref). """ -function constrained_triangulation!(tri::Triangulation, segments, boundary_nodes, full_polygon_hierarchy; rng=Random.default_rng(), delete_holes=true) +function constrained_triangulation!(tri::Triangulation, segments, boundary_nodes, full_polygon_hierarchy; rng = Random.default_rng(), delete_holes = true) ghost_vertex_map, ghost_vertex_ranges, new_tri = remake_triangulation_with_constraints(tri, segments, boundary_nodes) all_segments = merge_segments(new_tri, ghost_vertex_map) for e in each_edge(all_segments) @@ -821,4 +824,3 @@ function constrained_triangulation!(tri::Triangulation, segments, boundary_nodes end return new_tri_2 end - diff --git a/src/algorithms/triangulation/main.jl b/src/algorithms/triangulation/main.jl index a4c961849..d40607eb7 100644 --- a/src/algorithms/triangulation/main.jl +++ b/src/algorithms/triangulation/main.jl @@ -7,7 +7,7 @@ Postprocesses the triangulation `tri` after it has been constructed using [`tria - Clearing empty features using [`clear_empty_features!`](@ref) if `delete_empty_features` is `true`. - Recomputing the representative points using [`compute_representative_points!`](@ref) if `recompute_representative_points` is `true`. """ -function postprocess_triangulate!(tri; delete_ghosts=false, delete_empty_features=true, recompute_representative_points=true) +function postprocess_triangulate!(tri; delete_ghosts = false, delete_empty_features = true, recompute_representative_points = true) delete_ghosts && delete_ghost_triangles!(tri) delete_empty_features && clear_empty_features!(tri) recompute_representative_points && compute_representative_points!(tri) @@ -104,33 +104,35 @@ Computes the Delaunay triangulation of `points`, and then the constrained Delaun # Outputs - `tri::Triangulation`: The triangulation. """ -function triangulate(points::P; - segments=nothing, - boundary_nodes=nothing, - weights=ZeroWeight(), - IntegerType::Type{I}=Int, - EdgeType::Type{E}=isnothing(segments) ? NTuple{2,IntegerType} : (edge_type ∘ typeof)(segments), - TriangleType::Type{V}=NTuple{3,IntegerType}, - EdgesType::Type{Es}=isnothing(segments) ? Set{EdgeType} : typeof(segments), - TrianglesType::Type{Ts}=Set{TriangleType}, - randomise=true, - delete_ghosts=false, - delete_empty_features=true, - try_last_inserted_point=true, - skip_points=(), - num_sample_rule::M=default_num_samples, - rng::AbstractRNG=Random.default_rng(), - insertion_order::Vector=get_insertion_order(points, randomise, skip_points, IntegerType, rng), - recompute_representative_points=true, - delete_holes=true, - check_arguments=true, - full_polygon_hierarchy::H=nothing, - boundary_enricher=nothing, - boundary_curves=(), - polygonise_n=4096, - coarse_n=0, - enrich=false) where {P,I,E,V,Es,Ts,M,H} - number_type(points) == Float64 || @warn "Using non-Float64 coordinates may cause issues. If you run into problems, consider using Float64 coordinates." maxlog=1 +function triangulate( + points::P; + segments = nothing, + boundary_nodes = nothing, + weights = ZeroWeight(), + IntegerType::Type{I} = Int, + EdgeType::Type{E} = isnothing(segments) ? NTuple{2, IntegerType} : (edge_type ∘ typeof)(segments), + TriangleType::Type{V} = NTuple{3, IntegerType}, + EdgesType::Type{Es} = isnothing(segments) ? Set{EdgeType} : typeof(segments), + TrianglesType::Type{Ts} = Set{TriangleType}, + randomise = true, + delete_ghosts = false, + delete_empty_features = true, + try_last_inserted_point = true, + skip_points = (), + num_sample_rule::M = default_num_samples, + rng::AbstractRNG = Random.default_rng(), + insertion_order::Vector = get_insertion_order(points, randomise, skip_points, IntegerType, rng), + recompute_representative_points = true, + delete_holes = true, + check_arguments = true, + full_polygon_hierarchy::H = nothing, + boundary_enricher = nothing, + boundary_curves = (), + polygonise_n = 4096, + coarse_n = 0, + enrich = false, + ) where {P, I, E, V, Es, Ts, M, H} + number_type(points) == Float64 || @warn "Using non-Float64 coordinates may cause issues. If you run into problems, consider using Float64 coordinates." maxlog = 1 is_weighted(weights) && throw(ArgumentError("Weighted triangulations are not yet fully implemented.")) is_constrained = !(isnothing(segments) || isempty(segments)) || !(isnothing(boundary_nodes) || !has_boundary_nodes(boundary_nodes)) is_weighted(weights) && is_constrained && throw(ArgumentError("You cannot compute a constrained triangulation with weighted points.")) @@ -142,12 +144,16 @@ function triangulate(points::P; end check_arguments && check_args(points, boundary_nodes, full_polygon_hierarchy) tri = Triangulation(points; IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, weights, boundary_curves, boundary_enricher, build_cache = Val(true)) - return _triangulate!(tri, segments, boundary_nodes, randomise, try_last_inserted_point, skip_points, num_sample_rule, rng, insertion_order, - recompute_representative_points, delete_holes, full_polygon_hierarchy, delete_ghosts, delete_empty_features) + return _triangulate!( + tri, segments, boundary_nodes, randomise, try_last_inserted_point, skip_points, num_sample_rule, rng, insertion_order, + recompute_representative_points, delete_holes, full_polygon_hierarchy, delete_ghosts, delete_empty_features, + ) end -function _triangulate!(tri::Triangulation, segments, boundary_nodes, randomise, try_last_inserted_point, skip_points, num_sample_rule, rng, insertion_order, - recompute_representative_points, delete_holes, full_polygon_hierarchy, delete_ghosts, delete_empty_features) +function _triangulate!( + tri::Triangulation, segments, boundary_nodes, randomise, try_last_inserted_point, skip_points, num_sample_rule, rng, insertion_order, + recompute_representative_points, delete_holes, full_polygon_hierarchy, delete_ghosts, delete_empty_features, + ) unconstrained_triangulation!(tri; randomise, try_last_inserted_point, skip_points, num_sample_rule, rng, insertion_order) _tri = if !(isnothing(segments) || isempty(segments)) || !(isnothing(boundary_nodes) || !has_boundary_nodes(boundary_nodes)) constrained_triangulation!(tri, segments, boundary_nodes, full_polygon_hierarchy; rng, delete_holes) @@ -172,23 +178,25 @@ Retriangulates the triangulation `tri` using the points `points`, returning a ne - `kwargs...`: Extra keyword arguments passed to `triangulate`. Other keyword arguments, like `segments` and `boundary_nodes`, are automatically passed from the fields of `tri`, but may be overridden by passing the corresponding keyword arguments. """ -function retriangulate(tri::T, points=get_points(tri); - segments=get_interior_segments(tri), - boundary_nodes=get_boundary_nodes(tri), - skip_points = Set(filter(i -> !has_vertex(tri, i), each_point_index(tri))), - kwargs...) where {T<:Triangulation} +function retriangulate( + tri::T, points = get_points(tri); + segments = get_interior_segments(tri), + boundary_nodes = get_boundary_nodes(tri), + skip_points = Set(filter(i -> !has_vertex(tri, i), each_point_index(tri))), + kwargs..., + ) where {T <: Triangulation} return triangulate( points; segments, boundary_nodes, - weights=get_weights(tri), - IntegerType=integer_type(tri), - EdgeType=edge_type(tri), - TriangleType=triangle_type(tri), - EdgesType=edges_type(tri), - TrianglesType=triangles_type(tri), - check_arguments=false, + weights = get_weights(tri), + IntegerType = integer_type(tri), + EdgeType = edge_type(tri), + TriangleType = triangle_type(tri), + EdgesType = edges_type(tri), + TrianglesType = triangles_type(tri), + check_arguments = false, skip_points, - kwargs... + kwargs..., )::T -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/mesh_refinement.jl b/src/algorithms/triangulation/mesh_refinement.jl index 2bb4cc1a0..f7294a273 100644 --- a/src/algorithms/triangulation/mesh_refinement.jl +++ b/src/algorithms/triangulation/mesh_refinement.jl @@ -123,7 +123,7 @@ Finalises the triangulation after refinement, e.g. by deleting ghost triangles a """ function finalise!(tri::Triangulation, args::RefinementArguments) !args.had_ghosts && delete_ghost_triangles!(tri) - args.locked_convex_hull && unlock_convex_hull!(tri; reconstruct=true) + args.locked_convex_hull && unlock_convex_hull!(tri; reconstruct = true) return tri end @@ -252,7 +252,7 @@ function locate_steiner_point(tri::Triangulation, args::RefinementArguments, T, flag = point_position_relative_to_triangle(tri, T, c) !is_outside(flag) && return T, flag # T is never a ghost triangle, so don't worry about checking is_on(flag) here init = get_init_for_steiner_point(tri, T) - V, _ = find_triangle(tri, c; m=nothing, point_indices=nothing, try_points=nothing, k=init, args.rng, args.concavity_protection, use_barriers=Val(true)) + V, _ = find_triangle(tri, c; m = nothing, point_indices = nothing, try_points = nothing, k = init, args.rng, args.concavity_protection, use_barriers = Val(true)) flag = point_position_relative_to_triangle(tri, V, c) if is_ghost_triangle(V) && is_on(flag) V = replace_ghost_triangle_with_boundary_triangle(tri, V) @@ -341,7 +341,7 @@ function enqueue_newly_encroached_segments!(args::RefinementArguments, tri::Tria return any_encroached end -const MIDPOINT_TOLERANCE = 1e-6 +const MIDPOINT_TOLERANCE = 1.0e-6 """ compute_split_position(tri::Triangulation, args::RefinementArguments, e) -> NTuple{2, Float} @@ -577,7 +577,7 @@ function check_split_subsegment_precision(mx, my, p, q) abs_err_flag_1 = check_absolute_precision(mx, px) && check_absolute_precision(my, py) abs_err_flag_2 = check_absolute_precision(mx, qx) && check_absolute_precision(my, qy) abs_err_flag = abs_err_flag_1 || abs_err_flag_2 - return abs_err_flag + return abs_err_flag end """ @@ -654,7 +654,7 @@ function _split_subsegment_curve_bounded_standard!(tri::Triangulation, args::Ref r = I(num_points(tri)) is_interior = is_segment(enricher, i, j) complete_split_edge_and_legalise!(tri, i, j, r, Val(true), args.events) - split_edge!(enricher, i, j, r, Val(false), Val(false), is_interior) + split_edge!(enricher, i, j, r, Val(false), Val(false), is_interior) assess_added_triangles!(args, tri) push!(args.midpoint_split_list, r) return tri @@ -715,7 +715,7 @@ function delete_free_vertices_around_subsegment!(tri::Triangulation, args::Refin w = get_adjacent(tri, e′) r = get_point(tri, w) while is_free(args, w) && !is_outside(point_position_relative_to_diametral_circle(p, q, r)) - delete_point!(tri, w; store_event_history=Val(true), event_history=args.events, args.rng) + delete_point!(tri, w; store_event_history = Val(true), event_history = args.events, args.rng) w = get_adjacent(tri, e′) r = get_point(tri, w) end @@ -900,4 +900,4 @@ function assess_added_triangles!(args::RefinementArguments, tri::Triangulation) end end return args -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/triangulate_convex.jl b/src/algorithms/triangulation/triangulate_convex.jl index 065c60b4b..c80dd6a77 100644 --- a/src/algorithms/triangulation/triangulate_convex.jl +++ b/src/algorithms/triangulation/triangulate_convex.jl @@ -21,11 +21,13 @@ Triangulates the convex polygon `S`. # Output - `tri::Triangulation`: The triangulated polygon. """ -function triangulate_convex(points, S; - rng::AbstractRNG=Random.default_rng(), - delete_ghosts=false, - delete_empty_features=true, - kwargs...) +function triangulate_convex( + points, S; + rng::AbstractRNG = Random.default_rng(), + delete_ghosts = false, + delete_empty_features = true, + kwargs..., + ) tri = Triangulation(points; kwargs...) triangulate_convex!(tri, S; rng) postprocess_triangulate_convex!(tri, S; delete_ghosts, delete_empty_features) @@ -48,11 +50,11 @@ Triangulates the convex polygon `S` in-place into `tri`. There is no output, as `tri` is updated in-place. This function does not do any post-processing, e.g. deleting any ghost triangles. This is done by [`triangulate_convex`](@ref) or [`postprocess_triangulate_convex!`](@ref). """ -function triangulate_convex!(tri::Triangulation, S; rng::AbstractRNG=Random.default_rng()) +function triangulate_convex!(tri::Triangulation, S; rng::AbstractRNG = Random.default_rng()) list = ShuffledPolygonLinkedList(S; rng) delete_vertices_in_random_order!(list, tri, rng) u, v, w = get_triplet(list, 1) - add_triangle!(tri, u, v, w; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, u, v, w; protect_boundary = true, update_ghost_edges = false) for i in 4:list.k u, v, w = get_triplet(list, i) add_point_convex_triangulation!(tri, u, v, w, S) @@ -121,12 +123,12 @@ function add_point_convex_triangulation!(tri::Triangulation, u, v, w, S) x = get_adjacent(tri, w, v) if edge_exists(x) && is_inside(point_position_relative_to_circumcircle(tri, u, v, w, x)) # uvw and wvx are not Delaunay - delete_triangle!(tri, w, v, x; protect_boundary=true, update_ghost_edges=false) + delete_triangle!(tri, w, v, x; protect_boundary = true, update_ghost_edges = false) add_point_convex_triangulation!(tri, u, v, x, S) add_point_convex_triangulation!(tri, u, x, w, S) else # vw is a Delaunay edge - add_triangle!(tri, u, v, w; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, u, v, w; protect_boundary = true, update_ghost_edges = false) end return tri end @@ -157,9 +159,9 @@ function postprocess_triangulate_convex!(tri::Triangulation, S; delete_ghosts, d append!(hull, S) push!(hull, S[begin]) I = integer_type(tri) - for i in firstindex(S):(lastindex(S)-1) + for i in firstindex(S):(lastindex(S) - 1) u = S[i] - v = S[i+1] + v = S[i + 1] if !delete_ghosts add_triangle!(tri, v, u, I(𝒢)) else @@ -184,4 +186,4 @@ function postprocess_triangulate_convex!(tri::Triangulation, S; delete_ghosts, d representative_point_list = get_representative_point_list(tri) representative_point_list[1] = RepresentativeCoordinates(cx, cy, length(S)) return tri -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/triangulate_curve_bounded.jl b/src/algorithms/triangulation/triangulate_curve_bounded.jl index 8c55d404e..767202968 100644 --- a/src/algorithms/triangulation/triangulate_curve_bounded.jl +++ b/src/algorithms/triangulation/triangulate_curve_bounded.jl @@ -32,21 +32,24 @@ See also [`BoundaryEnricher`](@ref) and [`enrich_boundary!`](@ref). To refine the mesh further beyond its initial coarse discretisation, as produced from this function, please see [`refine!`](@ref). """ -function triangulate_curve_bounded(points::P; - segments=nothing, - boundary_nodes=nothing, - IntegerType::Type{I}=Int, - polygonise_n=4096, - coarse_n=0, - check_arguments=true, - delete_ghosts=false, - delete_empty_features=true, - recompute_representative_points=true, - rng::AbstractRNG=Random.default_rng(), - insertion_order=nothing, # use this so that it gets ignored by the kwargs - kwargs...) where {P,I} - enricher = BoundaryEnricher(points, boundary_nodes, segments; IntegerType, n=polygonise_n, coarse_n) - return _triangulate_curve_bounded(points, enricher; +function triangulate_curve_bounded( + points::P; + segments = nothing, + boundary_nodes = nothing, + IntegerType::Type{I} = Int, + polygonise_n = 4096, + coarse_n = 0, + check_arguments = true, + delete_ghosts = false, + delete_empty_features = true, + recompute_representative_points = true, + rng::AbstractRNG = Random.default_rng(), + insertion_order = nothing, # use this so that it gets ignored by the kwargs + kwargs..., + ) where {P, I} + enricher = BoundaryEnricher(points, boundary_nodes, segments; IntegerType, n = polygonise_n, coarse_n) + return _triangulate_curve_bounded( + points, enricher; IntegerType, check_arguments, delete_ghosts, @@ -54,34 +57,39 @@ function triangulate_curve_bounded(points::P; recompute_representative_points, rng, insertion_order, - kwargs...) + kwargs..., + ) end -function _triangulate_curve_bounded(points::P, enricher; - IntegerType::Type{I}=Int, - check_arguments=true, - delete_ghosts=false, - delete_empty_features=true, - recompute_representative_points=true, - rng::AbstractRNG=Random.default_rng(), - insertion_order=nothing, # use this so that it gets ignored by the kwargs - kwargs...) where {P,I} +function _triangulate_curve_bounded( + points::P, enricher; + IntegerType::Type{I} = Int, + check_arguments = true, + delete_ghosts = false, + delete_empty_features = true, + recompute_representative_points = true, + rng::AbstractRNG = Random.default_rng(), + insertion_order = nothing, # use this so that it gets ignored by the kwargs + kwargs..., + ) where {P, I} check_arguments && check_args(enricher) enrich_boundary!(enricher) new_boundary_nodes = get_boundary_nodes(enricher) new_segments = get_segments(enricher) full_polygon_hierarchy = get_polygon_hierarchy(enricher) boundary_curves = get_boundary_curves(enricher) - tri = triangulate(points; + tri = triangulate( + points; IntegerType, - segments=new_segments, - boundary_nodes=new_boundary_nodes, + segments = new_segments, + boundary_nodes = new_boundary_nodes, full_polygon_hierarchy, boundary_curves, - boundary_enricher=enricher, - check_arguments=false, - delete_ghosts=false, + boundary_enricher = enricher, + check_arguments = false, + delete_ghosts = false, rng, - kwargs...) + kwargs..., + ) postprocess_triangulate!(tri; delete_ghosts, delete_empty_features, recompute_representative_points) return tri end @@ -96,7 +104,7 @@ come from [`convert_boundary_curves!`](@ref). The argument `n` is the amount of If non-zero, this should be a power of two (otherwise it will be rounded up to the next power of two). If it is zero, then the splitting will continue until the maximum total variation over any subcurve is less than π/2. """ -function coarse_discretisation!(points, boundary_nodes, boundary_curves; n::I=0) where {I} +function coarse_discretisation!(points, boundary_nodes, boundary_curves; n::I = 0) where {I} !is_curve_bounded(boundary_curves) && return points, boundary_nodes if n > 0 n = max(n, I(4)) @@ -187,7 +195,7 @@ function _enrich_boundary_itr!(enricher::BoundaryEnricher) spatial_tree = get_spatial_tree(enricher) v = popfirst!(queue) r = get_point(points, v) - intersections = get_intersections(spatial_tree, v; cache_id=1) + intersections = get_intersections(spatial_tree, v; cache_id = 1) requeued = false for bbox in intersections i, j = get_edge(bbox) @@ -395,7 +403,7 @@ returned vertex is `$∅`. (The purpose of this function is similar to [`segment_vertices_adjoin_other_segments_at_acute_angle`](@ref).) """ -function has_acute_neighbouring_angles(enricher::BoundaryEnricher{P,B,C,I}, i, j) where {P,B,C,I} +function has_acute_neighbouring_angles(enricher::BoundaryEnricher{P, B, C, I}, i, j) where {P, B, C, I} is_segment(enricher, i, j) && return 0, I(∅) points = get_points(enricher) p, q = get_point(points, i, j) @@ -489,7 +497,7 @@ function test_visibility(points, boundary_nodes, boundary_curves, parent_curve_i end int₁ = false int₂ = false - intersections = get_intersections(spatial_tree, i, j, k; cache_id=2) + intersections = get_intersections(spatial_tree, i, j, k; cache_id = 2) for box in intersections u, v = get_edge(box) !edges_are_disjoint((i, j), (u, v)) && continue @@ -505,4 +513,4 @@ function test_visibility(points, boundary_nodes, boundary_curves, parent_curve_i int₁ && int₂ && return Cert.Invisible end return Cert.Visible -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/triangulate_rectangle.jl b/src/algorithms/triangulation/triangulate_rectangle.jl index 4e4317207..475736d74 100644 --- a/src/algorithms/triangulation/triangulate_rectangle.jl +++ b/src/algorithms/triangulation/triangulate_rectangle.jl @@ -24,23 +24,27 @@ Triangulates the rectangle `[a, b] × [c, d]`. # Outputs - `tri`: The triangulation of the rectangle. """ -@inline function triangulate_rectangle(a, b, c, d, nx, ny; - single_boundary=false, - delete_ghosts=false, - IntegerType::Type{I}=Int, - EdgeType::Type{E}=NTuple{2,IntegerType}, - TriangleType::Type{V}=NTuple{3,IntegerType}, - EdgesType::Type{Es}=Set{EdgeType}, - TrianglesType::Type{Ts}=Set{TriangleType}) where {I,E,V,Es,Ts} +@inline function triangulate_rectangle( + a, b, c, d, nx, ny; + single_boundary = false, + delete_ghosts = false, + IntegerType::Type{I} = Int, + EdgeType::Type{E} = NTuple{2, IntegerType}, + TriangleType::Type{V} = NTuple{3, IntegerType}, + EdgesType::Type{Es} = Set{EdgeType}, + TrianglesType::Type{Ts} = Set{TriangleType}, + ) where {I, E, V, Es, Ts} return _triangulate_rectangle(a, b, c, d, nx, ny, I, E, V, Es, Ts, single_boundary, delete_ghosts) end -@inline function _triangulate_rectangle(a, b, c, d, nx, ny, - ::Type{I}, ::Type{E}, ::Type{V}, ::Type{Es}, ::Type{Ts}, - single_boundary, delete_ghosts) where {I,E,V,Es,Ts} +@inline function _triangulate_rectangle( + a, b, c, d, nx, ny, + ::Type{I}, ::Type{E}, ::Type{V}, ::Type{Es}, ::Type{Ts}, + single_boundary, delete_ghosts, + ) where {I, E, V, Es, Ts} T, sub2ind = get_lattice_triangles(nx, ny, Ts, V) points = get_lattice_points(a, b, c, d, nx, ny, sub2ind) boundary_nodes = get_lattice_boundary(nx, ny, sub2ind, Val(single_boundary), I) - tri = Triangulation(points, T, boundary_nodes; IntegerType=I, EdgeType=E, TriangleType=V, EdgesType=Es, TrianglesType=Ts, delete_ghosts) + tri = Triangulation(points, T, boundary_nodes; IntegerType = I, EdgeType = E, TriangleType = V, EdgesType = Es, TrianglesType = Ts, delete_ghosts) compute_representative_points!(tri) return tri end @@ -66,8 +70,8 @@ See [`triangulate_rectangle`](@ref). @inline function get_lattice_triangles(nx, ny, ::Type{Ts}, ::Type{V}) where {Ts, V} T = Ts() sub2ind = LinearIndices((1:nx, 1:ny)) - for j in 1:(ny-1) - for i in 1:(nx-1) + for j in 1:(ny - 1) + for i in 1:(nx - 1) u = sub2ind[CartesianIndex(i, j)] v = sub2ind[CartesianIndex(i + 1, j)] w = sub2ind[CartesianIndex(i, j + 1)] @@ -103,7 +107,7 @@ See [`triangulate_rectangle`](@ref). - `points`: The points on the lattice, where `points[sub2ind[CartesianIndex(i, j)]]` is the point at the `i`th `x` point and the `j`th `y` point, """ @inline function get_lattice_points(a, b, c, d, nx, ny, sub2ind) - points = Vector{NTuple{2,Float64}}(undef, nx * ny) + points = Vector{NTuple{2, Float64}}(undef, nx * ny) Δx = (b - a) / (nx - 1) Δy = (d - c) / (ny - 1) for j in 1:ny @@ -147,10 +151,10 @@ See [`triangulate_rectangle`](@ref). b2[j] = sub2ind[CartesianIndex(nx, j)] end for i in nx:-1:1 - b3[nx-i+1] = sub2ind[CartesianIndex(i, ny)] + b3[nx - i + 1] = sub2ind[CartesianIndex(i, ny)] end for j in ny:-1:1 - b4[ny-j+1] = sub2ind[CartesianIndex(1, j)] + b4[ny - j + 1] = sub2ind[CartesianIndex(1, j)] end if is_true(single_boundary) popfirst!(b2) @@ -161,4 +165,4 @@ See [`triangulate_rectangle`](@ref). boundary_nodes = [b1, b2, b3, b4] end return boundary_nodes -end \ No newline at end of file +end diff --git a/src/algorithms/triangulation/unconstrained_triangulation.jl b/src/algorithms/triangulation/unconstrained_triangulation.jl index 79254fa5d..f233f6aae 100644 --- a/src/algorithms/triangulation/unconstrained_triangulation.jl +++ b/src/algorithms/triangulation/unconstrained_triangulation.jl @@ -42,7 +42,7 @@ Gets the initial triangle for the Bowyer-Watson algorithm. # Output - `initial_triangle`: The initial triangle. """ -function get_initial_triangle(tri::Triangulation, insertion_order, itr=0) +function get_initial_triangle(tri::Triangulation, insertion_order, itr = 0) i, j, k = @view insertion_order[1:3] # insertion_order got converted into a Vector, so indexing is safe initial_triangle = construct_positively_oriented_triangle(tri, i, j, k) i, j, k = triangle_vertices(initial_triangle) @@ -75,7 +75,7 @@ Initialises the Bowyer-Watson algorithm. function initialise_bowyer_watson!(tri::Triangulation, insertion_order) I = integer_type(tri) initial_triangle = get_initial_triangle(tri, insertion_order) - add_triangle!(tri, initial_triangle; update_ghost_edges=true) + add_triangle!(tri, initial_triangle; update_ghost_edges = true) new_representative_point!(tri, I(1)) for i in triangle_vertices(initial_triangle) p = get_point(tri, i) @@ -107,7 +107,7 @@ function get_initial_search_point(tri::Triangulation, num_points, new_point, ins currently_inserted_points = @view insertion_order[begin:num_currently_inserted] m = num_sample_rule(num_currently_inserted) try_points = try_last_inserted_point ? (last_inserted_point_index,) : (∅,) - initial_search_point = select_initial_point(tri, new_point; m, point_indices=currently_inserted_points, rng, try_points) + initial_search_point = select_initial_point(tri, new_point; m, point_indices = currently_inserted_points, rng, try_points) return initial_search_point end @@ -140,10 +140,10 @@ This function works as follows: The function [`add_point_bowyer_watson_dig_cavities!`](@ref) is the main workhorse of this function from `add_point_bowyer_watson_after_found_triangle`. See its docstring for the details. """ -function add_point_bowyer_watson!(tri::Triangulation, new_point, initial_search_point::I, rng::AbstractRNG=Random.default_rng(), update_representative_point=true, store_event_history=Val(false), event_history=nothing, peek::P=Val(false)) where {I,P} +function add_point_bowyer_watson!(tri::Triangulation, new_point, initial_search_point::I, rng::AbstractRNG = Random.default_rng(), update_representative_point = true, store_event_history = Val(false), event_history = nothing, peek::P = Val(false)) where {I, P} _new_point = is_true(peek) ? new_point : I(new_point) q = get_point(tri, _new_point) - V = find_triangle(tri, q; m=nothing, point_indices=nothing, try_points=nothing, k=initial_search_point, rng) + V = find_triangle(tri, q; m = nothing, point_indices = nothing, try_points = nothing, k = initial_search_point, rng) if is_weighted(tri) #= This part here is why the Bowyer-Watson algorithm is not implemented for weighted triangulations yet. I don't understand why it sometimes @@ -157,7 +157,7 @@ function add_point_bowyer_watson!(tri::Triangulation, new_point, initial_search_ return V end -function add_point_bowyer_watson_and_process_after_found_triangle!(tri::Triangulation, new_point, V, q, flag, update_representative_point=true, store_event_history=Val(false), event_history=nothing, peek::P=Val(false)) where {P} +function add_point_bowyer_watson_and_process_after_found_triangle!(tri::Triangulation, new_point, V, q, flag, update_representative_point = true, store_event_history = Val(false), event_history = nothing, peek::P = Val(false)) where {P} I = integer_type(tri) _new_point = is_true(peek) ? new_point : I(new_point) add_point_bowyer_watson_after_found_triangle!(tri, _new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek) @@ -165,7 +165,7 @@ function add_point_bowyer_watson_and_process_after_found_triangle!(tri::Triangul return V end -function add_point_bowyer_watson_after_found_triangle!(tri::Triangulation, new_point, V, q, flag, update_representative_point=true, store_event_history=Val(false), event_history=nothing, peek::P=Val(false)) where {P} +function add_point_bowyer_watson_after_found_triangle!(tri::Triangulation, new_point, V, q, flag, update_representative_point = true, store_event_history = Val(false), event_history = nothing, peek::P = Val(false)) where {P} if is_ghost_triangle(V) && is_constrained(tri) # When we have a constrained boundary edge, we don't want to walk into its interior. So let's just check this case now. V = sort_triangle(V) @@ -210,13 +210,13 @@ This function works as follows: will fix this case. The need for `is_ghost_triangle(V) && !is_boundary_node(tri, new_point)[1]` is in case the ghost edges were already correctly added. Nothing happens if the edge of `V` that `new_point` is on is not the boundary edge. """ -function add_point_bowyer_watson_dig_cavities!(tri::Triangulation, new_point::N, V, q, flag, update_representative_point=true, store_event_history=Val(false), event_history=nothing, peek::F=Val(false)) where {N,F} +function add_point_bowyer_watson_dig_cavities!(tri::Triangulation, new_point::N, V, q, flag, update_representative_point = true, store_event_history = Val(false), event_history = nothing, peek::F = Val(false)) where {N, F} _new_point = is_true(peek) ? num_points(tri) + 1 : new_point # If we are peeking, then we need to use the number of points in the triangulation as the index for the new point since we don't actually insert the point i, j, k = triangle_vertices(V) ℓ₁ = get_adjacent(tri, j, i) ℓ₂ = get_adjacent(tri, k, j) ℓ₃ = get_adjacent(tri, i, k) - !is_true(peek) && delete_triangle!(tri, V; protect_boundary=true, update_ghost_edges=false) + !is_true(peek) && delete_triangle!(tri, V; protect_boundary = true, update_ghost_edges = false) is_true(store_event_history) && delete_triangle!(event_history, V) dig_cavity!(tri, new_point, i, j, ℓ₁, flag, V, store_event_history, event_history, peek) dig_cavity!(tri, new_point, j, k, ℓ₂, flag, V, store_event_history, event_history, peek) @@ -234,10 +234,10 @@ function add_point_bowyer_watson_dig_cavities!(tri::Triangulation, new_point::N, end g = get_adjacent(tri, u, v) if !is_true(peek) - delete_triangle!(tri, v, u, new_point; protect_boundary=true, update_ghost_edges=false) - delete_triangle!(tri, u, v, g; protect_boundary=true, update_ghost_edges=false) - add_triangle!(tri, new_point, v, g; update_ghost_edges=false) - add_triangle!(tri, u, new_point, g; update_ghost_edges=false) + delete_triangle!(tri, v, u, new_point; protect_boundary = true, update_ghost_edges = false) + delete_triangle!(tri, u, v, g; protect_boundary = true, update_ghost_edges = false) + add_triangle!(tri, new_point, v, g; update_ghost_edges = false) + add_triangle!(tri, u, new_point, g; update_ghost_edges = false) end if is_true(store_event_history) trit = triangle_type(tri) @@ -306,7 +306,7 @@ This function works as follows: `(i, j)` is a segment, then the situation is more complicated. In particular, `r` being on an edge of `V` might imply that we are going to add a degenerate triangle `(r, i, j)` into `tri`, and so this needs to be avoided. So, we check if `is_on(flag) && contains_segment(tri, i, j)` and, if the edge that `r` is on is `(i, j)`, we add the triangle `(r, i, j)`. Otherwise, we do nothing. """ -function dig_cavity!(tri::Triangulation, r, i, j, ℓ, flag, V, store_event_history=Val(false), event_history=nothing, peek::F=Val(false)) where {F} +function dig_cavity!(tri::Triangulation, r, i, j, ℓ, flag, V, store_event_history = Val(false), event_history = nothing, peek::F = Val(false)) where {F} if !edge_exists(ℓ) # The triangle has already been deleted in this case. return tri @@ -315,7 +315,7 @@ function dig_cavity!(tri::Triangulation, r, i, j, ℓ, flag, V, store_event_hist if !contains_segment(tri, i, j) && !is_ghost_vertex(ℓ) && is_inside(point_position_relative_to_circumcircle(tri, r, i, j, ℓ)) ℓ₁ = get_adjacent(tri, ℓ, i) ℓ₂ = get_adjacent(tri, j, ℓ) - !is_true(peek) && delete_triangle!(tri, j, i, ℓ; protect_boundary=true, update_ghost_edges=false) + !is_true(peek) && delete_triangle!(tri, j, i, ℓ; protect_boundary = true, update_ghost_edges = false) dig_cavity!(tri, r, i, ℓ, ℓ₁, flag, V, store_event_history, event_history, peek) dig_cavity!(tri, r, ℓ, j, ℓ₂, flag, V, store_event_history, event_history, peek) if is_true(store_event_history) @@ -335,14 +335,14 @@ function dig_cavity!(tri::Triangulation, r, i, j, ℓ, flag, V, store_event_hist if u == i && v == j return tri else - !is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges=false) + !is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges = false) if is_true(store_event_history) trit = triangle_type(tri) add_triangle!(event_history, construct_triangle(trit, _r, i, j)) end end else - !is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges=false) + !is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges = false) if is_true(store_event_history) trit = triangle_type(tri) add_triangle!(event_history, construct_triangle(trit, _r, i, j)) @@ -352,7 +352,7 @@ function dig_cavity!(tri::Triangulation, r, i, j, ℓ, flag, V, store_event_hist return tri end -function add_point_bowyer_watson_onto_segment!(tri::Triangulation, new_point, V, q, flag, update_representative_point=true, store_event_history=Val(false), event_history=nothing, peek::P=Val(false)) where {P} +function add_point_bowyer_watson_onto_segment!(tri::Triangulation, new_point, V, q, flag, update_representative_point = true, store_event_history = Val(false), event_history = nothing, peek::P = Val(false)) where {P} _new_point = is_true(peek) ? num_points(tri) + 1 : new_point # If we are peeking, then we need to use the number of points in the triangulation as the index for the new point since we don't actually insert the point if is_on(flag) && is_constrained(tri) # If the point we are adding appears on a segment, then we perform the depth-first search @@ -412,19 +412,21 @@ Computes the unconstrained Delaunay triangulation of the points in `tri`. # Outputs There is no output, but `tri` is updated in-place. """ -function unconstrained_triangulation!(tri::Triangulation; - randomise=true, - try_last_inserted_point=true, - skip_points=(), - num_sample_rule::M=default_num_samples, - rng::AbstractRNG=Random.default_rng(), - insertion_order=get_insertion_order(tri, randomise, skip_points, rng)) where {M} +function unconstrained_triangulation!( + tri::Triangulation; + randomise = true, + try_last_inserted_point = true, + skip_points = (), + num_sample_rule::M = default_num_samples, + rng::AbstractRNG = Random.default_rng(), + insertion_order = get_insertion_order(tri, randomise, skip_points, rng), + ) where {M} initialise_bowyer_watson!(tri, insertion_order) - remaining_points = @view insertion_order[(begin+3):end] + remaining_points = @view insertion_order[(begin + 3):end] for (num_points, new_point) in enumerate(remaining_points) initial_search_point = get_initial_search_point(tri, num_points, new_point, insertion_order, num_sample_rule, rng, try_last_inserted_point) add_point_bowyer_watson!(tri, new_point, initial_search_point, rng) end - convex_hull!(tri; reconstruct=false) + convex_hull!(tri; reconstruct = false) return tri end diff --git a/src/algorithms/voronoi/centroidal.jl b/src/algorithms/voronoi/centroidal.jl index 0b763c923..78952e852 100644 --- a/src/algorithms/voronoi/centroidal.jl +++ b/src/algorithms/voronoi/centroidal.jl @@ -36,7 +36,7 @@ of the bounding box of the underlying point set. function default_displacement_tolerance(vorn::VoronoiTessellation) xmin, xmax, ymin, ymax = polygon_bounds(vorn) max_extent = max(xmax - xmin, ymax - ymin) - return oftype(max_extent, max_extent / 1e4) + return oftype(max_extent, max_extent / 1.0e4) end """ @@ -67,7 +67,7 @@ function _centroidal_smooth_itr(vorn::VoronoiTessellation, set_of_boundary_nodes end end _tri = retriangulate(get_triangulation(vorn), points; rng, kwargs...) - vorn = voronoi(_tri, clip=true) + vorn = voronoi(_tri, clip = true) return vorn, max_dist end @@ -92,7 +92,7 @@ Smooths `vorn` into a centroidal tessellation so that the new tessellation is of The algorithm is simple. We iteratively smooth the generators, moving them to the centroid of their associated Voronoi polygon for the current tessellation, continuing until the maximum distance moved of any generator is less than `tol`. Boundary generators are not moved. """ -function centroidal_smooth(vorn::VoronoiTessellation; maxiters=1000, tol=default_displacement_tolerance(vorn), rng=Random.default_rng(), kwargs...) +function centroidal_smooth(vorn::VoronoiTessellation; maxiters = 1000, tol = default_displacement_tolerance(vorn), rng = Random.default_rng(), kwargs...) iter = 0 F = number_type(vorn) max_dist = typemax(F) @@ -110,4 +110,4 @@ function centroidal_smooth(vorn::VoronoiTessellation; maxiters=1000, tol=default !has_bnds && unlock_convex_hull!(tri) !has_ghost && delete_ghost_triangles!(tri) return vorn -end \ No newline at end of file +end diff --git a/src/algorithms/voronoi/clipped.jl b/src/algorithms/voronoi/clipped.jl index 15f6697eb..7859d7e57 100644 --- a/src/algorithms/voronoi/clipped.jl +++ b/src/algorithms/voronoi/clipped.jl @@ -126,7 +126,7 @@ Add the edge `uv` to the list of intersected edges. # Outputs There are no outputs, as `intersected_edge_cache` is modified in-place. """ -function add_to_intersected_edge_cache!(intersected_edge_cache::AbstractVector{V}, u, v, a, b) where {E,V<:Pair{E,E}} +function add_to_intersected_edge_cache!(intersected_edge_cache::AbstractVector{V}, u, v, a, b) where {E, V <: Pair{E, E}} uv = construct_edge(E, u, v) ab = construct_edge(E, a, b) push!(intersected_edge_cache, uv => ab) @@ -164,15 +164,16 @@ Process the intersection of the Voronoi polygon of the site `u` with the ray ema In addition to the point `p`, [`add_segment_intersection!`](@ref) is also updated to incorporate the new intersection point, as is [`add_to_intersected_edge_cache!`](@ref). """ function process_ray_intersection!( - vorn::VoronoiTessellation, - u, - v, - incident_polygon, - intersected_edge_cache, - segment_intersections, - boundary_sites, - exterior_circumcenters, - equal_circumcenter_mapping) + vorn::VoronoiTessellation, + u, + v, + incident_polygon, + intersected_edge_cache, + segment_intersections, + boundary_sites, + exterior_circumcenters, + equal_circumcenter_mapping, + ) u_tri = get_circumcenter_to_triangle(vorn, u) a = geti(u_tri) b = getj(u_tri) @@ -222,16 +223,17 @@ Process the intersection of the Voronoi polygon's edge `(u, v)` with the edge `e In addition to the point `p`, [`add_segment_intersection!`](@ref) is also updated to incorporate the new intersection point, as is [`add_to_intersected_edge_cache!`](@ref). """ function process_segment_intersection!( - vorn::VoronoiTessellation, - u, - v, - e, - incident_polygon, - intersected_edge_cache, - segment_intersections, - boundary_sites, - exterior_circumcenters, - equal_circumcenter_mapping) + vorn::VoronoiTessellation, + u, + v, + e, + incident_polygon, + intersected_edge_cache, + segment_intersections, + boundary_sites, + exterior_circumcenters, + equal_circumcenter_mapping, + ) e = convert_to_edge_adjoining_ghost_vertex(vorn, e) a, b = edge_vertices(e) p, q = get_generator(vorn, a, b) @@ -284,20 +286,20 @@ function initialise_clipping_arrays(vorn::VoronoiTessellation) foreach(boundary_edges) do e push!(edges_to_process, e) end - polygon_edge_queue = Queue{Tuple{E,I}}() - boundary_sites = Dict{I,Set{I}}() + polygon_edge_queue = Queue{Tuple{E, I}}() + boundary_sites = Dict{I, Set{I}}() F = number_type(vorn) - segment_intersections = NTuple{2,F}[] - processed_pairs = Set{Tuple{E,I}}() - intersected_edge_cache = Pair{E,E}[] + segment_intersections = NTuple{2, F}[] + processed_pairs = Set{Tuple{E, I}}() + intersected_edge_cache = Pair{E, E}[] sizehint!(intersected_edge_cache, 2^3) exterior_circumcenters = Set{I}() left_edge_intersectors = Set{E}() right_edge_intersectors = Set{E}() current_edge_intersectors = Set{E}() - equal_circumcenter_mapping = Dict{I,I}() + equal_circumcenter_mapping = Dict{I, I}() return edges_to_process, polygon_edge_queue, boundary_sites, segment_intersections, processed_pairs, intersected_edge_cache, exterior_circumcenters, - left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, equal_circumcenter_mapping + left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, equal_circumcenter_mapping end """ @@ -317,7 +319,7 @@ function enqueue_new_edge!(polygon_edge_queue, vorn::VoronoiTessellation, e) u, v = edge_vertices(e) p, q = get_generator(vorn, u, v) m = midpoint(p, q) - incident_polygon = get_nearest_neighbour(vorn, m; k=u) + incident_polygon = get_nearest_neighbour(vorn, m; k = u) push!(polygon_edge_queue, (e, incident_polygon)) return polygon_edge_queue end @@ -383,18 +385,20 @@ Process the intersection of the ray from the ghost site `u` to the site `v` with # Outputs There are no outputs, but [`add_segment_intersection!`](@ref) and [`add_to_intersected_edge_cache!`](@ref) are used to update the intersection objects. """ -function process_ray_intersection_with_other_edges!(vorn::VoronoiTessellation, - u, - v, - e, - left_edge, - right_edge, - r, - segment_intersections, - boundary_sites, - incident_polygon, - equal_circumcenter_mapping, - intersected_edge_cache) +function process_ray_intersection_with_other_edges!( + vorn::VoronoiTessellation, + u, + v, + e, + left_edge, + right_edge, + r, + segment_intersections, + boundary_sites, + incident_polygon, + equal_circumcenter_mapping, + intersected_edge_cache, + ) if !any(isnan, r) E = edge_type(vorn) u_tri = get_circumcenter_to_triangle(vorn, u) @@ -556,12 +560,16 @@ This function works as follows: we need to get the polygon adjacent to that edge. Then, if `(current_edge, adjacent_incident_polygon)` or `(reverse_edge(current_edge), adjacent_incident_polygon)` have not been processed, we enqueue `(current_edge, adjacent_incident_polygon)`. 5. Once the edges have all been processed as above, we return. """ -function process_intersection_points!(polygon_edge_queue, vorn, current_incident_polygon, - left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, - left_edge, right_edge, current_edge, processed_pairs, segment_intersections, boundary_sites) - all_indices = (initial(left_edge), terminal(left_edge), +function process_intersection_points!( + polygon_edge_queue, vorn, current_incident_polygon, + left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, + left_edge, right_edge, current_edge, processed_pairs, segment_intersections, boundary_sites, + ) + all_indices = ( + initial(left_edge), terminal(left_edge), initial(right_edge), terminal(right_edge), - initial(current_edge), terminal(current_edge)) + initial(current_edge), terminal(current_edge), + ) if num_polygon_vertices(vorn) > 1 # A single triangle is a special case that we add the corners into manually for (e, intersectors) in zip((left_edge, right_edge), (left_edge_intersectors, right_edge_intersectors)) if (length(intersectors) > 0 && length(current_edge_intersectors) > 0) && ((e, current_incident_polygon) ∉ processed_pairs && (reverse_edge(e), current_incident_polygon) ∉ processed_pairs) @@ -628,9 +636,11 @@ This function works as follows: 5. Then, [`process_intersection_points!`](@ref) is used to process the intersection points, enqueueing new edges when needed. 6. We then delete the edge from `edges_to_process` if it is in there and return. """ -function dequeue_and_process!(vorn, polygon_edge_queue, edges_to_process, - intersected_edge_cache, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, - processed_pairs, boundary_sites, segment_intersections, exterior_circumcenters, equal_circumcenter_mapping) +function dequeue_and_process!( + vorn, polygon_edge_queue, edges_to_process, + intersected_edge_cache, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, + processed_pairs, boundary_sites, segment_intersections, exterior_circumcenters, equal_circumcenter_mapping, + ) if isempty(polygon_edge_queue) e = convert_to_edge_adjoining_ghost_vertex(vorn, first(edges_to_process)) enqueue_new_edge!(polygon_edge_queue, vorn, e) @@ -645,9 +655,11 @@ function dequeue_and_process!(vorn, polygon_edge_queue, edges_to_process, end left_edge, right_edge, e = process_polygon!(vorn, e, incident_polygon, boundary_sites, segment_intersections, intersected_edge_cache, exterior_circumcenters, equal_circumcenter_mapping) classify_intersections!(intersected_edge_cache, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, left_edge, right_edge, e) - process_intersection_points!(polygon_edge_queue, vorn, incident_polygon, + process_intersection_points!( + polygon_edge_queue, vorn, incident_polygon, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, - left_edge, right_edge, e, processed_pairs, segment_intersections, boundary_sites) + left_edge, right_edge, e, processed_pairs, segment_intersections, boundary_sites, + ) if contains_edge(e, edges_to_process) delete!(edges_to_process, e) elseif contains_edge(reverse_edge(e), edges_to_process) @@ -681,22 +693,24 @@ This algorithm works as follows: """ function find_all_intersections(vorn::VoronoiTessellation) edges_to_process, - polygon_edge_queue, - boundary_sites, - segment_intersections, - processed_pairs, - intersected_edge_cache, - exterior_circumcenters, - left_edge_intersectors, - right_edge_intersectors, - current_edge_intersectors, - equal_circumcenter_mapping = initialise_clipping_arrays(vorn) + polygon_edge_queue, + boundary_sites, + segment_intersections, + processed_pairs, + intersected_edge_cache, + exterior_circumcenters, + left_edge_intersectors, + right_edge_intersectors, + current_edge_intersectors, + equal_circumcenter_mapping = initialise_clipping_arrays(vorn) e = convert_to_edge_adjoining_ghost_vertex(vorn, first(edges_to_process)) enqueue_new_edge!(polygon_edge_queue, vorn, e) while !isempty(edges_to_process) || !isempty(polygon_edge_queue) - dequeue_and_process!(vorn, polygon_edge_queue, edges_to_process, + dequeue_and_process!( + vorn, polygon_edge_queue, edges_to_process, intersected_edge_cache, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, - processed_pairs, boundary_sites, segment_intersections, exterior_circumcenters, equal_circumcenter_mapping) + processed_pairs, boundary_sites, segment_intersections, exterior_circumcenters, equal_circumcenter_mapping, + ) end if num_polygon_vertices(vorn) == 1 # 1 triangle for i in each_generator(vorn) @@ -817,10 +831,10 @@ Clip the Voronoi tessellation `vorn` to the convex hull of the generators in `vo # Outputs There are no outputs, but the Voronoi tessellation is clipped in-place. """ -function clip_voronoi_tessellation!(vorn::VoronoiTessellation, is_convex=true) +function clip_voronoi_tessellation!(vorn::VoronoiTessellation, is_convex = true) boundary_sites, segment_intersections, exterior_circumcenters, equal_circumcenter_mapping = find_all_intersections(vorn) n = add_intersection_points!(vorn, segment_intersections) clip_all_polygons!(vorn, n, boundary_sites, exterior_circumcenters, equal_circumcenter_mapping, is_convex) add_all_boundary_polygons!(vorn, boundary_sites) return vorn -end \ No newline at end of file +end diff --git a/src/algorithms/voronoi/clipped_coordinates.jl b/src/algorithms/voronoi/clipped_coordinates.jl index 8ec079075..2f327c088 100644 --- a/src/algorithms/voronoi/clipped_coordinates.jl +++ b/src/algorithms/voronoi/clipped_coordinates.jl @@ -51,7 +51,7 @@ See also [`get_unbounded_polygon_coordinates`](@ref) and [`get_bounded_polygon_c # Outputs - `coords`: The coordinates of the polygon. This is a circular vector. """ -function get_polygon_coordinates(vorn::VoronoiTessellation, i, bounding_box=nothing) +function get_polygon_coordinates(vorn::VoronoiTessellation, i, bounding_box = nothing) if !isnothing(bounding_box) a, b, c, d = bounding_box @assert a < b && c < d "The bounding box must be of the form (xmin, xmax, ymin, ymax) with xmin < xmax and ymin < ymax." @@ -273,11 +273,11 @@ Returns the new vertices and points of the polygon, as well as the indices of th - `ghost_vertices`: The indices of the ghost vertices in `new_vertices`. """ function get_new_polygon_indices(vorn, vertices) - new_points = NTuple{2,Float64}[] + new_points = NTuple{2, Float64}[] sizehint!(new_points, length(vertices)) new_vertices = similar(vertices, length(vertices) - 1) ghost_vertices = (0, 0) - for i in firstindex(vertices):(lastindex(vertices)-1) + for i in firstindex(vertices):(lastindex(vertices) - 1) v = vertices[i] if is_ghost_vertex(v) is_first = is_first_ghost_vertex(vertices, i) @@ -305,7 +305,7 @@ function get_bounded_polygon_coordinates(vorn::VoronoiTessellation, i, bounding_ if isnothing(bounding_box) C = get_polygon(vorn, i) F = number_type(vorn) - coords = Vector{NTuple{2,F}}(undef, length(C)) + coords = Vector{NTuple{2, F}}(undef, length(C)) for j in eachindex(C) coords[j] = get_polygon_point(vorn, C[j]) end @@ -335,4 +335,4 @@ function clip_unbounded_polygon_to_bounding_box(vorn::VoronoiTessellation, i, bo a, b, c, d = bounding_box clip_points = ((a, c), (b, c), (b, d), (a, d)) return clip_polygon(new_vertices, new_points, clip_vertices, clip_points) -end \ No newline at end of file +end diff --git a/src/algorithms/voronoi/main.jl b/src/algorithms/voronoi/main.jl index af356b3d0..617b48b12 100644 --- a/src/algorithms/voronoi/main.jl +++ b/src/algorithms/voronoi/main.jl @@ -13,7 +13,7 @@ Computes the Voronoi tessellation dual to a triangulation. # Output - `vorn`: The [`VoronoiTessellation`](@ref). """ -function voronoi(tri::Triangulation; clip=false, smooth=false, kwargs...) +function voronoi(tri::Triangulation; clip = false, smooth = false, kwargs...) if smooth @assert clip "Smoothing requires clipping." end diff --git a/src/algorithms/voronoi/unbounded.jl b/src/algorithms/voronoi/unbounded.jl index 263dbd634..73439c758 100644 --- a/src/algorithms/voronoi/unbounded.jl +++ b/src/algorithms/voronoi/unbounded.jl @@ -9,20 +9,20 @@ Initialise a `VoronoiTessellation` from the triangulation `tri`. # Output - `vorn`: The [`VoronoiTessellation`](@ref). This tessellation is not yet filled in, as all the polygons and other fields need to be properly defined. This simply defines all the initial objects that will be pushed into. """ -function initialise_voronoi_tessellation(tri::Tr) where {Tr<:Triangulation} +function initialise_voronoi_tessellation(tri::Tr) where {Tr <: Triangulation} I = integer_type(tri) T = triangle_type(tri) F = number_type(tri) - P = NTuple{2,F} + P = NTuple{2, F} polygon_points = Vector{P}() - circumcenter_to_triangle = Dict{I,T}() - triangle_to_circumcenter = Dict{T,I}() + circumcenter_to_triangle = Dict{I, T}() + triangle_to_circumcenter = Dict{T, I}() sizehint!(polygon_points, num_triangles(tri)) sizehint!(circumcenter_to_triangle, num_triangles(tri)) sizehint!(triangle_to_circumcenter, num_triangles(tri)) cur_ghost_idx = I(0) - cocircular_dict = Dict{P,I}() - encountered_circumcenters = Dict{P,I}() + cocircular_dict = Dict{P, I}() + encountered_circumcenters = Dict{P, I}() cocircular_circumcenters = Set{I}() for V in each_triangle(tri) V = sort_triangle(V) @@ -50,24 +50,24 @@ function initialise_voronoi_tessellation(tri::Tr) where {Tr<:Triangulation} cocircular_dict[(cx, cy)] = num_points(polygon_points) end else - circumcenter_to_triangle[I(𝒢)-cur_ghost_idx] = V + circumcenter_to_triangle[I(𝒢) - cur_ghost_idx] = V triangle_to_circumcenter[V] = I(𝒢) - cur_ghost_idx cur_ghost_idx += I(1) end end - polygons = Dict{I,Vector{I}}() + polygons = Dict{I, Vector{I}}() sizehint!(polygons, num_solid_vertices(tri)) unbounded_polygons = Set{I}() sizehint!(unbounded_polygons, num_ghost_edges(tri)) - generators = Dict{I,P}() + generators = Dict{I, P}() sizehint!(generators, num_solid_vertices(tri)) for i in each_solid_vertex(tri) generators[i] = get_point(tri, i) end E = edge_type(tri) - adj = Adjacent{I,E}() + adj = Adjacent{I, E}() boundary_polygons = Set{I}() - return VoronoiTessellation{Tr,P,I,T,typeof(cocircular_circumcenters),E}(tri, generators, polygon_points, polygons, circumcenter_to_triangle, triangle_to_circumcenter, unbounded_polygons, cocircular_circumcenters, adj, boundary_polygons) + return VoronoiTessellation{Tr, P, I, T, typeof(cocircular_circumcenters), E}(tri, generators, polygon_points, polygons, circumcenter_to_triangle, triangle_to_circumcenter, unbounded_polygons, cocircular_circumcenters, adj, boundary_polygons) end """ @@ -194,11 +194,11 @@ function add_voronoi_polygon!(vorn::VoronoiTessellation, i) k = S[begin] encountered_duplicate_circumcenter = false prev_ci, encountered_duplicate_circumcenter, k = add_edge_to_voronoi_polygon!(B, vorn, i, k, S, m, encountered_duplicate_circumcenter) - for m in (firstindex(S)+2):lastindex(S) + for m in (firstindex(S) + 2):lastindex(S) ci, encountered_duplicate_circumcenter, k = add_edge_to_voronoi_polygon!(B, vorn, i, k, S, m, encountered_duplicate_circumcenter) add_adjacent!(vorn, prev_ci, ci, i) prev_ci = ci end close_voronoi_polygon!(vorn, B, i, encountered_duplicate_circumcenter, prev_ci) return B -end \ No newline at end of file +end diff --git a/src/data_structures.jl b/src/data_structures.jl index 76b1bd127..c1fb869e9 100644 --- a/src/data_structures.jl +++ b/src/data_structures.jl @@ -40,4 +40,4 @@ include("data_structures/mesh_refinement/refinement_queue.jl") include("data_structures/mesh_refinement/refinement_arguments.jl") include("data_structures/voronoi.jl") include("data_structures/polygon.jl") -include("data_structures/shuffled_polygon_linked_list.jl") \ No newline at end of file +include("data_structures/shuffled_polygon_linked_list.jl") diff --git a/src/data_structures/convex_hull.jl b/src/data_structures/convex_hull.jl index 26ac82691..2f7692529 100644 --- a/src/data_structures/convex_hull.jl +++ b/src/data_structures/convex_hull.jl @@ -11,7 +11,7 @@ Struct for representing a convex hull. See also [`convex_hull`](@ref). ConvexHull(points, vertices) convex_hull(points; IntegerType=Int) """ -struct ConvexHull{P,I} +struct ConvexHull{P, I} points::P vertices::Vector{I} end @@ -51,4 +51,4 @@ function Base.empty!(ch::ConvexHull) vertices = get_vertices(ch) empty!(vertices) return ch -end \ No newline at end of file +end diff --git a/src/data_structures/mesh_refinement/boundary_enricher.jl b/src/data_structures/mesh_refinement/boundary_enricher.jl index a27a2d679..0fd764cc6 100644 --- a/src/data_structures/mesh_refinement/boundary_enricher.jl +++ b/src/data_structures/mesh_refinement/boundary_enricher.jl @@ -105,8 +105,8 @@ get_members(complex::SmallAngleComplex) = complex.members Returns a map from an apex vertex to a list of all curves that define a small angle complex associated with that apex vertex. """ -function get_small_angle_complexes(points, boundary_nodes, boundary_curves, segments=nothing; IntegerType=Int) - d = Dict{IntegerType,Vector{SmallAngleComplex{IntegerType}}}() +function get_small_angle_complexes(points, boundary_nodes, boundary_curves, segments = nothing; IntegerType = Int) + d = Dict{IntegerType, Vector{SmallAngleComplex{IntegerType}}}() if has_multiple_curves(boundary_nodes) _get_small_angle_complexes_multiple_curves!(d, boundary_nodes, boundary_curves, IntegerType) elseif has_multiple_sections(boundary_nodes) @@ -208,7 +208,7 @@ Segments are stored twice. The vertices associated with a vertex are sorted coun to define the coordinates. """ function construct_segment_map(segments, points, ::Type{I}) where {I} - segment_map = Dict{I,Vector{I}}() + segment_map = Dict{I, Vector{I}}() for e in each_edge(segments) i, j = edge_vertices(e) iset = get!(Vector{I}, segment_map, i) @@ -224,12 +224,14 @@ function construct_segment_map(segments, points, ::Type{I}) where {I} px, py = getxy(p) qx, qy = getxy(q) base = (qx - px, qy - py) - sort!(vertices, by=_vertex -> begin + sort!( + vertices, by = _vertex -> begin _q = get_point(points, _vertex) _qx, _qy = getxy(_q) next_base = (_qx - px, _qy - py) return angle_between(base, next_base) - end, rev=false) + end, rev = false, + ) end return segment_map end @@ -248,12 +250,14 @@ function sort_members!(complex::SmallAngleComplex, points) px, py = getxy(p) qx, qy = getxy(q) base = (qx - px, qy - py) - sort!(members, by=member -> begin + sort!( + members, by = member -> begin _q = get_point(points, get_next_edge(member)) _qx, _qy = getxy(_q) next_base = (_qx - px, _qy - py) return angle_between(base, next_base) - end, rev=false) + end, rev = false, + ) return complex end @@ -363,34 +367,34 @@ field will no longer aliased with the input `boundary_nodes`, although `points` The argument `n` is used in [`polygonise`](@ref) for filling out the boundary temporarily in order to construct the [`PolygonHierarchy`](@ref). The argument `coarse_n` defines the initial coarse discretisation through [`coarse_discretisation!`](@ref); the default `n=0` means that the coarse discretisation will be performed until the maximum total variation of a subcurve is less than π/2. """ -struct BoundaryEnricher{P,B,C,I,BM,S} +struct BoundaryEnricher{P, B, C, I, BM, S} points::P boundary_nodes::B segments::S boundary_curves::C polygon_hierarchy::PolygonHierarchy{I} - parent_map::Dict{NTuple{2,I},I} - curve_index_map::Dict{I,I} + parent_map::Dict{NTuple{2, I}, I} + curve_index_map::Dict{I, I} boundary_edge_map::BM spatial_tree::BoundaryRTree{P} queue::Queue{I} - small_angle_complexes::Dict{I,Vector{SmallAngleComplex{I}}} + small_angle_complexes::Dict{I, Vector{SmallAngleComplex{I}}} end -function BoundaryEnricher(points::P, boundary_nodes::B, segments=nothing; IntegerType=Int, n=4096, coarse_n=0) where {P,B} +function BoundaryEnricher(points::P, boundary_nodes::B, segments = nothing; IntegerType = Int, n = 4096, coarse_n = 0) where {P, B} boundary_curves, new_boundary_nodes = convert_boundary_curves!(points, boundary_nodes, IntegerType) polygon_hierarchy = construct_polygon_hierarchy(points, new_boundary_nodes, boundary_curves; IntegerType, n) - return _construct_boundary_enricher(points, new_boundary_nodes, boundary_curves, polygon_hierarchy, segments, n, coarse_n, IntegerType) + return _construct_boundary_enricher(points, new_boundary_nodes, boundary_curves, polygon_hierarchy, segments, n, coarse_n, IntegerType) end function _construct_boundary_enricher(points, boundary_nodes, boundary_curves, polygon_hierarchy, segments, n, coarse_n, ::Type{I}) where {I} expand_bounds!(polygon_hierarchy, ε) - coarse_discretisation!(points, boundary_nodes, boundary_curves; n=coarse_n) + coarse_discretisation!(points, boundary_nodes, boundary_curves; n = coarse_n) boundary_edge_map = construct_boundary_edge_map(boundary_nodes, I) - parent_map = Dict{NTuple{2,I},I}() - curve_index_map = Dict{I,I}() + parent_map = Dict{NTuple{2, I}, I}() + curve_index_map = Dict{I, I}() spatial_tree = BoundaryRTree(points) queue = Queue{I}() - small_angle_complexes = get_small_angle_complexes(points, boundary_nodes, boundary_curves, segments; IntegerType=I) - _segments = isnothing(segments) ? Set{NTuple{2,I}}() : segments + small_angle_complexes = get_small_angle_complexes(points, boundary_nodes, boundary_curves, segments; IntegerType = I) + _segments = isnothing(segments) ? Set{NTuple{2, I}}() : segments enricher = BoundaryEnricher(points, boundary_nodes, _segments, boundary_curves, polygon_hierarchy, parent_map, curve_index_map, boundary_edge_map, spatial_tree, queue, small_angle_complexes) construct_parent_map!(enricher) construct_curve_index_map!(enricher) @@ -569,7 +573,7 @@ end Returns the parent of the edge `(i, j)` in `boundary_enricher`. If the edge is not in the parent map, then `$∅` is returned. """ -get_parent(boundary_enricher::BoundaryEnricher{P,B,C,I}, i, j) where {P,B,C,I} = get(get_parent_map(boundary_enricher), (i, j), I(∅)) +get_parent(boundary_enricher::BoundaryEnricher{P, B, C, I}, i, j) where {P, B, C, I} = get(get_parent_map(boundary_enricher), (i, j), I(∅)) """ set_parent!(boundary_enricher::BoundaryEnricher, i, j, k) @@ -644,7 +648,7 @@ function _construct_parent_map_multiple_curves!(enricher::BoundaryEnricher) end return enricher end -function _construct_parent_map_multiple_sections!(enricher::BoundaryEnricher, boundary_nodes=get_boundary_nodes(enricher), ctr=1) +function _construct_parent_map_multiple_sections!(enricher::BoundaryEnricher, boundary_nodes = get_boundary_nodes(enricher), ctr = 1) ns = num_sections(boundary_nodes) for i in 1:ns section_nodes = get_boundary_nodes(boundary_nodes, i) @@ -653,7 +657,7 @@ function _construct_parent_map_multiple_sections!(enricher::BoundaryEnricher, bo end return enricher end -function _construct_parent_map_contiguous!(enricher::BoundaryEnricher, boundary_nodes=get_boundary_nodes(enricher), ctr=1) +function _construct_parent_map_contiguous!(enricher::BoundaryEnricher, boundary_nodes = get_boundary_nodes(enricher), ctr = 1) n = num_boundary_edges(boundary_nodes) for i in 1:n u = get_boundary_nodes(boundary_nodes, i) @@ -715,7 +719,7 @@ Returns `true` if the `curve_index`th curve in `enricher` is piecewise linear, a boundary_curves = get_boundary_curves(enricher) return is_piecewise_linear(boundary_curves, curve_index) end -@inline function is_piecewise_linear(boundary_curves::C, curve_index) where {C<:Tuple} +@inline function is_piecewise_linear(boundary_curves::C, curve_index) where {C <: Tuple} isempty(boundary_curves) && return true return eval_fnc_at_het_tuple_element(is_piecewise_linear, boundary_curves, curve_index) end @@ -729,7 +733,7 @@ Returns the inverse of the `curve_index`th curve at `q`. boundary_curves = get_boundary_curves(enricher) return get_inverse(boundary_curves, curve_index, q) end -@inline function get_inverse(boundary_curves::C, curve_index, q) where {C<:Tuple} +@inline function get_inverse(boundary_curves::C, curve_index, q) where {C <: Tuple} return eval_fnc_at_het_tuple_element_with_arg(get_inverse, boundary_curves, (q,), curve_index) end @@ -742,7 +746,7 @@ Returns the equivariation split of the `curve_index`th curve between `t₁` and boundary_curves = get_boundary_curves(enricher) return get_equivariation_split(boundary_curves, curve_index, t₁, t₂) end -@inline function get_equivariation_split(boundary_curves::C, curve_index, t₁, t₂) where {C<:Tuple} +@inline function get_equivariation_split(boundary_curves::C, curve_index, t₁, t₂) where {C <: Tuple} return eval_fnc_at_het_tuple_element_with_arg(get_equivariation_split, boundary_curves, (t₁, t₂), curve_index) end @@ -755,7 +759,7 @@ Returns the equidistant split of the `curve_index`th curve between `t₁` and `t boundary_curves = get_boundary_curves(enricher) return get_equidistant_split(boundary_curves, curve_index, t₁, t₂) end -@inline function get_equidistant_split(boundary_curves::C, curve_index, t₁, t₂) where {C<:Tuple} +@inline function get_equidistant_split(boundary_curves::C, curve_index, t₁, t₂) where {C <: Tuple} return eval_fnc_at_het_tuple_element_with_arg(get_equidistant_split, boundary_curves, (t₁, t₂), curve_index) end @@ -769,7 +773,7 @@ Returns the `curve_index`th boundary curve at `t`. boundary_curves = get_boundary_curves(enricher) return eval_boundary_curve(boundary_curves, curve_index, t) end -@inline function eval_boundary_curve(boundary_curves::C, curve_index, t) where {C<:Tuple} +@inline function eval_boundary_curve(boundary_curves::C, curve_index, t) where {C <: Tuple} return eval_fnc_in_het_tuple(boundary_curves, t, curve_index) end @@ -786,7 +790,7 @@ Returns a [`Certificate`](@ref) which is boundary_curves = get_boundary_curves(enricher) return point_position_relative_to_curve(boundary_curves, curve_index, p) end -@inline function point_position_relative_to_curve(boundary_curves::C, curve_index, p) where {C<:Tuple} +@inline function point_position_relative_to_curve(boundary_curves::C, curve_index, p) where {C <: Tuple} return eval_fnc_at_het_tuple_element_with_arg(point_position_relative_to_curve, boundary_curves, (p,), curve_index) end @@ -844,7 +848,7 @@ Fills out a set of points for a curve-bounded domain for use with [`PolygonHiera If the boundary is not curve bounded, then `new_points` and `new_boundary_nodes` remain aliased with the input `points` and `boundary_nodes`. """ -function polygonise(points, boundary_nodes, boundary_curves; n=4096) +function polygonise(points, boundary_nodes, boundary_curves; n = 4096) new_points = deepcopy(points) new_boundary_nodes = deepcopy(boundary_nodes) coarse_discretisation!(new_points, new_boundary_nodes, boundary_curves; n) @@ -895,7 +899,7 @@ Updates the fields of `enricher` after splitting a boundary edge `(i, j)` at the can be used to avoid inserting an additional boundary node when `boundary_nodes` was already updated somewhere else (e.g., we need this for mesh refinement which already updates the `boundary_nodes` which is aliased with the same field in the enricher). """ -function split_boundary_edge!(enricher::BoundaryEnricher, i, j, r, update_boundary_nodes=Val(true)) +function split_boundary_edge!(enricher::BoundaryEnricher, i, j, r, update_boundary_nodes = Val(true)) boundary_nodes = get_boundary_nodes(enricher) boundary_edge_map = get_boundary_edge_map(enricher) spatial_tree = get_spatial_tree(enricher) @@ -915,7 +919,7 @@ Updates the fields of `enricher` after splitting an interior segment `(i, j)` at The `update_segments` argument can be used to avoid inserting an additional segment when `segments` was already updated somewhere else (e.g., we need this for mesh refinement which already updates the `interior_segments` which is aliased with the `segments` field in the enricher). """ -function split_interior_segment!(enricher::BoundaryEnricher, i, j, r, update_segments=Val(true)) +function split_interior_segment!(enricher::BoundaryEnricher, i, j, r, update_segments = Val(true)) segments = get_segments(enricher) spatial_tree = get_spatial_tree(enricher) E = edge_type(segments) @@ -941,7 +945,7 @@ The `is_interior` argument can be used to specify whether the edge is an interio See also [`split_boundary_edge!`](@ref) and [`split_interior_segment!`](@ref). """ -function split_edge!(enricher::BoundaryEnricher, i, j, r, update_boundary_nodes=Val(true), update_segments=Val(true), is_interior=is_segment(enricher, i, j)) +function split_edge!(enricher::BoundaryEnricher, i, j, r, update_boundary_nodes = Val(true), update_segments = Val(true), is_interior = is_segment(enricher, i, j)) if is_interior split_interior_segment!(enricher, i, j, r, update_segments) else @@ -990,4 +994,4 @@ function replace_next_edge!(enricher::BoundaryEnricher, apex, complex_id, member complex = complexes[complex_id] replace_next_edge!(complex, member_id, next_edge) return enricher -end \ No newline at end of file +end diff --git a/src/data_structures/mesh_refinement/curves.jl b/src/data_structures/mesh_refinement/curves.jl index 8f9581df5..026767cae 100644 --- a/src/data_structures/mesh_refinement/curves.jl +++ b/src/data_structures/mesh_refinement/curves.jl @@ -1,255 +1,257 @@ -const GL_NW = permutedims([ - -0.999953919435642 0.00011825670068171721 - -0.9997572122115891 0.00027526103865831744 - -0.9994033532930161 0.00043245460060038196 - -0.9988923197258543 0.0005896003421932499 - -0.998224182256913 0.0007466574055662421 - -0.9973990436722557 0.0009035982480626941 - -0.9964170329848294 0.0010603974326420873 - -0.9952783043339365 0.0012170300415936897 - -0.9939830366739069 0.0013734713364273322 - -0.992531433650476 0.0015296966649272486 - -0.9909237235316215 0.0016856814323170032 - -0.9891601591554368 0.0018414010924821323 - -0.9872410178826077 0.0019968311464057843 - -0.9851666015488034 0.002151947143493035 - -0.9829372364150317 0.002306724684154767 - -0.9805532731150799 0.0024611394229790977 - -0.9780150865996246 0.002615167072191434 - -0.9753230760767991 0.0027687834052614944 - -0.9724776649491127 0.002921964260586262 - -0.9694793007466641 0.00307468554521151 - -0.9663284550566241 0.0032269232385712526 - -0.963025623448975 0.0033786533962332863 - -0.959571325398504 0.0035298521536436056 - -0.9559661042030546 0.0036804957298652166 - -0.9522105268980449 0.003830560431308329 - -0.9483051841672582 0.003980022655449804 - -0.944250690249923 0.0041288588945403645 - -0.94004768284409 0.004277045739298241 - -0.9356968230063247 0.004424559882588365 - -0.931198795047727 0.004571378123086171 - -0.9265543064262952 0.004717477368925247 - -0.9217640876356519 0.0048628346413281485 - -0.9168288920901461 0.005007427078219678 - -0.911749496006352 0.0051512319378220145 - -0.9065266982809823 0.005294226602231066 - -0.901161320365234 0.005436388580973459 - -0.8956542061355872 0.0055776955145435516 - -0.890006221761078 0.0057181251779199384 - -0.8842182555670642 0.00585765548406083 - -0.8782912178955077 0.005996264487377793 - -0.8722260409617927 0.006133930387187249 - -0.866023678708105 0.006270631531139229 - -0.8596851066533939 0.006406346418622805 - -0.85321132173994 0.00654105370414767 - -0.8466033421765535 0.006674732200701343 - -0.8398622072784298 0.006807360883081451 - -0.8329889773036814 0.006938918891202568 - -0.8259847332865807 0.007069385533377089 - -0.818850576867531 0.007198740289569644 - -0.8115876301197994 0.007326962814624488 - -0.804197035373034 0.007454032941465406 - -0.796679955033597 0.007579930684267617 - -0.7890375714017384 0.007704636241601166 - -0.7812710864856423 0.007828129999545307 - -0.7733817218123715 0.007950392534773417 - -0.7653707182357452 0.00807140461760791 - -0.7572393357411735 0.008191147215044737 - -0.7489888532474854 0.008309601493746885 - -0.740620568405778 0.008426748823006541 - -0.732135797395319 0.008542570777675352 - -0.7235358747165359 0.008657049141062358 - -0.7148221529811238 0.008770165907799143 - -0.705996002699303 0.008881903286671764 - -0.6970588120642633 0.008992243703418954 - -0.6880119867338267 0.009101169803496257 - -0.6788569496093618 0.00920866445480557 - -0.6695951406119885 0.00931471075038971 - -0.6602280164561035 0.009419292011091571 - -0.6507570504202663 0.009522391788177445 - -0.641183732115479 0.00962399386592412 - -0.6315095672508971 0.0097240822641693 - -0.6217360773970098 0.009822641240825014 - -0.6118647997463229 0.009919655294353544 - -0.6018972868715882 0.010015109166205537 - -0.5918351064816105 0.010108987843219902 - -0.5816798411746766 0.010201276559985107 - -0.5714330881896406 0.010291960801161504 - -0.5610964591547072 0.010381026303764331 - -0.550671579833952 0.010468459059407015 - -0.5401600898716189 0.010554245316504453 - -0.529563642534233 0.010638371582435857 - -0.5188839044505712 0.010720824625666934 - -0.5081225553495348 0.01080159147783093 - -0.49728128779595404 0.010880659435768353 - -0.48636180692438263 0.01095801606352491 - -0.4753658301709075 0.011033649194307498 - -0.4642950870030309 0.011107546932397785 - -0.4531513186476536 0.011179697655023212 - -0.4419362778172123 0.011250090014185036 - -0.43065172843401034 0.011318712938443162 - -0.4192994453527847 0.011385555634657481 - -0.4078812140815536 0.011450607589685441 - -0.39639883050078745 0.011513858572035563 - -0.38485410058095026 0.011575298633476675 - -0.37324884009845394 0.011634918110602589 - -0.3615848743500686 0.01169270762635197 - -0.34986403786583664 0.011748658091483198 - -0.33808817412053493 0.011802760706003907 - -0.32625913524372974 0.011855006960555099 - -0.3143787817284691 0.011905388637749498 - -0.30244898213866317 0.011953897813463982 - -0.29047161281519085 0.012000526858085933 - -0.27844855758078807 0.012045268437713197 - -0.2663817074437531 0.012088115515307618 - -0.2542729603005287 0.012129061351801793 - -0.24212422063719571 0.012168099507159044 - -0.2299373992299318 0.012205223841386304 - -0.21771441284448234 0.012240428515499802 - -0.20545718393468665 0.012273707992443457 - -0.19316764034011163 0.012305057037959772 - -0.1808477149828374 0.012334470721413042 - -0.16849934556344323 0.012361944416564878 - -0.15612447425624337 0.012387473802301837 - -0.14372504740381872 0.012411054863315053 - -0.1313030152108904 0.01243268389073175 - -0.11886033143758944 0.01245235748269861 - -0.10639895309216538 0.012470072544916794 - -0.09392084012318516 0.01248582629112865 - -0.08142795511126816 0.01249961624355592 - -0.0689222629604074 0.012511440233289444 - -0.05640573058892591 0.012521296400630325 - -0.043880326620117996 0.01252918319538237 - -0.031348021072617915 0.01253509937709596 - -0.01881078505055355 0.012539044015263127 - -0.0062705904335270835 0.012541016489463895 - 0.0062705904335270835 0.012541016489463895 - 0.01881078505055355 0.012539044015263127 - 0.031348021072617915 0.01253509937709596 - 0.043880326620117996 0.01252918319538237 - 0.05640573058892591 0.012521296400630325 - 0.0689222629604074 0.012511440233289444 - 0.08142795511126816 0.01249961624355592 - 0.09392084012318516 0.01248582629112865 - 0.10639895309216538 0.012470072544916794 - 0.11886033143758944 0.01245235748269861 - 0.1313030152108904 0.01243268389073175 - 0.14372504740381872 0.012411054863315053 - 0.15612447425624337 0.012387473802301837 - 0.16849934556344323 0.012361944416564878 - 0.1808477149828374 0.012334470721413042 - 0.19316764034011163 0.012305057037959772 - 0.20545718393468665 0.012273707992443457 - 0.21771441284448234 0.012240428515499802 - 0.2299373992299318 0.012205223841386304 - 0.24212422063719571 0.012168099507159044 - 0.2542729603005287 0.012129061351801793 - 0.2663817074437531 0.012088115515307618 - 0.27844855758078807 0.012045268437713197 - 0.29047161281519085 0.012000526858085933 - 0.30244898213866317 0.011953897813463982 - 0.3143787817284691 0.011905388637749498 - 0.32625913524372974 0.011855006960555099 - 0.33808817412053493 0.011802760706003907 - 0.34986403786583664 0.011748658091483198 - 0.3615848743500686 0.01169270762635197 - 0.37324884009845394 0.011634918110602589 - 0.38485410058095026 0.011575298633476675 - 0.39639883050078745 0.011513858572035563 - 0.4078812140815536 0.011450607589685441 - 0.4192994453527847 0.011385555634657481 - 0.43065172843401034 0.011318712938443162 - 0.4419362778172123 0.011250090014185036 - 0.4531513186476536 0.011179697655023212 - 0.4642950870030309 0.011107546932397785 - 0.4753658301709075 0.011033649194307498 - 0.48636180692438263 0.01095801606352491 - 0.49728128779595404 0.010880659435768353 - 0.5081225553495348 0.01080159147783093 - 0.5188839044505712 0.010720824625666934 - 0.529563642534233 0.010638371582435857 - 0.5401600898716189 0.010554245316504453 - 0.550671579833952 0.010468459059407015 - 0.5610964591547072 0.010381026303764331 - 0.5714330881896406 0.010291960801161504 - 0.5816798411746766 0.010201276559985107 - 0.5918351064816105 0.010108987843219902 - 0.6018972868715882 0.010015109166205537 - 0.6118647997463229 0.009919655294353544 - 0.6217360773970098 0.009822641240825014 - 0.6315095672508971 0.0097240822641693 - 0.641183732115479 0.00962399386592412 - 0.6507570504202663 0.009522391788177445 - 0.6602280164561035 0.009419292011091571 - 0.6695951406119885 0.00931471075038971 - 0.6788569496093618 0.00920866445480557 - 0.6880119867338267 0.009101169803496257 - 0.6970588120642633 0.008992243703418954 - 0.705996002699303 0.008881903286671764 - 0.7148221529811238 0.008770165907799143 - 0.7235358747165359 0.008657049141062358 - 0.732135797395319 0.008542570777675352 - 0.740620568405778 0.008426748823006541 - 0.7489888532474854 0.008309601493746885 - 0.7572393357411735 0.008191147215044737 - 0.7653707182357452 0.00807140461760791 - 0.7733817218123715 0.007950392534773417 - 0.7812710864856423 0.007828129999545307 - 0.7890375714017384 0.007704636241601166 - 0.796679955033597 0.007579930684267617 - 0.804197035373034 0.007454032941465406 - 0.8115876301197994 0.007326962814624488 - 0.818850576867531 0.007198740289569644 - 0.8259847332865807 0.007069385533377089 - 0.8329889773036814 0.006938918891202568 - 0.8398622072784298 0.006807360883081451 - 0.8466033421765535 0.006674732200701343 - 0.85321132173994 0.00654105370414767 - 0.8596851066533939 0.006406346418622805 - 0.866023678708105 0.006270631531139229 - 0.8722260409617927 0.006133930387187249 - 0.8782912178955077 0.005996264487377793 - 0.8842182555670642 0.00585765548406083 - 0.890006221761078 0.0057181251779199384 - 0.8956542061355872 0.0055776955145435516 - 0.901161320365234 0.005436388580973459 - 0.9065266982809823 0.005294226602231066 - 0.911749496006352 0.0051512319378220145 - 0.9168288920901461 0.005007427078219678 - 0.9217640876356519 0.0048628346413281485 - 0.9265543064262952 0.004717477368925247 - 0.931198795047727 0.004571378123086171 - 0.9356968230063247 0.004424559882588365 - 0.94004768284409 0.004277045739298241 - 0.944250690249923 0.0041288588945403645 - 0.9483051841672582 0.003980022655449804 - 0.9522105268980449 0.003830560431308329 - 0.9559661042030546 0.0036804957298652166 - 0.959571325398504 0.0035298521536436056 - 0.963025623448975 0.0033786533962332863 - 0.9663284550566241 0.0032269232385712526 - 0.9694793007466641 0.00307468554521151 - 0.9724776649491127 0.002921964260586262 - 0.9753230760767991 0.0027687834052614944 - 0.9780150865996246 0.002615167072191434 - 0.9805532731150799 0.0024611394229790977 - 0.9829372364150317 0.002306724684154767 - 0.9851666015488034 0.002151947143493035 - 0.9872410178826077 0.0019968311464057843 - 0.9891601591554368 0.0018414010924821323 - 0.9909237235316215 0.0016856814323170032 - 0.992531433650476 0.0015296966649272486 - 0.9939830366739069 0.0013734713364273322 - 0.9952783043339365 0.0012170300415936897 - 0.9964170329848294 0.0010603974326420873 - 0.9973990436722557 0.0009035982480626941 - 0.998224182256913 0.0007466574055662421 - 0.9988923197258543 0.0005896003421932499 - 0.9994033532930161 0.00043245460060038196 - 0.9997572122115891 0.00027526103865831744 - 0.999953919435642 0.00011825670068171721 -]) +const GL_NW = permutedims( + [ + -0.999953919435642 0.00011825670068171721 + -0.9997572122115891 0.00027526103865831744 + -0.9994033532930161 0.00043245460060038196 + -0.9988923197258543 0.0005896003421932499 + -0.998224182256913 0.0007466574055662421 + -0.9973990436722557 0.0009035982480626941 + -0.9964170329848294 0.0010603974326420873 + -0.9952783043339365 0.0012170300415936897 + -0.9939830366739069 0.0013734713364273322 + -0.992531433650476 0.0015296966649272486 + -0.9909237235316215 0.0016856814323170032 + -0.9891601591554368 0.0018414010924821323 + -0.9872410178826077 0.0019968311464057843 + -0.9851666015488034 0.002151947143493035 + -0.9829372364150317 0.002306724684154767 + -0.9805532731150799 0.0024611394229790977 + -0.9780150865996246 0.002615167072191434 + -0.9753230760767991 0.0027687834052614944 + -0.9724776649491127 0.002921964260586262 + -0.9694793007466641 0.00307468554521151 + -0.9663284550566241 0.0032269232385712526 + -0.963025623448975 0.0033786533962332863 + -0.959571325398504 0.0035298521536436056 + -0.9559661042030546 0.0036804957298652166 + -0.9522105268980449 0.003830560431308329 + -0.9483051841672582 0.003980022655449804 + -0.944250690249923 0.0041288588945403645 + -0.94004768284409 0.004277045739298241 + -0.9356968230063247 0.004424559882588365 + -0.931198795047727 0.004571378123086171 + -0.9265543064262952 0.004717477368925247 + -0.9217640876356519 0.0048628346413281485 + -0.9168288920901461 0.005007427078219678 + -0.911749496006352 0.0051512319378220145 + -0.9065266982809823 0.005294226602231066 + -0.901161320365234 0.005436388580973459 + -0.8956542061355872 0.0055776955145435516 + -0.890006221761078 0.0057181251779199384 + -0.8842182555670642 0.00585765548406083 + -0.8782912178955077 0.005996264487377793 + -0.8722260409617927 0.006133930387187249 + -0.866023678708105 0.006270631531139229 + -0.8596851066533939 0.006406346418622805 + -0.85321132173994 0.00654105370414767 + -0.8466033421765535 0.006674732200701343 + -0.8398622072784298 0.006807360883081451 + -0.8329889773036814 0.006938918891202568 + -0.8259847332865807 0.007069385533377089 + -0.818850576867531 0.007198740289569644 + -0.8115876301197994 0.007326962814624488 + -0.804197035373034 0.007454032941465406 + -0.796679955033597 0.007579930684267617 + -0.7890375714017384 0.007704636241601166 + -0.7812710864856423 0.007828129999545307 + -0.7733817218123715 0.007950392534773417 + -0.7653707182357452 0.00807140461760791 + -0.7572393357411735 0.008191147215044737 + -0.7489888532474854 0.008309601493746885 + -0.740620568405778 0.008426748823006541 + -0.732135797395319 0.008542570777675352 + -0.7235358747165359 0.008657049141062358 + -0.7148221529811238 0.008770165907799143 + -0.705996002699303 0.008881903286671764 + -0.6970588120642633 0.008992243703418954 + -0.6880119867338267 0.009101169803496257 + -0.6788569496093618 0.00920866445480557 + -0.6695951406119885 0.00931471075038971 + -0.6602280164561035 0.009419292011091571 + -0.6507570504202663 0.009522391788177445 + -0.641183732115479 0.00962399386592412 + -0.6315095672508971 0.0097240822641693 + -0.6217360773970098 0.009822641240825014 + -0.6118647997463229 0.009919655294353544 + -0.6018972868715882 0.010015109166205537 + -0.5918351064816105 0.010108987843219902 + -0.5816798411746766 0.010201276559985107 + -0.5714330881896406 0.010291960801161504 + -0.5610964591547072 0.010381026303764331 + -0.550671579833952 0.010468459059407015 + -0.5401600898716189 0.010554245316504453 + -0.529563642534233 0.010638371582435857 + -0.5188839044505712 0.010720824625666934 + -0.5081225553495348 0.01080159147783093 + -0.49728128779595404 0.010880659435768353 + -0.48636180692438263 0.01095801606352491 + -0.4753658301709075 0.011033649194307498 + -0.4642950870030309 0.011107546932397785 + -0.4531513186476536 0.011179697655023212 + -0.4419362778172123 0.011250090014185036 + -0.43065172843401034 0.011318712938443162 + -0.4192994453527847 0.011385555634657481 + -0.4078812140815536 0.011450607589685441 + -0.39639883050078745 0.011513858572035563 + -0.38485410058095026 0.011575298633476675 + -0.37324884009845394 0.011634918110602589 + -0.3615848743500686 0.01169270762635197 + -0.34986403786583664 0.011748658091483198 + -0.33808817412053493 0.011802760706003907 + -0.32625913524372974 0.011855006960555099 + -0.3143787817284691 0.011905388637749498 + -0.30244898213866317 0.011953897813463982 + -0.29047161281519085 0.012000526858085933 + -0.27844855758078807 0.012045268437713197 + -0.2663817074437531 0.012088115515307618 + -0.2542729603005287 0.012129061351801793 + -0.24212422063719571 0.012168099507159044 + -0.2299373992299318 0.012205223841386304 + -0.21771441284448234 0.012240428515499802 + -0.20545718393468665 0.012273707992443457 + -0.19316764034011163 0.012305057037959772 + -0.1808477149828374 0.012334470721413042 + -0.16849934556344323 0.012361944416564878 + -0.15612447425624337 0.012387473802301837 + -0.14372504740381872 0.012411054863315053 + -0.1313030152108904 0.01243268389073175 + -0.11886033143758944 0.01245235748269861 + -0.10639895309216538 0.012470072544916794 + -0.09392084012318516 0.01248582629112865 + -0.08142795511126816 0.01249961624355592 + -0.0689222629604074 0.012511440233289444 + -0.05640573058892591 0.012521296400630325 + -0.043880326620117996 0.01252918319538237 + -0.031348021072617915 0.01253509937709596 + -0.01881078505055355 0.012539044015263127 + -0.0062705904335270835 0.012541016489463895 + 0.0062705904335270835 0.012541016489463895 + 0.01881078505055355 0.012539044015263127 + 0.031348021072617915 0.01253509937709596 + 0.043880326620117996 0.01252918319538237 + 0.05640573058892591 0.012521296400630325 + 0.0689222629604074 0.012511440233289444 + 0.08142795511126816 0.01249961624355592 + 0.09392084012318516 0.01248582629112865 + 0.10639895309216538 0.012470072544916794 + 0.11886033143758944 0.01245235748269861 + 0.1313030152108904 0.01243268389073175 + 0.14372504740381872 0.012411054863315053 + 0.15612447425624337 0.012387473802301837 + 0.16849934556344323 0.012361944416564878 + 0.1808477149828374 0.012334470721413042 + 0.19316764034011163 0.012305057037959772 + 0.20545718393468665 0.012273707992443457 + 0.21771441284448234 0.012240428515499802 + 0.2299373992299318 0.012205223841386304 + 0.24212422063719571 0.012168099507159044 + 0.2542729603005287 0.012129061351801793 + 0.2663817074437531 0.012088115515307618 + 0.27844855758078807 0.012045268437713197 + 0.29047161281519085 0.012000526858085933 + 0.30244898213866317 0.011953897813463982 + 0.3143787817284691 0.011905388637749498 + 0.32625913524372974 0.011855006960555099 + 0.33808817412053493 0.011802760706003907 + 0.34986403786583664 0.011748658091483198 + 0.3615848743500686 0.01169270762635197 + 0.37324884009845394 0.011634918110602589 + 0.38485410058095026 0.011575298633476675 + 0.39639883050078745 0.011513858572035563 + 0.4078812140815536 0.011450607589685441 + 0.4192994453527847 0.011385555634657481 + 0.43065172843401034 0.011318712938443162 + 0.4419362778172123 0.011250090014185036 + 0.4531513186476536 0.011179697655023212 + 0.4642950870030309 0.011107546932397785 + 0.4753658301709075 0.011033649194307498 + 0.48636180692438263 0.01095801606352491 + 0.49728128779595404 0.010880659435768353 + 0.5081225553495348 0.01080159147783093 + 0.5188839044505712 0.010720824625666934 + 0.529563642534233 0.010638371582435857 + 0.5401600898716189 0.010554245316504453 + 0.550671579833952 0.010468459059407015 + 0.5610964591547072 0.010381026303764331 + 0.5714330881896406 0.010291960801161504 + 0.5816798411746766 0.010201276559985107 + 0.5918351064816105 0.010108987843219902 + 0.6018972868715882 0.010015109166205537 + 0.6118647997463229 0.009919655294353544 + 0.6217360773970098 0.009822641240825014 + 0.6315095672508971 0.0097240822641693 + 0.641183732115479 0.00962399386592412 + 0.6507570504202663 0.009522391788177445 + 0.6602280164561035 0.009419292011091571 + 0.6695951406119885 0.00931471075038971 + 0.6788569496093618 0.00920866445480557 + 0.6880119867338267 0.009101169803496257 + 0.6970588120642633 0.008992243703418954 + 0.705996002699303 0.008881903286671764 + 0.7148221529811238 0.008770165907799143 + 0.7235358747165359 0.008657049141062358 + 0.732135797395319 0.008542570777675352 + 0.740620568405778 0.008426748823006541 + 0.7489888532474854 0.008309601493746885 + 0.7572393357411735 0.008191147215044737 + 0.7653707182357452 0.00807140461760791 + 0.7733817218123715 0.007950392534773417 + 0.7812710864856423 0.007828129999545307 + 0.7890375714017384 0.007704636241601166 + 0.796679955033597 0.007579930684267617 + 0.804197035373034 0.007454032941465406 + 0.8115876301197994 0.007326962814624488 + 0.818850576867531 0.007198740289569644 + 0.8259847332865807 0.007069385533377089 + 0.8329889773036814 0.006938918891202568 + 0.8398622072784298 0.006807360883081451 + 0.8466033421765535 0.006674732200701343 + 0.85321132173994 0.00654105370414767 + 0.8596851066533939 0.006406346418622805 + 0.866023678708105 0.006270631531139229 + 0.8722260409617927 0.006133930387187249 + 0.8782912178955077 0.005996264487377793 + 0.8842182555670642 0.00585765548406083 + 0.890006221761078 0.0057181251779199384 + 0.8956542061355872 0.0055776955145435516 + 0.901161320365234 0.005436388580973459 + 0.9065266982809823 0.005294226602231066 + 0.911749496006352 0.0051512319378220145 + 0.9168288920901461 0.005007427078219678 + 0.9217640876356519 0.0048628346413281485 + 0.9265543064262952 0.004717477368925247 + 0.931198795047727 0.004571378123086171 + 0.9356968230063247 0.004424559882588365 + 0.94004768284409 0.004277045739298241 + 0.944250690249923 0.0041288588945403645 + 0.9483051841672582 0.003980022655449804 + 0.9522105268980449 0.003830560431308329 + 0.9559661042030546 0.0036804957298652166 + 0.959571325398504 0.0035298521536436056 + 0.963025623448975 0.0033786533962332863 + 0.9663284550566241 0.0032269232385712526 + 0.9694793007466641 0.00307468554521151 + 0.9724776649491127 0.002921964260586262 + 0.9753230760767991 0.0027687834052614944 + 0.9780150865996246 0.002615167072191434 + 0.9805532731150799 0.0024611394229790977 + 0.9829372364150317 0.002306724684154767 + 0.9851666015488034 0.002151947143493035 + 0.9872410178826077 0.0019968311464057843 + 0.9891601591554368 0.0018414010924821323 + 0.9909237235316215 0.0016856814323170032 + 0.992531433650476 0.0015296966649272486 + 0.9939830366739069 0.0013734713364273322 + 0.9952783043339365 0.0012170300415936897 + 0.9964170329848294 0.0010603974326420873 + 0.9973990436722557 0.0009035982480626941 + 0.998224182256913 0.0007466574055662421 + 0.9988923197258543 0.0005896003421932499 + 0.9994033532930161 0.00043245460060038196 + 0.9997572122115891 0.00027526103865831744 + 0.999953919435642 0.00011825670068171721 + ], +) """ abstract type AbstractParametricCurve <: Function end @@ -280,7 +282,7 @@ Functions that are defined for all [`AbstractParametricCurve`](@ref) subtypes ar """ abstract type AbstractParametricCurve <: Function end # defined in t ∈ [0, 1] -Base.show(io::IO, c::C) where C <: AbstractParametricCurve = print(io, string(C)) +Base.show(io::IO, c::C) where {C <: AbstractParametricCurve} = print(io, string(C)) """ is_curve_bounded(c::AbstractParametricCurve) -> Bool @@ -413,13 +415,13 @@ function marked_total_variation(b::AbstractParametricCurve, t₁, t₂) return θ₁ + θ₂ else T₁ = differentiate(b, t₁) - T₂ = differentiate(b, b.orientation_markers[i₁+1]) + T₂ = differentiate(b, b.orientation_markers[i₁ + 1]) θ = angle_between(T₁, T₂) θ > π && (θ = 2π - θ) Δθ = θ - for i in (i₁+1):(i₂-1) + for i in (i₁ + 1):(i₂ - 1) T₁ = T₂ - T₂ = differentiate(b, b.orientation_markers[i+1]) + T₂ = differentiate(b, b.orientation_markers[i + 1]) θ = angle_between(T₁, T₂) θ > π && (θ = 2π - θ) Δθ += θ @@ -461,7 +463,7 @@ function convert_lookup_idx(b::AbstractParametricCurve, i) return (i - 1) / (n - 1) end -const PROJECTION_INTERVAL_TOL = 1e-12 +const PROJECTION_INTERVAL_TOL = 1.0e-12 """ get_closest_point(b::AbstractParametricCurve p) -> (Float64, NTuple{2,Float64}) @@ -489,8 +491,8 @@ function get_closest_point(b::AbstractParametricCurve, p) t, q = _get_closest_point_right_search(b, p, δ) else tmid, pmid = convert_lookup_idx(b, i), b.lookup_table[i] - tleft, pleft = convert_lookup_idx(b, i - 1), b.lookup_table[i-1] - tright, pright = convert_lookup_idx(b, i + 1), b.lookup_table[i+1] + tleft, pleft = convert_lookup_idx(b, i - 1), b.lookup_table[i - 1] + tright, pright = convert_lookup_idx(b, i + 1), b.lookup_table[i + 1] t, q = _get_closest_point_interior_search(b, p, tmid, pmid, tleft, pleft, tright, pright, δ) end return t, q @@ -551,7 +553,7 @@ function _get_closest_point_left_search(b::AbstractParametricCurve, p, δ) end end function _get_closest_point_right_search(b::AbstractParametricCurve, p, δ) - tleft, pleft = convert_lookup_idx(b, length(b.lookup_table) - 1), b.lookup_table[end-1] + tleft, pleft = convert_lookup_idx(b, length(b.lookup_table) - 1), b.lookup_table[end - 1] tright, pright = 1.0, b.lookup_table[end] δleft, δright = dist_sqr(p, pleft), δ tmid = midpoint(tleft, tright) @@ -600,7 +602,7 @@ end Protects against bad division in root-finding algorithms. This function checks if `val` is close to `0` or if `roots[i]` is outside of `[0, 1]`. If either of these conditions are true, then `roots[i]` and `residuals[i]` are set to `NaN` and `true` is returned. Otherwise, `false` is returned. """ function protect_against_bad_division!(roots, residuals, val, i) - if abs(val) < 1e-8 || roots[i] < 0 || roots[i] > 1 + if abs(val) < 1.0e-8 || roots[i] < 0 || roots[i] > 1 roots[i] = NaN residuals[i] = NaN return true @@ -629,7 +631,7 @@ Returns points `t` such that `x'(t) = 0` and `0 ≤ t ≤ 1`, where `x'` is the # Output - `t`: All turning points, given in sorted order. """ -function horizontal_turning_points(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) +function horizontal_turning_points(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) roots = collect(LinRange(0, 1, steps)) residuals = fill(Inf, steps) for i in eachindex(roots) @@ -669,7 +671,7 @@ Returns points `t` such that `y'(t) = 0` and `0 ≤ t ≤ 1`, where `y'` is the # Output - `t`: All turning points, given in sorted order. """ -function vertical_turning_points(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) +function vertical_turning_points(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) roots = collect(LinRange(0, 1, steps)) residuals = fill(Inf, steps) for i in eachindex(roots) @@ -710,7 +712,7 @@ Note that these are only technically inflection points if `x'''(t) ≠ 0` at the # Output - `t`: All inflection points, given in sorted order. """ -function horizontal_inflection_points(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) +function horizontal_inflection_points(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) roots = collect(LinRange(0, 1, steps)) residuals = fill(Inf, steps) for i in eachindex(roots) @@ -751,7 +753,7 @@ Note that these are only technically inflection points if `y'''(t) ≠ 0` at the # Output - `t`: All inflection points, given in sorted order. """ -function vertical_inflection_points(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) +function vertical_inflection_points(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) roots = collect(LinRange(0, 1, steps)) residuals = fill(Inf, steps) for i in eachindex(roots) @@ -788,7 +790,7 @@ Returns points `t` such that `κ(t) = 0` and `0 ≤ t ≤ 1`, where `κ` is the - `iters=50`: The number of iterations to run Newton's method for. - `tol=1e-5`: The tolerance to use for [`uniquetol`](@ref). Also used for deciding whether a root is a valid root, i.e. if `abs(κ(t)) > tol` for a found root `t`, then `t` is not a valid root and is rejected. """ -function inflection_points(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) +function inflection_points(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) roots = collect(LinRange(0, 1, steps)) residuals = fill(Inf, steps) for i in eachindex(roots) @@ -848,12 +850,12 @@ See also [`horizontal_turning_points`](@ref), [`vertical_turning_points`](@ref), of any `t` is not considered (so the `t`-values in the returned vector are unique). These values can be used to split the curve into monotone pieces, meaning the orientation is monotone. These markers also guarantee that, over any monotone piece, the orientation changes by an angle of at most `π/2`. """ -function orientation_markers(c::AbstractParametricCurve; steps=200, iters=50, tol=1e-5) - t₁ = horizontal_turning_points(c, steps=steps, iters=iters, tol=tol) - t₂ = vertical_turning_points(c, steps=steps, iters=iters, tol=tol) - t₃ = horizontal_inflection_points(c, steps=steps, iters=iters, tol=tol) - t₄ = vertical_inflection_points(c, steps=steps, iters=iters, tol=tol) - t₅ = inflection_points(c, steps=steps, iters=iters, tol=tol) +function orientation_markers(c::AbstractParametricCurve; steps = 200, iters = 50, tol = 1.0e-5) + t₁ = horizontal_turning_points(c, steps = steps, iters = iters, tol = tol) + t₂ = vertical_turning_points(c, steps = steps, iters = iters, tol = tol) + t₃ = horizontal_inflection_points(c, steps = steps, iters = iters, tol = tol) + t₄ = vertical_inflection_points(c, steps = steps, iters = iters, tol = tol) + t₅ = inflection_points(c, steps = steps, iters = iters, tol = tol) all_t = vcat(t₁, t₂, t₃, t₄, t₅) isempty(all_t) && return [0.0, 1.0] sort!(all_t) @@ -876,7 +878,7 @@ function get_equidistant_split(c::AbstractParametricCurve, t₁, t₂) t = midpoint(a, t₂) for _ in 1:100 # limit iterations to 100 s₁t = arc_length(c, a, t) - if abs(s₁t - s) < 1e-3 || abs(t₁ - t₂) < 2e-8 + if abs(s₁t - s) < 1.0e-3 || abs(t₁ - t₂) < 2.0e-8 return t end s₁t > s ? (t₂ = t) : (t₁ = t) @@ -899,7 +901,7 @@ function get_equivariation_split(c::AbstractParametricCurve, t₁, t₂) t = get_equidistant_split(c, a, t₂) for _ in 1:100 # limit iterations to 100 Δθ₁t = total_variation(c, a, t) - if abs(Δθ₁t - Δθ) < 1e-4 || abs(t₁ - t₂) < 2e-8 + if abs(Δθ₁t - Δθ) < 1.0e-4 || abs(t₁ - t₂) < 2.0e-8 return t, Δθ₁t end Δθ₁t > Δθ ? (t₂ = t) : (t₁ = t) @@ -948,7 +950,7 @@ function get_circle_intersection(c::AbstractParametricCurve, t₁, t₂, r) for _ in 1:100 q = c(t) δ = dist(p, q) - if abs(δ - r) < 1e-3 || abs(tᵢ - tⱼ) < 2e-8 + if abs(δ - r) < 1.0e-3 || abs(tᵢ - tⱼ) < 2.0e-8 return t, q end (δ > r) ? (tⱼ = t) : (tᵢ = t) @@ -1023,8 +1025,8 @@ You can construct a `LineSegment` using LineSegment(first, last) """ struct LineSegment <: AbstractParametricCurve # line segment - first::NTuple{2,Float64} - last::NTuple{2,Float64} + first::NTuple{2, Float64} + last::NTuple{2, Float64} length::Float64 end Base.:(==)(L₁::LineSegment, L₂::LineSegment) = L₁.first == L₂.first && L₁.last == L₂.last @@ -1141,7 +1143,7 @@ know that its `boundary_nodes` field should be used instead. on the curve, and the last point otherwise (meaning `L(h)` is constant for `h > 0`), and similarly for differentiation. Do NOT rely on the implementation of these methods. """ -struct PiecewiseLinear{P,V} <: AbstractParametricCurve +struct PiecewiseLinear{P, V} <: AbstractParametricCurve points::P boundary_nodes::V end @@ -1224,13 +1226,13 @@ distance between `center` and `first`. The `positive` keyword argument is used t arc is positively oriented or negatively oriented. """ struct CircularArc <: AbstractParametricCurve - center::NTuple{2,Float64} + center::NTuple{2, Float64} radius::Float64 start_angle::Float64 sector_angle::Float64 - first::NTuple{2,Float64} - last::NTuple{2,Float64} - pqr::NTuple{3,NTuple{2,Float64}} + first::NTuple{2, Float64} + last::NTuple{2, Float64} + pqr::NTuple{3, NTuple{2, Float64}} end function Base.:(==)(c₁::CircularArc, c₂::CircularArc) c₁.center ≠ c₂.center && return false @@ -1240,7 +1242,7 @@ function Base.:(==)(c₁::CircularArc, c₂::CircularArc) return true end -function CircularArc(p, q, c; positive=true) +function CircularArc(p, q, c; positive = true) px, py = getxy(p) qx, qy = getxy(q) cx, cy = getxy(c) @@ -1323,8 +1325,8 @@ end get_equidistant_split(c::CircularArc, t₁, t₂) = midpoint(t₁, t₂) get_equivariation_split(c::CircularArc, t₁, t₂) = let t = midpoint(t₁, t₂) - (t, total_variation(c, t₁, t)) - end + (t, total_variation(c, t₁, t)) +end function get_inverse(c::CircularArc, p) if p == c.first @@ -1374,14 +1376,14 @@ where `rotation` is the angle of rotation of the ellipse, in degrees. The `posit arc is positively oriented or negatively oriented. """ struct EllipticalArc <: AbstractParametricCurve - center::NTuple{2,Float64} + center::NTuple{2, Float64} horz_radius::Float64 vert_radius::Float64 - rotation_scales::NTuple{2,Float64} + rotation_scales::NTuple{2, Float64} start_angle::Float64 sector_angle::Float64 - first::NTuple{2,Float64} - last::NTuple{2,Float64} + first::NTuple{2, Float64} + last::NTuple{2, Float64} end function Base.:(==)(e₁::EllipticalArc, e₂::EllipticalArc) e₁.center ≠ e₂.center && return false @@ -1393,7 +1395,7 @@ function Base.:(==)(e₁::EllipticalArc, e₂::EllipticalArc) return true end -function EllipticalArc(p, q, c, α, β, θ°; positive=true) +function EllipticalArc(p, q, c, α, β, θ°; positive = true) px, py = getxy(p) qx, qy = getxy(q) cx, cy = getxy(c) @@ -1555,9 +1557,9 @@ You can construct a `BezierCurve` using The keyword argument `lookup_steps=100` controls how many time points in `[0, 1]` are used for the lookup table. The `kwargs...` are keyword arguments passed to [`orientation_markers`](@ref). """ struct BezierCurve <: AbstractParametricCurve - control_points::Vector{NTuple{2,Float64}} - cache::Vector{NTuple{2,Float64}} - lookup_table::Vector{NTuple{2,Float64}} + control_points::Vector{NTuple{2, Float64}} + cache::Vector{NTuple{2, Float64}} + lookup_table::Vector{NTuple{2, Float64}} orientation_markers::Vector{Float64} end function Base.:(==)(b₁::BezierCurve, b₂::BezierCurve) @@ -1565,7 +1567,7 @@ function Base.:(==)(b₁::BezierCurve, b₂::BezierCurve) return true end -function BezierCurve(control_points::Vector{NTuple{2,Float64}}; lookup_steps=5000, kwargs...) +function BezierCurve(control_points::Vector{NTuple{2, Float64}}; lookup_steps = 5000, kwargs...) cache = similar(control_points) # will be copyto! later lookup_table = similar(control_points, lookup_steps) markers = Float64[] @@ -1580,7 +1582,7 @@ function BezierCurve(control_points::Vector{NTuple{2,Float64}}; lookup_steps=500 return spl end -function (b::BezierCurve)(t)::NTuple{2,Float64} +function (b::BezierCurve)(t)::NTuple{2, Float64} return _eval_bezier_curve(b.control_points, b.cache, t) end function de_casteljau!(control_points, t) @@ -1591,9 +1593,9 @@ function de_casteljau!(control_points, t) else n = length(control_points) - 1 for j in 1:n - for k in 1:n-j+1 + for k in 1:(n - j + 1) xₖ, yₖ = getxy(control_points[k]) - xₖ₊₁, yₖ₊₁ = getxy(control_points[k+1]) + xₖ₊₁, yₖ₊₁ = getxy(control_points[k + 1]) x = (one(t) - t) * xₖ + t * xₖ₊₁ y = (one(t) - t) * yₖ + t * yₖ₊₁ control_points[k] = (x, y) @@ -1612,10 +1614,10 @@ function differentiate(b::BezierCurve, t) n = length(b.control_points) - 1 for i in 1:n xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) b.cache[i] = (n * (xᵢ₊₁ - xᵢ), n * (yᵢ₊₁ - yᵢ)) end - return @views de_casteljau!(b.cache[begin:end-1], t) + return @views de_casteljau!(b.cache[begin:(end - 1)], t) end function twice_differentiate(b::BezierCurve, t) @@ -1624,10 +1626,10 @@ function twice_differentiate(b::BezierCurve, t) if n == 1 return (0.0, 0.0) end - for i in 1:(n-1) + for i in 1:(n - 1) xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) - xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i+2]) + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) + xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i + 2]) # To compute the second derivative control points, we note that e.g. # for points [A, B, C, D], the first derivative gives [3(B - A), 3(C - B), 3(D - C)]. # Let these new points be [A', B', C']. Thus, differentiating again, we obtain @@ -1640,7 +1642,7 @@ function twice_differentiate(b::BezierCurve, t) scale = n * (n - 1) b.cache[i] = (scale * (xᵢ₊₂ - 2xᵢ₊₁ + xᵢ), scale * (yᵢ₊₂ - 2yᵢ₊₁ + yᵢ)) end - return @views de_casteljau!(b.cache[begin:end-2], t) + return @views de_casteljau!(b.cache[begin:(end - 2)], t) end function thrice_differentiate(b::BezierCurve, t) @@ -1649,11 +1651,11 @@ function thrice_differentiate(b::BezierCurve, t) if n ≤ 2 return (0.0, 0.0) end - for i in 1:(n-2) + for i in 1:(n - 2) xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) - xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i+2]) - xᵢ₊₃, yᵢ₊₃ = getxy(b.control_points[i+3]) + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) + xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i + 2]) + xᵢ₊₃, yᵢ₊₃ = getxy(b.control_points[i + 3]) # We know that Qᵢ′ = p(Pᵢ₊₁ - Pᵢ), where Qᵢ′ is the ith control point for the first derivative, # p is the degree of b, and Pᵢ is the ith control point of b. Thus, # Qᵢ′′ = (p-1)(Qᵢ₊₁′ - Qᵢ′) = p(p-1)(Pᵢ₊₂ - 2Pᵢ₊₁ + Pᵢ), and then @@ -1661,7 +1663,7 @@ function thrice_differentiate(b::BezierCurve, t) scale = n * (n - 1) * (n - 2) b.cache[i] = (scale * (xᵢ₊₃ - 3xᵢ₊₂ + 3xᵢ₊₁ - xᵢ), scale * (yᵢ₊₃ - 3yᵢ₊₂ + 3yᵢ₊₁ - yᵢ)) end - return @views de_casteljau!(b.cache[begin:end-3], t) + return @views de_casteljau!(b.cache[begin:(end - 3)], t) end total_variation(b::BezierCurve, t₁, t₂) = marked_total_variation(b, t₁, t₂) @@ -1703,10 +1705,10 @@ The keyword argument `lookup_steps` is used to build the lookup table for the cu `degree=3` corresponds to a cubic B-spline curve. The `kwargs...` are keyword arguments passed to [`orientation_markers`](@ref). """ struct BSpline <: AbstractParametricCurve - control_points::Vector{NTuple{2,Float64}} + control_points::Vector{NTuple{2, Float64}} knots::Vector{Int} - cache::Vector{NTuple{2,Float64}} - lookup_table::Vector{NTuple{2,Float64}} + cache::Vector{NTuple{2, Float64}} + lookup_table::Vector{NTuple{2, Float64}} orientation_markers::Vector{Float64} end function Base.:(==)(b₁::BSpline, b₂::BSpline) @@ -1715,7 +1717,7 @@ function Base.:(==)(b₁::BSpline, b₂::BSpline) return true end -function BSpline(control_points::Vector{NTuple{2,Float64}}; degree=3, lookup_steps=5000, kwargs...) +function BSpline(control_points::Vector{NTuple{2, Float64}}; degree = 3, lookup_steps = 5000, kwargs...) nc = length(control_points) @assert degree ≥ 1 "Degree must be at least 1, got $degree." @assert degree ≤ nc - 1 "Degree must be at most n - 1 = $(nc - 1), where n is the number of control points, got $degree." @@ -1726,7 +1728,7 @@ function BSpline(control_points::Vector{NTuple{2,Float64}}; degree=3, lookup_ste if i ≤ order knots[i] = 0 elseif i < nc + 1 - knots[i] = knots[i-1] + 1 + knots[i] = knots[i - 1] + 1 else knots[i] = knots[nc] + 1 end @@ -1744,7 +1746,7 @@ function BSpline(control_points::Vector{NTuple{2,Float64}}; degree=3, lookup_ste return spl end -function (b::BSpline)(t)::NTuple{2,Float64} +function (b::BSpline)(t)::NTuple{2, Float64} return _eval_bspline(b.control_points, b.knots, b.cache, t) end @@ -1762,12 +1764,12 @@ function de_boor!(control_points, knots, t) t = a + t * (b - a) s = @views searchsortedfirst(knots[domain[1]:domain[2]], t) + domain[1] - 2 for L in 1:order - for i in s:-1:(s-order+L+1) + for i in s:-1:(s - order + L + 1) numerator = t - knots[i] - denominator = knots[i+order-L] - knots[i] + denominator = knots[i + order - L] - knots[i] α = numerator / denominator α′ = 1 - α - xᵢ₋₁, yᵢ₋₁ = getxy(control_points[i-1]) + xᵢ₋₁, yᵢ₋₁ = getxy(control_points[i - 1]) xᵢ, yᵢ = getxy(control_points[i]) control_points[i] = (α′ * xᵢ₋₁ + α * xᵢ, α′ * yᵢ₋₁ + α * yᵢ) end @@ -1789,13 +1791,13 @@ function differentiate(b::BSpline, t) nc = length(b.control_points) nk = length(b.knots) degree = nk - nc - 1 - for i in 1:(nc-1) + for i in 1:(nc - 1) xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) - scale = degree / (b.knots[i+degree+1] - b.knots[i+1]) + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) + scale = degree / (b.knots[i + degree + 1] - b.knots[i + 1]) b.cache[i] = (scale * (xᵢ₊₁ - xᵢ), scale * (yᵢ₊₁ - yᵢ)) end - deriv = @views de_boor!(b.cache[begin:(end-1)], b.knots[(begin+1):(end-1)], t) + deriv = @views de_boor!(b.cache[begin:(end - 1)], b.knots[(begin + 1):(end - 1)], t) # Need to scale, since the formula used assumes that the knots are all in [0, 1] range = b.knots[end] - b.knots[begin] return (deriv[1] * range, deriv[2] * range) @@ -1809,18 +1811,18 @@ function twice_differentiate(b::BSpline, t) if degree == 1 return (0.0, 0.0) end - for i in 1:(nc-2) + for i in 1:(nc - 2) xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) - xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i+2]) - scale1 = degree / (b.knots[i+degree+1] - b.knots[i+1]) - scale2 = degree / (b.knots[i+degree+2] - b.knots[i+2]) - scale3 = (degree - 1) / (b.knots[i+degree+1] - b.knots[i+2]) # different shifts between the knots are knots[begin+1:end-1] + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) + xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i + 2]) + scale1 = degree / (b.knots[i + degree + 1] - b.knots[i + 1]) + scale2 = degree / (b.knots[i + degree + 2] - b.knots[i + 2]) + scale3 = (degree - 1) / (b.knots[i + degree + 1] - b.knots[i + 2]) # different shifts between the knots are knots[begin+1:end-1] Qᵢ′x, Qᵢ′y = (scale1 * (xᵢ₊₁ - xᵢ), scale1 * (yᵢ₊₁ - yᵢ)) Qᵢ₊₁′x, Qᵢ₊₁′y = (scale2 * (xᵢ₊₂ - xᵢ₊₁), scale2 * (yᵢ₊₂ - yᵢ₊₁)) b.cache[i] = (scale3 * (Qᵢ₊₁′x - Qᵢ′x), scale3 * (Qᵢ₊₁′y - Qᵢ′y)) end - deriv = @views de_boor!(b.cache[begin:(end-2)], b.knots[(begin+2):(end-2)], t) + deriv = @views de_boor!(b.cache[begin:(end - 2)], b.knots[(begin + 2):(end - 2)], t) range = (b.knots[end] - b.knots[begin])^2 return (deriv[1] * range, deriv[2] * range) end @@ -1833,17 +1835,17 @@ function thrice_differentiate(b::BSpline, t) # yes there is a way to evaluate (B if degree ≤ 2 return (0.0, 0.0) end - for i in 1:(nc-3) + for i in 1:(nc - 3) xᵢ, yᵢ = getxy(b.control_points[i]) - xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i+1]) - xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i+2]) - xᵢ₊₃, yᵢ₊₃ = getxy(b.control_points[i+3]) - scale1 = degree / (b.knots[i+degree+1] - b.knots[i+1]) - scale2 = degree / (b.knots[i+degree+2] - b.knots[i+2]) - scale3 = degree / (b.knots[i+degree+3] - b.knots[i+3]) - scale4 = (degree - 1) / (b.knots[i+degree+1] - b.knots[i+2]) - scale5 = (degree - 1) / (b.knots[i+degree+2] - b.knots[i+3]) - scale6 = (degree - 2) / (b.knots[i+degree+1] - b.knots[i+3]) + xᵢ₊₁, yᵢ₊₁ = getxy(b.control_points[i + 1]) + xᵢ₊₂, yᵢ₊₂ = getxy(b.control_points[i + 2]) + xᵢ₊₃, yᵢ₊₃ = getxy(b.control_points[i + 3]) + scale1 = degree / (b.knots[i + degree + 1] - b.knots[i + 1]) + scale2 = degree / (b.knots[i + degree + 2] - b.knots[i + 2]) + scale3 = degree / (b.knots[i + degree + 3] - b.knots[i + 3]) + scale4 = (degree - 1) / (b.knots[i + degree + 1] - b.knots[i + 2]) + scale5 = (degree - 1) / (b.knots[i + degree + 2] - b.knots[i + 3]) + scale6 = (degree - 2) / (b.knots[i + degree + 1] - b.knots[i + 3]) Qᵢ′x, Qᵢ′y = (scale1 * (xᵢ₊₁ - xᵢ), scale1 * (yᵢ₊₁ - yᵢ)) Qᵢ₊₁′x, Qᵢ₊₁′y = (scale2 * (xᵢ₊₂ - xᵢ₊₁), scale2 * (yᵢ₊₂ - yᵢ₊₁)) Qᵢ₊₂′x, Qᵢ₊₂′y = (scale3 * (xᵢ₊₃ - xᵢ₊₂), scale3 * (yᵢ₊₃ - yᵢ₊₂)) @@ -1851,7 +1853,7 @@ function thrice_differentiate(b::BSpline, t) # yes there is a way to evaluate (B Qᵢ₊₁′′x, Qᵢ₊₁′′y = (scale5 * (Qᵢ₊₂′x - Qᵢ₊₁′x), scale5 * (Qᵢ₊₂′y - Qᵢ₊₁′y)) b.cache[i] = (scale6 * (Qᵢ₊₁′′x - Qᵢ′′x), scale6 * (Qᵢ₊₁′′y - Qᵢ′′y)) end - deriv = @views de_boor!(b.cache[begin:(end-3)], b.knots[(begin+3):(end-3)], t) + deriv = @views de_boor!(b.cache[begin:(end - 3)], b.knots[(begin + 3):(end - 3)], t) range = (b.knots[end] - b.knots[begin])^3 return (deriv[1] * range, deriv[2] * range) end @@ -1900,12 +1902,12 @@ The parameter `τ` is the tension, and controls the tightness of the segment. ` control points. Both `α` and `τ` must be in `[0, 1]`. """ struct CatmullRomSplineSegment <: AbstractParametricCurve - a::NTuple{2,Float64} - b::NTuple{2,Float64} - c::NTuple{2,Float64} - d::NTuple{2,Float64} - p₁::NTuple{2,Float64} - p₂::NTuple{2,Float64} + a::NTuple{2, Float64} + b::NTuple{2, Float64} + c::NTuple{2, Float64} + d::NTuple{2, Float64} + p₁::NTuple{2, Float64} + p₂::NTuple{2, Float64} end function (c::CatmullRomSplineSegment)(t) if iszero(t) @@ -2031,13 +2033,13 @@ The keyword argument `lookup_steps` is used to build the lookup table for the cu The `kwargs...` are keyword arguments passed to [`orientation_markers`](@ref). """ struct CatmullRomSpline <: AbstractParametricCurve - control_points::Vector{NTuple{2,Float64}} + control_points::Vector{NTuple{2, Float64}} knots::Vector{Float64} - lookup_table::Vector{NTuple{2,Float64}} + lookup_table::Vector{NTuple{2, Float64}} alpha::Float64 tension::Float64 - left::NTuple{2,Float64} - right::NTuple{2,Float64} + left::NTuple{2, Float64} + right::NTuple{2, Float64} lengths::Vector{Float64} segments::Vector{CatmullRomSplineSegment} orientation_markers::Vector{Float64} @@ -2052,7 +2054,7 @@ end is_interpolating(spl::CatmullRomSpline) = true -function CatmullRomSpline(control_points; _alpha=1 / 2, _tension=0.0, lookup_steps=5000, kwargs...) +function CatmullRomSpline(control_points; _alpha = 1 / 2, _tension = 0.0, lookup_steps = 5000, kwargs...) alpha = _alpha tension = _tension @assert length(control_points) ≥ 4 "Catmull-Rom splines require at least 4 control points, got $(length(control_points))." @@ -2061,7 +2063,7 @@ function CatmullRomSpline(control_points; _alpha=1 / 2, _tension=0.0, lookup_ste @assert 0 ≤ tension ≤ 1 "Tension must be in [0, 1], got $tension." knots = zeros(nc) for i in 2:nc - knots[i] = knots[i-1] + dist(control_points[i-1], control_points[i])^alpha + knots[i] = knots[i - 1] + dist(control_points[i - 1], control_points[i])^alpha end left = extend_left_control_point(control_points) right = extend_right_control_point(control_points) @@ -2073,14 +2075,14 @@ function CatmullRomSpline(control_points; _alpha=1 / 2, _tension=0.0, lookup_ste markers = Float64[] segments = Vector{CatmullRomSplineSegment}(undef, nc - 1) spl = CatmullRomSpline(control_points, knots, lookup_table, alpha, tension, left, right, lengths, segments, markers) - for i in 1:(nc-1) + for i in 1:(nc - 1) spl.segments[i] = _get_segment(spl, i) end for i in 1:lookup_steps t = (i - 1) / (lookup_steps - 1) spl.lookup_table[i] = spl(t) end - for i in 1:(nc-1) + for i in 1:(nc - 1) segment = get_segment(spl, i) spl.lengths[i] = arc_length(segment, 0.0, 1.0) end @@ -2093,9 +2095,9 @@ end function extend_left_control_point(control_points) is_closed = control_points[begin] == control_points[end] if is_closed - return control_points[end-1] + return control_points[end - 1] else - c₁, c₂, c₃, c₄ = control_points[begin], control_points[begin+1], control_points[begin+2], control_points[begin+3] + c₁, c₂, c₃, c₄ = control_points[begin], control_points[begin + 1], control_points[begin + 2], control_points[begin + 3] x₁, x₂ = getx(c₁), getx(c₂) reverse_flag = x₁ == x₂ if reverse_flag @@ -2114,9 +2116,9 @@ end function extend_right_control_point(control_points) is_closed = control_points[begin] == control_points[end] if is_closed - return control_points[begin+1] + return control_points[begin + 1] else - cₙ₋₃, cₙ₋₂, cₙ₋₁, cₙ = control_points[end-3], control_points[end-2], control_points[end-1], control_points[end] + cₙ₋₃, cₙ₋₂, cₙ₋₁, cₙ = control_points[end - 3], control_points[end - 2], control_points[end - 1], control_points[end] xₙ₋₁, xₙ = getx(cₙ₋₁), getx(cₙ) reverse_flag = xₙ₋₁ == xₙ if reverse_flag @@ -2221,14 +2223,14 @@ function (c::CatmullRomSpline)(t) end function map_t_to_segment(c::CatmullRomSpline, i, t) - tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i+1] + tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i + 1] t′ = (t - tᵢ) / (tᵢ₊₁ - tᵢ) return t′ end function differentiate(c::CatmullRomSpline, t) segment, i = get_segment(c, t) - tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i+1] + tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i + 1] t′ = map_t_to_segment(c, i, t) ∂x, ∂y = getxy(differentiate(segment, t′)) scale = inv(tᵢ₊₁ - tᵢ) @@ -2237,7 +2239,7 @@ end function twice_differentiate(c::CatmullRomSpline, t) segment, i = get_segment(c, t) - tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i+1] + tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i + 1] t′ = map_t_to_segment(c, i, t) ∂x, ∂y = getxy(twice_differentiate(segment, t′)) scale = inv(tᵢ₊₁ - tᵢ) @@ -2246,7 +2248,7 @@ end function thrice_differentiate(c::CatmullRomSpline, t) segment, i = get_segment(c, t) - tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i+1] + tᵢ, tᵢ₊₁ = c.knots[i], c.knots[i + 1] t′ = map_t_to_segment(c, i, t) ∂x, ∂y = getxy(thrice_differentiate(segment, t′)) scale = inv(tᵢ₊₁ - tᵢ) @@ -2267,14 +2269,14 @@ function _get_segment(c::CatmullRomSpline, i::Int) if i == firstindex(c.control_points) pᵢ₋₁ = c.left else - pᵢ₋₁ = c.control_points[i-1] + pᵢ₋₁ = c.control_points[i - 1] end if i == lastindex(c.control_points) - 1 pᵢ₊₂ = c.right else - pᵢ₊₂ = c.control_points[i+2] + pᵢ₊₂ = c.control_points[i + 2] end - pᵢ, pᵢ₊₁ = c.control_points[i], c.control_points[i+1] + pᵢ, pᵢ₊₁ = c.control_points[i], c.control_points[i + 1] segment = catmull_rom_spline_segment(pᵢ₋₁, pᵢ, pᵢ₊₁, pᵢ₊₂, c.alpha, c.tension) return segment end @@ -2300,7 +2302,7 @@ function arc_length(c::CatmullRomSpline, t₁, t₂) return s₁ + s₂ else # at least one complete segment separates the outer segments s = 0.0 - for i in (i₁+1):(i₂-1) + for i in (i₁ + 1):(i₂ - 1) s += c.lengths[i] end t₁′ = map_t_to_segment(c, i₁, t₁) @@ -2318,4 +2320,4 @@ has_lookup_table(c::CatmullRomSpline) = true #function is_piecewise_linear(c::CatmullRomSpline) # tension = c.tension # return isone(tension) -#end \ No newline at end of file +#end diff --git a/src/data_structures/mesh_refinement/insertion_event_history.jl b/src/data_structures/mesh_refinement/insertion_event_history.jl index daa381828..dc42aa04e 100644 --- a/src/data_structures/mesh_refinement/insertion_event_history.jl +++ b/src/data_structures/mesh_refinement/insertion_event_history.jl @@ -18,7 +18,7 @@ The default constructor is available, but we also provide which will initialise this struct with empty, appropriately `sizehint!`ed, sets. """ -struct InsertionEventHistory{T,E} +struct InsertionEventHistory{T, E} added_triangles::Set{T} deleted_triangles::Set{T} added_segments::Set{E} @@ -56,7 +56,7 @@ function InsertionEventHistory(tri::Triangulation) sizehint!(delete_edge_set, 8) sizehint!(add_bnd_set, 8) sizehint!(delete_bnd_set, 8) - return InsertionEventHistory{T,E}(add_set, delete_set, add_edge_set, delete_edge_set, add_bnd_set, delete_bnd_set) + return InsertionEventHistory{T, E}(add_set, delete_set, add_edge_set, delete_edge_set, add_bnd_set, delete_bnd_set) end """ @@ -92,7 +92,7 @@ delete_edge!(events::InsertionEventHistory, e) = push!(events.deleted_segments, Add the edge `(u, v)` to the `deleted_boundary_segments` of `events` and add the edges `(u, new_point)` and `(new_point, v)` to the `added_boundary_segments` of `events`. """ -function split_boundary_edge!(events::InsertionEventHistory{T,E}, u, v, new_point) where {T,E} +function split_boundary_edge!(events::InsertionEventHistory{T, E}, u, v, new_point) where {T, E} !contains_edge(construct_edge(E, v, u), events.deleted_boundary_segments) && push!(events.deleted_boundary_segments, construct_edge(E, u, v)) !contains_edge(construct_edge(E, new_point, u), events.added_boundary_segments) && push!(events.added_boundary_segments, construct_edge(E, u, new_point)) !contains_edge(construct_edge(E, v, new_point), events.added_boundary_segments) && push!(events.added_boundary_segments, construct_edge(E, new_point, v)) @@ -105,8 +105,12 @@ end Returns `true` if there are any changes to the segments in `events`, and `false` otherwise. """ function has_segment_changes(events::InsertionEventHistory) - return any(!isempty, (events.added_segments, events.deleted_segments, - events.added_boundary_segments, events.deleted_boundary_segments)) + return any( + !isempty, ( + events.added_segments, events.deleted_segments, + events.added_boundary_segments, events.deleted_boundary_segments, + ), + ) end """ @@ -160,13 +164,13 @@ recorded into `events` and the vertex is `num_points(tri)`. If you do not want to delete the latest vertex from the triangulation, set `pop` to `Val(false)`. """ -function undo_insertion!(tri::Triangulation, events::InsertionEventHistory, pop=Val(true)) +function undo_insertion!(tri::Triangulation, events::InsertionEventHistory, pop = Val(true)) vertex = num_points(tri) for T in events.added_triangles - delete_triangle!(tri, T; protect_boundary=true, update_ghost_edges=false) + delete_triangle!(tri, T; protect_boundary = true, update_ghost_edges = false) end for T in events.deleted_triangles - add_triangle!(tri, T; protect_boundary=true, update_ghost_edges=false) + add_triangle!(tri, T; protect_boundary = true, update_ghost_edges = false) end undo_segment_changes!(tri, events) undo_boundary_segment_changes!(tri, events) @@ -218,4 +222,4 @@ function undo_boundary_segment_changes!(tri::Triangulation, events::InsertionEve e = pop!(deleted_boundary_segments) merge_boundary_edge!(tri, e, vertex) return tri -end \ No newline at end of file +end diff --git a/src/data_structures/mesh_refinement/refinement_arguments.jl b/src/data_structures/mesh_refinement/refinement_arguments.jl index 5889a86f1..7b4803d18 100644 --- a/src/data_structures/mesh_refinement/refinement_arguments.jl +++ b/src/data_structures/mesh_refinement/refinement_arguments.jl @@ -28,7 +28,7 @@ In addition to the default constructor, we provide for constructing this struct. This constructor will lock the convex hull and add ghost triangles to `tri` if needed ([`refine!`](@ref) will undo these changes once the refinement is finished)) """ -struct RefinementArguments{Q,C,H,I,E,R,T} +struct RefinementArguments{Q, C, H, I, E, R, T} queue::Q constraints::C events::H @@ -58,19 +58,21 @@ match those from [`refine!`](@ref). has no constrained boundary, then the convex hull will be locked so that it is treated as a constrained boundary. These changes will be undone in [`refine!`](@ref) once the refinement is finished. """ -function RefinementArguments(tri::Triangulation; - min_angle=30.0, - max_angle=180.0, - min_area=get_area(tri) / 1e9, - max_area=typemax(number_type(tri)), - max_points=max(1_000, num_solid_vertices(tri))^2, - seditious_angle=20.0, - custom_constraint=(_tri, T) -> false, - use_circumcenter=true, # TODO: When we implement generalised Steiner points, change this default to FALSE. - use_lens=true, - steiner_scale=0.999, - rng=Random.default_rng(), - concavity_protection=false) +function RefinementArguments( + tri::Triangulation; + min_angle = 30.0, + max_angle = 180.0, + min_area = get_area(tri) / 1.0e9, + max_area = typemax(number_type(tri)), + max_points = max(1_000, num_solid_vertices(tri))^2, + seditious_angle = 20.0, + custom_constraint = (_tri, T) -> false, + use_circumcenter = true, # TODO: When we implement generalised Steiner points, change this default to FALSE. + use_lens = true, + steiner_scale = 0.999, + rng = Random.default_rng(), + concavity_protection = false, + ) if !use_circumcenter throw(ArgumentError("Generalised Steiner points are not yet implemented.")) end @@ -85,7 +87,7 @@ function RefinementArguments(tri::Triangulation; max_area, max_points, seditious_angle, - custom_constraint + custom_constraint, ) queue = RefinementQueue(tri) events = InsertionEventHistory(tri) @@ -119,7 +121,7 @@ function RefinementArguments(tri::Triangulation; lock_convex_hull, has_ghosts, rng, - concavity_protection + concavity_protection, ) end diff --git a/src/data_structures/mesh_refinement/refinement_constraints.jl b/src/data_structures/mesh_refinement/refinement_constraints.jl index d953fb7fe..77d2ed562 100644 --- a/src/data_structures/mesh_refinement/refinement_constraints.jl +++ b/src/data_structures/mesh_refinement/refinement_constraints.jl @@ -23,13 +23,14 @@ struct RefinementConstraints{F} seditious_angle::Float64 custom_constraint::F function RefinementConstraints(; - min_angle=0.0, - max_angle=180.0, - min_area=0.0, - max_area=Inf, - max_points=typemax(Int), - seditious_angle=20.0, - custom_constraint=(tri, triangle) -> false) + min_angle = 0.0, + max_angle = 180.0, + min_area = 0.0, + max_area = Inf, + max_points = typemax(Int), + seditious_angle = 20.0, + custom_constraint = (tri, triangle) -> false, + ) max_radius_edge_ratio = cscd(min_angle) / 2 min_angle, max_angle, min_area, max_area, max_radius_edge_ratio, seditious_angle = convert.(Float64, (min_angle, max_angle, min_area, max_area, max_radius_edge_ratio, seditious_angle)) F = typeof(custom_constraint) diff --git a/src/data_structures/mesh_refinement/refinement_queue.jl b/src/data_structures/mesh_refinement/refinement_queue.jl index b6968a011..bc48de5ce 100644 --- a/src/data_structures/mesh_refinement/refinement_queue.jl +++ b/src/data_structures/mesh_refinement/refinement_queue.jl @@ -14,11 +14,11 @@ The default constructor is available, but we also provide which will initialise this struct with empty queues with the appropriate types. """ -struct RefinementQueue{T,E,F} - segments::MaxPriorityQueue{E,F} - triangles::MaxPriorityQueue{T,F} - function RefinementQueue{T,E,F}() where {T,E,F} - return new{T,E,F}(MaxPriorityQueue{E,F}(), MaxPriorityQueue{T,F}()) +struct RefinementQueue{T, E, F} + segments::MaxPriorityQueue{E, F} + triangles::MaxPriorityQueue{T, F} + function RefinementQueue{T, E, F}() where {T, E, F} + return new{T, E, F}(MaxPriorityQueue{E, F}(), MaxPriorityQueue{T, F}()) end end function Base.show(io::IO, ::MIME"text/plain", queue::RefinementQueue) @@ -31,7 +31,7 @@ function RefinementQueue(tri::Triangulation) T = triangle_type(tri) E = edge_type(tri) F = number_type(tri) - return RefinementQueue{T,E,F}() + return RefinementQueue{T, E, F}() end """ @@ -39,7 +39,7 @@ end Return `true` if `queue` has `segment` or its reverse, and `false` otherwise. """ -function Base.haskey(queue::RefinementQueue{T,E,F}, segment::E) where {T,E,F} +function Base.haskey(queue::RefinementQueue{T, E, F}, segment::E) where {T, E, F} return haskey(queue.segments, segment) || haskey(queue.segments, reverse_edge(segment)) end @@ -48,10 +48,10 @@ end Return `true` if `queue` has `triangle` or any of its counter-clockwise rotations, and `false` otherwise. """ -function Base.haskey(queue::RefinementQueue{T,E,F}, triangle::T) where {T,E,F} +function Base.haskey(queue::RefinementQueue{T, E, F}, triangle::T) where {T, E, F} return haskey(queue.triangles, triangle) || - haskey(queue.triangles, rotate_triangle(triangle, Val(1))) || - haskey(queue.triangles, rotate_triangle(triangle, Val(2))) + haskey(queue.triangles, rotate_triangle(triangle, Val(1))) || + haskey(queue.triangles, rotate_triangle(triangle, Val(2))) end """ @@ -60,7 +60,7 @@ end Return the radius-edge ratio of `triangle` in `queue`. """ -function Base.getindex(queue::RefinementQueue{T,E,F}, triangle::T) where {T,E,F} +function Base.getindex(queue::RefinementQueue{T, E, F}, triangle::T) where {T, E, F} if haskey(queue.triangles, triangle) return queue.triangles[triangle] elseif haskey(queue.triangles, rotate_triangle(triangle, Val(1))) @@ -77,7 +77,7 @@ end Add a `segment` to `queue` whose squared length is `ℓ²`. If the `segment` is already in the `queue`, its priority is updated to `ℓ`. """ -function Base.setindex!(queue::RefinementQueue{T,E,F}, ℓ²::F, segment::E) where {T,E,F} +function Base.setindex!(queue::RefinementQueue{T, E, F}, ℓ²::F, segment::E) where {T, E, F} segments = queue.segments if haskey(segments, reverse_edge(segment)) segments[reverse_edge(segment)] = ℓ² @@ -93,7 +93,7 @@ end Add a `triangle` to `queue` whose radius-edge ratio is `ρ`. If the `triangle` is already in the `queue`, its priority is updated to `ρ`. """ -function Base.setindex!(queue::RefinementQueue{T,E,F}, ρ, triangle::T) where {T,E,F} +function Base.setindex!(queue::RefinementQueue{T, E, F}, ρ, triangle::T) where {T, E, F} triangles = queue.triangles if haskey(triangles, triangle) triangles[triangle] = ρ @@ -140,4 +140,4 @@ has_triangles(queue::RefinementQueue) = !isempty(queue.triangles) Return `true` if `queue` has no segments or triangles, `false` otherwise. """ -Base.isempty(queue::RefinementQueue) = !has_segments(queue) && !has_triangles(queue) \ No newline at end of file +Base.isempty(queue::RefinementQueue) = !has_segments(queue) && !has_triangles(queue) diff --git a/src/data_structures/point_location_history.jl b/src/data_structures/point_location_history.jl index f1de77cc0..45d726c6c 100644 --- a/src/data_structures/point_location_history.jl +++ b/src/data_structures/point_location_history.jl @@ -10,13 +10,13 @@ History from using [`find_triangle`](@ref). - `left_vertices::Vector{I}`: Vertices from the visited triangles to the left of `pq`. - `right_verices::Vector{I}`: Vertices from the visited triangles to the right of `pq`. """ -struct PointLocationHistory{T,E,I} +struct PointLocationHistory{T, E, I} triangles::Vector{T} collinear_segments::Vector{E} collinear_point_indices::Vector{I} left_vertices::Vector{I} right_vertices::Vector{I} - PointLocationHistory{T,E,I}() where {T,E,I} = new{T,E,I}(T[], E[], I[], I[], I[]) + PointLocationHistory{T, E, I}() where {T, E, I} = new{T, E, I}(T[], E[], I[], I[], I[]) end """ @@ -24,20 +24,20 @@ end Adds the triangle `(i, j, k)` to the `triangles` field of `history`. """ -add_triangle!(history::Ts, i::I, j::I, k::I) where {Ts<:PointLocationHistory,I<:Integer} = add_triangle!(history.triangles, i, j, k) +add_triangle!(history::Ts, i::I, j::I, k::I) where {Ts <: PointLocationHistory, I <: Integer} = add_triangle!(history.triangles, i, j, k) """ add_edge!(history::PointLocationHistory{T,E}, i, j) Adds the edge `(i, j)` to the `collinear_segments` field of `history`. """ -add_edge!(history::PointLocationHistory{T,E}, i, j) where {T,E} = add_edge!(history.collinear_segments, construct_edge(E, i, j)) +add_edge!(history::PointLocationHistory{T, E}, i, j) where {T, E} = add_edge!(history.collinear_segments, construct_edge(E, i, j)) """ add_left_vertex!(history::PointLocationHistory, i) Adds the vertex `i` to the `left_vertices` field of `history`. -""" +""" add_left_vertex!(history::PointLocationHistory, i) = push!(history.left_vertices, i) """ @@ -59,4 +59,4 @@ add_index!(history::PointLocationHistory, i) = push!(history.collinear_point_ind Returns the number of edges in `history.collinear_segments`. """ -num_edges(history::PointLocationHistory) = num_edges(history.collinear_segments) \ No newline at end of file +num_edges(history::PointLocationHistory) = num_edges(history.collinear_segments) diff --git a/src/data_structures/polygon.jl b/src/data_structures/polygon.jl index 7468344ee..9dd7e82c5 100644 --- a/src/data_structures/polygon.jl +++ b/src/data_structures/polygon.jl @@ -13,20 +13,20 @@ the integers themselves refer to points in `points`. In the case where `vertices[begin] ≠ vertices[end]`, the `vertices` field is exactly the same as the input `vertices`. Where `vertices[begin] = vertices[end]`, the `vertices` field is a view of `vertices` that excludes the last element. """ -struct Polygon{T,V,P} <: AbstractVector{T} +struct Polygon{T, V, P} <: AbstractVector{T} vertices::V points::P is_circular::Bool - @inline function Polygon(vertices::V, points::P) where {V,P} + @inline function Polygon(vertices::V, points::P) where {V, P} p = get_point(points, vertices[begin]) T = typeof(p) - return new{T,V,P}(vertices, points, is_circular(vertices)) + return new{T, V, P}(vertices, points, is_circular(vertices)) end end Base.length(P::Polygon) = length(P.vertices) - P.is_circular Base.size(P::Polygon) = (length(P),) Base.getindex(P::Polygon, i::Int) = get_point(P.points, P.vertices[i]) -Base.getindex(P::Polygon, i::Vararg{Int,N}) where {N} = +Base.getindex(P::Polygon, i::Vararg{Int, N}) where {N} = map(i) do j - P[j] - end \ No newline at end of file + P[j] +end diff --git a/src/data_structures/queue/max_priority_queue.jl b/src/data_structures/queue/max_priority_queue.jl index f60520e4c..ba257a1c1 100644 --- a/src/data_structures/queue/max_priority_queue.jl +++ b/src/data_structures/queue/max_priority_queue.jl @@ -10,15 +10,15 @@ Struct for a max priority queue. - `data::Vector{Pair{K, V}}`: The data of the queue, stored in a vector of key-value pairs mapping elements to their priority. - `map::Dict{K, Int}`: A dictionary mapping elements to their index in the data vector. """ -struct MaxPriorityQueue{K,V} <: AbstractDict{K,V} - data::Vector{Pair{K,V}} - map::Dict{K,Int} +struct MaxPriorityQueue{K, V} <: AbstractDict{K, V} + data::Vector{Pair{K, V}} + map::Dict{K, Int} end -function MaxPriorityQueue{K,V}() where {K,V} - return MaxPriorityQueue{K,V}(Pair{K,V}[], Dict{K,Int}()) +function MaxPriorityQueue{K, V}() where {K, V} + return MaxPriorityQueue{K, V}(Pair{K, V}[], Dict{K, Int}()) end -function MaxPriorityQueue(data::Dict{K,V}) where {K,V} - queue = MaxPriorityQueue{K,V}() +function MaxPriorityQueue(data::Dict{K, V}) where {K, V} + queue = MaxPriorityQueue{K, V}() for pair in data push!(queue, pair) end @@ -163,8 +163,8 @@ end Sets the priority of the element with key `key` in a `queue` to `priority`, or adds the element to the `queue` if it is not already present. """ -function Base.setindex!(queue::MaxPriorityQueue{K,V}, priority, key) where {K,V} - new_pair = Pair{K,V}(key, priority) +function Base.setindex!(queue::MaxPriorityQueue{K, V}, priority, key) where {K, V} + new_pair = Pair{K, V}(key, priority) if haskey(queue, key) idx = queue.map[key] orig_priority = queue.data[idx].second @@ -231,4 +231,4 @@ end function Base.iterate(queue::MaxPriorityQueue, state::MaxPriorityQueue) isempty(state) && return nothing return popfirst!(state), state -end \ No newline at end of file +end diff --git a/src/data_structures/queue/queue.jl b/src/data_structures/queue/queue.jl index 4b3b3203e..1961f5c6f 100644 --- a/src/data_structures/queue/queue.jl +++ b/src/data_structures/queue/queue.jl @@ -7,11 +7,11 @@ Struct for a first-in first-out queue. Under the hood, `Queue` simply uses a `Vector`. This may not be as optimised compared to other implementations, e.g. DataStructure.jl's block-based approach with a `Dequeue`. -""" +""" struct Queue{T} data::Vector{T} end -Queue{T}() where T = Queue{T}(T[]) +Queue{T}() where {T} = Queue{T}(T[]) Base.:(==)(q1::Queue, q2::Queue) = q1.data == q2.data """ @@ -55,4 +55,3 @@ Base.popfirst!(queue::Queue) = popfirst!(queue.data) Adds all `data` to the end of the `queue`. """ enqueue_all!(queue::Queue, data) = append!(queue.data, data) - diff --git a/src/data_structures/representative_coordinates/cell.jl b/src/data_structures/representative_coordinates/cell.jl index 83ff6b1ce..e0798ac98 100644 --- a/src/data_structures/representative_coordinates/cell.jl +++ b/src/data_structures/representative_coordinates/cell.jl @@ -58,4 +58,4 @@ getx(c::Cell) = c.x Returns the y-coordinate of `c`. """ -gety(c::Cell) = c.y \ No newline at end of file +gety(c::Cell) = c.y diff --git a/src/data_structures/representative_coordinates/cell_queue.jl b/src/data_structures/representative_coordinates/cell_queue.jl index 64cec7149..cebc67f54 100644 --- a/src/data_structures/representative_coordinates/cell_queue.jl +++ b/src/data_structures/representative_coordinates/cell_queue.jl @@ -12,10 +12,10 @@ according to their maximum distance. Constructs a new `CellQueue` with elements of type `Cell{T}`. """ -struct CellQueue{T} - queue::MaxPriorityQueue{Cell{T},T} +struct CellQueue{T} + queue::MaxPriorityQueue{Cell{T}, T} function CellQueue{T}() where {T} - return new{T}(MaxPriorityQueue{Cell{T},T}()) + return new{T}(MaxPriorityQueue{Cell{T}, T}()) end end @@ -43,4 +43,4 @@ get_next_cell!(queue::CellQueue) = popfirst!(queue.queue).first Returns `true` if the `queue` is empty, and `false` otherwise. """ -Base.isempty(queue::CellQueue) = Base.isempty(queue.queue) \ No newline at end of file +Base.isempty(queue::CellQueue) = Base.isempty(queue.queue) diff --git a/src/data_structures/representative_coordinates/representative_coordinates.jl b/src/data_structures/representative_coordinates/representative_coordinates.jl index 834407b34..c3f34e6ac 100644 --- a/src/data_structures/representative_coordinates/representative_coordinates.jl +++ b/src/data_structures/representative_coordinates/representative_coordinates.jl @@ -8,13 +8,13 @@ A mutable struct for representing the coordinates of a representative point of p - `y::NumberType`: The y-coordinate of the representative point. - `n::IntegerType`: The number of points represented by the representative point. """ -mutable struct RepresentativeCoordinates{I,T} +mutable struct RepresentativeCoordinates{I, T} x::T y::T n::I end -function RepresentativeCoordinates{I,T}() where {I,T} - return RepresentativeCoordinates{I,T}(zero(T), zero(T), zero(I)) +function RepresentativeCoordinates{I, T}() where {I, T} + return RepresentativeCoordinates{I, T}(zero(T), zero(T), zero(I)) end function Base.:(==)(p::RepresentativeCoordinates, q::RepresentativeCoordinates) getx(p) ≠ getx(q) && return false @@ -22,13 +22,13 @@ function Base.:(==)(p::RepresentativeCoordinates, q::RepresentativeCoordinates) getn(p) ≠ getn(q) && return false return true end -function Base.convert(::Type{RepresentativeCoordinates{I,T}}, c::RepresentativeCoordinates) where {I,T} +function Base.convert(::Type{RepresentativeCoordinates{I, T}}, c::RepresentativeCoordinates) where {I, T} x = getx(c) y = gety(c) n = getn(c) return RepresentativeCoordinates(T(x), T(y), I(n)) end -function Base.convert(::Type{RepresentativeCoordinates{I,T}}, c::RepresentativeCoordinates{I,T}) where {I,T} +function Base.convert(::Type{RepresentativeCoordinates{I, T}}, c::RepresentativeCoordinates{I, T}) where {I, T} return c end @@ -58,7 +58,7 @@ getn(c::RepresentativeCoordinates) = c.n Resets the coordinates of `c` to zero. """ -function reset!(c::RepresentativeCoordinates{I,T}) where {I,T} +function reset!(c::RepresentativeCoordinates{I, T}) where {I, T} c.x = zero(T) c.y = zero(T) c.n = zero(I) @@ -102,4 +102,4 @@ function compute_centroid!(c::RepresentativeCoordinates, points) add_point!(c, p) end return c -end \ No newline at end of file +end diff --git a/src/data_structures/shuffled_polygon_linked_list.jl b/src/data_structures/shuffled_polygon_linked_list.jl index 285b3b142..2ea7207cd 100644 --- a/src/data_structures/shuffled_polygon_linked_list.jl +++ b/src/data_structures/shuffled_polygon_linked_list.jl @@ -19,20 +19,20 @@ To construct this, use The argument `rng` is used for shuffling the `shuffled_indices` vector. """ -struct ShuffledPolygonLinkedList{I,T} +struct ShuffledPolygonLinkedList{I, T} next::Vector{I} prev::Vector{I} shuffled_indices::Vector{I} k::I S::T - function ShuffledPolygonLinkedList(next::Vector{I}, prev::Vector{I}, shuffled_indices::Vector{I}, k::I, S::T) where {I,T} + function ShuffledPolygonLinkedList(next::Vector{I}, prev::Vector{I}, shuffled_indices::Vector{I}, k::I, S::T) where {I, T} Base.require_one_based_indexing(S) @assert !is_circular(S) "S must not be circular." @assert length(next) == length(prev) == length(shuffled_indices) == k == length(S) "The lengths of next, prev, shuffled_indices, and S must be equal." new{I, T}(next, prev, shuffled_indices, k, S) end end -function ShuffledPolygonLinkedList(S::AbstractVector{I}; rng::AbstractRNG=Random.default_rng()) where {I} +function ShuffledPolygonLinkedList(S::AbstractVector{I}; rng::AbstractRNG = Random.default_rng()) where {I} k = I(length(S)) shuffled_indices = collect(I, eachindex(S)) next = zeros(I, k) @@ -48,10 +48,10 @@ end Resets the linked `list`, so that `list.next[i] = mod1(i+1, list.k)` and `list.prev[i] = mod1(i-1, list.k)`, and also reshuffles the `list.shuffled_indices` vector. """ -function reset!(list::ShuffledPolygonLinkedList; rng::AbstractRNG=Random.default_rng()) - for i in 1:list.k - list.next[i] = mod1(i+1, list.k) - list.prev[i] = mod1(i-1, list.k) +function reset!(list::ShuffledPolygonLinkedList; rng::AbstractRNG = Random.default_rng()) + for i in 1:list.k + list.next[i] = mod1(i + 1, list.k) + list.prev[i] = mod1(i - 1, list.k) end shuffle!(rng, list.shuffled_indices) return list @@ -83,7 +83,7 @@ we perform which is the same as removing `S[πᵢ]` from the linked `list`. """ function delete_vertex!(list::ShuffledPolygonLinkedList, i) - πᵢ = list.shuffled_indices[i] + πᵢ = list.shuffled_indices[i] list.next[list.prev[πᵢ]] = list.next[πᵢ] list.prev[list.next[πᵢ]] = list.prev[πᵢ] return list @@ -98,4 +98,4 @@ Reorders the permutation `list.shuffled_indices` of the linked `list`, swapping function swap_permutation!(list::ShuffledPolygonLinkedList, i, j) list.shuffled_indices[i], list.shuffled_indices[j] = list.shuffled_indices[j], list.shuffled_indices[i] return list -end \ No newline at end of file +end diff --git a/src/data_structures/statistics/individual_triangle_statistics.jl b/src/data_structures/statistics/individual_triangle_statistics.jl index 4192276fa..2e3bb5c9c 100644 --- a/src/data_structures/statistics/individual_triangle_statistics.jl +++ b/src/data_structures/statistics/individual_triangle_statistics.jl @@ -50,20 +50,20 @@ The relevant functions used for computing these statistics are """ struct IndividualTriangleStatistics{T} area::T - lengths::NTuple{3,T} - circumcenter::NTuple{2,T} + lengths::NTuple{3, T} + circumcenter::NTuple{2, T} circumradius::T - angles::NTuple{3,T} + angles::NTuple{3, T} radius_edge_ratio::T - edge_midpoints::NTuple{3,NTuple{2,T}} + edge_midpoints::NTuple{3, NTuple{2, T}} aspect_ratio::T inradius::T perimeter::T - centroid::NTuple{2,T} - offcenter::NTuple{2,T} - sink::NTuple{2,T} + centroid::NTuple{2, T} + offcenter::NTuple{2, T} + sink::NTuple{2, T} end -function IndividualTriangleStatistics(p, q, r, sink=(NaN, NaN)) +function IndividualTriangleStatistics(p, q, r, sink = (NaN, NaN)) F = number_type(p) ℓmin², ℓmed², ℓmax² = squared_triangle_lengths(p, q, r) ℓmin, ℓmed, ℓmax = sqrt(ℓmin²), sqrt(ℓmed²), sqrt(ℓmax²) @@ -137,8 +137,8 @@ A^2 = \dfrac{1}{16}\left\{\left[\ell_3 + \left(\ell_2 + \ell_1\right)\right]\lef """ squared_triangle_area_v2(ℓ₁²::Number, ℓ₂²::Number, ℓ₃²::Number) = let a = sqrt(ℓ₃²), b = sqrt(ℓ₂²), c = sqrt(ℓ₁²) - return (a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c)) / 16 # https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf - end + return (a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c)) / 16 # https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf +end @doc raw""" triangle_circumradius(A, ℓmin², ℓmed², ℓmax²) -> Number @@ -353,7 +353,7 @@ where ``d_{11} = \|p - r\|_2^2``, ``d_{12} = p_y - r_y``, ``d_{21} = \|q - r\|_2 All coordinates are converted into Float64, but the returned area is converted back into the original precision. """ -function triangle_circumcenter(_p, _q, _r, _A=triangle_area(_p, _q, _r)) +function triangle_circumcenter(_p, _q, _r, _A = triangle_area(_p, _q, _r)) p, q, r = _getxy(_p), _getxy(_q), _getxy(_r) A = Float64(_A) px, py = getxy(p) @@ -415,7 +415,7 @@ Computes the off-center of the triangle `(p, q, r)`. be the circumcenter if it the triangle `pqc₁` has radius-edge ratio less than `β`. Here, we just let the off-center be the point `c` so that `pqc` has radius-edge ratio of exactly `β`. """ -function triangle_offcenter(p, q, r, c₁=triangle_circumcenter(p, q, r), β=1.0) +function triangle_offcenter(p, q, r, c₁ = triangle_circumcenter(p, q, r), β = 1.0) ℓ₁², ℓ₂², _, idx = squared_triangle_lengths_and_smallest_index(p, q, r) ℓ₁ = sqrt(ℓ₁²) p, q, r = make_shortest_edge_first(p, q, r, idx) @@ -632,7 +632,7 @@ Sinks were introduced in [this paper](https://doi.org/10.1145/378583.378644). Fo In cases where the triangulation has holes, this definition can lead to loops. In such a case, we just pick one of the triangles in the loop as the sink triangle. """ -function triangle_sink(tri::Triangulation, T, prev_T=construct_triangle(triangle_type(tri), integer_type(tri)(∅), integer_type(tri)(∅), integer_type(tri)(∅))) +function triangle_sink(tri::Triangulation, T, prev_T = construct_triangle(triangle_type(tri), integer_type(tri)(∅), integer_type(tri)(∅), integer_type(tri)(∅))) # TODO: This function would be faster if we just always search away from the largest angle. T = sort_triangle(T) c = triangle_circumcenter(tri, T) @@ -666,4 +666,4 @@ function triangle_sink(tri::Triangulation, T, prev_T=construct_triangle(triangle end sort_triangle(next_T) == prev_T && return c return triangle_sink(tri, next_T, T) -end \ No newline at end of file +end diff --git a/src/data_structures/statistics/triangulation_statistics.jl b/src/data_structures/statistics/triangulation_statistics.jl index 951b2393b..a980ed7fe 100644 --- a/src/data_structures/statistics/triangulation_statistics.jl +++ b/src/data_structures/statistics/triangulation_statistics.jl @@ -29,7 +29,7 @@ A struct containing statistics about a triangulation. # Constructors To construct these statistics, use [`statistics`](@ref), which you call as `statistics(tri::Triangulation)`. """ -struct TriangulationStatistics{T,V,I} +struct TriangulationStatistics{T, V, I} num_vertices::I num_solid_vertices::I num_ghost_vertices::I @@ -50,7 +50,7 @@ struct TriangulationStatistics{T,V,I} smallest_radius_edge_ratio::V largest_radius_edge_ratio::V area::V - individual_statistics::Dict{T,IndividualTriangleStatistics{V}} + individual_statistics::Dict{T, IndividualTriangleStatistics{V}} end function Base.show(io::IO, ::MIME"text/plain", stats::TriangulationStatistics) println(io, "Delaunay Triangulation Statistics.") @@ -102,7 +102,7 @@ function statistics(tri::Triangulation) nsegments = num_edges(segments) convex_hull_vertices = get_convex_hull_vertices(tri) nconvex_hull_vertices = max(0, length(convex_hull_vertices) - 1) # -1 because the last index is the same as the first - individual_statistics = Dict{V,IndividualTriangleStatistics{F}}() + individual_statistics = Dict{V, IndividualTriangleStatistics{F}}() sizehint!(individual_statistics, nsolid_tris) smallest_angle = typemax(F) largest_angle = typemin(F) @@ -144,7 +144,7 @@ function statistics(tri::Triangulation) smallest_radius_edge_ratio, largest_radius_edge_ratio, total_area, - individual_statistics + individual_statistics, ) end for n in fieldnames(TriangulationStatistics) @@ -176,10 +176,10 @@ for n in fieldnames(IndividualTriangleStatistics) Returns the $($name) field from the individual triangle statistics for the triangle `T` in the [`TriangulationStatistics`](@ref) `stats`. """ ($(Symbol("get_$n")))(stats::TriangulationStatistics, T) = let indiv_stats = get_individual_statistics(stats) - T = contains_triangle(T, keys(indiv_stats)) - !T[2] && throw(BoundsError(indiv_stats, T)) - return indiv_stats[T[1]].$n - end + T = contains_triangle(T, keys(indiv_stats)) + !T[2] && throw(BoundsError(indiv_stats, T)) + return indiv_stats[T[1]].$n + end end end @@ -221,4 +221,4 @@ function get_all_stat!(stats::Vector{F}, indiv_stats::Dict, stat::Symbol) where stats[i] = getfield(indiv_stats[T], stat)::F end return stats -end \ No newline at end of file +end diff --git a/src/data_structures/trees/bst.jl b/src/data_structures/trees/bst.jl index 12211520c..6687ebcb3 100644 --- a/src/data_structures/trees/bst.jl +++ b/src/data_structures/trees/bst.jl @@ -24,9 +24,9 @@ mutable struct BalancedBSTNode{K} key::K height::Int8 count::Int32 - parent::Union{Nothing,BalancedBSTNode{K}} - left::Union{Nothing,BalancedBSTNode{K}} - right::Union{Nothing,BalancedBSTNode{K}} + parent::Union{Nothing, BalancedBSTNode{K}} + left::Union{Nothing, BalancedBSTNode{K}} + right::Union{Nothing, BalancedBSTNode{K}} function BalancedBSTNode(key::K) where {K} new{K}(key, 1, 1, nothing, nothing, nothing) end @@ -170,7 +170,7 @@ Struct representing a balanced binary search tree. Nodes with duplicate keys are not supported. If a duplicate key is inserted, the tree will not be modified. """ mutable struct BalancedBST{K} - root::Union{Nothing,BalancedBSTNode{K}} + root::Union{Nothing, BalancedBSTNode{K}} count::Int32 BalancedBST(root::BalancedBSTNode{K}, count) where {K} = new{K}(root, count) BalancedBST{K}(root::BalancedBSTNode{K}, count) where {K} = new{K}(root, count) @@ -299,7 +299,7 @@ end Computes the count of the subtree rooted at `node`, i.e. the number of nodes in the subtree rooted at `node`, including `node`. """ -function compute_count(node::Union{Nothing,BalancedBSTNode}) +function compute_count(node::Union{Nothing, BalancedBSTNode}) if isnothing(node) return Int32(0) else @@ -316,7 +316,7 @@ end Computes the height of the subtree rooted at `node`. """ -function compute_height(node::Union{Nothing,BalancedBSTNode}) +function compute_height(node::Union{Nothing, BalancedBSTNode}) if isnothing(node) return Int8(0) else @@ -333,7 +333,7 @@ end Computes the balance of the subtree rooted at `node`. This is the difference between the left and right heights. """ -function compute_balance(node::Union{Nothing,BalancedBSTNode}) +function compute_balance(node::Union{Nothing, BalancedBSTNode}) if isnothing(node) return Int8(0) else @@ -488,9 +488,9 @@ end Returns the node with the minimum key in the subtree rooted at `node`. If `node` is `nothing`, returns `nothing`. """ -function _minimum(node::Union{BalancedBSTNode,Nothing}) +function _minimum(node::Union{BalancedBSTNode, Nothing}) while !isnothing(node) && has_left(node) node = get_left(node) end return node -end \ No newline at end of file +end diff --git a/src/data_structures/trees/polygon_hierarchy.jl b/src/data_structures/trees/polygon_hierarchy.jl index f8f517148..7de78049c 100644 --- a/src/data_structures/trees/polygon_hierarchy.jl +++ b/src/data_structures/trees/polygon_hierarchy.jl @@ -16,19 +16,19 @@ A tree structure used to define a polygon hierarchy. Constructs a [`PolygonTree`](@ref) with `parent`, `index`, and `height`, and no children. """ mutable struct PolygonTree{I} - parent::Union{Nothing,PolygonTree{I}} + parent::Union{Nothing, PolygonTree{I}} children::Set{PolygonTree{I}} # would do const, but for compat reasons I don't. can't seem to fix this with @static either index::I # would do const, but for compat reasons I don't height::Int end -PolygonTree{I}(parent::Union{Nothing,PolygonTree{I}}, index, height) where {I} = PolygonTree{I}(parent, Set{PolygonTree{I}}(), index, height) +PolygonTree{I}(parent::Union{Nothing, PolygonTree{I}}, index, height) where {I} = PolygonTree{I}(parent, Set{PolygonTree{I}}(), index, height) function hash_tree(tree::PolygonTree) height = get_height(tree) index = get_index(tree) parent_index = has_parent(tree) ? get_index(get_parent(tree)) : 0 h = hash((parent_index, index, height)) children = collect(get_children(tree)) - sort!(children, by=get_index) + sort!(children, by = get_index) for child in children h = hash((h, hash_tree(child))) end @@ -174,10 +174,10 @@ Constructs a [`PolygonHierarchy`](@ref) with no polygons. struct PolygonHierarchy{I} polygon_orientations::BitVector bounding_boxes::Vector{BoundingBox} - trees::Dict{I,PolygonTree{I}} + trees::Dict{I, PolygonTree{I}} reorder_cache::Vector{PolygonTree{I}} end -PolygonHierarchy{I}() where {I} = PolygonHierarchy{I}(BitVector(), BoundingBox[], Dict{I,PolygonTree{I}}(), PolygonTree{I}[]) +PolygonHierarchy{I}() where {I} = PolygonHierarchy{I}(BitVector(), BoundingBox[], Dict{I, PolygonTree{I}}(), PolygonTree{I}[]) @static if VERSION ≥ v"1.10" function Base.deepcopy(hierarchy::PolygonHierarchy{I}) where {I} # without this definition, deepcopy would occassionally segfault polygon_orientations = get_polygon_orientations(hierarchy) @@ -186,7 +186,7 @@ PolygonHierarchy{I}() where {I} = PolygonHierarchy{I}(BitVector(), BoundingBox[] reorder_cache = get_reorder_cache(hierarchy) new_polygon_orientations = copy(polygon_orientations) new_bounding_boxes = copy(bounding_boxes) - new_trees = Dict{I,PolygonTree{I}}() + new_trees = Dict{I, PolygonTree{I}}() for (index, tree) in trees new_trees[index] = deepcopy(tree) end @@ -354,7 +354,7 @@ end Returns a [`PolygonHierarchy`](@ref) defining the polygon hierarchy for a given set of `points`. This defines a hierarchy with a single polygon. """ -function construct_polygon_hierarchy(points; IntegerType=Int) +function construct_polygon_hierarchy(points; IntegerType = Int) hierarchy = PolygonHierarchy{IntegerType}() return construct_polygon_hierarchy!(hierarchy, points) end @@ -374,11 +374,11 @@ end Returns a [`PolygonHierarchy`](@ref) defining the polygon hierarchy for a given set of `boundary_nodes` that define a set of piecewise linear curves. """ -function construct_polygon_hierarchy(points, boundary_nodes; IntegerType=Int) +function construct_polygon_hierarchy(points, boundary_nodes; IntegerType = Int) hierarchy = PolygonHierarchy{IntegerType}() return construct_polygon_hierarchy!(hierarchy, points, boundary_nodes) end -construct_polygon_hierarchy(points, ::Nothing; IntegerType=Int) = construct_polygon_hierarchy(points; IntegerType) +construct_polygon_hierarchy(points, ::Nothing; IntegerType = Int) = construct_polygon_hierarchy(points; IntegerType) function construct_polygon_hierarchy!(hierarchy::PolygonHierarchy{I}, points, boundary_nodes) where {I} if !has_boundary_nodes(boundary_nodes) return construct_polygon_hierarchy!(hierarchy, points) @@ -600,7 +600,7 @@ end Expands the bounding boxes of `hierarchy` by a factor of `perc` in each direction. """ -function expand_bounds!(hierarchy::PolygonHierarchy, perc=0.10) +function expand_bounds!(hierarchy::PolygonHierarchy, perc = 0.1) bboxes = get_bounding_boxes(hierarchy) for (i, bbox) in enumerate(bboxes) bboxes[i] = expand(bbox, perc) @@ -623,9 +623,9 @@ from the curves in `boundary_curves`. Uses [`polygonise`](@ref) to fill in the b - `IntegerType=Int`: The integer type to use for indexing the polygons. - `n=4096`: The number of points to use for filling in the boundary curves in [`polygonise`](@ref). """ -function construct_polygon_hierarchy(points, boundary_nodes, boundary_curves; IntegerType=Int, n=4096) +function construct_polygon_hierarchy(points, boundary_nodes, boundary_curves; IntegerType = Int, n = 4096) new_points, new_boundary_nodes = polygonise(points, boundary_nodes, boundary_curves; n) hierarchy = PolygonHierarchy{IntegerType}() return construct_polygon_hierarchy!(hierarchy, new_points, new_boundary_nodes) end -construct_polygon_hierarchy(points, boundary_nodes, ::Tuple{}; IntegerType=Int, n=4096) = construct_polygon_hierarchy(points, boundary_nodes; IntegerType) \ No newline at end of file +construct_polygon_hierarchy(points, boundary_nodes, ::Tuple{}; IntegerType = Int, n = 4096) = construct_polygon_hierarchy(points, boundary_nodes; IntegerType) diff --git a/src/data_structures/trees/rtree.jl b/src/data_structures/trees/rtree.jl index 64dcc0e12..1bc7e6785 100644 --- a/src/data_structures/trees/rtree.jl +++ b/src/data_structures/trees/rtree.jl @@ -145,7 +145,7 @@ A constant for representing an invalid rectangle, i.e. a rectangle with `NaN` en """ const InvalidBoundingBox = BoundingBox(InvalidBoundingInterval, InvalidBoundingInterval) BoundingBox(a, b, c, d) = BoundingBox(BoundingInterval(a, b), BoundingInterval(c, d)) -BoundingBox(p::NTuple{2,<:Number}) = BoundingBox(getx(p), getx(p), gety(p), gety(p)) +BoundingBox(p::NTuple{2, <:Number}) = BoundingBox(getx(p), getx(p), gety(p), gety(p)) """ hspan(r::BoundingBox) -> Float64 @@ -224,7 +224,7 @@ Base.in(r1::BoundingBox, r2::BoundingBox) = (r1.x ∈ r2.x) && (r1.y ∈ r2.y) Tests whether `p` is in `r`. """ -Base.in(p::NTuple{2,<:Number}, r::BoundingBox) = BoundingBox(p) ∈ r +Base.in(p::NTuple{2, <:Number}, r::BoundingBox) = BoundingBox(p) ∈ r """ is_touching(r1::BoundingBox, r2::BoundingBox) -> Bool @@ -263,7 +263,7 @@ end Returns the bounding box of the circle `(center, radius)`. """ -function bounding_box(center::NTuple{2,<:Number}, radius::Number) +function bounding_box(center::NTuple{2, <:Number}, radius::Number) cx, cy = getxy(center) return BoundingBox(cx - radius, cx + radius, cy - radius, cy + radius) end @@ -293,7 +293,7 @@ end Expands the bounding box `box` by a factor `perc` in each direction. """ -function expand(box::BoundingBox, perc=0.10) +function expand(box::BoundingBox, perc = 0.1) x = box.x y = box.y a, b = x.a, x.b @@ -328,7 +328,7 @@ Type for representing a bounding box generated from an edge's diametral circle. """ struct DiametralBoundingBox bounding_box::BoundingBox - edge::NTuple{2,Int} + edge::NTuple{2, Int} end """ @@ -493,7 +493,7 @@ Type for representing a leaf node in an R-tree. Leaf(parent::Union{Branch,Nothing}=nothing) = Leaf{Branch}(parent, InvalidBoundingBox, DiametralBoundingBox[]) """ mutable struct Leaf{Branch} <: AbstractNode - parent::Union{Branch,Nothing} + parent::Union{Branch, Nothing} bounding_box::BoundingBox children::Vector{DiametralBoundingBox} # would do const, but for compat reasons I don't Leaf(parent::Branch, bounding_box, children) where {Branch} = new{Branch}(parent, bounding_box, children) @@ -524,13 +524,13 @@ Type for representing a branch node in an R-tree. Branch(parent::Union{Branch,Nothing}=nothing, ::Type{C}=Branch) where {C<:AbstractNode} = new(parent, InvalidBoundingBox, C[], 1) """ mutable struct Branch <: AbstractNode - parent::Union{Branch,Nothing} + parent::Union{Branch, Nothing} bounding_box::BoundingBox - children::Union{Vector{Branch},Vector{Leaf{Branch}}} # if we do e.g. Branch{C}, it makes resolving some of the other types a bit difficult, especially Leaf{Branch}. (Also: would do const, but for compat reasons I don't) + children::Union{Vector{Branch}, Vector{Leaf{Branch}}} # if we do e.g. Branch{C}, it makes resolving some of the other types a bit difficult, especially Leaf{Branch}. (Also: would do const, but for compat reasons I don't) level::Int end -Branch(parent::Union{Branch,Nothing}=nothing, ::Type{C}=Branch) where {C<:AbstractNode} = Branch(parent, InvalidBoundingBox, C[], 1) -Leaf(parent::Union{Branch,Nothing}=nothing) = Leaf{Branch}(parent, InvalidBoundingBox, DiametralBoundingBox[]) +Branch(parent::Union{Branch, Nothing} = nothing, ::Type{C} = Branch) where {C <: AbstractNode} = Branch(parent, InvalidBoundingBox, C[], 1) +Leaf(parent::Union{Branch, Nothing} = nothing) = Leaf{Branch}(parent, InvalidBoundingBox, DiametralBoundingBox[]) function Base.:(==)(branch1::Branch, branch2::Branch) xor(isnothing(branch1), isnothing(branch1)) && return false # if we test get_parent(branch1) ≠ get_parent(branch2), then we get a StackOverflowError @@ -605,13 +605,13 @@ Type for representing a cache of nodes whose children are of type `Child`. This NodeCache{Node,Child}(size_limit::Int) where {Node,Child} = new{Node,Child}(Node[], size_limit) """ -struct NodeCache{Node,Child} # similar to why we use TriangulationCache. Think of it like implementing some CapacityVector that fails to push if it's full. +struct NodeCache{Node, Child} # similar to why we use TriangulationCache. Think of it like implementing some CapacityVector that fails to push if it's full. cache::Vector{Node} size_limit::Int - function NodeCache{Node,Child}(size_limit::Int) where {Node,Child} + function NodeCache{Node, Child}(size_limit::Int) where {Node, Child} cache = Node[] sizehint!(cache, size_limit) - return new{Node,Child}(cache, size_limit) + return new{Node, Child}(cache, size_limit) end end @@ -620,21 +620,21 @@ end Type for representing a cache of branch nodes. """ -const BranchCache = NodeCache{Branch,Branch} +const BranchCache = NodeCache{Branch, Branch} """ TwigCache Type for representing a cache of twig nodes, i.e. branch nodes at level 2. """ -const TwigCache = NodeCache{Branch,Leaf{Branch}} +const TwigCache = NodeCache{Branch, Leaf{Branch}} """ LeafCache Type for representing a cache of leaf nodes. """ -const LeafCache = NodeCache{Leaf{Branch},DiametralBoundingBox} +const LeafCache = NodeCache{Leaf{Branch}, DiametralBoundingBox} """ length(cache::NodeCache) -> Int @@ -752,16 +752,16 @@ Type for representing an R-tree with linear splitting. The `size_limit` is the node capacity. All node types have the same capacity. """ mutable struct RTree # linear - root::Union{Branch,Leaf{Branch}} + root::Union{Branch, Leaf{Branch}} num_elements::Int branch_cache::BranchCache # would do const, but for compat reasons I don't twig_cache::TwigCache # would do const, but for compat reasons I don't leaf_cache::LeafCache # would do const, but for compat reasons I don't fill_factor::Float64 # would do const, but for compat reasons I don't free_cache::BitVector # would do const, but for compat reasons I don't - detached_cache::Vector{Union{Branch,Leaf{Branch}}} # would do const, but for compat reasons I don't - intersection_cache::NTuple{2,RTreeIntersectionCache} # would do const, but for compat reasons I don't - function RTree(; size_limit=100, fill_factor=0.7) # https://en.wikipedia.org/wiki/R-tree: "however best performance has been experienced with a minimum fill of 30%–40%) + detached_cache::Vector{Union{Branch, Leaf{Branch}}} # would do const, but for compat reasons I don't + intersection_cache::NTuple{2, RTreeIntersectionCache} # would do const, but for compat reasons I don't + function RTree(; size_limit = 100, fill_factor = 0.7) # https://en.wikipedia.org/wiki/R-tree: "however best performance has been experienced with a minimum fill of 30%–40%) branch_cache = BranchCache(size_limit) twig_cache = TwigCache(size_limit) leaf_cache = LeafCache(size_limit) @@ -769,7 +769,7 @@ mutable struct RTree # linear num_elements = 0 free_cache = BitVector() sizehint!(free_cache, size_limit) - detached_cache = Vector{Union{Branch,Leaf{Branch}}}() + detached_cache = Vector{Union{Branch, Leaf{Branch}}}() sizehint!(detached_cache, size_limit) cache1, cache2 = RTreeIntersectionCache(), RTreeIntersectionCache() sizehint!(cache1, ceil(Int, log2(size_limit))) @@ -783,7 +783,7 @@ mutable struct RTree # linear fill_factor, free_cache, detached_cache, - (cache1, cache2) + (cache1, cache2), ) end end @@ -1127,7 +1127,7 @@ end Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that intersect with the diametral circle of the edge between `i` and `j`. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::BoundaryRTree, i, j; cache_id=1) +function get_intersections(tree::BoundaryRTree, i, j; cache_id = 1) bbox = bounding_box(tree, i, j) return get_intersections(tree.tree, get_bounding_box(bbox); cache_id) end @@ -1138,7 +1138,7 @@ end Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that intersect with the bounding box of the triangle `(i, j, k)`. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::BoundaryRTree, i, j, k; cache_id=1) +function get_intersections(tree::BoundaryRTree, i, j, k; cache_id = 1) points = tree.points p, q, r = get_point(points, i, j, k) bbox = bounding_box(p, q, r) @@ -1151,7 +1151,7 @@ end Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that intersect with the `i`th vertex. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::BoundaryRTree, i; cache_id=1) +function get_intersections(tree::BoundaryRTree, i; cache_id = 1) p = get_point(tree.points, i) return get_intersections(tree.tree, p; cache_id) end @@ -1162,6 +1162,6 @@ end Returns an [`RTreeIntersectionIterator`](@ref) over the elements in `tree` that intersect with `bbox`. `cache_id` must be `1` or `2`, and determines what cache to use for the intersection query. """ -function get_intersections(tree::BoundaryRTree, bbox::BoundingBox; cache_id=1) +function get_intersections(tree::BoundaryRTree, bbox::BoundingBox; cache_id = 1) return get_intersections(tree.tree, bbox; cache_id) -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/adjacent.jl b/src/data_structures/triangulation/adjacent.jl index 019278853..f66c4031d 100644 --- a/src/data_structures/triangulation/adjacent.jl +++ b/src/data_structures/triangulation/adjacent.jl @@ -12,14 +12,14 @@ The map taking edges `(u, v)` to `w` such that `(u, v, w)` is a positively orien Adjacent{IntegerType, EdgeType}() Adjacent(adjacent::Dict{EdgeType, IntegerType}) """ -struct Adjacent{I,E} - adjacent::Dict{E,I} +struct Adjacent{I, E} + adjacent::Dict{E, I} end -Adjacent{I,E}() where {I,E} = Adjacent{I,E}(Dict{E,I}()) +Adjacent{I, E}() where {I, E} = Adjacent{I, E}(Dict{E, I}()) Base.:(==)(adj::Adjacent, adj2::Adjacent) = get_adjacent(adj) == get_adjacent(adj2) -function Base.show(io::IO, m::MIME"text/plain", adj::Adjacent{I,E}) where {I,E} - println(io, "Adjacent{$I, $E}, with map:") - show(io, m, get_adjacent(adj)) +function Base.show(io::IO, m::MIME"text/plain", adj::Adjacent{I, E}) where {I, E} + println(io, "Adjacent{$I, $E}, with map:") + show(io, m, get_adjacent(adj)) end Base.sizehint!(adj::Adjacent, n) = sizehint!(get_adjacent(adj), n) @@ -89,13 +89,13 @@ julia> get_adjacent(adj, (1, 6)) 0 ``` """ -function get_adjacent(adj::Adjacent{I,E}, uv::E) where {I,E} - dict = get_adjacent(adj) - return get(dict, uv, I(∅)) +function get_adjacent(adj::Adjacent{I, E}, uv::E) where {I, E} + dict = get_adjacent(adj) + return get(dict, uv, I(∅)) end -function get_adjacent(adj::Adjacent{I,E}, u, v) where {I,E} - e = construct_edge(E, u, v) - return get_adjacent(adj, e) +function get_adjacent(adj::Adjacent{I, E}, u, v) where {I, E} + e = construct_edge(E, u, v) + return get_adjacent(adj, e) end @@ -131,13 +131,13 @@ Dict{Tuple{Int64, Int64}, Int64} with 3 entries: ``` """ function add_adjacent!(adj::Adjacent, uv, w) - dict = get_adjacent(adj) - dict[uv] = w - return adj + dict = get_adjacent(adj) + dict[uv] = w + return adj end -function add_adjacent!(adj::Adjacent{I,E}, u, v, w) where {I,E} - e = construct_edge(E, u, v) - return add_adjacent!(adj, e, w) +function add_adjacent!(adj::Adjacent{I, E}, u, v, w) where {I, E} + e = construct_edge(E, u, v) + return add_adjacent!(adj, e, w) end """ @@ -178,13 +178,13 @@ Dict{Tuple{Int64, Int64}, Int64} with 3 entries: ``` """ function delete_adjacent!(adj::Adjacent, uv) - dict = get_adjacent(adj) - delete!(dict, uv) - return adj + dict = get_adjacent(adj) + delete!(dict, uv) + return adj end -function delete_adjacent!(adj::Adjacent{I,E}, u, v) where {I,E} - e = construct_edge(E, u, v) - return delete_adjacent!(adj, e) +function delete_adjacent!(adj::Adjacent{I, E}, u, v) where {I, E} + e = construct_edge(E, u, v) + return delete_adjacent!(adj, e) end """ @@ -218,10 +218,10 @@ Dict{Tuple{Int32, Int32}, Int32} with 6 entries: ``` """ function add_triangle!(adj::Adjacent, u::Integer, v::Integer, w::Integer) # method ambiguity - add_adjacent!(adj, u, v, w) - add_adjacent!(adj, v, w, u) - add_adjacent!(adj, w, u, v) - return adj + add_adjacent!(adj, u, v, w) + add_adjacent!(adj, v, w, u) + add_adjacent!(adj, w, u, v) + return adj end add_triangle!(adj::Adjacent, T) = add_triangle!(adj, geti(T), getj(T), getk(T)) @@ -264,15 +264,15 @@ Dict{Tuple{Int32, Int32}, Int32}() ``` """ function delete_triangle!(adj::Adjacent, u::Integer, v::Integer, w::Integer) # method ambiguity - for (i, j) in triangle_edges(u, v, w) - delete_adjacent!(adj, i, j) - end - return adj + for (i, j) in triangle_edges(u, v, w) + delete_adjacent!(adj, i, j) + end + return adj end delete_triangle!(adj::Adjacent, T) = delete_triangle!(adj, geti(T), getj(T), getk(T)) function Base.empty!(adj::Adjacent) - dict = get_adjacent(adj) - empty!(dict) - return adj -end \ No newline at end of file + dict = get_adjacent(adj) + empty!(dict) + return adj +end diff --git a/src/data_structures/triangulation/adjacent2vertex.jl b/src/data_structures/triangulation/adjacent2vertex.jl index a518d1b01..c61facfcd 100644 --- a/src/data_structures/triangulation/adjacent2vertex.jl +++ b/src/data_structures/triangulation/adjacent2vertex.jl @@ -12,15 +12,15 @@ The map taking `w` to the set of all `(u, v)` such that `(u, v, w)` is a positiv Adjacent2Vertex{IntegerType, EdgesType}() Adjacent2Vertex(adj2v::Dict{IntegerType, EdgesType}) """ -struct Adjacent2Vertex{I,Es} - adjacent2vertex::Dict{I,Es} - Adjacent2Vertex(adj2v::Dict{I,Es}) where {I,Es} = new{I,Es}(adj2v) +struct Adjacent2Vertex{I, Es} + adjacent2vertex::Dict{I, Es} + Adjacent2Vertex(adj2v::Dict{I, Es}) where {I, Es} = new{I, Es}(adj2v) end -Adjacent2Vertex{I,Es}() where {I,Es} = Adjacent2Vertex(Dict{I,Es}()) +Adjacent2Vertex{I, Es}() where {I, Es} = Adjacent2Vertex(Dict{I, Es}()) Base.:(==)(adj2v::Adjacent2Vertex, adj2v2::Adjacent2Vertex) = get_adjacent2vertex(adj2v) == get_adjacent2vertex(adj2v2) -function Base.show(io::IO, m::MIME"text/plain", adj2v::Adjacent2Vertex{I,Es}) where {I,Es} - println(io, "Adjacent2Vertex{", I, ", ", Es, "} with map:") - show(io, m, get_adjacent2vertex(adj2v)) +function Base.show(io::IO, m::MIME"text/plain", adj2v::Adjacent2Vertex{I, Es}) where {I, Es} + println(io, "Adjacent2Vertex{", I, ", ", Es, "} with map:") + show(io, m, get_adjacent2vertex(adj2v)) end Base.sizehint!(adj2v::Adjacent2Vertex, n) = Base.sizehint!(get_adjacent2vertex(adj2v), n) @@ -86,8 +86,8 @@ Set{Tuple{Int64, Int64}} with 3 elements: ``` """ function get_adjacent2vertex(adj2v::Adjacent2Vertex, w) - dict = get_adjacent2vertex(adj2v) - return dict[w] + dict = get_adjacent2vertex(adj2v) + return dict[w] end """ @@ -122,16 +122,16 @@ Dict{Int64, Set{Tuple{Int64, Int64}}} with 2 entries: 1 => Set([(5, 7), (2, 3)]) ``` """ -function add_adjacent2vertex!(adj2v::Adjacent2Vertex{I,Es}, w, uv) where {I,Es} - dict = get_adjacent2vertex(adj2v) - existing_edges = get!(Es, dict, w) - add_edge!(existing_edges, uv) - return adj2v +function add_adjacent2vertex!(adj2v::Adjacent2Vertex{I, Es}, w, uv) where {I, Es} + dict = get_adjacent2vertex(adj2v) + existing_edges = get!(Es, dict, w) + add_edge!(existing_edges, uv) + return adj2v end -function add_adjacent2vertex!(adj2v::Adjacent2Vertex{I,Es}, w, u, v) where {I,Es} - E = edge_type(Es) - uv = construct_edge(E, u, v) - return add_adjacent2vertex!(adj2v, w, uv) +function add_adjacent2vertex!(adj2v::Adjacent2Vertex{I, Es}, w, u, v) where {I, Es} + E = edge_type(Es) + uv = construct_edge(E, u, v) + return add_adjacent2vertex!(adj2v, w, uv) end """ @@ -165,14 +165,14 @@ Dict{Int64, Set{Tuple{Int64, Int64}}} with 2 entries: ``` """ function delete_adjacent2vertex!(adj2v::Adjacent2Vertex, w, uv) - existing_edges = get_adjacent2vertex(adj2v, w) - delete_edge!(existing_edges, uv) - return adj2v + existing_edges = get_adjacent2vertex(adj2v, w) + delete_edge!(existing_edges, uv) + return adj2v end -function delete_adjacent2vertex!(adj2v::Adjacent2Vertex{I,Es}, w, u, v) where {I,Es} - E = edge_type(Es) - uv = construct_edge(E, u, v) - return delete_adjacent2vertex!(adj2v, w, uv) +function delete_adjacent2vertex!(adj2v::Adjacent2Vertex{I, Es}, w, u, v) where {I, Es} + E = edge_type(Es) + uv = construct_edge(E, u, v) + return delete_adjacent2vertex!(adj2v, w, uv) end """ @@ -201,9 +201,9 @@ Dict{Int64, Set{Tuple{Int64, Int64}}}() ``` """ function delete_adjacent2vertex!(adj2v::Adjacent2Vertex, w) - dict = get_adjacent2vertex(adj2v) - delete!(dict, w) - return adj2v + dict = get_adjacent2vertex(adj2v) + delete!(dict, w) + return adj2v end """ @@ -238,10 +238,10 @@ Dict{Int32, Set{Tuple{Int32, Int32}}} with 5 entries: ``` """ function add_triangle!(adj2v::Adjacent2Vertex, u::Integer, v::Integer, w::Integer) - add_adjacent2vertex!(adj2v, u, v, w) - add_adjacent2vertex!(adj2v, v, w, u) - add_adjacent2vertex!(adj2v, w, u, v) - return adj2v + add_adjacent2vertex!(adj2v, u, v, w) + add_adjacent2vertex!(adj2v, v, w, u) + add_adjacent2vertex!(adj2v, w, u, v) + return adj2v end add_triangle!(adj2v::Adjacent2Vertex, T) = add_triangle!(adj2v, geti(T), getj(T), getk(T)) @@ -295,10 +295,10 @@ Dict{Int32, Set{Tuple{Int32, Int32}}} with 5 entries: ``` """ function delete_triangle!(adj2v::Adjacent2Vertex, u::Integer, v::Integer, w::Integer) - delete_adjacent2vertex!(adj2v, u, v, w) - delete_adjacent2vertex!(adj2v, v, w, u) - delete_adjacent2vertex!(adj2v, w, u, v) - return adj2v + delete_adjacent2vertex!(adj2v, u, v, w) + delete_adjacent2vertex!(adj2v, v, w, u) + delete_adjacent2vertex!(adj2v, w, u, v) + return adj2v end delete_triangle!(adj2v::Adjacent2Vertex, T) = delete_triangle!(adj2v, geti(T), getj(T), getk(T)) @@ -335,15 +335,15 @@ Dict{Int64, Set{Tuple{Int64, Int64}}}() ``` """ function clear_empty_keys!(adj2v::Adjacent2Vertex) - dict = get_adjacent2vertex(adj2v) - for (w, S) in dict - isempty(S) && delete_adjacent2vertex!(adj2v, w) - end - return adj2v + dict = get_adjacent2vertex(adj2v) + for (w, S) in dict + isempty(S) && delete_adjacent2vertex!(adj2v, w) + end + return adj2v end function Base.empty!(adj2v::Adjacent2Vertex) - dict = get_adjacent2vertex(adj2v) - empty!(dict) - return adj2v -end \ No newline at end of file + dict = get_adjacent2vertex(adj2v) + empty!(dict) + return adj2v +end diff --git a/src/data_structures/triangulation/graph.jl b/src/data_structures/triangulation/graph.jl index 08e2a9cf5..509268b7f 100644 --- a/src/data_structures/triangulation/graph.jl +++ b/src/data_structures/triangulation/graph.jl @@ -20,10 +20,10 @@ The map taking vertices `u` to the set of all `v` such that `(u, v)` is an edge """ struct Graph{I} vertices::Set{I} - edges::Set{NTuple{2,I}} - neighbours::Dict{I,Set{I}} + edges::Set{NTuple{2, I}} + neighbours::Dict{I, Set{I}} end -Graph{I}() where {I} = Graph(Set{I}(), Set{NTuple{2,I}}(), Dict{I,Set{I}}()) +Graph{I}() where {I} = Graph(Set{I}(), Set{NTuple{2, I}}(), Dict{I, Set{I}}()) function Base.show(io::IO, ::MIME"text/plain", graph::Graph) println(io, "Graph") println(io, " Number of edges: ", num_edges(graph)) diff --git a/src/data_structures/triangulation/methods/adjacent.jl b/src/data_structures/triangulation/methods/adjacent.jl index 4d2c5e51a..f606a509e 100644 --- a/src/data_structures/triangulation/methods/adjacent.jl +++ b/src/data_structures/triangulation/methods/adjacent.jl @@ -60,4 +60,4 @@ add_adjacent!(tri::Triangulation, u, v, w) = add_adjacent!(get_adjacent(tri), u, Deletes the key `(u, v)` from the adjacency map of `tri`. """ delete_adjacent!(tri::Triangulation, uv) = delete_adjacent!(get_adjacent(tri), uv) -delete_adjacent!(tri::Triangulation, u, v) = delete_adjacent!(get_adjacent(tri), u, v) \ No newline at end of file +delete_adjacent!(tri::Triangulation, u, v) = delete_adjacent!(get_adjacent(tri), u, v) diff --git a/src/data_structures/triangulation/methods/adjacent2vertex.jl b/src/data_structures/triangulation/methods/adjacent2vertex.jl index aa9c950c2..22f399f94 100644 --- a/src/data_structures/triangulation/methods/adjacent2vertex.jl +++ b/src/data_structures/triangulation/methods/adjacent2vertex.jl @@ -28,4 +28,4 @@ delete_adjacent2vertex!(tri::Triangulation, w, u, v) = delete_adjacent2vertex!(g Deletes the key `w` from the [`Adjacent2Vertex`](@ref) map of `tri`. """ -delete_adjacent2vertex!(tri::Triangulation, w) = delete_adjacent2vertex!(get_adjacent2vertex(tri), w) \ No newline at end of file +delete_adjacent2vertex!(tri::Triangulation, w) = delete_adjacent2vertex!(get_adjacent2vertex(tri), w) diff --git a/src/data_structures/triangulation/methods/boundary_curves.jl b/src/data_structures/triangulation/methods/boundary_curves.jl index 60e90b21d..859fc79f4 100644 --- a/src/data_structures/triangulation/methods/boundary_curves.jl +++ b/src/data_structures/triangulation/methods/boundary_curves.jl @@ -51,7 +51,7 @@ end return (PiecewiseLinear(points, boundary_nodes),) end end -@inline function _to_boundary_curves_multiple_sections(points, boundary_nodes, section=1, boundary_curves=()) +@inline function _to_boundary_curves_multiple_sections(points, boundary_nodes, section = 1, boundary_curves = ()) if section > num_sections(boundary_nodes) return boundary_curves else @@ -60,7 +60,7 @@ end return _to_boundary_curves_multiple_sections(points, boundary_nodes, section + 1, (boundary_curves..., new_boundary_curves...)) end end -@inline function _to_boundary_curves_multiple_curves(points, boundary_nodes, curve=1, boundary_curves=()) +@inline function _to_boundary_curves_multiple_curves(points, boundary_nodes, curve = 1, boundary_curves = ()) if curve > num_curves(boundary_nodes) return boundary_curves else @@ -90,7 +90,7 @@ triangulation. In particular: - `boundary_curves`: The boundary curves associated with `boundary_nodes`. - `boundary_nodes`: The modified boundary nodes. """ -@inline function convert_boundary_curves!(points, boundary_nodes, ::Type{I}) where {I<:Integer} +@inline function convert_boundary_curves!(points, boundary_nodes, ::Type{I}) where {I <: Integer} boundary_curves = to_boundary_curves(points, boundary_nodes) !is_curve_bounded(boundary_curves) && return boundary_curves, boundary_nodes new_boundary_nodes = get_skeleton(boundary_nodes, I) @@ -106,7 +106,7 @@ end @inline function _convert_boundary_curves_multiple_curves!(points, boundary_nodes, boundary_curves, new_boundary_nodes) ctr = 1 for curve_index in 1:num_curves(boundary_nodes) - curve_nodes =get_boundary_nodes(boundary_nodes, curve_index) + curve_nodes = get_boundary_nodes(boundary_nodes, curve_index) new_curve_nodes = get_boundary_nodes(new_boundary_nodes, curve_index) for section_index in 1:num_sections(curve_nodes) section_nodes = get_boundary_nodes(curve_nodes, section_index) @@ -128,7 +128,7 @@ end @inline function _convert_boundary_curves_contiguous!(points, boundary_nodes, boundary_curves, curve_index, new_boundary_nodes) if is_piecewise_linear(boundary_curves, curve_index) n = num_boundary_edges(boundary_nodes) - for i in 1:(n+1) + for i in 1:(n + 1) v = get_boundary_nodes(boundary_nodes, i) insert_boundary_node!(new_boundary_nodes, (new_boundary_nodes, i), v) end @@ -147,4 +147,3 @@ end end return nothing end - diff --git a/src/data_structures/triangulation/methods/boundary_edge_map.jl b/src/data_structures/triangulation/methods/boundary_edge_map.jl index fbbc4b7e6..c3ae92fd0 100644 --- a/src/data_structures/triangulation/methods/boundary_edge_map.jl +++ b/src/data_structures/triangulation/methods/boundary_edge_map.jl @@ -23,7 +23,7 @@ each_boundary_edge(tri::Triangulation) = keys(get_boundary_edge_map(tri)) After splitting an edge starting at `pos` on the boundary, updates the `boundary_edge_map` to reflect the new boundary edges. See [`split_boundary_edge!`](@ref). """ -function split_boundary_edge_map!(boundary_edge_map::Dict{E,T}, boundary_nodes, pos, i, j) where {E,T} +function split_boundary_edge_map!(boundary_edge_map::Dict{E, T}, boundary_nodes, pos, i, j) where {E, T} e = construct_edge(E, i, j) delete!(boundary_edge_map, e) nodes = get_boundary_nodes(boundary_nodes, pos[1]) @@ -35,4 +35,4 @@ function split_boundary_edge_map!(boundary_edge_map::Dict{E,T}, boundary_nodes, boundary_edge_map[e] = (pos[1], k) end return boundary_edge_map -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/boundary_nodes.jl b/src/data_structures/triangulation/methods/boundary_nodes.jl index d4ceaf51e..fc9301a79 100644 --- a/src/data_structures/triangulation/methods/boundary_nodes.jl +++ b/src/data_structures/triangulation/methods/boundary_nodes.jl @@ -25,9 +25,9 @@ There are several forms for the methods: """ @inline get_boundary_nodes(tri::Triangulation, mnℓ...) = get_boundary_nodes(get_boundary_nodes(tri), mnℓ...) @inline get_boundary_nodes(tri::Triangulation, m::Integer) = get_boundary_nodes(get_boundary_nodes(tri), m) # method ambiguity -@inline get_boundary_nodes(tri::Triangulation, (m, n)::NTuple{2,Integer}) = get_boundary_nodes(get_boundary_nodes(tri), (m, n)) # method ambiguity +@inline get_boundary_nodes(tri::Triangulation, (m, n)::NTuple{2, Integer}) = get_boundary_nodes(get_boundary_nodes(tri), (m, n)) # method ambiguity @inline get_boundary_nodes(tri::Triangulation, m::Integer, n::Integer) = get_boundary_nodes(get_boundary_nodes(tri), m, n) # method ambiguity -@inline get_boundary_nodes(tri::A, ::A) where {A<:Triangulation} = get_boundary_nodes(tri) # ambiguity. method doesn't really make sense +@inline get_boundary_nodes(tri::A, ::A) where {A <: Triangulation} = get_boundary_nodes(tri) # ambiguity. method doesn't really make sense """ get_right_boundary_node(tri::Triangulation, k, ghost_vertex) -> Vertex @@ -191,7 +191,7 @@ function split_boundary_edge_at_collinear_segments!(tri::Triangulation, collinea # u -- r₁ -- r₂ -- r₃ -- r₄ -------- v -> split(r₃, v, r₄) # u -- r₁ -- r₂ -- r₃ -- r₄ -- r₅ -- v -> split(r₄, v, r₅) v = terminal(last(collinear_segments)) - for k in (firstindex(collinear_segments)):(lastindex(collinear_segments)-1) + for k in (firstindex(collinear_segments)):(lastindex(collinear_segments) - 1) segment = collinear_segments[k] rₖ₋₁, rₖ = edge_vertices(segment) split_boundary_edge!(tri, rₖ₋₁, v, rₖ) @@ -216,7 +216,7 @@ function get_all_boundary_nodes(tri::Triangulation) for section_index in boundary_sections bn_nodes = get_boundary_nodes(tri, section_index) nedges = num_boundary_edges(bn_nodes) - for node_idx in 1:(nedges+1) + for node_idx in 1:(nedges + 1) vᵢ = get_boundary_nodes(bn_nodes, node_idx) push!(all_nodes, vᵢ) end @@ -257,4 +257,4 @@ function contains_boundary_edge(tri::Triangulation, i, j) E = edge_type(tri) e = construct_edge(E, i, j) return contains_boundary_edge(tri, e) -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/checks.jl b/src/data_structures/triangulation/methods/checks.jl index e6be9c0de..f36116455 100644 --- a/src/data_structures/triangulation/methods/checks.jl +++ b/src/data_structures/triangulation/methods/checks.jl @@ -6,9 +6,9 @@ Tests if the edge `(i, j)` is in `tri`, returning `true` if so and `false` other See also [`unoriented_edge_exists`](@ref). """ -edge_exists(i::I) where {I<:Integer} = i ≠ I(∅) -edge_exists(tri::Triangulation, ij) = edge_exists(get_adjacent(tri,ij)) -edge_exists(tri::Triangulation, i, j) = edge_exists(get_adjacent(tri,i,j)) +edge_exists(i::I) where {I <: Integer} = i ≠ I(∅) +edge_exists(tri::Triangulation, ij) = edge_exists(get_adjacent(tri, ij)) +edge_exists(tri::Triangulation, i, j) = edge_exists(get_adjacent(tri, i, j)) """ unoriented_edge_exists(tri::Triangulation, ij) -> Bool @@ -59,9 +59,9 @@ has_multiple_sections(tri::Triangulation) = has_multiple_sections(get_boundary_n Returns `true` if `tri` has boundary nodes, and `false` otherwise. """ -function has_boundary_nodes(boundary_nodes) +function has_boundary_nodes(boundary_nodes) return has_multiple_sections(boundary_nodes) || num_boundary_edges(boundary_nodes) ≠ 0 || eltype(boundary_nodes) <: AbstractParametricCurve -end +end has_boundary_nodes(tri::Triangulation) = has_boundary_nodes(get_boundary_nodes(tri)) has_boundary_nodes(::Nothing) = false @@ -70,4 +70,4 @@ has_boundary_nodes(::Nothing) = false Returns `true` if `tri` is weighted, and `false` otherwise. """ -is_weighted(tri::Triangulation) = is_weighted(get_weights(tri)) \ No newline at end of file +is_weighted(tri::Triangulation) = is_weighted(get_weights(tri)) diff --git a/src/data_structures/triangulation/methods/convex_hull.jl b/src/data_structures/triangulation/methods/convex_hull.jl index c8f19a1a5..92459b88c 100644 --- a/src/data_structures/triangulation/methods/convex_hull.jl +++ b/src/data_structures/triangulation/methods/convex_hull.jl @@ -19,7 +19,7 @@ Updates the `convex_hull` field of `tri` to match the current triangulation. - `reconstruct=has_boundary_nodes(tri)`: If `true`, then the convex hull is reconstructed from scratch, using [`convex_hull`](@ref) on the points. Otherwise, computes the convex hull using the ghost triangles of `tri`. If there are no ghost triangles but `reconstruct=true`, then the convex hull is reconstructed from scratch. """ -function convex_hull!(tri::Triangulation; reconstruct=has_boundary_nodes(tri)) +function convex_hull!(tri::Triangulation; reconstruct = has_boundary_nodes(tri)) I = integer_type(tri) if reconstruct convex_hull!(get_convex_hull(tri)) @@ -42,8 +42,8 @@ function convex_hull!(tri::Triangulation; reconstruct=has_boundary_nodes(tri)) return tri else add_ghost_triangles!(tri) - convex_hull!(tri; reconstruct=false) + convex_hull!(tri; reconstruct = false) delete_ghost_triangles!(tri) end return tri -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/exterior_curve_indices.jl b/src/data_structures/triangulation/methods/exterior_curve_indices.jl index 618bc34dc..5d7de0b3c 100644 --- a/src/data_structures/triangulation/methods/exterior_curve_indices.jl +++ b/src/data_structures/triangulation/methods/exterior_curve_indices.jl @@ -24,4 +24,4 @@ num_exterior_curves(tri::Triangulation) = (length ∘ get_exterior_curve_indices Returns `true` if `tri` has disjoint exterior boundary curves, and `false` otherwise. """ -is_disjoint(tri::Triangulation) = num_exterior_curves(tri) > 1 \ No newline at end of file +is_disjoint(tri::Triangulation) = num_exterior_curves(tri) > 1 diff --git a/src/data_structures/triangulation/methods/ghost_vertex_map.jl b/src/data_structures/triangulation/methods/ghost_vertex_map.jl index a96a1fade..6e2c47944 100644 --- a/src/data_structures/triangulation/methods/ghost_vertex_map.jl +++ b/src/data_structures/triangulation/methods/ghost_vertex_map.jl @@ -46,4 +46,4 @@ get_section_index(tri::Triangulation, ℓ) = get_section_index(ghost_vertex_map( Given a ghost vertex `ℓ` in `tri`, returns the corresponding section in the `boundary_nodes` of `tri`. See also [`get_ghost_vertex_map`](@ref). """ -map_ghost_vertex(tri::Triangulation, ℓ) = get_ghost_vertex_map(tri)[ℓ] \ No newline at end of file +map_ghost_vertex(tri::Triangulation, ℓ) = get_ghost_vertex_map(tri)[ℓ] diff --git a/src/data_structures/triangulation/methods/ghost_vertex_ranges.jl b/src/data_structures/triangulation/methods/ghost_vertex_ranges.jl index c31e19c53..4f1b1324f 100644 --- a/src/data_structures/triangulation/methods/ghost_vertex_ranges.jl +++ b/src/data_structures/triangulation/methods/ghost_vertex_ranges.jl @@ -11,4 +11,4 @@ get_ghost_vertex_range(tri::Triangulation, ℓ) = get_ghost_vertex_ranges(tri)[ Returns the set of all ghost vertices in `tri`. """ -all_ghost_vertices(tri::Triangulation) = keys(get_ghost_vertex_ranges(tri)) \ No newline at end of file +all_ghost_vertices(tri::Triangulation) = keys(get_ghost_vertex_ranges(tri)) diff --git a/src/data_structures/triangulation/methods/graph.jl b/src/data_structures/triangulation/methods/graph.jl index a8f89c39d..aa9f439a0 100644 --- a/src/data_structures/triangulation/methods/graph.jl +++ b/src/data_structures/triangulation/methods/graph.jl @@ -68,7 +68,7 @@ add_neighbour!(tri::Triangulation, u, v...) = add_neighbour!(get_graph(tri), u, delete_neighbour!(tri::Triangulation, u, v...) Deletes the neighbours `v...` from `u` in the graph of `tri`. -""" +""" delete_neighbour!(tri::Triangulation, u, v...) = delete_neighbour!(get_graph(tri), u, v...) """ diff --git a/src/data_structures/triangulation/methods/iterators.jl b/src/data_structures/triangulation/methods/iterators.jl index 95b948c33..92b93ebe8 100644 --- a/src/data_structures/triangulation/methods/iterators.jl +++ b/src/data_structures/triangulation/methods/iterators.jl @@ -52,7 +52,7 @@ An iterator over all solid vertices in a triangulation. - `vertices::V`: The iterator over all vertices in the triangulation. - `tri::T`: The triangulation. """ -struct EachSolidVertex{V,T} <: AbstractEachVertex{V} +struct EachSolidVertex{V, T} <: AbstractEachVertex{V} vertices::V tri::T end @@ -66,7 +66,7 @@ An iterator over all ghost vertices in a triangulation. - `vertices::V`: The iterator over all vertices in the triangulation. - `tri::T`: The triangulation. """ -struct EachGhostVertex{V,T} <: AbstractEachVertex{V} +struct EachGhostVertex{V, T} <: AbstractEachVertex{V} vertices::V tri::T end @@ -157,7 +157,7 @@ An iterator over all solid triangles in a triangulation. - `triangles::V`: The iterator over all triangles in the triangulation. - `tri::T`: The triangulation. """ -struct EachSolidTriangle{V,T} <: AbstractEachTriangle{V} +struct EachSolidTriangle{V, T} <: AbstractEachTriangle{V} triangles::V tri::T end @@ -171,7 +171,7 @@ An iterator over all ghost triangles in a triangulation. - `triangles::V`: The iterator over all triangles in the triangulation. - `tri::T`: The triangulation. """ -struct EachGhostTriangle{V,T} <: AbstractEachTriangle{V} +struct EachGhostTriangle{V, T} <: AbstractEachTriangle{V} triangles::V tri::T end @@ -273,7 +273,7 @@ An iterator over all solid edges in a triangulation. - `edges::E`: The iterator over all edges in the triangulation. - `tri::T`: The triangulation. """ -struct EachSolidEdge{E,T} <: AbstractEachEdge{E} +struct EachSolidEdge{E, T} <: AbstractEachEdge{E} edges::E tri::T end @@ -287,7 +287,7 @@ An iterator over all ghost edges in a triangulation. - `edges::E`: The iterator over all edges in the triangulation. - `tri::T`: The triangulation. """ -struct EachGhostEdge{E,T} <: AbstractEachEdge{E} +struct EachGhostEdge{E, T} <: AbstractEachEdge{E} edges::E tri::T end @@ -361,4 +361,4 @@ function Random.rand(rng::AbstractRNG, v::Random.SamplerTrivial{<:EachGhostEdge} e = rand(rng, edges) end return e -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/points.jl b/src/data_structures/triangulation/methods/points.jl index af916ec82..d21616c9e 100644 --- a/src/data_structures/triangulation/methods/points.jl +++ b/src/data_structures/triangulation/methods/points.jl @@ -17,7 +17,7 @@ function get_point(tri::Triangulation, i) return c end end -get_point(tri::Triangulation, i::Vararg{Any,N}) where {N} = ntuple(j -> get_point(tri, i[j]), Val(N)) +get_point(tri::Triangulation, i::Vararg{Any, N}) where {N} = ntuple(j -> get_point(tri, i[j]), Val(N)) """ num_points(tri::Triangulation) -> Integer @@ -56,4 +56,4 @@ pop_point!(tri::Triangulation) = pop_point!(get_points(tri)) Sets the `i`th point of `tri` to `p = (x, y)`. """ set_point!(tri::Triangulation, i, x, y) = set_point!(get_points(tri), i, x, y) -set_point!(tri::Triangulation, i, p) = set_point!(get_points(tri), i, p) \ No newline at end of file +set_point!(tri::Triangulation, i, p) = set_point!(get_points(tri), i, p) diff --git a/src/data_structures/triangulation/methods/representative_point_list.jl b/src/data_structures/triangulation/methods/representative_point_list.jl index f570214e7..3ef65f0a3 100644 --- a/src/data_structures/triangulation/methods/representative_point_list.jl +++ b/src/data_structures/triangulation/methods/representative_point_list.jl @@ -26,12 +26,12 @@ end update_centroid_after_addition!(tri::Triangulation, curve_index, p) Updates the centroid of the `curve_index`th curve in `tri` after the addition of the point `p`. -""" +""" function update_centroid_after_addition!(tri::Triangulation, curve_index, p) I = integer_type(tri) F = number_type(tri) representative_point_list = get_representative_point_list(tri) - centroid = get!(RepresentativeCoordinates{I,F}, representative_point_list, curve_index) + centroid = get!(RepresentativeCoordinates{I, F}, representative_point_list, curve_index) add_point!(centroid, p) return representative_point_list end @@ -45,7 +45,7 @@ function update_centroid_after_deletion!(tri::Triangulation, curve_index, p) I = integer_type(tri) F = number_type(tri) representative_point_list = get_representative_point_list(tri) - centroid = get!(RepresentativeCoordinates{I,F}, representative_point_list, curve_index) + centroid = get!(RepresentativeCoordinates{I, F}, representative_point_list, curve_index) delete_point!(centroid, p) return representative_point_list end @@ -98,7 +98,7 @@ There are no outputs as `tri` is updated in-place, but for each curve the repres might have representative points that are in a hole of one of their interior holes. This isn't much of a problem, indeed it wouldn't be a significant problem even if we had the representative point in a hole of the first curve, but it is something to be aware of. """ -function compute_representative_points!(tri::Triangulation; use_convex_hull=!has_boundary_nodes(tri), precision=one(number_type(tri))) +function compute_representative_points!(tri::Triangulation; use_convex_hull = !has_boundary_nodes(tri), precision = one(number_type(tri))) reset_representative_points!(tri) if use_convex_hull return _compute_representative_points!(tri, get_convex_hull_vertices(tri); precision) @@ -106,7 +106,7 @@ function compute_representative_points!(tri::Triangulation; use_convex_hull=!has return _compute_representative_points!(tri, get_boundary_nodes(tri); precision) end end -function _compute_representative_points!(tri::Triangulation, boundary_nodes; precision=one(number_type(tri))) # need this to be separate for type stability. +function _compute_representative_points!(tri::Triangulation, boundary_nodes; precision = one(number_type(tri))) # need this to be separate for type stability. points = get_points(tri) representative_point_list = get_representative_point_list(tri) I = integer_type(tri) @@ -124,4 +124,4 @@ function _compute_representative_points!(tri::Triangulation, boundary_nodes; pre representative_point_list[1] = RepresentativeCoordinates(x, y, zero(I)) end return representative_point_list -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/segments.jl b/src/data_structures/triangulation/methods/segments.jl index 4865624ee..0fec60681 100644 --- a/src/data_structures/triangulation/methods/segments.jl +++ b/src/data_structures/triangulation/methods/segments.jl @@ -20,4 +20,4 @@ function contains_segment(tri::Triangulation, i, j) E = edge_type(tri) e = construct_edge(E, i, j) return contains_segment(tri, e) -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/methods/triangles.jl b/src/data_structures/triangulation/methods/triangles.jl index f9a2a0aaa..696ac0f3a 100644 --- a/src/data_structures/triangulation/methods/triangles.jl +++ b/src/data_structures/triangulation/methods/triangles.jl @@ -50,4 +50,4 @@ end Returns the number of solid triangles in `tri`. """ -num_solid_triangles(tri::Triangulation) = num_triangles(tri) - num_ghost_triangles(tri) \ No newline at end of file +num_solid_triangles(tri::Triangulation) = num_triangles(tri) - num_ghost_triangles(tri) diff --git a/src/data_structures/triangulation/methods/weights.jl b/src/data_structures/triangulation/methods/weights.jl index 66a864003..1096f16be 100644 --- a/src/data_structures/triangulation/methods/weights.jl +++ b/src/data_structures/triangulation/methods/weights.jl @@ -127,7 +127,7 @@ Using a greedy search, finds the closest vertex in `tri` to the vertex `i` (whic measuring distance in lifted space (i.e., using the power distance - see [`get_power_distance`](@ref)). The search starts from the vertex `j` which should be in `tri`. """ -function get_weighted_nearest_neighbour(tri::Triangulation, i, j=rand(each_solid_vertex(tri))) +function get_weighted_nearest_neighbour(tri::Triangulation, i, j = rand(each_solid_vertex(tri))) if has_vertex(tri, i) return i else @@ -170,8 +170,8 @@ function is_submerged(tri::Triangulation, i) V = find_triangle(tri, q) return is_submerged(tri, i, V) end -function is_submerged(tri::Triangulation, i, V) +function is_submerged(tri::Triangulation, i, V) is_ghost_vertex(i) && return false cert = point_position_relative_to_circumcircle(tri, V, i) return is_outside(cert) -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/triangulation.jl b/src/data_structures/triangulation/triangulation.jl index 0bc11d54a..22544745c 100644 --- a/src/data_structures/triangulation/triangulation.jl +++ b/src/data_structures/triangulation/triangulation.jl @@ -76,7 +76,7 @@ The [`BoundaryEnricher`](@ref) used for triangulating a curve-bounded domain. If A [`TriangulationCache`](@ref) used as a cache for [`add_segment!`](@ref) which requires a separate `Triangulation` structure for use. This will not contain any segments or boundary nodes. Also stores segments useful for [`lock_convex_hull!`](@ref) and [`unlock_convex_hull!`](@ref). """ -struct Triangulation{P,T,BN,W,I,E,Es,BC,BEM,GVM,GVR,BPL,C,BE} +struct Triangulation{P, T, BN, W, I, E, Es, BC, BEM, GVM, GVR, BPL, C, BE} # Geometry points::P triangles::T @@ -85,8 +85,8 @@ struct Triangulation{P,T,BN,W,I,E,Es,BC,BEM,GVM,GVR,BPL,C,BE} all_segments::Es weights::W # Topology - adjacent::Adjacent{I,E} - adjacent2vertex::Adjacent2Vertex{I,Es} + adjacent::Adjacent{I, E} + adjacent2vertex::Adjacent2Vertex{I, Es} graph::Graph{I} # Boundary handling boundary_curves::BC @@ -94,7 +94,7 @@ struct Triangulation{P,T,BN,W,I,E,Es,BC,BEM,GVM,GVR,BPL,C,BE} ghost_vertex_map::GVM ghost_vertex_ranges::GVR # Other - convex_hull::ConvexHull{P,I} + convex_hull::ConvexHull{P, I} representative_point_list::BPL polygon_hierarchy::PolygonHierarchy{I} boundary_enricher::BE @@ -325,28 +325,28 @@ number_type(::Triangulation{P}) where {P} = number_type(P) Returns the type used for representing vertices in `tri`. """ -integer_type(::Triangulation{P,T,BN,W,I}) where {P,T,BN,W,I} = I +integer_type(::Triangulation{P, T, BN, W, I}) where {P, T, BN, W, I} = I """ edges_type(tri::Triangulation) -> DataType Returns the type used for representing collections of edges in `tri`. """ -edges_type(::Triangulation{P,T,BN,W,I,E,Es}) where {P,T,BN,W,I,E,Es} = Es +edges_type(::Triangulation{P, T, BN, W, I, E, Es}) where {P, T, BN, W, I, E, Es} = Es """ edge_type(tri::Triangulation) -> DataType Returns the type used for representing individual edges in `tri`. """ -edge_type(::Triangulation{P,T,BN,W,I,E}) where {P,T,BN,W,I,E} = E +edge_type(::Triangulation{P, T, BN, W, I, E}) where {P, T, BN, W, I, E} = E """ triangle_type(tri::Triangulation) -> DataType Returns the type used for representing collections of triangles in `tri`. """ -triangles_type(::Triangulation{P,T}) where {P,T} = T +triangles_type(::Triangulation{P, T}) where {P, T} = T """ triangle_type(tri::Triangulation) -> DataType @@ -355,11 +355,13 @@ Returns the type used for representing individual triangles in `tri`. """ triangle_type(tri::Triangulation) = triangle_type(triangles_type(tri)) -@inline function __Triangulation(points::P, boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}, - TriangleType::Type{V}, EdgesType::Type{Es}, TrianglesType::Type{Ts}) where {P,I,E,V,Es,Ts} +@inline function __Triangulation( + points::P, boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}, + TriangleType::Type{V}, EdgesType::Type{Es}, TrianglesType::Type{Ts}, + ) where {P, I, E, V, Es, Ts} T = TrianglesType() - adj = Adjacent{IntegerType,EdgeType}() - adj2v = Adjacent2Vertex{IntegerType,EdgesType}() + adj = Adjacent{IntegerType, EdgeType}() + adj2v = Adjacent2Vertex{IntegerType, EdgesType}() graph = Graph{IntegerType}() all_segments = EdgesType() boundary_edge_map = construct_boundary_edge_map(boundary_nodes, IntegerType, EdgeType) @@ -376,24 +378,27 @@ triangle_type(tri::Triangulation) = triangle_type(triangles_type(tri)) return T, adj, adj2v, graph, all_segments, boundary_edge_map, ghost_vertex_map, ghost_vertex_ranges, ch, polygon_hierarchy end -@inline function _build_cache(points::P, IntegerType::Type{I}, EdgeType::Type{E}, - TriangleType::Type{V}, EdgesType::Type{Es}, TrianglesType::Type{T}, weights::W, build_cache::Val{B}) where {P,I,E,V,Es,T,W,B} +@inline function _build_cache( + points::P, IntegerType::Type{I}, EdgeType::Type{E}, + TriangleType::Type{V}, EdgesType::Type{Es}, TrianglesType::Type{T}, weights::W, build_cache::Val{B}, + ) where {P, I, E, V, Es, T, W, B} if B BN = Vector{IntegerType} BC = Tuple{} - BEM = Dict{EdgeType,Tuple{Vector{IntegerType},IntegerType}} - GVM = Dict{IntegerType,Vector{IntegerType}} - GVR = Dict{IntegerType,UnitRange{IntegerType}} - BPL = Dict{IntegerType,RepresentativeCoordinates{IntegerType,number_type(points)}} - C = TriangulationCache{Nothing,Nothing,Nothing,Nothing,Nothing} + BEM = Dict{EdgeType, Tuple{Vector{IntegerType}, IntegerType}} + GVM = Dict{IntegerType, Vector{IntegerType}} + GVR = Dict{IntegerType, UnitRange{IntegerType}} + BPL = Dict{IntegerType, RepresentativeCoordinates{IntegerType, number_type(points)}} + C = TriangulationCache{Nothing, Nothing, Nothing, Nothing, Nothing} cache = TriangulationCache( - Triangulation(points; weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, build_cache=Val(false)), - Triangulation(points; weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, build_cache=Val(false)), - I[], Es(), I[], T())::TriangulationCache{ - Triangulation{P,T,BN,W,I,E,Es,BC,BEM,GVM,GVR,BPL,C,Nothing},Vector{I},Es,Vector{I},T + Triangulation(points; weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, build_cache = Val(false)), + Triangulation(points; weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, build_cache = Val(false)), + I[], Es(), I[], T(), + )::TriangulationCache{ + Triangulation{P, T, BN, W, I, E, Es, BC, BEM, GVM, GVR, BPL, C, Nothing}, Vector{I}, Es, Vector{I}, T, } else - cache = TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing)::TriangulationCache{Nothing,Nothing,Nothing,Nothing,Nothing} + cache = TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing)::TriangulationCache{Nothing, Nothing, Nothing, Nothing, Nothing} end return cache end @@ -404,32 +409,40 @@ end Initialises an empty `Triangulation` for triangulating `points`. The keyword arguments `kwargs...` match those of [`triangulate`](@ref). """ -@inline function Triangulation(points::P; - IntegerType::Type{I}=Int, - EdgeType::Type{E}=NTuple{2,IntegerType}, - TriangleType::Type{T}=NTuple{3,IntegerType}, - EdgesType::Type{Es}=Set{EdgeType}, - TrianglesType::Type{Vs}=Set{TriangleType}, - boundary_nodes=IntegerType[], - segments=EdgesType(), - weights=ZeroWeight(), - representative_point_list=Dict{IntegerType,RepresentativeCoordinates{IntegerType,number_type(points)}}(), - boundary_curves=(), - build_cache=true, - boundary_enricher=nothing) where {P,I,E,T,Es,Vs} - return _Triangulation(points, +@inline function Triangulation( + points::P; + IntegerType::Type{I} = Int, + EdgeType::Type{E} = NTuple{2, IntegerType}, + TriangleType::Type{T} = NTuple{3, IntegerType}, + EdgesType::Type{Es} = Set{EdgeType}, + TrianglesType::Type{Vs} = Set{TriangleType}, + boundary_nodes = IntegerType[], + segments = EdgesType(), + weights = ZeroWeight(), + representative_point_list = Dict{IntegerType, RepresentativeCoordinates{IntegerType, number_type(points)}}(), + boundary_curves = (), + build_cache = true, + boundary_enricher = nothing, + ) where {P, I, E, T, Es, Vs} + return _Triangulation( + points, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType, boundary_nodes, segments, weights, representative_point_list, - boundary_curves, _to_val(build_cache), boundary_enricher) + boundary_curves, _to_val(build_cache), boundary_enricher, + ) end -@inline function _Triangulation(points, ::Type{I}, ::Type{E}, ::Type{V}, ::Type{Es}, ::Type{Ts}, - boundary_nodes, segments, weights, representative_point_list, - boundary_curves, build_cache::Val{B}, boundary_enricher) where {I,E,V,Es,Ts,B} +@inline function _Triangulation( + points, ::Type{I}, ::Type{E}, ::Type{V}, ::Type{Es}, ::Type{Ts}, + boundary_nodes, segments, weights, representative_point_list, + boundary_curves, build_cache::Val{B}, boundary_enricher, + ) where {I, E, V, Es, Ts, B} T, adj, adj2v, graph, all_segments, boundary_edge_map, ghost_vertex_map, ghost_vertex_ranges, ch, polygon_hierarchy = __Triangulation(points, boundary_nodes, I, E, V, Es, Ts) cache = _build_cache(points, I, E, V, Es, Ts, weights, build_cache) - tri = Triangulation(points, T, boundary_nodes, segments, all_segments, weights, + tri = Triangulation( + points, T, boundary_nodes, segments, all_segments, weights, adj, adj2v, graph, boundary_curves, boundary_edge_map, - ghost_vertex_map, ghost_vertex_ranges, ch, representative_point_list, polygon_hierarchy, boundary_enricher, cache) + ghost_vertex_map, ghost_vertex_ranges, ch, representative_point_list, polygon_hierarchy, boundary_enricher, cache, + ) return tri end @@ -455,16 +468,18 @@ Returns the `Triangulation` corresponding to the triangulation of `points` with # Output - `tri`: The [`Triangulation`](@ref). """ -@inline function Triangulation(points::P, triangles::T, boundary_nodes::BN; - IntegerType::Type{I}=Int, - EdgeType::Type{E}=NTuple{2,IntegerType}, - TriangleType::Type{V}=NTuple{3,IntegerType}, - EdgesType::Type{Es}=Set{EdgeType}, - TrianglesType::Type{Ts}=Set{TriangleType}, - weights=ZeroWeight(), - delete_ghosts=false) where {P,T,BN,I,E,V,Es,Ts} +@inline function Triangulation( + points::P, triangles::T, boundary_nodes::BN; + IntegerType::Type{I} = Int, + EdgeType::Type{E} = NTuple{2, IntegerType}, + TriangleType::Type{V} = NTuple{3, IntegerType}, + EdgesType::Type{Es} = Set{EdgeType}, + TrianglesType::Type{Ts} = Set{TriangleType}, + weights = ZeroWeight(), + delete_ghosts = false, + ) where {P, T, BN, I, E, V, Es, Ts} _bn = copy(boundary_nodes) - tri = Triangulation(points; boundary_nodes=_bn, weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType) + tri = Triangulation(points; boundary_nodes = _bn, weights, IntegerType, EdgeType, TriangleType, EdgesType, TrianglesType) return build_triangulation_from_data!(tri, triangles, _bn, delete_ghosts) end @@ -491,7 +506,7 @@ Given an empty `triangulation`, `tri`, adds all the `triangles` and `boundary_no end add_boundary_information!(tri) add_ghost_triangles!(tri) - convex_hull!(tri; reconstruct=true) + convex_hull!(tri; reconstruct = true) segments = get_all_segments(tri) ghost_vertex_map = get_ghost_vertex_map(tri) all_segments = merge_segments(ghost_vertex_map, boundary_nodes, Es()) @@ -500,4 +515,4 @@ Given an empty `triangulation`, `tri`, adds all the `triangles` and `boundary_no end postprocess_triangulate!(tri; delete_ghosts) return tri -end \ No newline at end of file +end diff --git a/src/data_structures/triangulation/triangulation_cache.jl b/src/data_structures/triangulation/triangulation_cache.jl index ad8ed2dac..3917d2a07 100644 --- a/src/data_structures/triangulation/triangulation_cache.jl +++ b/src/data_structures/triangulation/triangulation_cache.jl @@ -24,7 +24,7 @@ A cache to be used as a field in [`Triangulation`](@ref). The `points` of the cache's `triangulation` will be aliased to the `points` of the parent triangulation. """ -struct TriangulationCache{T,M,I,S,F} +struct TriangulationCache{T, M, I, S, F} triangulation::T triangulation_2::T marked_vertices::M @@ -122,4 +122,4 @@ function empty_unconstrained_triangulation!(tri::Triangulation) empty!(convex_hull) empty!(representative_points) return tri -end \ No newline at end of file +end diff --git a/src/data_structures/voronoi.jl b/src/data_structures/voronoi.jl index c9bd4415d..dcad078d8 100644 --- a/src/data_structures/voronoi.jl +++ b/src/data_structures/voronoi.jl @@ -24,16 +24,16 @@ See also [`voronoi`](@ref). - `boundary_polygons::Set{I}`: A `Set` of indices of the polygons that are on the boundary of the tessellation. Only relevant for clipped tessellations, otherwise see `unbounded_polygons`. """ -struct VoronoiTessellation{Tr<:Triangulation,P,I,T,S,E} +struct VoronoiTessellation{Tr <: Triangulation, P, I, T, S, E} triangulation::Tr - generators::Dict{I,P} + generators::Dict{I, P} polygon_points::Vector{P} # not guaranteed to be unique if a circumcenter appears on the boundary, but the vertices (below) do handle this automatically - polygons::Dict{I,Vector{I}} - circumcenter_to_triangle::Dict{I,T} - triangle_to_circumcenter::Dict{T,I} + polygons::Dict{I, Vector{I}} + circumcenter_to_triangle::Dict{I, T} + triangle_to_circumcenter::Dict{T, I} unbounded_polygons::Set{I} cocircular_circumcenters::S - adjacent::Adjacent{I,E} + adjacent::Adjacent{I, E} boundary_polygons::Set{I} end @@ -127,28 +127,28 @@ end Type used for representing individual edges in the Voronoi tessellation. """ -edge_type(::VoronoiTessellation{Tr,P,I,T,S,E}) where {Tr,P,I,T,S,E} = E +edge_type(::VoronoiTessellation{Tr, P, I, T, S, E}) where {Tr, P, I, T, S, E} = E """ number_type(vorn::VoronoiTessellation) -> DataType Type used for representing individual coordinates in the Voronoi tessellation. """ -number_type(::VoronoiTessellation{Tr,P}) where {Tr,P} = number_type(P) +number_type(::VoronoiTessellation{Tr, P}) where {Tr, P} = number_type(P) """ integer_type(vorn::VoronoiTessellation) -> DataType Type used for representing indices in the Voronoi tessellation. """ -integer_type(::VoronoiTessellation{Tr,P,I}) where {Tr,P,I} = I +integer_type(::VoronoiTessellation{Tr, P, I}) where {Tr, P, I} = I """ triangle_type(vorn::VoronoiTessellation) -> DataType Type used for representing individual triangles in the Voronoi tessellation. """ -triangle_type(::VoronoiTessellation{Tr,P,I,T}) where {Tr,P,I,T} = T +triangle_type(::VoronoiTessellation{Tr, P, I, T}) where {Tr, P, I, T} = T """ get_generator(vor::VoronoiTessellation, i) -> NTuple{2, Number} @@ -410,7 +410,7 @@ Gets the bounding box for the Voronoi tessellation `vorn`. - `ymin`: Given by `ymin′ - unbounded_extension_factor * (ymin′ - ymin′)`, where `ymin′` is the original minimum `y`-coordinate of the computed bounding box and similarly for `ymax′`. - `ymax`: Given by `ymax′ + unbounded_extension_factor * (ymax′ - ymax′)`, where `ymax′` is the original maximum `y`-coordinate of the computed bounding box and similarly for `ymin′`. """ -function polygon_bounds(vorn::VoronoiTessellation, unbounded_extension_factor=0.0; include_polygon_vertices=true) +function polygon_bounds(vorn::VoronoiTessellation, unbounded_extension_factor = 0.0; include_polygon_vertices = true) F = number_type(vorn) xmin = typemax(F) xmax = typemin(F) diff --git a/src/exports.jl b/src/exports.jl index eb6ada822..b854a82fa 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -100,4 +100,4 @@ export get_boundary_curves, map_ghost_vertex, polygon_bounds, - num_neighbours \ No newline at end of file + num_neighbours diff --git a/src/geometric_primitives.jl b/src/geometric_primitives.jl index 706734cb9..7b1b2c26c 100644 --- a/src/geometric_primitives.jl +++ b/src/geometric_primitives.jl @@ -1,4 +1,4 @@ include("geometric_primitives/boundary_nodes.jl") include("geometric_primitives/edges.jl") include("geometric_primitives/points.jl") -include("geometric_primitives/triangles.jl") \ No newline at end of file +include("geometric_primitives/triangles.jl") diff --git a/src/geometric_primitives/boundary_nodes.jl b/src/geometric_primitives/boundary_nodes.jl index 6772f7535..16389a6ad 100644 --- a/src/geometric_primitives/boundary_nodes.jl +++ b/src/geometric_primitives/boundary_nodes.jl @@ -19,9 +19,9 @@ true ``` """ has_multiple_curves -has_multiple_curves(::AAA) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}} = true -has_multiple_curves(::AA) where {F<:Number,A<:AV{F},AA<:AV{A}} = false -has_multiple_curves(::A) where {F<:Number,A<:AV{F}} = false +has_multiple_curves(::AAA) where {F <: Number, A <: AV{F}, AA <: AV{A}, AAA <: AV{AA}} = true +has_multiple_curves(::AA) where {F <: Number, A <: AV{F}, AA <: AV{A}} = false +has_multiple_curves(::A) where {F <: Number, A <: AV{F}} = false function has_multiple_curves(boundary_nodes::AV) #= Need this since, e.g. @@ -62,9 +62,9 @@ true ``` """ has_multiple_sections -has_multiple_sections(::AAA) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}} = true -has_multiple_sections(::AA) where {F<:Number,A<:AV{F},AA<:AV{A}} = true -has_multiple_sections(::A) where {F<:Number,A<:AV{F}} = false +has_multiple_sections(::AAA) where {F <: Number, A <: AV{F}, AA <: AV{A}, AAA <: AV{AA}} = true +has_multiple_sections(::AA) where {F <: Number, A <: AV{F}, AA <: AV{A}} = true +has_multiple_sections(::A) where {F <: Number, A <: AV{F}} = false function has_multiple_sections(boundary_nodes::AV) #= Need this since, e.g. @@ -193,10 +193,10 @@ julia> get_boundary_nodes([1, 2, 3, 4, 5, 1], [1, 2, 3, 4, 5, 1]) get_boundary_nodes @inline get_boundary_nodes(boundary_nodes, m::Integer) = boundary_nodes[m] @inline get_boundary_nodes(boundary_nodes, m::Integer, n::Integer) = get_boundary_nodes(get_boundary_nodes(boundary_nodes, m), n) -@inline get_boundary_nodes(boundary_nodes, (m, n)::NTuple{2,Integer}) = get_boundary_nodes(boundary_nodes, m, n) # for indexing from a boundary map +@inline get_boundary_nodes(boundary_nodes, (m, n)::NTuple{2, Integer}) = get_boundary_nodes(boundary_nodes, m, n) # for indexing from a boundary map @inline get_boundary_nodes(boundary_nodes::A, ::A) where {A} = boundary_nodes # for indexing from a boundary map -@inline get_boundary_nodes(boundary_nodes::A, ::A) where {A<:Tuple{Integer,Integer}} = boundary_nodes # ambiguity -@inline get_boundary_nodes(boundary_nodes::A, ::A) where {A<:Integer} = boundary_nodes # ambiguity +@inline get_boundary_nodes(boundary_nodes::A, ::A) where {A <: Tuple{Integer, Integer}} = boundary_nodes # ambiguity +@inline get_boundary_nodes(boundary_nodes::A, ::A) where {A <: Integer} = boundary_nodes # ambiguity """ each_boundary_node(boundary_nodes) -> Iterator @@ -286,7 +286,7 @@ end This works for any form of `boundary_nodes`. """ -@inline function construct_ghost_vertex_map(boundary_nodes, IntegerType::Type{I}=number_type(boundary_nodes)) where {I} +@inline function construct_ghost_vertex_map(boundary_nodes, IntegerType::Type{I} = number_type(boundary_nodes)) where {I} if has_multiple_curves(boundary_nodes) return _construct_ghost_vertex_map_multiple_curves(boundary_nodes, IntegerType) elseif has_multiple_sections(boundary_nodes) @@ -296,7 +296,7 @@ This works for any form of `boundary_nodes`. end end function _construct_ghost_vertex_map_multiple_curves(boundary_nodes, IntegerType::Type{I}) where {I} - dict = Dict{I,NTuple{2,I}}() + dict = Dict{I, NTuple{2, I}}() nc = num_curves(boundary_nodes) current_idx = I(𝒢) for m in 1:nc @@ -310,7 +310,7 @@ function _construct_ghost_vertex_map_multiple_curves(boundary_nodes, IntegerType return dict end function _construct_ghost_vertex_map_multiple_sections(boundary_nodes, IntegerType::Type{I}) where {I} - dict = Dict{I,I}() + dict = Dict{I, I}() ns = num_sections(boundary_nodes) current_idx = I(𝒢) for n in 1:ns @@ -372,9 +372,11 @@ Dict{Tuple{Int64, Int64}, Tuple{Tuple{Int64, Int64}, Int64}} with 12 entries: (85, 91) => ((2, 2), 3) ``` """ -@inline function construct_boundary_edge_map(boundary_nodes::A, - IntegerType::Type{I}=number_type(boundary_nodes), - EdgeType::Type{E}=NTuple{2,IntegerType}) where {A,I,E} +@inline function construct_boundary_edge_map( + boundary_nodes::A, + IntegerType::Type{I} = number_type(boundary_nodes), + EdgeType::Type{E} = NTuple{2, IntegerType}, + ) where {A, I, E} if has_multiple_curves(boundary_nodes) return _construct_boundary_edge_map_multiple_curves(boundary_nodes, IntegerType, EdgeType) elseif has_multiple_sections(boundary_nodes) @@ -383,8 +385,8 @@ Dict{Tuple{Int64, Int64}, Tuple{Tuple{Int64, Int64}, Int64}} with 12 entries: return _construct_boundary_edge_map_contiguous(boundary_nodes, IntegerType, EdgeType) end end -function _construct_boundary_edge_map_multiple_curves(boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}) where {I,E} - dict = Dict{E,Tuple{NTuple{2,I},I}}() +function _construct_boundary_edge_map_multiple_curves(boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}) where {I, E} + dict = Dict{E, Tuple{NTuple{2, I}, I}}() nc = num_curves(boundary_nodes) for m in 1:nc bn_m = get_boundary_nodes(boundary_nodes, m) @@ -402,8 +404,8 @@ function _construct_boundary_edge_map_multiple_curves(boundary_nodes, IntegerTyp end return dict end -function _construct_boundary_edge_map_multiple_sections(boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}) where {I,E} - dict = Dict{E,NTuple{2,I}}() +function _construct_boundary_edge_map_multiple_sections(boundary_nodes, IntegerType::Type{I}, EdgeType::Type{E}) where {I, E} + dict = Dict{E, NTuple{2, I}}() ns = num_sections(boundary_nodes) for n in 1:ns bn_n = get_boundary_nodes(boundary_nodes, n) @@ -417,8 +419,8 @@ function _construct_boundary_edge_map_multiple_sections(boundary_nodes, IntegerT end return dict end -function _construct_boundary_edge_map_contiguous(boundary_nodes::A, IntegerType::Type{I}, EdgeType::Type{E}) where {A,I,E} - dict = Dict{E,Tuple{A,I}}() +function _construct_boundary_edge_map_contiguous(boundary_nodes::A, IntegerType::Type{I}, EdgeType::Type{E}) where {A, I, E} + dict = Dict{E, Tuple{A, I}}() ne = num_boundary_edges(boundary_nodes) for ℓ in 1:ne u = get_boundary_nodes(boundary_nodes, ℓ) @@ -656,7 +658,7 @@ Dict{Int64, UnitRange{Int64}} with 7 entries: -6 => -7:-4 ``` """ -@inline function construct_ghost_vertex_ranges(boundary_nodes, IntegerType::Type{I}=number_type(boundary_nodes)) where {I} +@inline function construct_ghost_vertex_ranges(boundary_nodes, IntegerType::Type{I} = number_type(boundary_nodes)) where {I} if has_multiple_curves(boundary_nodes) return _construct_ghost_vertex_ranges_multiple_curves(boundary_nodes, IntegerType) elseif has_multiple_sections(boundary_nodes) @@ -668,7 +670,7 @@ end function _construct_ghost_vertex_ranges_multiple_curves(boundary_nodes, IntegerType::Type{I}) where {I} start = I(𝒢) current_ghost_vertex = I(𝒢) - dict = Dict{I,UnitRange{I}}() + dict = Dict{I, UnitRange{I}}() nc = num_curves(boundary_nodes) for i in 1:nc bn = get_boundary_nodes(boundary_nodes, i) @@ -684,9 +686,9 @@ function _construct_ghost_vertex_ranges_multiple_curves(boundary_nodes, IntegerT end function _construct_ghost_vertex_ranges_multiple_sections(boundary_nodes, IntegerType::Type{I}) where {I} current_ghost_vertex = I(𝒢) - dict = Dict{I,UnitRange{I}}() + dict = Dict{I, UnitRange{I}}() ns = num_sections(boundary_nodes) - range = (current_ghost_vertex-ns+1):current_ghost_vertex + range = (current_ghost_vertex - ns + 1):current_ghost_vertex for _ in 1:ns dict[current_ghost_vertex] = range current_ghost_vertex -= 1 @@ -695,7 +697,7 @@ function _construct_ghost_vertex_ranges_multiple_sections(boundary_nodes, Intege end function _construct_ghost_vertex_ranges_contiguous(IntegerType::Type{I}) where {I} current_ghost_vertex = I(𝒢) - dict = Dict{I,UnitRange{I}}() + dict = Dict{I, UnitRange{I}}() dict[current_ghost_vertex] = current_ghost_vertex:current_ghost_vertex return dict end @@ -734,4 +736,4 @@ end end @inline function _get_skeleton_contiguous(boundary_nodes, ::Type{I}) where {I} return I[] -end \ No newline at end of file +end diff --git a/src/geometric_primitives/edges.jl b/src/geometric_primitives/edges.jl index 3f1c0363b..3adbdec50 100644 --- a/src/geometric_primitives/edges.jl +++ b/src/geometric_primitives/edges.jl @@ -17,9 +17,9 @@ julia> DelaunayTriangulation.construct_edge(Vector{Int32}, 5, 15) ``` """ construct_edge -construct_edge(::Type{NTuple{2,I}}, i, j) where {I} = (I(i), I(j)) +construct_edge(::Type{NTuple{2, I}}, i, j) where {I} = (I(i), I(j)) construct_edge(::Type{Vector{I}}, i, j) where {I} = I[i, j] -construct_edge(::Type{A}, i, j) where {I,A<:AbstractVector{I}} = A(I[i, j]) +construct_edge(::Type{A}, i, j) where {I, A <: AbstractVector{I}} = A(I[i, j]) """ initial(e) -> Vertex @@ -140,9 +140,9 @@ true ``` """ function compare_unoriented_edges(u, v) - i, j = edge_vertices(u) - k, ℓ = edge_vertices(v) - return (i, j) == (k, ℓ) || (i, j) == (ℓ, k) + i, j = edge_vertices(u) + k, ℓ = edge_vertices(v) + return (i, j) == (k, ℓ) || (i, j) == (ℓ, k) end """ @@ -299,9 +299,9 @@ Set{Tuple{Int64, Int64}} with 7 elements: ``` """ function add_edge!(E, e...) - for v in e - add_to_edges!(E, v) - end + for v in e + add_to_edges!(E, v) + end end """ @@ -364,9 +364,9 @@ Set{Vector{Int64}} with 2 elements: ``` """ function delete_edge!(E, e...) - for v in e - delete_from_edges!(E, v) - end + for v in e + delete_from_edges!(E, v) + end end """ @@ -443,11 +443,11 @@ random_edge(rng, E) = rand(rng, E) Tests if the edge collections `E` and `F` are equal, ignoring edge orientation. """ function compare_unoriented_edge_collections(E, F) - num_edges(E) ≠ num_edges(F) && return false - for e in each_edge(E) - contains_unoriented_edge(e, F) || return false - end - return true + num_edges(E) ≠ num_edges(F) && return false + for e in each_edge(E) + contains_unoriented_edge(e, F) || return false + end + return true end """ @@ -458,4 +458,4 @@ Returns `true` if `e` and `e′` have any shared vertex, and `false` otherwise. function edges_are_disjoint(e, e′) w = get_shared_vertex(e, e′) return w == ∅ -end \ No newline at end of file +end diff --git a/src/geometric_primitives/points.jl b/src/geometric_primitives/points.jl index d9fd72237..4238b2853 100644 --- a/src/geometric_primitives/points.jl +++ b/src/geometric_primitives/points.jl @@ -202,8 +202,8 @@ NTuple{4, Tuple{Float64, Float64}} ``` """ get_point -get_point(points, i) = getpoint(points, i) -get_point(points, i::Vararg{Any,N}) where {N} = ntuple(j -> get_point(points, i[j]), Val(N)) +get_point(points, i) = getpoint(points, i) +get_point(points, i::Vararg{Any, N}) where {N} = ntuple(j -> get_point(points, i[j]), Val(N)) @doc """ each_point_index(points) -> Iterator @@ -308,9 +308,9 @@ false function points_are_unique(points) n = num_points(points) T = number_type(points) - seen = Set{NTuple{2,T}}() + seen = Set{NTuple{2, T}}() sizehint!(seen, n) - for i in each_point_index(points) + for i in each_point_index(points) p = get_point(points, i) p ∈ seen && return false push!(seen, p) @@ -388,9 +388,9 @@ julia> DelaunayTriangulation.push_point!(points, (17.3, 5.0)) ``` """ push_point! -push_point!(points::AbstractVector{T}, x, y) where {F,T<:NTuple{2,F}} = push!(points, (F(x), F(y))) -push_point!(points::AbstractVector{T}, x, y) where {F<:Number,T<:AbstractVector{F}} = push!(points, F[x, y]) -push_point!(points::AbstractMatrix{T}, x, y) where {T<:Number} = append!(points, (x, y)) # ElasticArrays +push_point!(points::AbstractVector{T}, x, y) where {F, T <: NTuple{2, F}} = push!(points, (F(x), F(y))) +push_point!(points::AbstractVector{T}, x, y) where {F <: Number, T <: AbstractVector{F}} = push!(points, F[x, y]) +push_point!(points::AbstractMatrix{T}, x, y) where {T <: Number} = append!(points, (x, y)) # ElasticArrays push_point!(points, p) = push_point!(points, getx(p), gety(p)) @doc """ @@ -456,7 +456,7 @@ julia> (1.0 + 17.3)/2, (2.0 + 5.3)/2 (9.15, 3.65) ``` """ -function mean_points(points, vertices=each_point_index(points)) +function mean_points(points, vertices = each_point_index(points)) F = number_type(points) x = zero(F) y = zero(F) @@ -540,7 +540,7 @@ Returns a `Dict` of `points` that maps each duplicate point to a `Vector` of the function find_duplicate_points(points) T = number_type(points) n = num_points(points) - dup_seen = Dict{NTuple{2,T},Vector{Int}}() + dup_seen = Dict{NTuple{2, T}, Vector{Int}}() sizehint!(dup_seen, n) for i in each_point_index(points) p = get_point(points, i) @@ -551,4 +551,4 @@ function find_duplicate_points(points) length(ivec) > 1 end return dup_seen -end \ No newline at end of file +end diff --git a/src/geometric_primitives/triangles.jl b/src/geometric_primitives/triangles.jl index 8d43d5e32..1fe90d558 100644 --- a/src/geometric_primitives/triangles.jl +++ b/src/geometric_primitives/triangles.jl @@ -18,9 +18,9 @@ julia> DelaunayTriangulation.construct_triangle(Vector{Int32}, 1, 2, 3) ``` """ construct_triangle -construct_triangle(::Type{NTuple{3,I}}, i, j, k) where {I} = (I(i), I(j), I(k)) +construct_triangle(::Type{NTuple{3, I}}, i, j, k) where {I} = (I(i), I(j), I(k)) construct_triangle(::Type{Vector{I}}, i, j, k) where {I} = I[i, j, k] -construct_triangle(::Type{A}, i, j, k) where {I,A<:AbstractVector{I}} = A(I[i, j, k]) +construct_triangle(::Type{A}, i, j, k) where {I, A <: AbstractVector{I}} = A(I[i, j, k]) """ geti(T) -> Vertex @@ -190,7 +190,7 @@ julia> DelaunayTriangulation.rotate_triangle(T, 3) (1, 2, 3) ``` """ -function rotate_triangle(T::V, ::Val{N}) where {N,V} +function rotate_triangle(T::V, ::Val{N}) where {N, V} i, j, k = triangle_vertices(T) N < 0 && throw(ArgumentError("Cannot rotate triangle $T by a negative amount.")) if N == 0 @@ -302,8 +302,8 @@ function compare_triangles(T, V) i, j, k = triangle_vertices(T) u, v, w = triangle_vertices(V) return (i, j, k) == (u, v, w) || - (i, j, k) == (v, w, u) || - (i, j, k) == (w, u, v) + (i, j, k) == (v, w, u) || + (i, j, k) == (w, u, v) end @doc """ @@ -338,7 +338,7 @@ julia> DelaunayTriangulation.contains_triangle(9, 7, 8, V) ``` """ contains_triangle -function contains_triangle(T::F, V::S) where {F,S} +function contains_triangle(T::F, V::S) where {F, S} if F ≠ triangle_type(S) i, j, k = triangle_vertices(T) Tfix = construct_triangle(triangle_type(S), i, j, k) @@ -433,7 +433,7 @@ Set{Tuple{Int64, Int64, Int64}} with 4 elements: (-1, 3, 6) ``` """ -function add_to_triangles!(T::Ts, V::VT) where {Ts,VT} +function add_to_triangles!(T::Ts, V::VT) where {Ts, VT} if VT ≠ triangle_type(Ts) i, j, k = triangle_vertices(V) U = construct_triangle(triangle_type(Ts), i, j, k) @@ -672,4 +672,4 @@ function sort_triangles(T::Ts) where {Ts} add_to_triangles!(V, σ) end return V -end \ No newline at end of file +end diff --git a/src/predicates.jl b/src/predicates.jl index fbf78dae5..714aab075 100644 --- a/src/predicates.jl +++ b/src/predicates.jl @@ -1,4 +1,4 @@ include("predicates/certificate.jl") include("predicates/exactpredicates_definitions.jl") include("predicates/predicates.jl") -include("predicates/boundaries_and_ghosts.jl") \ No newline at end of file +include("predicates/boundaries_and_ghosts.jl") diff --git a/src/predicates/boundaries_and_ghosts.jl b/src/predicates/boundaries_and_ghosts.jl index c42eb81a8..182736533 100644 --- a/src/predicates/boundaries_and_ghosts.jl +++ b/src/predicates/boundaries_and_ghosts.jl @@ -3,7 +3,7 @@ Tests if `i` is a ghost vertex, meaning `i ≤ $𝒢`. """ -is_ghost_vertex(i::I) where {I<:Integer} = i ≤ I(𝒢) +is_ghost_vertex(i::I) where {I <: Integer} = i ≤ I(𝒢) is_ghost_vertex(i) = false # in case we provide a point instead of an integer """ @@ -121,4 +121,4 @@ function is_boundary_node(tri::Triangulation, i) end I = integer_type(tri) return (false, I(∅)) -end \ No newline at end of file +end diff --git a/src/predicates/certificate.jl b/src/predicates/certificate.jl index 349b675dd..448cd808f 100644 --- a/src/predicates/certificate.jl +++ b/src/predicates/certificate.jl @@ -71,7 +71,7 @@ for inst in instances(Certificate.T) Returns `true` if `cert` is `$($name)`, and `false` otherwise. """ ($(Symbol("is_$(lowercase(name))")))(cert::Certificate.T) = cert == $inst - end + end end """ is_positively_oriented(cert::Certificate) -> Bool @@ -128,4 +128,4 @@ Given `cert ∈ (-1, 0, 1)`, return `Cert1`, `Cert2` or `Cert3` depending on if end end -const Cert = Certificate \ No newline at end of file +const Cert = Certificate diff --git a/src/predicates/exactpredicates_definitions.jl b/src/predicates/exactpredicates_definitions.jl index 981e6d9c1..849b1b357 100644 --- a/src/predicates/exactpredicates_definitions.jl +++ b/src/predicates/exactpredicates_definitions.jl @@ -70,7 +70,7 @@ opposite_signs(x, y) = xor(x, y) == -2 sgn(x) -> Int Returns `Int(sign(x))`. -""" +""" sgn(x) = Int(sign(x)) """ @@ -289,9 +289,9 @@ function meet_predicate(p, q, a, b) return -1 elseif pqa == 0 && pqb == 0 if sameside_predicate(a, b, p) == 1 && - sameside_predicate(a, b, q) == 1 && - sameside_predicate(p, q, a) == 1 && - sameside_predicate(p, q, b) == 1 + sameside_predicate(a, b, q) == 1 && + sameside_predicate(p, q, a) == 1 && + sameside_predicate(p, q, b) == 1 return -1 else return 0 @@ -330,4 +330,4 @@ meaning `∠prq`, is acute, returning: - `0`: `∠prq` is a right angle. - `-1`: `∠prq` is obtuse. """ -angle_is_acute \ No newline at end of file +angle_is_acute diff --git a/src/predicates/predicates.jl b/src/predicates/predicates.jl index 31fc38a23..81afbda03 100644 --- a/src/predicates/predicates.jl +++ b/src/predicates/predicates.jl @@ -12,8 +12,7 @@ Computes the orientation of the triangle `T = (i, j, k)` with correspondig coord triangle_orientation function triangle_orientation(p, q, r) cert = orient_predicate(p, q, r) - return convert_certificate(cert, Cert.NegativelyOriented, Cert.Degenerate, - Cert.PositivelyOriented) + return convert_certificate(cert, Cert.NegativelyOriented, Cert.Degenerate, Cert.PositivelyOriented) end function triangle_orientation(tri::Triangulation, i, j, k) if is_exterior_ghost_triangle(tri, i, j, k) @@ -286,17 +285,18 @@ function is_legal(p, q, r, s) end function is_legal(tri::Triangulation, i, j) - (contains_segment(tri, i, j) || - is_boundary_edge(tri, j, i) || - is_boundary_edge(tri, i, j) || - !edge_exists(tri, i, j) || - !edge_exists(tri, j, i) || - is_ghost_edge(i, j)) && return Cert.Legal - k = get_adjacent(tri, i, j) - ℓ = get_adjacent(tri, j, i) - p, q, r, s = get_point(tri, i, j, k, ℓ) - cert = is_legal(p, q, r, s) - return cert + if contains_segment(tri, i, j) || + is_boundary_edge(tri, j, i) || is_boundary_edge(tri, i, j) || + !edge_exists(tri, i, j) || !edge_exists(tri, j, i) || + is_ghost_edge(i, j) + return Cert.Legal + else + k = get_adjacent(tri, i, j) + ℓ = get_adjacent(tri, j, i) + p, q, r, s = get_point(tri, i, j, k, ℓ) + cert = is_legal(p, q, r, s) + return cert + end end @doc """ @@ -512,8 +512,8 @@ function point_position_relative_to_circumcircle(tri::Triangulation, i, j, k, else cert = point_position_relative_to_witness_plane(tri, i, j, k, ℓ) return is_above(cert) ? Cert.Outside : - is_below(cert) ? Cert.Inside : - Cert.On + is_below(cert) ? Cert.Inside : + Cert.On end end point_position_relative_to_circumcircle(tri::Triangulation, T, ℓ) = point_position_relative_to_circumcircle(tri, geti(T), getj(T), getk(T), ℓ) @@ -621,7 +621,7 @@ To test if a point `r` is inside the diametral lens with lens angle `θ°`, we s at that point, i.e. the angle at `r` in the triangle `pqr`. If this angle is greater than `180° - 2θ°`, then `r` is inside of the lens. This result comes from [Shewchuk (2002)](https://doi.org/10.1016/S0925-7721(01)00047-5). Note that this is the same as a diametral circle in the case `θ° = 45°`. """ -function point_position_relative_to_diametral_lens(p, q, r, lens_angle=30.0) +function point_position_relative_to_diametral_lens(p, q, r, lens_angle = 30.0) px, py = _getxy(p) qx, qy = _getxy(q) rx, ry = _getxy(r) @@ -656,7 +656,7 @@ the two does not intersect any segments. - `cert`: A [`Certificate`](@ref). This will be `Visible` if `i` is visible from `q`, and `Invisible` otherwise. """ function test_visibility(tri::Triangulation, q, i) - V, invisible_flag = find_triangle(tri, q; use_barriers=Val(true), k=i, concavity_protection=true) + V, invisible_flag = find_triangle(tri, q; use_barriers = Val(true), k = i, concavity_protection = true) if invisible_flag return Certificate.Invisible else @@ -682,7 +682,7 @@ of `(u, v)` can see `i`. To test this, we only check `10` points equally spaced # Outputs - `cert`: A [`Certificate`](@ref). This will be `Visible` if `i` is visible from `(u, v)`, and `Invisible` otherwise. """ -function test_visibility(tri::Triangulation, u, v, i; shift=0.0, attractor=get_point(tri,i)) +function test_visibility(tri::Triangulation, u, v, i; shift = 0.0, attractor = get_point(tri, i)) pu, pv = get_point(tri, u, v) pux, puy = getxy(pu) pvx, pvy = getxy(pv) @@ -695,4 +695,4 @@ function test_visibility(tri::Triangulation, u, v, i; shift=0.0, attractor=get_p is_visible(cert) && return Certificate.Visible end return Cert.Invisible -end \ No newline at end of file +end diff --git a/src/setup.jl b/src/setup.jl index e1a26faf5..8c09b225b 100644 --- a/src/setup.jl +++ b/src/setup.jl @@ -53,7 +53,7 @@ end @static if VERSION ≥ v"1.6" const PREDICATES = @load_preference("PREDICATES", "EXACT")::String # This default is not guaranteed to be consistent between versions -else +else const PREDICATES = "EXACT" end @static if PREDICATES ∉ ("EXACT", "INEXACT") @@ -92,4 +92,3 @@ PREDICATES const USE_EXACTPREDICATES = PREDICATES == "EXACT" const USE_INEXACTPREDICATES = PREDICATES == "INEXACT" - diff --git a/src/utils.jl b/src/utils.jl index bd2257ebd..146a8041b 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,2 +1,2 @@ include("utils/geometry_utils.jl") -include("utils/utils.jl") \ No newline at end of file +include("utils/utils.jl") diff --git a/src/utils/geometry_utils.jl b/src/utils/geometry_utils.jl index 6c7ea0cc5..d0d13c6cf 100644 --- a/src/utils/geometry_utils.jl +++ b/src/utils/geometry_utils.jl @@ -123,7 +123,7 @@ function polygon_features(points, boundary_nodes) return polygon_features_single_segment(points, boundary_nodes) end end -function polygon_features_single_segment(points, boundary_nodes; scale=Val(true)) +function polygon_features_single_segment(points, boundary_nodes; scale = Val(true)) F = number_type(points) cx = zero(F) cy = zero(F) @@ -132,7 +132,7 @@ function polygon_features_single_segment(points, boundary_nodes; scale=Val(true) vᵢ = get_boundary_nodes(boundary_nodes, 1) pᵢ = get_point(points, vᵢ) xᵢ, yᵢ = getxy(pᵢ) - for j in 2:(n_edge+1) + for j in 2:(n_edge + 1) vᵢ₊₁ = get_boundary_nodes(boundary_nodes, j) pᵢ₊₁ = get_point(points, vᵢ₊₁) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) @@ -156,8 +156,10 @@ function polygon_features_multiple_segments(points, boundary_nodes) ns = num_sections(boundary_nodes) for i in 1:ns bn = get_boundary_nodes(boundary_nodes, i) - sub_a, (sub_cx, sub_cy) = polygon_features_single_segment(points, bn; - scale=Val(false)) + sub_a, (sub_cx, sub_cy) = polygon_features_single_segment( + points, bn; + scale = Val(false), + ) a += sub_a cx += sub_cx cy += sub_cy @@ -217,7 +219,7 @@ function distance_to_polygon(q, points, boundary_nodes) return distance_to_polygon_single_segment(q, points, boundary_nodes) end end -function distance_to_polygon_single_segment(q, points, boundary_nodes, is_in_outer=false; return_sqrt=Val(true)) +function distance_to_polygon_single_segment(q, points, boundary_nodes, is_in_outer = false; return_sqrt = Val(true)) x, y = getxy(q) F = number_type(points) dist = typemax(F) @@ -225,7 +227,7 @@ function distance_to_polygon_single_segment(q, points, boundary_nodes, is_in_out vᵢ = get_boundary_nodes(boundary_nodes, 1) pᵢ = get_point(points, vᵢ) xᵢ, yᵢ = getxy(pᵢ) - for j in 2:(n_edge+1) + for j in 2:(n_edge + 1) vᵢ₊₁ = get_boundary_nodes(boundary_nodes, j) pᵢ₊₁ = get_point(points, vᵢ₊₁) xᵢ₊₁, yᵢ₊₁ = getxy(pᵢ₊₁) @@ -242,13 +244,13 @@ function distance_to_polygon_single_segment(q, points, boundary_nodes, is_in_out dist = is_true(return_sqrt) ? sqrt(dist) : dist return is_in_outer ? dist : -dist end -function distance_to_polygon_multiple_segments(q, points, boundary_nodes, is_in_outer=-one(number_type(points)); return_sqrt=Val(true)) +function distance_to_polygon_multiple_segments(q, points, boundary_nodes, is_in_outer = -one(number_type(points)); return_sqrt = Val(true)) F = number_type(points) dist = typemax(F) ns = num_sections(boundary_nodes) for i in 1:ns bn = get_boundary_nodes(boundary_nodes, i) - new_dist = distance_to_polygon_single_segment(q, points, bn, is_in_outer == one(F); return_sqrt=Val(false)) + new_dist = distance_to_polygon_single_segment(q, points, bn, is_in_outer == one(F); return_sqrt = Val(false)) is_in_outer = sign(new_dist) new_dist = abs(new_dist) dist = new_dist < dist ? new_dist : dist @@ -263,8 +265,10 @@ function distance_to_polygon_multiple_curves(q, points, boundary_nodes) nc = num_curves(boundary_nodes) for i in 1:nc bn = get_boundary_nodes(boundary_nodes, i) - new_dist = distance_to_polygon_multiple_segments(q, points, bn, is_in_outer == one(F); - return_sqrt=Val(false)) + new_dist = distance_to_polygon_multiple_segments( + q, points, bn, is_in_outer == one(F); + return_sqrt = Val(false), + ) is_in_outer = sign(new_dist) new_dist = abs(new_dist) dist = new_dist < dist ? new_dist : dist @@ -278,7 +282,7 @@ end Computes the bounding box of the polygon defined by `(points, boundary_nodes)`. The `boundary_nodes` must match the specification in the documentation and in [`check_args`](@ref). If `check_all_curves` is `true`, then the bounding box of the union of all curves of the `polygon` is computed instead of just the first curve. """ -function polygon_bounds(points, boundary_nodes, check_all_curves=Val(false)) +function polygon_bounds(points, boundary_nodes, check_all_curves = Val(false)) if has_multiple_curves(boundary_nodes) if !is_true(check_all_curves) return polygon_bounds_multiple_segments(points, get_boundary_nodes(boundary_nodes, 1)) # 1 is the outermost boundary, unless you have a multiple polygon. PolygonHierarchy would be better for this but too bad @@ -343,7 +347,7 @@ function sort_convex_polygon!(vertices, points) cx, cy = mean_points(points, vertices) to_angle = p -> atan(gety(p) - cy, getx(p) - cx) vert_to_angle = v -> (to_angle ∘ get_point)(points, v) - sort!(vertices, by=vert_to_angle) + sort!(vertices, by = vert_to_angle) return vertices end @@ -447,4 +451,4 @@ function angle_between(p, q) a = px * qx + py * qy b = px * -qy + py * qx return mod(atan(b, a), 2π) -end \ No newline at end of file +end diff --git a/src/utils/utils.jl b/src/utils/utils.jl index fab4a7be7..92bc97b84 100644 --- a/src/utils/utils.jl +++ b/src/utils/utils.jl @@ -34,7 +34,7 @@ Float64 """ number_type number_type(x) = number_type(typeof(x)) -number_type(::Type{T}) where {T<:AbstractArray} = number_type(eltype(T)) +number_type(::Type{T}) where {T <: AbstractArray} = number_type(eltype(T)) number_type(x::Type{<:NTuple{N}}) where {N} = eltype(x) number_type(::Type{Tuple{}}) = Any number_type(::Type{T}) where {T} = T @@ -133,12 +133,12 @@ is_circular(A) = isempty(A) || (A[begin] == A[end]) Compares the two circular vectors `A` and `B` for equality up to circular rotation, using `by` to compare individual elements. """ -function circular_equality(A, B, by=isequal) +function circular_equality(A, B, by = isequal) @assert is_circular(A) && is_circular(B) "A and B must be circular" length(A) ≠ length(B) && return false isempty(A) && return true # isempty(B) is true as well because of the previous assertion - _A = @views A[begin:(end-1)] - _B = @views B[begin:(end-1)] + _A = @views A[begin:(end - 1)] + _B = @views B[begin:(end - 1)] same_idx = findfirst(by(_A[begin]), _B) same_idx === nothing && return false n = length(_A) @@ -505,7 +505,7 @@ end Returns the unique elements of `A` up to tolerance `tol`. We say that two values `x` and `y` are within tolerance if `abs(u - v) ≤ M*tol`, where `M = maximum(abs.(A))`. It is assumed that `A` is sorted - this is NOT checked. """ -function uniquetol(A::Vector{Float64}; tol=1e-12) +function uniquetol(A::Vector{Float64}; tol = 1.0e-12) isempty(A) && return Float64[] M = max(abs(A[begin]), abs(A[end])) # assuming A is sorted intol = (x, y) -> abs(x - y) ≤ M * tol @@ -524,14 +524,14 @@ end Evaluates `f(tup[idx])` in a type-stable way. If `idx > length(tup)`, then `f` is evaluated on the last element of `tup`. """ -@inline function eval_fnc_at_het_tuple_element(f::F, tup::T, idx) where {F,T} +@inline function eval_fnc_at_het_tuple_element(f::F, tup::T, idx) where {F, T} return _eval_fnc_at_het_tuple_element(f, idx, tup...) end -@inline function _eval_fnc_at_het_tuple_element(f::F, idx, el::E, tup...) where {F,E} +@inline function _eval_fnc_at_het_tuple_element(f::F, idx, el::E, tup...) where {F, E} idx == 1 && return _eval_fnc_at_het_tuple_element(f, 1, el) return _eval_fnc_at_het_tuple_element(f, idx - 1, tup...) end -@inline function _eval_fnc_at_het_tuple_element(f::F, idx, el::E) where {F,E} +@inline function _eval_fnc_at_het_tuple_element(f::F, idx, el::E) where {F, E} return f(el) end @@ -540,21 +540,21 @@ end Evaluates `f(tup[idx1], tup[idx2])` in a type-stable way. """ -@inline function eval_fnc_at_het_tuple_two_elements(f::F, tup::T, idx1, idx2) where {F,T<:Tuple} +@inline function eval_fnc_at_het_tuple_two_elements(f::F, tup::T, idx1, idx2) where {F, T <: Tuple} return _eval_fnc_at_het_tuple_two_elements(f, idx2, tup, idx1, tup...) end -@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, next_tup::T, idx1, el::E, tup...) where {F,E,T<:Tuple} +@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, next_tup::T, idx1, el::E, tup...) where {F, E, T <: Tuple} idx1 == 1 && return _eval_fnc_at_het_tuple_two_elements(f, idx2, next_tup, 1, el) return _eval_fnc_at_het_tuple_two_elements(f, idx2, next_tup, idx1 - 1, tup...) end -@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, next_tup::T, idx1, el::E) where {F,E,T<:Tuple} +@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, next_tup::T, idx1, el::E) where {F, E, T <: Tuple} return _eval_fnc_at_het_tuple_two_elements(f, idx2, el, next_tup...) end -@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, el::E, el2::V, tup...) where {F,E,V} +@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, el::E, el2::V, tup...) where {F, E, V} idx2 == 1 && return _eval_fnc_at_het_tuple_two_elements(f, 1, el, el2) return _eval_fnc_at_het_tuple_two_elements(f, idx2 - 1, el, tup...) end -@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, el::E, el2::V) where {F,E,V} +@inline function _eval_fnc_at_het_tuple_two_elements(f::F, idx2, el::E, el2::V) where {F, E, V} return f(el, el2) end @@ -563,14 +563,14 @@ end Evaluates `f(tup[idx], arg...)` in a type-stable way. If `idx > length(tup)`, then `f` is evaluated on the last element of `tup`. """ -@inline function eval_fnc_at_het_tuple_element_with_arg(f::F, tup::T, arg, idx) where {F,T} +@inline function eval_fnc_at_het_tuple_element_with_arg(f::F, tup::T, arg, idx) where {F, T} return _eval_fnc_at_het_tuple_element_with_arg(f, idx, arg, tup...) end -@inline function _eval_fnc_at_het_tuple_element_with_arg(f::F, idx, arg, el::E, tup...) where {F,E} +@inline function _eval_fnc_at_het_tuple_element_with_arg(f::F, idx, arg, el::E, tup...) where {F, E} idx == 1 && return _eval_fnc_at_het_tuple_element_with_arg(f, 1, arg, el) return _eval_fnc_at_het_tuple_element_with_arg(f, idx - 1, arg, tup...) end -@inline function _eval_fnc_at_het_tuple_element_with_arg(f::F, idx, arg, el::E) where {F,E} +@inline function _eval_fnc_at_het_tuple_element_with_arg(f::F, idx, arg, el::E) where {F, E} return f(el, arg...) end @@ -579,7 +579,7 @@ end Evaluates `tup[idx](arg...)` in a type-stable way. If `idx > length(tup)`, then `tup[end](arg...)` is evaluated. """ -@inline function eval_fnc_in_het_tuple(tup::T, arg::A, idx) where {T,A} +@inline function eval_fnc_in_het_tuple(tup::T, arg::A, idx) where {T, A} return eval_fnc_at_het_tuple_element_with_arg(self_eval, tup, arg, idx) end @@ -596,4 +596,4 @@ Evaluates `f(args...)`. Wraps `v` in a `Val`, or if `v isa Val` simply returns `v`. """ @inline _to_val(v::V) where {V} = Val(v)::Val{v} -@inline _to_val(v::Val{B}) where {B} = v \ No newline at end of file +@inline _to_val(v::Val{B}) where {B} = v diff --git a/src/validation.jl b/src/validation.jl index 7fa78b6f0..c512650b9 100644 --- a/src/validation.jl +++ b/src/validation.jl @@ -35,7 +35,7 @@ end struct TriangleOrientationState <: AbstractTriangulationState flag::Bool - bad_triangle::NTuple{3,Int} + bad_triangle::NTuple{3, Int} triangle_orientation::Symbol end TriangleOrientationState(tri) = test_triangle_orientation(tri) @@ -58,7 +58,7 @@ end struct DelaunayCriterionState <: AbstractTriangulationState flag::Bool - bad_triangle::NTuple{3,Int} + bad_triangle::NTuple{3, Int} bad_vertex::Int end DelaunayCriterionState(tri) = test_delaunay_criterion(tri) @@ -78,7 +78,7 @@ function test_delaunay_criterion(tri) points = get_points(tri) triangle_tree = BoundaryRTree(points) segment_tree = BoundaryRTree(points) - failures = Tuple{triangle_type(tri),integer_type(tri)}[] + failures = Tuple{triangle_type(tri), integer_type(tri)}[] for T in each_solid_triangle(tri) i, j, k = triangle_vertices(T) p, q, r = get_point(tri, i, j, k) @@ -106,7 +106,7 @@ function test_delaunay_criterion(tri) end for r in shuffle(collect(each_solid_vertex(tri))) !isempty(failures) && break - intersects = get_intersections(triangle_tree, r, cache_id=1) # can't use multithreading here + intersects = get_intersections(triangle_tree, r, cache_id = 1) # can't use multithreading here for box in intersects i, j = get_edge(box) k = get_adjacent(tri, i, j) @@ -121,7 +121,7 @@ function test_delaunay_criterion(tri) for (i, j) in triangle_edges(i, j, k) contains_segment(tri, i, j) && continue # visibility is defined according to the relative interior of the simplex, which means that it's fine if a segment can see the vertex if rand() < 1 / 2 # just testing both - cert = test_visibility(tri, i, j, r, shift=0.01, attractor=c) + cert = test_visibility(tri, i, j, r, shift = 0.01, attractor = c) else cert = test_visibility(tri, segment_tree, i, j, r, c) end @@ -142,7 +142,7 @@ function test_delaunay_criterion(tri) rethrow(e) end end -function test_visibility(tri::Triangulation, segment_tree, i, j, k, centroid=nothing) +function test_visibility(tri::Triangulation, segment_tree, i, j, k, centroid = nothing) if is_boundary_edge(tri, j, i) i, j = j, i end @@ -178,7 +178,7 @@ function test_visibility(tri::Triangulation, segment_tree, i, j, k, centroid=not ax, ay = getxy(a) xmin, ymin, xmax, ymax = min(mx, ax), min(my, ay), max(mx, ax), max(my, ay) bbox = BoundingBox(xmin, xmax, ymin, ymax) - intersections = get_intersections(segment_tree, bbox; cache_id=2) + intersections = get_intersections(segment_tree, bbox; cache_id = 2) for box in intersections u, v = get_edge(box) p′, q′ = get_point(tri, u, v) @@ -192,7 +192,7 @@ end struct EdgesHaveTwoIncidentTrianglesState <: AbstractTriangulationState flag::Bool - bad_edge::NTuple{2,Int} + bad_edge::NTuple{2, Int} end EdgesHaveTwoIncidentTrianglesState(tri) = test_each_edge_has_two_incident_triangles(tri) function Base.summary(state::EdgesHaveTwoIncidentTrianglesState) @@ -224,8 +224,8 @@ end struct AdjacentMapState <: AbstractTriangulationState flag::Bool - bad_triangle::NTuple{3,Int} - bad_edge::NTuple{2,Int} + bad_triangle::NTuple{3, Int} + bad_edge::NTuple{2, Int} bad_vertex::Int end AdjacentMapState(tri) = test_adjacent_map_matches_triangles(tri) @@ -252,10 +252,10 @@ end struct Adjacent2VertexMapState <: AbstractTriangulationState flag::Bool - bad_triangle::NTuple{3,Int} - bad_edge::NTuple{2,Int} + bad_triangle::NTuple{3, Int} + bad_edge::NTuple{2, Int} bad_vertex::Int - bad_edge_set::Set{NTuple{2,Int}} + bad_edge_set::Set{NTuple{2, Int}} end Adjacent2VertexMapState(tri) = test_adjacent2vertex_map_matches_triangles(tri) function Base.summary(state::Adjacent2VertexMapState) @@ -274,20 +274,20 @@ function test_adjacent2vertex_map_matches_triangles(tri) Su = get_adjacent2vertex(tri, u) flag = contains_edge(vw, Su) if !flag - _Su = Set{NTuple{2,Int}}(Int.(edge_vertices(e)) for e in each_edge(Su)) + _Su = Set{NTuple{2, Int}}(Int.(edge_vertices(e)) for e in each_edge(Su)) return Adjacent2VertexMapState(flag, Int.(triangle_vertices(T)), Int.((v, w)), Int(u), _Su) end end end - return Adjacent2VertexMapState(true, (∅, ∅, ∅), (∅, ∅), ∅, Set{NTuple{2,Int}}()) + return Adjacent2VertexMapState(true, (∅, ∅, ∅), (∅, ∅), ∅, Set{NTuple{2, Int}}()) end struct AdjacentMapAdjacent2VertexMapState <: AbstractTriangulationState flag::Bool bad_vertex::Int bad_vertex2::Int - bad_edge_set::Set{NTuple{2,Int}} - bad_edge::NTuple{2,Int} + bad_edge_set::Set{NTuple{2, Int}} + bad_edge::NTuple{2, Int} end AdjacentMapAdjacent2VertexMapState(tri) = test_adjacent_map_matches_adjacent2vertex_map(tri) function Base.summary(state::AdjacentMapAdjacent2VertexMapState) @@ -299,20 +299,20 @@ function Base.summary(state::AdjacentMapAdjacent2VertexMapState) end function test_adjacent_map_matches_adjacent2vertex_map(tri) for (k, S) in get_adjacent2vertex(get_adjacent2vertex(tri)) - _S = Set{NTuple{2,Int}}(Int.(edge_vertices(e)) for e in each_edge(S)) + _S = Set{NTuple{2, Int}}(Int.(edge_vertices(e)) for e in each_edge(S)) for e in each_edge(S) flag = get_adjacent(tri, e) == k !flag && return AdjacentMapAdjacent2VertexMapState(flag, Int(k), get_adjacent(tri, e), _S, Int.(edge_vertices(e))) end end clear_empty_features!(tri) - return AdjacentMapAdjacent2VertexMapState(true, ∅, ∅, Set{NTuple{2,Int}}(), (∅, ∅)) + return AdjacentMapAdjacent2VertexMapState(true, ∅, ∅, Set{NTuple{2, Int}}(), (∅, ∅)) end struct Adjacent2VertexMapAdjacentMapState <: AbstractTriangulationState flag::Bool bad_vertex::Int - bad_edge::NTuple{2,Int} + bad_edge::NTuple{2, Int} in_adjacent2vertex::Bool end Adjacent2VertexMapAdjacentMapState(tri) = test_adjacent2vertex_map_matches_adjacent_map(tri) @@ -370,7 +370,7 @@ end struct GraphAdjacentMapState <: AbstractTriangulationState flag::Bool - bad_edge::NTuple{2,Int} + bad_edge::NTuple{2, Int} end GraphAdjacentMapState(tri) = test_graph_matches_adjacent_map(tri) function Base.summary(state::GraphAdjacentMapState) @@ -403,8 +403,8 @@ end struct AdjacentMapGraphState <: AbstractTriangulationState flag::Bool bad_vertex::Int - bad_edge::NTuple{2,Int} - bad_edge_2::NTuple{2,Int} + bad_edge::NTuple{2, Int} + bad_edge_2::NTuple{2, Int} is_k::Bool adjacent_vertex::Int end @@ -435,8 +435,8 @@ end struct GraphTrianglesState <: AbstractTriangulationState flag::Bool - bad_triangle::NTuple{3,Int} - bad_edge::NTuple{2,Int} + bad_triangle::NTuple{3, Int} + bad_edge::NTuple{2, Int} bad_vertex::Int end GraphTrianglesState(tri) = test_graph_matches_triangles(tri) @@ -471,7 +471,7 @@ end struct SegmentState <: AbstractTriangulationState flag::Bool - segment::NTuple{2,Int} + segment::NTuple{2, Int} type::Int end SegmentState(tri) = test_segments(tri) @@ -502,8 +502,8 @@ function test_segments(tri) flag = edge_exists(tri, e) || edge_exists(tri, reverse_edge(e)) !flag && return SegmentState(flag, Int.(edge_vertices(e)), 0) end - int_segs = Set{NTuple{2,Int}}() - all_segs = Set{NTuple{2,Int}}() + int_segs = Set{NTuple{2, Int}}() + all_segs = Set{NTuple{2, Int}}() for e in get_interior_segments(tri) u, v = edge_vertices(e) push!(int_segs, minmax(u, v)) @@ -519,8 +519,8 @@ end struct BoundaryEdgeMapBoundaryNodesState <: AbstractTriangulationState flag::Bool - bad_edge::NTuple{2,Int} - bad_edge_2::NTuple{2,Int} + bad_edge::NTuple{2, Int} + bad_edge_2::NTuple{2, Int} bad_pos::Tuple end BoundaryEdgeMapBoundaryNodesState(tri) = test_boundary_edge_map_matches_boundary_nodes(tri) @@ -544,7 +544,7 @@ end struct BoundaryNodesBoundaryEdgeMapState <: AbstractTriangulationState flag::Bool - bad_edge::NTuple{2,Int} + bad_edge::NTuple{2, Int} bad_pos::Tuple bad_pos_2::Tuple end @@ -660,17 +660,17 @@ function Base.summary(state::IteratorState) return summary(state.output_state) # !test_state(state.output_state) end function IteratorState( - unique_flag, length_flag, output_flag, - iterator_length, correct_length, - iterator_name, primitive_name, iterator_function_name -) + unique_flag, length_flag, output_flag, + iterator_length, correct_length, + iterator_name, primitive_name, iterator_function_name, + ) flag = unique_flag && length_flag && output_flag return IteratorState( flag, UniqueIteratorOutputState(unique_flag, iterator_name, primitive_name), IteratorLengthState(length_flag, iterator_name, primitive_name, iterator_function_name, iterator_length, correct_length), IteratorOutputState(output_flag, iterator_name, primitive_name, iterator_function_name), - iterator_name + iterator_name, ) end function VertexIteratorState(length_flag, output_flag, iterator_length, correct_length) @@ -702,8 +702,8 @@ function GhostEdgeIteratorState(unique_flag, length_flag, output_flag, iterator_ end function test_iterators(tri::Triangulation) I = integer_type(tri) - T = NTuple{3,I} - E = NTuple{2,I} + T = NTuple{3, I} + E = NTuple{2, I} solid_triangles = T[] ghost_triangles = T[] all_triangles = T[] @@ -801,14 +801,14 @@ function test_iterators(tri::Triangulation) GhostTriangleIteratorState(unique_ghost_triangle_flag, ghost_triangle_length_flag, ghost_triangle_output_flag, ghost_triangle_iterator_length, ghost_triangle_correct_length), EdgeIteratorState(unique_edge_flag, edge_length_flag, edge_output_flag, edge_iterator_length, edge_correct_length), SolidEdgeIteratorState(unique_solid_edge_flag, solid_edge_length_flag, solid_edge_output_flag, solid_edge_iterator_length, solid_edge_correct_length), - GhostEdgeIteratorState(unique_ghost_edge_flag, ghost_edge_length_flag, ghost_edge_output_flag, ghost_edge_iterator_length, ghost_edge_correct_length) + GhostEdgeIteratorState(unique_ghost_edge_flag, ghost_edge_length_flag, ghost_edge_output_flag, ghost_edge_iterator_length, ghost_edge_correct_length), ) end struct DuplicateSegmentsState <: AbstractTriangulationState flag::Bool interior::Bool - bad_edge::NTuple{2,Int} + bad_edge::NTuple{2, Int} end DuplicateSegmentsState(tri) = test_no_duplicate_segments(tri) function Base.summary(state::DuplicateSegmentsState) @@ -884,7 +884,7 @@ function TriangulationState(tri::Triangulation) GraphTrianglesState(tri), SegmentState(tri), TriangleOrientationState(tri), - test_iterators(tri)... + test_iterators(tri)..., ) !has_ghosts && delete_ghost_triangles!(tri) return state @@ -918,7 +918,7 @@ Tests if `tri` is a valid `Triangulation`. Returns `true` if so, and `false` otherwise. If `print_result=true` and `tri` is not a valid triangulation, all the issues with `tri` will be printed. """ -function validate_triangulation(tri::Triangulation; print_result=true) +function validate_triangulation(tri::Triangulation; print_result = true) state = TriangulationState(tri) print_result && !test_state(state) && println(state) return test_state(state) diff --git a/test/constrained_triangulation/segment_insertion.jl b/test/constrained_triangulation/segment_insertion.jl index bb14ba138..ef3a0220d 100644 --- a/test/constrained_triangulation/segment_insertion.jl +++ b/test/constrained_triangulation/segment_insertion.jl @@ -63,13 +63,15 @@ end DT.delete_intersected_triangles!(tri, T) points = get_points(tri) _tri_1 = tri.cache - DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) - DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) - true_tri = ([ # two triangles to account for the cocircular points (2, 9, 3, 10) + true_tri = ( + [ + # two triangles to account for the cocircular points (2, 9, 3, 10) (1, 4, 2) (8, 11, 10) (8, 7, 11) @@ -112,7 +114,7 @@ end (5, 4, DT.𝒢) (4, 1, DT.𝒢) (1, 2, DT.𝒢) - ] + ], ) @test any(T -> DT.compare_triangle_collections(get_triangles(tri), T), true_tri) push!(get_all_segments(tri), e) @@ -124,10 +126,10 @@ end DT.delete_intersected_triangles!(tri, T) points = get_points(tri) _tri_1 = tri.cache - DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) - DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) true_tri = [ @@ -161,10 +163,10 @@ end T, C, L, R = DT.locate_intersecting_triangles(tri, e) DT.delete_intersected_triangles!(tri, T) _tri_1 = tri.cache - DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) - DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) true_tri = [ @@ -204,10 +206,10 @@ end DT.delete_intersected_triangles!(tri, T) points = get_points(tri) _tri_1 = tri.cache - DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, L, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) - DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices,_tri_1.fan_triangles) + DT.triangulate_cavity_cdt!(_tri_1.triangulation, R, _tri_1.triangulation_2, _tri_1.marked_vertices, _tri_1.fan_triangles) DT.add_new_triangles!(tri, _tri_1.triangulation) empty!(_tri_1) end @@ -252,4 +254,4 @@ end ] @test DT.compare_triangle_collections(get_triangles(tri), true_tri) @test validate_triangulation(tri) -end \ No newline at end of file +end diff --git a/test/constrained_triangulation/segment_location.jl b/test/constrained_triangulation/segment_location.jl index 7e0ca3a5b..3573dcfbf 100644 --- a/test/constrained_triangulation/segment_location.jl +++ b/test/constrained_triangulation/segment_location.jl @@ -14,7 +14,7 @@ using Preferences [(1, 4, 2), (4, 5, 9), (5, 6, 8)], [(3, 4, 10), (10, 8, 11)], [(3, 2, 4), (2, 1, 4)], - [(3, 4, 10), (10, 4, 9), (10, 9, 5), (8, 5, 6), (5, 8, 10)] + [(3, 4, 10), (10, 4, 9), (10, 9, 5), (8, 5, 6), (5, 8, 10)], ] collinear = [ [], @@ -23,7 +23,7 @@ using Preferences [(1, 4), (4, 5), (5, 6)], ([(11, 10), (10, 3)], [(3, 10), (10, 11)]), [(1, 2), (2, 3)], - [] + [], ] for _ in 1:250 for (edge, tris, edges) in zip(e, allT, collinear) @@ -38,7 +38,7 @@ using Preferences (Set(((1, 4), (4, 5), (5, 6))),), (Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3))),), (Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (3, 10), (10, 11))), Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (11, 10), (10, 3)))), - (Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (3, 10), (10, 11), (11, 7), (7, 6))), Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (11, 10), (10, 3), (11, 7), (7, 6)))) + (Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (3, 10), (10, 11), (11, 7), (7, 6))), Set(((1, 4), (4, 5), (5, 6), (1, 2), (2, 3), (11, 10), (10, 3), (11, 7), (7, 6)))), ] for _ in 1:250 tri = shewchuk_example_constrained() @@ -82,36 +82,36 @@ end e[1] = (7, 28) _T1 = [(7, 8, 12), (12, 8, 13), (17, 12, 13), (17, 13, 18), (22, 17, 18), (22, 18, 23), (27, 22, 23), (27, 23, 28)] crossed_triangles[1] = (_T1, reverse(_T1)) - constrained_edges[1] = Set{NTuple{2,Int}}((e[1],)) - collinear_segments[1] = NTuple{2,Int}[] + constrained_edges[1] = Set{NTuple{2, Int}}((e[1],)) + collinear_segments[1] = NTuple{2, Int}[] e[2] = (44, 21) crossed_triangles[2] = [(21, 22, 26), (26, 22, 27), (31, 26, 27), (31, 27, 32), (32, 27, 28), (32, 28, 33), (37, 32, 33), (37, 33, 38), (38, 33, 34), (38, 34, 39), (43, 38, 39), (43, 39, 44)] - constrained_edges[2] = Set{NTuple{2,Int}}((e[1], e[2])) - collinear_segments[2] = NTuple{2,Int}[] + constrained_edges[2] = Set{NTuple{2, Int}}((e[1], e[2])) + collinear_segments[2] = NTuple{2, Int}[] e[3] = (8, 14) crossed_triangles[3] = ([(13, 8, 9), (13, 9, 14)], [(13, 9, 14), (13, 8, 9)]) - constrained_edges[3] = Set{NTuple{2,Int}}((e[1], e[2], e[3])) - collinear_segments[3] = NTuple{2,Int}[] + constrained_edges[3] = Set{NTuple{2, Int}}((e[1], e[2], e[3])) + collinear_segments[3] = NTuple{2, Int}[] e[4] = (1, 50) _T4 = [(6, 1, 2), (6, 2, 7), (11, 6, 7), (11, 7, 12), (16, 11, 12), (16, 12, 17), (17, 12, 13), (17, 13, 18), (22, 17, 18), (22, 18, 23), (27, 22, 23), (27, 23, 28), (28, 23, 24), (28, 24, 29), (33, 28, 29), (33, 29, 34), (38, 33, 34), (38, 34, 39), (39, 34, 35), (39, 35, 40), (44, 39, 40), (44, 40, 45), (49, 44, 45), (49, 45, 50)] crossed_triangles[4] = (_T4, reverse(_T4)) - constrained_edges[4] = Set{NTuple{2,Int}}((e[1], e[2], e[3], e[4])) - collinear_segments[4] = NTuple{2,Int}[] + constrained_edges[4] = Set{NTuple{2, Int}}((e[1], e[2], e[3], e[4])) + collinear_segments[4] = NTuple{2, Int}[] e[5] = (47, 4) _T5 = [(47, 42, 43), (42, 38, 43), (42, 37, 38), (38, 37, 33), (37, 32, 33), (32, 28, 33), (32, 27, 28), (27, 23, 28), (28, 23, 24), (23, 19, 24), (23, 18, 19), (18, 14, 19), (18, 13, 14), (13, 9, 14), (13, 8, 9), (8, 4, 9)] crossed_triangles[5] = (_T5, reverse(_T5)) - constrained_edges[5] = Set{NTuple{2,Int}}((e[1], e[2], e[3], e[4], e[5])) - collinear_segments[5] = NTuple{2,Int}[] + constrained_edges[5] = Set{NTuple{2, Int}}((e[1], e[2], e[3], e[4], e[5])) + collinear_segments[5] = NTuple{2, Int}[] e[6] = (17, 24) _T6 = [(22, 17, 18), (22, 18, 23), (23, 18, 19), (23, 19, 24)] crossed_triangles[6] = (_T6, reverse(_T6)) - constrained_edges[6] = Set{NTuple{2,Int}}((e[1], e[2], e[3], e[4], e[5], e[6])) - collinear_segments[6] = NTuple{2,Int}[] + constrained_edges[6] = Set{NTuple{2, Int}}((e[1], e[2], e[3], e[4], e[5], e[6])) + collinear_segments[6] = NTuple{2, Int}[] e[7] = (17, 27) _T7a = [(22, 21, 17), (21, 22, 26), (26, 22, 27)] @@ -119,7 +119,7 @@ end _T7c = [(22, 23, 27), (23, 22, 18), (18, 22, 17)] _T7d = [(26, 22, 27), (22, 26, 21), (22, 21, 17)] crossed_triangles[7] = (_T7a, _T7b, _T7c, _T7d) - constrained_edges[7] = Set{NTuple{2,Int}}((e[1], e[2], e[3], e[4], e[5], e[6], (27, 22), (22, 17))) + constrained_edges[7] = Set{NTuple{2, Int}}((e[1], e[2], e[3], e[4], e[5], e[6], (27, 22), (22, 17))) collinear_segments[7] = ([(27, 22), (22, 17)], [(17, 22), (22, 27)]) e[8] = (32, 24) @@ -288,17 +288,19 @@ if !USE_INEXACTPREDICATES d = 0.01 nx = 25 ny = 25 - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) tri = triangulate(get_points(tri)) for i in 2:24 add_segment!(tri, i, 600 + i) end - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) tri = triangulate(get_points(tri)) e = (23, 71) - history = DT.PointLocationHistory{NTuple{3,Int},NTuple{2,Int},Int}() - find_triangle(tri, get_point(tri, 71); - m=nothing, k=23, store_history=true, history=history) + history = DT.PointLocationHistory{NTuple{3, Int}, NTuple{2, Int}, Int}() + find_triangle( + tri, get_point(tri, 71); + m = nothing, k = 23, store_history = true, history = history, + ) collinear_segments = history.collinear_segments DT.connect_segments!(collinear_segments) DT.extend_segments!(collinear_segments, e) @@ -308,11 +310,13 @@ if !USE_INEXACTPREDICATES end @testset "Some other previously broken examples, dealing with segments going through points without passing through segments" begin - tri = triangulate_rectangle(0, 5, 0, 10, 6, 11; delete_ghosts=false) + tri = triangulate_rectangle(0, 5, 0, 10, 6, 11; delete_ghosts = false) e = (14, 40) - history = DT.PointLocationHistory{NTuple{3,Int},NTuple{2,Int},Int}() - find_triangle(tri, get_point(tri, 40); - m=nothing, k=14, store_history=true, history=history) + history = DT.PointLocationHistory{NTuple{3, Int}, NTuple{2, Int}, Int}() + find_triangle( + tri, get_point(tri, 40); + m = nothing, k = 14, store_history = true, history = history, + ) collinear_segments = history.collinear_segments DT.fix_segments!(collinear_segments, history.collinear_point_indices) DT.connect_segments!(collinear_segments) @@ -320,13 +324,15 @@ end @test collinear_segments == [(14, 27), (27, 40)] e = (2, 54) - history = DT.PointLocationHistory{NTuple{3,Int},NTuple{2,Int},Int}() - find_triangle(tri, get_point(tri, 54); - m=nothing, k=2, store_history=true, history=history) + history = DT.PointLocationHistory{NTuple{3, Int}, NTuple{2, Int}, Int}() + find_triangle( + tri, get_point(tri, 54); + m = nothing, k = 2, store_history = true, history = history, + ) collinear_segments = history.collinear_segments bad_indices = history.collinear_point_indices DT.fix_segments!(collinear_segments, bad_indices) DT.connect_segments!(collinear_segments) DT.extend_segments!(collinear_segments, e) @test collinear_segments == [(2, 15), (15, 28), (28, 41), (41, 54)] -end \ No newline at end of file +end diff --git a/test/data_structures/adjacent.jl b/test/data_structures/adjacent.jl index 7f4988459..b4d77a3bc 100644 --- a/test/data_structures/adjacent.jl +++ b/test/data_structures/adjacent.jl @@ -4,12 +4,12 @@ using DataStructures using StaticArrays global def_adj = DT.∅ -global default_1 = Dict{NTuple{2,Int},Int}() -global default_2 = Dict{NTuple{2,Int32},Int32}() -global default_3 = Dict{Vector{Int},Int}() -global adj_1 = DT.Adjacent{Int,NTuple{2,Int}}() -global adj_2 = DT.Adjacent{Int32,NTuple{2,Int32}}() -global adj_3 = DT.Adjacent{Int,Vector{Int}}() +global default_1 = Dict{NTuple{2, Int}, Int}() +global default_2 = Dict{NTuple{2, Int32}, Int32}() +global default_3 = Dict{Vector{Int}, Int}() +global adj_1 = DT.Adjacent{Int, NTuple{2, Int}}() +global adj_2 = DT.Adjacent{Int32, NTuple{2, Int32}}() +global adj_3 = DT.Adjacent{Int, Vector{Int}}() @testset "Constructors and getters" begin @test adj_1.adjacent == default_1 @@ -24,10 +24,14 @@ global adj_3 = DT.Adjacent{Int,Vector{Int}}() end global dict_1 = Dict((1, 2) => 4, (2, 3) => 10, (5, 6) => 15, (20, 5) => 72) -global dict_2 = Dict(@SVector[1, 2] => 4, @SVector[2, 3] => 10, @SVector[5, 6] => 15, - @SVector[20, 5] => 72) -global dict_3 = Dict{NTuple{2,Int32},Int32}((1, 2) => 4, (2, 3) => 10, (5, 6) => 15, - (20, 5) => 72) +global dict_2 = Dict( + @SVector[1, 2] => 4, @SVector[2, 3] => 10, @SVector[5, 6] => 15, + @SVector[20, 5] => 72, +) +global dict_3 = Dict{NTuple{2, Int32}, Int32}( + (1, 2) => 4, (2, 3) => 10, (5, 6) => 15, + (20, 5) => 72, +) global ddict_1 = Dict(dict_1) global ddict_2 = Dict(dict_2) global ddict_3 = Dict(dict_3) @@ -107,4 +111,4 @@ end @test !isempty(get_adjacent(adj)) empty!(adj) @test isempty(get_adjacent(adj)) -end \ No newline at end of file +end diff --git a/test/data_structures/adjacent2vertex.jl b/test/data_structures/adjacent2vertex.jl index 76054c079..99d31f216 100644 --- a/test/data_structures/adjacent2vertex.jl +++ b/test/data_structures/adjacent2vertex.jl @@ -3,12 +3,12 @@ const DT = DelaunayTriangulation using DataStructures using StaticArrays -global dict_1 = Dict{Int,Set{NTuple{2,Int}}}() -global dict_2 = Dict{Int,Vector{NTuple{2,Int}}}() -global dict_3 = Dict{Int32,Set{SVector{2,Int32}}}() -global adj2v_1 = DT.Adjacent2Vertex{Int,Set{NTuple{2,Int}}}() -global adj2v_2 = DT.Adjacent2Vertex{Int,Vector{NTuple{2,Int}}}() -global adj2v_3 = DT.Adjacent2Vertex{Int32,Set{SVector{2,Int32}}}() +global dict_1 = Dict{Int, Set{NTuple{2, Int}}}() +global dict_2 = Dict{Int, Vector{NTuple{2, Int}}}() +global dict_3 = Dict{Int32, Set{SVector{2, Int32}}}() +global adj2v_1 = DT.Adjacent2Vertex{Int, Set{NTuple{2, Int}}}() +global adj2v_2 = DT.Adjacent2Vertex{Int, Vector{NTuple{2, Int}}}() +global adj2v_3 = DT.Adjacent2Vertex{Int32, Set{SVector{2, Int32}}}() @testset "Constructors and getters" begin @test adj2v_1.adjacent2vertex == dict_1 @@ -22,22 +22,40 @@ global adj2v_3 = DT.Adjacent2Vertex{Int32,Set{SVector{2,Int32}}}() @test get_adjacent2vertex(adj2v_3) == dict_3 end -global dict_1 = Dict(1 => Set(((1, 2), (3, 4), (10, 15), (2, 5))), +global dict_1 = Dict( + 1 => Set(((1, 2), (3, 4), (10, 15), (2, 5))), 2 => Set(((5, 7), (10, 14), (2, 3), (5, 9))), - 3 => Set(((10, 25), (23, 29)))) -global dict_2 = Dict(1 => [(1, 2), (3, 4), (10, 15), (2, 5)], + 3 => Set(((10, 25), (23, 29))), +) +global dict_2 = Dict( + 1 => [(1, 2), (3, 4), (10, 15), (2, 5)], 2 => [(5, 7), (10, 14), (2, 3), (5, 9)], - 3 => [(10, 25), (23, 29)]) -global dict_3 = Dict{Int32,Set{SVector{2,Int32}}}(1 => Set{SVector{2,Int32}}((@SVector[1, 2], - @SVector[3, 4], - @SVector[10, 15], - @SVector[2, 5])), - 2 => Set{SVector{2,Int32}}((@SVector[5, 7], - @SVector[10, 14], - @SVector[2, 3], - @SVector[5, 9])), - 3 => Set{SVector{2,Int32}}((@SVector[10, 25], - @SVector[23, 29]))) + 3 => [(10, 25), (23, 29)], +) +global dict_3 = Dict{Int32, Set{SVector{2, Int32}}}( + 1 => Set{SVector{2, Int32}}( + ( + @SVector[1, 2], + @SVector[3, 4], + @SVector[10, 15], + @SVector[2, 5], + ), + ), + 2 => Set{SVector{2, Int32}}( + ( + @SVector[5, 7], + @SVector[10, 14], + @SVector[2, 3], + @SVector[5, 9], + ), + ), + 3 => Set{SVector{2, Int32}}( + ( + @SVector[10, 25], + @SVector[23, 29], + ), + ), +) global adj2v_1 = DT.Adjacent2Vertex(dict_1) global adj2v_2 = DT.Adjacent2Vertex(dict_2) global adj2v_3 = DT.Adjacent2Vertex(dict_3) @@ -57,12 +75,20 @@ global adj2v_3 = DT.Adjacent2Vertex(dict_3) @test w3 == [(10, 25), (23, 29)] elseif adj2v === adj2v_3 @test w1 == - Set{SVector{2,Int32}}((@SVector[1, 2], @SVector[3, 4], @SVector[10, 15], - @SVector[2, 5])) + Set{SVector{2, Int32}}( + ( + @SVector[1, 2], @SVector[3, 4], @SVector[10, 15], + @SVector[2, 5], + ), + ) @test w2 == - Set{SVector{2,Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3], - @SVector[5, 9])) - @test w3 == Set{SVector{2,Int32}}((@SVector[10, 25], @SVector[23, 29])) + Set{SVector{2, Int32}}( + ( + @SVector[5, 7], @SVector[10, 14], @SVector[2, 3], + @SVector[5, 9], + ), + ) + @test w3 == Set{SVector{2, Int32}}((@SVector[10, 25], @SVector[23, 29])) end DT.add_adjacent2vertex!(adj2v, 1, 23, 50) @@ -77,13 +103,25 @@ global adj2v_3 = DT.Adjacent2Vertex(dict_3) @test w3 == [(10, 25), (23, 29), (38, 173)] elseif adj2v === adj2v_3 @test w1 == - Set{SVector{2,Int32}}((@SVector[1, 2], @SVector[3, 4], @SVector[10, 15], - @SVector[2, 5], @SVector[23, 50])) + Set{SVector{2, Int32}}( + ( + @SVector[1, 2], @SVector[3, 4], @SVector[10, 15], + @SVector[2, 5], @SVector[23, 50], + ), + ) @test w2 == - Set{SVector{2,Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3], - @SVector[5, 9])) - @test w3 == Set{SVector{2,Int32}}((@SVector[10, 25], @SVector[23, 29], - @SVector[38, 173])) + Set{SVector{2, Int32}}( + ( + @SVector[5, 7], @SVector[10, 14], @SVector[2, 3], + @SVector[5, 9], + ), + ) + @test w3 == Set{SVector{2, Int32}}( + ( + @SVector[10, 25], @SVector[23, 29], + @SVector[38, 173], + ), + ) end if !(adj2v === adj2v_2) @@ -99,12 +137,20 @@ global adj2v_3 = DT.Adjacent2Vertex(dict_3) @test w3 == [(10, 25), (23, 29), (38, 173)] elseif adj2v === adj2v_3 @test w1 == - Set{SVector{2,Int32}}((@SVector[1, 2], @SVector[10, 15], @SVector[2, 5], - @SVector[23, 50])) + Set{SVector{2, Int32}}( + ( + @SVector[1, 2], @SVector[10, 15], @SVector[2, 5], + @SVector[23, 50], + ), + ) @test w2 == - Set{SVector{2,Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3])) - @test w3 == Set{SVector{2,Int32}}((@SVector[10, 25], @SVector[23, 29], - @SVector[38, 173])) + Set{SVector{2, Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3])) + @test w3 == Set{SVector{2, Int32}}( + ( + @SVector[10, 25], @SVector[23, 29], + @SVector[38, 173], + ), + ) end end @@ -118,10 +164,14 @@ global adj2v_3 = DT.Adjacent2Vertex(dict_3) @test w2 == [(5, 7), (10, 14), (2, 3), (5, 9)] elseif adj2v === adj2v_3 @test w1 == - Set{SVector{2,Int32}}((@SVector[1, 2], @SVector[10, 15], @SVector[2, 5], - @SVector[23, 50])) + Set{SVector{2, Int32}}( + ( + @SVector[1, 2], @SVector[10, 15], @SVector[2, 5], + @SVector[23, 50], + ), + ) @test w2 == - Set{SVector{2,Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3])) + Set{SVector{2, Int32}}((@SVector[5, 7], @SVector[10, 14], @SVector[2, 3])) end DT.add_triangle!(adj2v, 51, 52, 53) @@ -168,7 +218,7 @@ global adj2v_3 = DT.Adjacent2Vertex(dict_3) end @testset "Seeing if Adjacent2Vertex is empty and clearing empty sets" begin - adj2v = DT.Adjacent2Vertex{Int,Set{NTuple{2,Int}}}() + adj2v = DT.Adjacent2Vertex{Int, Set{NTuple{2, Int}}}() DT.add_adjacent2vertex!(adj2v, 2, 5, 7) DT.add_adjacent2vertex!(adj2v, 2, 7, 13) DT.add_adjacent2vertex!(adj2v, 13, 5, 23) @@ -188,4 +238,4 @@ end @test !isempty(get_adjacent2vertex(adj2v)) empty!(adj2v) @test isempty(get_adjacent2vertex(adj2v)) -end \ No newline at end of file +end diff --git a/test/data_structures/bst.jl b/test/data_structures/bst.jl index 638a39e13..c445c1d44 100644 --- a/test/data_structures/bst.jl +++ b/test/data_structures/bst.jl @@ -1,6 +1,6 @@ -using ..DelaunayTriangulation -using Test -using DataStructures +using ..DelaunayTriangulation +using Test +using DataStructures const DT = DelaunayTriangulation tree = DT.BalancedBST{Int}() @@ -24,8 +24,8 @@ end @test DT.inorder(tree) == __inorder(tree_avl) @test length(DT.inorder(tree)) == tree.count -tree = DT.BalancedBST{NTuple{2,Int}}() -tree_avl = AVLTree{NTuple{2,Int}}() +tree = DT.BalancedBST{NTuple{2, Int}}() +tree_avl = AVLTree{NTuple{2, Int}}() for _ in 1:100000 i = (rand(1:10000), rand(1:10000)) push!(tree, i) @@ -36,11 +36,11 @@ end @test DT.inorder(tree) == __inorder(tree_avl) @test length(DT.inorder(tree)) == tree.count inord = DT.inorder(tree) -for i in [inord; (0,0); (-1,-1);(-2,-2);(-3,-3)] +for i in [inord; (0, 0); (-1, -1);(-2, -2);(-3, -3)] delete!(tree, i) delete!(tree_avl, i) end @test tree.count == tree_avl.count @test DT.get_height(tree.root) == DataStructures.get_height(tree_avl.root) @test DT.inorder(tree) == __inorder(tree_avl) -@test length(DT.inorder(tree)) == tree.count \ No newline at end of file +@test length(DT.inorder(tree)) == tree.count diff --git a/test/data_structures/convex_hull.jl b/test/data_structures/convex_hull.jl index 140c4a9bf..07afff0a3 100644 --- a/test/data_structures/convex_hull.jl +++ b/test/data_structures/convex_hull.jl @@ -66,7 +66,7 @@ end end @testset "empty!" begin - tri = triangulate(rand(2,50)) + tri = triangulate(rand(2, 50)) ch = get_convex_hull(tri) @test !isempty(DT.get_vertices(ch)) empty!(ch) @@ -76,4 +76,4 @@ end @testset "Issue #109" begin points = rand(2, 50) @test convex_hull(points).vertices == convex_hull(vcat(points, points)).vertices -end \ No newline at end of file +end diff --git a/test/data_structures/curves.jl b/test/data_structures/curves.jl index 43b1c2955..c3e3c1c57 100644 --- a/test/data_structures/curves.jl +++ b/test/data_structures/curves.jl @@ -61,9 +61,9 @@ using ReferenceTests L = LineSegment(p, q) for t in LinRange(0, 1, 100) der1 = DT.differentiate(L, t) - h = 1e-8 + h = 1.0e-8 der2 = (L(t + h) .- L(t - h)) ./ (2h) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end @test DT.twice_differentiate(L, rand()) == (0.0, 0.0) @inferred DT.differentiate(L, rand()) @@ -74,10 +74,10 @@ using ReferenceTests ## Total variation TV = DT.total_variation(L) - @test TV ≈ 0.0 atol = 1e-6 + @test TV ≈ 0.0 atol = 1.0e-6 TV = DT.total_variation(L, 0.2, 0.5) - @test TV ≈ 0.0 atol = 1e-6 - @test TV ≈ slow_total_absolute_curvature(L, 0.2, 0.5) atol = 1e-3 + @test TV ≈ 0.0 atol = 1.0e-6 + @test TV ≈ slow_total_absolute_curvature(L, 0.2, 0.5) atol = 1.0e-3 ## Equidistant split t = DT.get_equidistant_split(L, 0, 1) @@ -186,21 +186,21 @@ end @test !DT.is_piecewise_linear(arc) @test !DT.is_interpolating(arc) @inferred CircularArc(p1, q1, center1) - negarc = CircularArc(p1, q1, center1, positive=false) + negarc = CircularArc(p1, q1, center1, positive = false) revarc = CircularArc(q1, p1, center1) - revnegarc = CircularArc(q1, p1, center1, positive=false) + revnegarc = CircularArc(q1, p1, center1, positive = false) center2 = (3.0, -5.0) p2 = (6.0, 5.0) circ = CircularArc(p2, p2, center2) - revcirc = CircularArc(p2, p2, center2, positive=false) + revcirc = CircularArc(p2, p2, center2, positive = false) @test arc.center == negarc.center == revarc.center == revnegarc.center == center1 @test circ.center == revcirc.center == center2 @test arc.radius == negarc.radius == revarc.radius == revnegarc.radius ≈ sqrt(41) @test circ.radius == revcirc.radius ≈ sqrt(109) - @test arc.start_angle ≈ 0.8960554793197029 rtol = 1e-6 - @test negarc.start_angle ≈ 0.8960554793197029 rtol = 1e-6 - @test arc.sector_angle ≈ deg2rad(167.3196155081802) rtol = 1e-6 - @test negarc.sector_angle ≈ deg2rad(167.3196155081802) - 2π rtol = 1e-6 + @test arc.start_angle ≈ 0.8960554793197029 rtol = 1.0e-6 + @test negarc.start_angle ≈ 0.8960554793197029 rtol = 1.0e-6 + @test arc.sector_angle ≈ deg2rad(167.3196155081802) rtol = 1.0e-6 + @test negarc.sector_angle ≈ deg2rad(167.3196155081802) - 2π rtol = 1.0e-6 @test arc.first == negarc.first == revarc.last == revnegarc.last == p1 @test arc.last == negarc.last == revarc.first == revnegarc.first == q1 @test circ.first == revcirc.first == circ.last == revcirc.last == p2 @@ -212,8 +212,8 @@ end ## Evaluation @test arc(0.0) ⪧ negarc(0.0) ⪧ revarc(1.0) ⪧ revnegarc(1.0) ⪧ p1 @test arc(1.0) ⪧ negarc(1.0) ⪧ revarc(0.0) ⪧ revnegarc(0.0) ⪧ q1 - @test arc(1e-16) ⪧ negarc(1e-16) ⪧ revarc(1 - 1e-16) ⪧ revnegarc(1 - 1e-16) ⪧ p1 - @test arc(1 - 1e-16) ⪧ negarc(1 - 1e-16) ⪧ revarc(1e-16) ⪧ revnegarc(1e-16) ⪧ q1 + @test arc(1.0e-16) ⪧ negarc(1.0e-16) ⪧ revarc(1 - 1.0e-16) ⪧ revnegarc(1 - 1.0e-16) ⪧ p1 + @test arc(1 - 1.0e-16) ⪧ negarc(1 - 1.0e-16) ⪧ revarc(1.0e-16) ⪧ revnegarc(1.0e-16) ⪧ q1 t = LinRange(0, 1, 500) θ₀_arc, θ₁_arc = arc.start_angle, arc.start_angle + arc.sector_angle @@ -295,9 +295,9 @@ end for c in (arc, negarc, revarc, revnegarc, circ, revcirc) for t in LinRange(0, 1, 100) der1 = DT.differentiate(c, t) - h = 1e-8 + h = 1.0e-8 der2 = (c(t + h) .- c(t - h)) ./ (2h) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -305,9 +305,9 @@ end for c in (arc, negarc, revarc, revnegarc, circ, revcirc) for t in LinRange(0, 1, 100) der1 = DT.twice_differentiate(c, t) - h = 1e-4 + h = 1.0e-4 der2 = (c(t + h) .- 2 .* c(t) .+ c(t - h)) ./ (h^2) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -320,7 +320,7 @@ end vec2 = [∂²x, ∂²y, 0.0] cur1 = DT.curvature(c, t) cur2 = cross(vec1, vec2)[3] / norm(vec1)^3 - @test cur1 ≈ cur2 rtol = 1e-5 atol = 1e-5 + @test cur1 ≈ cur2 rtol = 1.0e-5 atol = 1.0e-5 @test cur1 ≈ sign(c.sector_angle) / c.radius end end @@ -336,7 +336,7 @@ end TV = DT.total_variation(c, t1, t2) @inferred DT.total_variation(c, t1, t2) TVslow = slow_total_absolute_curvature(c, t1, t2) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-1 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-1 end end @@ -348,7 +348,7 @@ end t = DT.get_equidistant_split(c, t1, t2) s1 = DT.arc_length(c, t1, t) s2 = DT.arc_length(c, t, t2) - @test s1 ≈ s2 rtol = 1e-1 atol = 1e-1 + @test s1 ≈ s2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 @test DT.arc_length(c, t1, t2) ≈ 2s1 end @@ -362,7 +362,7 @@ end t, T = DT.get_equivariation_split(c, t1, t2) T1 = DT.total_variation(c, t1, t) T2 = DT.total_variation(c, t, t2) - @test T1 ≈ T2 rtol = 1e-1 atol = 1e-1 + @test T1 ≈ T2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 @test T ≈ T1 end @@ -386,12 +386,12 @@ end t₁, t₂, r = 0.0, 0.5, 0.5 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.22995991983967937 && q′ ⪧ (0.45551153816025436, -0.2057058712828833) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 c = CircularArc((0.0, 0.0), (0.0, 0.0), (0.5, 0.5)) t₁, t₂, r = 0.0, 0.5, 1.3 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.37124248496993983 && q′ ⪧ (1.2069097223005656, 0.48330735141035414) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 ## == @test arc ≠ negarc @@ -411,9 +411,9 @@ end @test !DT.is_piecewise_linear(arc) @test !DT.is_interpolating(arc) @inferred EllipticalArc(A, B, (Cx, Cy), Rx, Ry, s) - negarc = EllipticalArc(A, B, (Cx, Cy), Rx, Ry, s, positive=false) + negarc = EllipticalArc(A, B, (Cx, Cy), Rx, Ry, s, positive = false) revarc = EllipticalArc(B, A, (Cx, Cy), Rx, Ry, s) - revnegarc = EllipticalArc(B, A, (Cx, Cy), Rx, Ry, s, positive=false) + revnegarc = EllipticalArc(B, A, (Cx, Cy), Rx, Ry, s, positive = false) @test arc.center == negarc.center == revarc.center == revnegarc.center == (Cx, Cy) @test arc.first == negarc.first == revarc.last == revnegarc.last == A @test arc.last == negarc.last == revarc.first == revnegarc.first == B @@ -429,7 +429,7 @@ end @test revarc.sector_angle > 0 @test revnegarc.sector_angle < 0 closed_arc = EllipticalArc(A, A, (Cx, Cy), Rx, Ry, s) - revclosed_arc = EllipticalArc(A, A, (Cx, Cy), Rx, Ry, s, positive=false) + revclosed_arc = EllipticalArc(A, A, (Cx, Cy), Rx, Ry, s, positive = false) @test closed_arc.sector_angle ≈ 2π @test revclosed_arc.sector_angle ≈ -2π @test closed_arc.center == revclosed_arc.center == (Cx, Cy) @@ -440,12 +440,12 @@ end ## Evaluation @test arc(0.0) ⪧ negarc(0.0) ⪧ revarc(1.0) ⪧ revnegarc(1.0) ⪧ A @test arc(1.0) ⪧ negarc(1.0) ⪧ revarc(0.0) ⪧ revnegarc(0.0) ⪧ B - @test arc(1e-16) ⪧ negarc(1e-16) ⪧ revarc(1 - 1e-16) ⪧ revnegarc(1 - 1e-16) ⪧ A - @test arc(1 - 1e-16) ⪧ negarc(1 - 1e-16) ⪧ revarc(1e-16) ⪧ revnegarc(1e-16) ⪧ B + @test arc(1.0e-16) ⪧ negarc(1.0e-16) ⪧ revarc(1 - 1.0e-16) ⪧ revnegarc(1 - 1.0e-16) ⪧ A + @test arc(1 - 1.0e-16) ⪧ negarc(1 - 1.0e-16) ⪧ revarc(1.0e-16) ⪧ revnegarc(1.0e-16) ⪧ B @test closed_arc(0.0) ⪧ revclosed_arc(0.0) ⪧ A @test closed_arc(1.0) ⪧ revclosed_arc(1.0) ⪧ A - @test closed_arc(1e-16) ⪧ revclosed_arc(1e-16) ⪧ A - @test closed_arc(1 - 1e-16) ⪧ revclosed_arc(1 - 1e-16) ⪧ A + @test closed_arc(1.0e-16) ⪧ revclosed_arc(1.0e-16) ⪧ A + @test closed_arc(1 - 1.0e-16) ⪧ revclosed_arc(1 - 1.0e-16) ⪧ A arc1, arc2, arc3 = arc(0), arc(1 / 2), arc(1) negarc1, negarc2, negarc3 = negarc(0), negarc(1 / 2), negarc(1) revarc1, revarc2, revarc3 = revarc(0), revarc(1 / 2), revarc(1) @@ -544,9 +544,9 @@ end for c in (arc, negarc, revarc, revnegarc, closed_arc, revclosed_arc) for t in LinRange(0, 1, 100) der1 = DT.differentiate(c, t) - h = 1e-8 + h = 1.0e-8 der2 = (c(t + h) .- c(t - h)) ./ (2h) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -573,9 +573,9 @@ end for t in LinRange(0, 1, 100) der1 = DT.twice_differentiate(c, t) @inferred DT.twice_differentiate(c, t) - h = 1e-4 + h = 1.0e-4 der2 = (c(t + h) .- 2 .* c(t) .+ c(t - h)) ./ (h^2) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -588,7 +588,7 @@ end vec2 = [∂²x, ∂²y, 0.0] cur1 = DT.curvature(c, t) cur2 = cross(vec1, vec2)[3] / norm(vec1)^3 - @test cur1 ≈ cur2 rtol = 1e-5 atol = 1e-5 + @test cur1 ≈ cur2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -603,7 +603,7 @@ end TV = DT.total_variation(c, t1, t2) @inferred DT.total_variation(c, t1, t2) TVslow = slow_total_absolute_curvature(c, t1, t2) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-1 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-1 end end @@ -615,9 +615,9 @@ end t = DT.get_equidistant_split(c, t1, t2) s1 = DT.arc_length(c, t1, t) s2 = DT.arc_length(c, t, t2) - @test s1 ≈ s2 rtol = 1e-1 atol = 1e-1 + @test s1 ≈ s2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 - @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1e-1 + @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1.0e-1 end end @@ -629,9 +629,9 @@ end t, T = DT.get_equivariation_split(c, t1, t2) T1 = DT.total_variation(c, t1, t) T2 = DT.total_variation(c, t, t2) - @test T1 ≈ T2 rtol = 1e-1 atol = 1e-1 + @test T1 ≈ T2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 - @test T ≈ T1 rtol = 1e-1 atol = 1e-1 + @test T ≈ T1 rtol = 1.0e-1 atol = 1.0e-1 end end @@ -652,14 +652,14 @@ end Rx, Ry, Cx, Cy, s = 2.2, 2.75, 0.6, 0.65, 60.0 A, B = (-1.9827767129992, 1.4963893939715), (2.5063071261053, -1.2608915244961) c = EllipticalArc(A, B, (Cx, Cy), Rx, Ry, s) - t₁, t₂, r, = 0.2, 0.5, 0.8 + t₁, t₂, r = 0.2, 0.5, 0.8 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.32234468937857575 && q′ ⪧ (-1.489595166177109, -0.3863541400710244) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 - t₁, t₂, r, = 1.0, 0.5, 0.18889 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 + t₁, t₂, r = 1.0, 0.5, 0.18889 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.967434869739479 && q′ ⪧ (2.349597231970133, -1.368111418490932) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-2 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-2 ## == @test arc ≠ negarc @@ -678,7 +678,7 @@ end @test !DT.is_piecewise_linear(bezier) @test !DT.is_interpolating(bezier) @test bezier.control_points == control_points - @test typeof(bezier.cache) == Vector{NTuple{2,Float64}} && length(bezier.cache) == 5 + @test typeof(bezier.cache) == Vector{NTuple{2, Float64}} && length(bezier.cache) == 5 @test length(bezier.lookup_table) == 5000 for i in 1:5000 t = (i - 1) / 4999 @@ -687,8 +687,8 @@ end ## Evaluation @test bezier(0.0) ⪧ (0.0, 0.0) - @test bezier(1e-16) ⪧ (0.0, 0.0) atol = 1e-9 - @test bezier(1.0) ⪧ bezier(1 - 1e-16) ⪧ (1 / 2, 1 / 2) + @test bezier(1.0e-16) ⪧ (0.0, 0.0) atol = 1.0e-9 + @test bezier(1.0) ⪧ bezier(1 - 1.0e-16) ⪧ (1 / 2, 1 / 2) t = LinRange(0, 1, 1500) for t in t @test bezier(t) ⪧ slow_bezier_eval(control_points, t) @@ -699,7 +699,7 @@ end t = LinRange(0, 1, 1500) for t in t der1 = ForwardDiff.derivative(t -> slow_bezier_eval(control_points, t), t) - der2 = (bezier(t + 1e-6) .- bezier(t - 1e-6)) ./ (2 * 1e-6) + der2 = (bezier(t + 1.0e-6) .- bezier(t - 1.0e-6)) ./ (2 * 1.0e-6) der3 = DT.differentiate(bezier, t) @test der1 ⪧ der2 ⪧ der3 @inferred DT.differentiate(bezier, t) @@ -708,8 +708,8 @@ end ## Closest point invert(points) = let y = maximum(last.(points)) - return [(x, y - y′) for (x, y′) in points] - end # just to match my reference figure + return [(x, y - y′) for (x, y′) in points] + end # just to match my reference figure control_points = invert([(207.0, 65.0), (84.0, 97.0), (58.0, 196.0), (261.0, 130.0), (216.0, 217.0), (54.0, 122.0), (52.0, 276.0), (85.0, 330.0), (258.0, 334.0), (209.0, 286.0)]) for lookup_steps in (100, 500, 1000) if lookup_steps ≠ 500 @@ -725,16 +725,16 @@ end t′, q = DT.get_closest_point(bezier, p) @test q ⪧ bezier(t′) _t, _q = closest_point_on_curve(bezier, p) - @test _t ≈ t′ rtol = 1e-1 atol = 1e-1 - @test q ⪧ _q rtol = 1e-1 atol = 1e-1 - @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1e-1 atol = 1e-1 + @test _t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 + @test q ⪧ _q rtol = 1.0e-1 atol = 1.0e-1 + @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1.0e-1 atol = 1.0e-1 end for t in LinRange(0, 1, 150) p = bezier(t) t′, q = DT.get_closest_point(bezier, p) @test q ⪧ bezier(t′) - @test t ≈ t′ rtol = 1e-1 atol = 1e-1 - @test p ⪧ q rtol = 1e-1 atol = 1e-1 + @test t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 + @test p ⪧ q rtol = 1.0e-1 atol = 1.0e-1 end @test DT.get_closest_point(bezier, bezier(0.0))[1] == 0.0 @test DT.get_closest_point(bezier, bezier(1.0))[1] == 1.0 @@ -820,18 +820,18 @@ end bezier3 = BezierCurve(control_points3) bezier4 = BezierCurve(control_points4) for bezier in (bezier1, bezier2, bezier3, bezier4) - @test DT.arc_length(bezier) ≈ slow_arc_length(bezier, 0, 1) rtol = 1e-4 + @test DT.arc_length(bezier) ≈ slow_arc_length(bezier, 0, 1) rtol = 1.0e-4 @inferred DT.arc_length(bezier) @test DT.arc_length(bezier, 0.1, 0.15) ≈ slow_arc_length(bezier, 0.1, 0.15) @test DT.arc_length(bezier, 0.0, 0.0) ≈ 0.0 @test DT.arc_length(bezier, 1.0, 1.0) ≈ 0.0 - @test DT.arc_length(bezier, 0.0, 1.0) ≈ slow_arc_length(bezier, 0.0, 1.0) rtol = 1e-4 + @test DT.arc_length(bezier, 0.0, 1.0) ≈ slow_arc_length(bezier, 0.0, 1.0) rtol = 1.0e-4 @test DT.arc_length(bezier, 0.3, 0.9) ≈ slow_arc_length(bezier, 0.3, 0.9) @test DT.arc_length(bezier, 0.2, 0.21) ≈ slow_arc_length(bezier, 0.2, 0.21) for _ in 1:1000 t₁, t₂ = rand(2) t₁, t₂ = minmax(t₁, t₂) - @test DT.arc_length(bezier, t₁, t₂) ≈ slow_arc_length(bezier, t₁, t₂) rtol = 1e-2 + @test DT.arc_length(bezier, t₁, t₂) ≈ slow_arc_length(bezier, t₁, t₂) rtol = 1.0e-2 end end @@ -839,9 +839,9 @@ end for bezier in (bezier1, bezier2, bezier3, bezier4) for t in LinRange(0, 1, 1000) der1 = DT.twice_differentiate(bezier, t) - h = 1e-4 + h = 1.0e-4 der2 = (bezier(t + h) .- 2 .* bezier(t) .+ bezier(t - h)) ./ (h^2) - @test der1 ⪧ der2 rtol = 1e-5 atol = 1e-5 + @test der1 ⪧ der2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -849,10 +849,10 @@ end for bezier in (bezier1, bezier2, bezier3, bezier4) for t in LinRange(0, 1, 1000) der1 = DT.thrice_differentiate(bezier, t) - h = 1e-6 + h = 1.0e-6 f = t -> DT.twice_differentiate(bezier, t) der2 = (f(t + h) .- f(t - h)) ./ (2h) - @test der1 ⪧ der2 rtol = 1e-3 atol = 1e-3 + @test der1 ⪧ der2 rtol = 1.0e-3 atol = 1.0e-3 end end @@ -865,7 +865,7 @@ end vec2 = [∂²x, ∂²y, 0.0] cur1 = DT.curvature(c, t) cur2 = cross(vec1, vec2)[3] / norm(vec1)^3 - @test cur1 ≈ cur2 rtol = 1e-5 atol = 1e-5 + @test cur1 ≈ cur2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -931,14 +931,16 @@ end @test allt ≈ [0.0, 0.5, 1.0] @test allt == bezier.orientation_markers - control_points = [(-12.0, 5.0), (-9.77, 6.29), + control_points = [ + (-12.0, 5.0), (-9.77, 6.29), (-8.11, 4.55), (-7.47, 1.49), (-7.61, -1.29), (-9.63, -3.69), (-13.65, -4.37), (-15.65, -1.25), (-15.39, 0.93), (-14.17, 1.63), (-12.37, -0.93), (-13.51, -1.17), (-12.59, -2.39), (-10.6, -2.47), - (-9.19, 0.11), (-9.95, 2.79)] + (-9.19, 0.11), (-9.95, 2.79), + ] bezier = BezierCurve(control_points) tx = DT.horizontal_turning_points(bezier) ty = DT.vertical_turning_points(bezier) @@ -954,10 +956,12 @@ end @test allt ≈ sort([tx; ty; κx; κy; κ; 0.0; 1.0]) @test allt == bezier.orientation_markers - control_points = [(-12.0, -4.0), (-8.0, -8.0), (-4.0, -6.0), (-2.0, -4.0), + control_points = [ + (-12.0, -4.0), (-8.0, -8.0), (-4.0, -6.0), (-2.0, -4.0), (-6.0, 0.0), (-10.0, 4.0), (-14.0, 8.0), (-10.0, 12.0), (-4.0, 14.0), (4.0, 10.0), (0.0, 8.0), (-2.0, 6.0), (2.0, 4.0), (6.0, -2.0), (6.0, -8.0), (0.0, -12.0), (-10.0, -12.0), - (-18.0, -12.0), (-18.0, -2.0), (-18.0, -2.0), (-12.0, -4.0)] + (-18.0, -12.0), (-18.0, -2.0), (-18.0, -2.0), (-12.0, -4.0), + ] bezier = BezierCurve(control_points) tx = DT.horizontal_turning_points(bezier) ty = DT.vertical_turning_points(bezier) @@ -978,18 +982,22 @@ end control_points2 = invert([(207.0, 65.0), (84.0, 97.0), (58.0, 196.0), (261.0, 130.0), (216.0, 217.0), (54.0, 122.0), (52.0, 276.0), (85.0, 330.0), (258.0, 334.0), (209.0, 286.0)]) control_points3 = [(0.0, 0.0), (1.0, 1.0)] control_points4 = [(0.0, 0.0), (1 / 2, 1 / 2), (0.0, 1.0)] - control_points5 = [(-12.0, 5.0), (-9.77, 6.29), + control_points5 = [ + (-12.0, 5.0), (-9.77, 6.29), (-8.11, 4.55), (-7.47, 1.49), (-7.61, -1.29), (-9.63, -3.69), (-13.65, -4.37), (-15.65, -1.25), (-15.39, 0.93), (-14.17, 1.63), (-12.37, -0.93), (-13.51, -1.17), (-12.59, -2.39), (-10.6, -2.47), - (-9.19, 0.11), (-9.95, 2.79)] - control_points6 = [(-12.0, -4.0), (-8.0, -8.0), (-4.0, -6.0), (-2.0, -4.0), + (-9.19, 0.11), (-9.95, 2.79), + ] + control_points6 = [ + (-12.0, -4.0), (-8.0, -8.0), (-4.0, -6.0), (-2.0, -4.0), (-6.0, 0.0), (-10.0, 4.0), (-14.0, 8.0), (-10.0, 12.0), (-4.0, 14.0), (4.0, 10.0), (0.0, 8.0), (-2.0, 6.0), (2.0, 4.0), (6.0, -2.0), (6.0, -8.0), (0.0, -12.0), (-10.0, -12.0), - (-18.0, -12.0), (-18.0, -2.0), (-18.0, -2.0), (-12.0, -4.0)] # periodic + (-18.0, -12.0), (-18.0, -2.0), (-18.0, -2.0), (-12.0, -4.0), + ] # periodic control_points7 = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)] # periodic bezier1 = BezierCurve(control_points1) bezier2 = BezierCurve(control_points2) @@ -1003,13 +1011,13 @@ end TV = DT.total_variation(c) @inferred DT.total_variation(c) TVslow = slow_total_absolute_curvature(c, 0, 1) - @test TV ≈ TVslow rtol = 1e-3 atol = 1e-3 + @test TV ≈ TVslow rtol = 1.0e-3 atol = 1.0e-3 for _ in 1:1000 t1, t2 = minmax(rand(2)...) TV = DT.total_variation(c, t1, t2) @inferred DT.total_variation(c, t1, t2) TVslow = slow_total_absolute_curvature(c, t1, t2) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-1 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-1 end end @@ -1021,9 +1029,9 @@ end t = DT.get_equidistant_split(c, t1, t2) s1 = DT.arc_length(c, t1, t) s2 = DT.arc_length(c, t, t2) - @test s1 ≈ s2 rtol = 1e-2 atol = 1e-2 + @test s1 ≈ s2 rtol = 1.0e-2 atol = 1.0e-2 @test t1 ≤ t ≤ t2 - @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1e-1 + @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1.0e-1 end end @@ -1035,7 +1043,7 @@ end t, T = DT.get_equivariation_split(c, t1, t2) T1 = DT.total_variation(c, t1, t) T2 = DT.total_variation(c, t, t2) - @test T1 ≈ T2 rtol = 1e-1 atol = 1e-1 + @test T1 ≈ T2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 @test T ≈ T1 end @@ -1057,14 +1065,14 @@ end ## get_circle_intersection control_points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)] c = BezierCurve(control_points) - t₁, t₂, r, = 0.2, 0.5, 0.2 + t₁, t₂, r = 0.2, 0.5, 0.2 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.3019603920784157 && q′ ⪧ (0.6773887113970392, 0.34344590594423263) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 - t₁, t₂, r, = 1.0, 0.5, 0.6 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 + t₁, t₂, r = 1.0, 0.5, 0.6 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.7954590918183637 && q′ ⪧ (0.186063568848561, 0.5706424003210613) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-2 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-2 ## == ctrl1 = [(0.0, 0.0), (1.3, 1.5), (2.7, 5.3), (17.3, 5.2), (23.5, -0.5)] @@ -1081,7 +1089,7 @@ end @test !DT.is_piecewise_linear(spline) @test !DT.is_interpolating(spline) @test spline.control_points ⪧ control_points - @test typeof(spline.cache) == Vector{NTuple{2,Float64}} && length(spline.cache) == 4 + @test typeof(spline.cache) == Vector{NTuple{2, Float64}} && length(spline.cache) == 4 @test spline.knots == [0, 0, 0, 0, 1, 1, 1, 1] @test length(spline.lookup_table) == 5000 for i in 1:5000 @@ -1091,7 +1099,7 @@ end periodic_control_points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (1 / 2, 1 / 2), (0.0, 0.0)] periodic_spline = BSpline(periodic_control_points) @test periodic_spline.control_points ⪧ [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (1 / 2, 1 / 2), (0.0, 0.0)] - @test typeof(periodic_spline.cache) == Vector{NTuple{2,Float64}} && length(periodic_spline.cache) == 6 + @test typeof(periodic_spline.cache) == Vector{NTuple{2, Float64}} && length(periodic_spline.cache) == 6 @test periodic_spline.knots == [0, 0, 0, 0, 1, 2, 3, 3, 3, 3] @test length(periodic_spline.lookup_table) == 5000 for i in 1:5000 @@ -1099,9 +1107,9 @@ end end longer_control_points = [(0.3, 0.3), (0.5, -1.0), (2.0, 0.0), (2.5, 3.2), (-10.0, 10.0)] - longer_spline = BSpline(longer_control_points; lookup_steps=2500) + longer_spline = BSpline(longer_control_points; lookup_steps = 2500) @test longer_spline.control_points ⪧ longer_control_points - @test typeof(longer_spline.cache) == Vector{NTuple{2,Float64}} && length(longer_spline.cache) == 5 + @test typeof(longer_spline.cache) == Vector{NTuple{2, Float64}} && length(longer_spline.cache) == 5 @test longer_spline.knots == [0, 0, 0, 0, 1, 2, 2, 2, 2] @test length(longer_spline.lookup_table) == 2500 for i in 1:2500 @@ -1109,9 +1117,9 @@ end end quadratic_control_points = [(0.1, 0.1), (0.2, 0.2), (0.5, 0.8), (1.0, 2.0), (0.0, 15.0), (-5.0, 10.0), (-10.0, 0.0)] - quadratic_spline = BSpline(quadratic_control_points; degree=2) + quadratic_spline = BSpline(quadratic_control_points; degree = 2) @test quadratic_spline.control_points ⪧ quadratic_control_points - @test typeof(quadratic_spline.cache) == Vector{NTuple{2,Float64}} && length(quadratic_spline.cache) == 7 + @test typeof(quadratic_spline.cache) == Vector{NTuple{2, Float64}} && length(quadratic_spline.cache) == 7 @test quadratic_spline.knots == [0, 0, 0, 1, 2, 3, 4, 5, 5, 5] @test length(quadratic_spline.lookup_table) == 5000 for i in 1:5000 @@ -1119,9 +1127,9 @@ end end sextic_control_points = [(cos(t), sin(t)) for t in LinRange(0, π - π / 3, 10)] - sextic_spline = BSpline(sextic_control_points; degree=6) + sextic_spline = BSpline(sextic_control_points; degree = 6) @test sextic_spline.control_points ⪧ sextic_control_points - @test typeof(sextic_spline.cache) == Vector{NTuple{2,Float64}} && length(sextic_spline.cache) == 10 + @test typeof(sextic_spline.cache) == Vector{NTuple{2, Float64}} && length(sextic_spline.cache) == 10 @test sextic_spline.knots == [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4] @test length(sextic_spline.lookup_table) == 5000 for i in 1:5000 @@ -1130,9 +1138,9 @@ end quadratic_periodic_control_points = [(cos(t), sin(t)) for t in LinRange(0, 2π, 5)] quadratic_periodic_control_points[end] = quadratic_periodic_control_points[1] - quadratic_periodic_spline = BSpline(quadratic_periodic_control_points; degree=2) + quadratic_periodic_spline = BSpline(quadratic_periodic_control_points; degree = 2) @test quadratic_periodic_spline.control_points ⪧ quadratic_periodic_control_points - @test typeof(quadratic_periodic_spline.cache) == Vector{NTuple{2,Float64}} && length(quadratic_periodic_spline.cache) == 5 + @test typeof(quadratic_periodic_spline.cache) == Vector{NTuple{2, Float64}} && length(quadratic_periodic_spline.cache) == 5 @test quadratic_periodic_spline.knots == [0, 0, 0, 1, 2, 3, 3, 3] @test length(quadratic_periodic_spline.lookup_table) == 5000 for i in 1:5000 @@ -1152,28 +1160,28 @@ end @test spline(0.0) ⪧ control_points[begin] @test spline(1.0) ⪧ control_points[end] - @test spline(1e-16) ⪧ control_points[begin] atol = 1e-9 - @test spline(1 - 1e-16) ⪧ control_points[end] atol = 1e-9 + @test spline(1.0e-16) ⪧ control_points[begin] atol = 1.0e-9 + @test spline(1 - 1.0e-16) ⪧ control_points[end] atol = 1.0e-9 @test periodic_spline(0.0) ⪧ periodic_control_points[begin] @test periodic_spline(1.0) ⪧ periodic_control_points[end] - @test periodic_spline(1e-16) ⪧ periodic_control_points[begin] atol = 1e-9 - @test periodic_spline(1 - 1e-16) ⪧ periodic_control_points[end] atol = 1e-9 + @test periodic_spline(1.0e-16) ⪧ periodic_control_points[begin] atol = 1.0e-9 + @test periodic_spline(1 - 1.0e-16) ⪧ periodic_control_points[end] atol = 1.0e-9 @test longer_spline(0.0) ⪧ longer_control_points[begin] @test longer_spline(1.0) ⪧ longer_control_points[end] - @test longer_spline(1e-16) ⪧ longer_control_points[begin] atol = 1e-9 - @test longer_spline(1 - 1e-16) ⪧ longer_control_points[end] atol = 1e-9 + @test longer_spline(1.0e-16) ⪧ longer_control_points[begin] atol = 1.0e-9 + @test longer_spline(1 - 1.0e-16) ⪧ longer_control_points[end] atol = 1.0e-9 @test quadratic_spline(0.0) ⪧ quadratic_control_points[begin] @test quadratic_spline(1.0) ⪧ quadratic_control_points[end] - @test quadratic_spline(1e-16) ⪧ quadratic_control_points[begin] atol = 1e-9 - @test quadratic_spline(1 - 1e-16) ⪧ quadratic_control_points[end] atol = 1e-9 + @test quadratic_spline(1.0e-16) ⪧ quadratic_control_points[begin] atol = 1.0e-9 + @test quadratic_spline(1 - 1.0e-16) ⪧ quadratic_control_points[end] atol = 1.0e-9 @test sextic_spline(0.0) ⪧ sextic_control_points[begin] @test sextic_spline(1.0) ⪧ sextic_control_points[end] - @test sextic_spline(1e-16) ⪧ sextic_control_points[begin] atol = 1e-9 - @test sextic_spline(1 - 1e-16) ⪧ sextic_control_points[end] atol = 1e-9 + @test sextic_spline(1.0e-16) ⪧ sextic_control_points[begin] atol = 1.0e-9 + @test sextic_spline(1 - 1.0e-16) ⪧ sextic_control_points[end] atol = 1.0e-9 @test quadratic_periodic_spline(0.0) ⪧ quadratic_periodic_control_points[begin] @test quadratic_periodic_spline(1.0) ⪧ quadratic_periodic_control_points[end] - @test quadratic_periodic_spline(1e-16) ⪧ quadratic_periodic_control_points[begin] atol = 1e-9 - @test quadratic_periodic_spline(1 - 1e-16) ⪧ quadratic_periodic_control_points[end] atol = 1e-9 + @test quadratic_periodic_spline(1.0e-16) ⪧ quadratic_periodic_control_points[begin] atol = 1.0e-9 + @test quadratic_periodic_spline(1 - 1.0e-16) ⪧ quadratic_periodic_control_points[end] atol = 1.0e-9 t = 0:0.1:1 spline_t = [ @@ -1187,7 +1195,7 @@ end [15.4883, 17.471899999999998], [16.471200000000003, 18.6896], [17.0869, 18.745700000000003], - [17.3, 17.3] + [17.3, 17.3], ] periodic_spline_t = [ [0, 0], @@ -1200,7 +1208,7 @@ end [0.286875, 0.8336250000000002], [0.315, 0.657], [0.2756250000000001, 0.3858750000000003], - [6.661338147750935e-16, 6.661338147750937e-16] + [6.661338147750935e-16, 6.661338147750937e-16], ] longer_spline_t = [ [0.3, 0.3], @@ -1213,7 +1221,7 @@ end [1.4300000000000004, 2.3716], [-0.3199999999999982, 4.038399999999999], [-3.929999999999996, 6.506799999999997], - [-9.999999999999995, 9.999999999999995] + [-9.999999999999995, 9.999999999999995], ] quadratic_spline_t = [ [0.1, 0.1], @@ -1226,7 +1234,7 @@ end [-0.5, 12.75], [-2.4999999999999982, 12.500000000000004], [-5.625, 8.125], - [-9.999999999999991, 1.7763568394002498e-14] + [-9.999999999999991, 1.7763568394002498e-14], ] sextic_spline_t = [ [1, 0], @@ -1239,7 +1247,7 @@ end [0.2246521007365532, 0.9523458140503687], [0.0622718120248865, 0.9784464185342435], [-0.1472786929037561, 0.9723545852185906], - [-0.49999999999999956, 0.8660254037844393] + [-0.49999999999999956, 0.8660254037844393], ] quadratic_periodic_spline_t = [ [1, 0], @@ -1252,7 +1260,7 @@ end [-0.3950000000000005, -0.5849999999999997], [-0.02000000000000024, -0.66], [0.44499999999999945, -0.4650000000000003], - [0.9999999999999991, -8.881784197001249e-16] + [0.9999999999999991, -8.881784197001249e-16], ] @test spline.(t) ⪧ spline_t @test periodic_spline.(t) ⪧ periodic_spline_t @@ -1268,10 +1276,10 @@ end t = LinRange(0, 1, 25000) f = tuple.(sin.(π .* t), cos.(π .* t)) spl = BSpline(f) - for t in t[3:end-2] - @test spl(t) ⪧ (sin(π * t), cos(π * t)) rtol = 1e-2 + for t in t[3:(end - 2)] + @test spl(t) ⪧ (sin(π * t), cos(π * t)) rtol = 1.0e-2 der = DT.differentiate(spl, t) - @test ⪧(der, (π * cos(π * t), -π * sin(π * t)); atol=1e-2) + @test ⪧(der, (π * cos(π * t), -π * sin(π * t)); atol = 1.0e-2) end t = LinRange(0, 1, 25000) @@ -1279,10 +1287,10 @@ end f[end] = f[begin] spl = BSpline(f) ctr = 0 - for t in t[3:end-2] - @test spl(t) ⪧ (sin(2π * t), cos(2π * t)) rtol = 1e-2 + for t in t[3:(end - 2)] + @test spl(t) ⪧ (sin(2π * t), cos(2π * t)) rtol = 1.0e-2 der = DT.differentiate(spl, t) - @test ⪧(der, (2π * cos(2π * t), -2π * sin(2π * t)); atol=1e-2) + @test ⪧(der, (2π * cos(2π * t), -2π * sin(2π * t)); atol = 1.0e-2) end t = LinRange(0, 1, 1500) @@ -1291,7 +1299,7 @@ end der1 = ForwardDiff.derivative(t -> slow_eval_bspline(spl.control_points, spl.knots, t), t) der2 = DT.differentiate(spl, t) @inferred DT.differentiate(spl, t) - h = 1e-4 + h = 1.0e-4 if h < t < 1 - h der3 = (spl(t + h) .- spl(t - h)) ./ (2h) elseif t < h @@ -1299,8 +1307,8 @@ end else der3 = (spl(t) .- spl(t - h)) ./ h end - flag1 = ⪧(der1, der2, rtol=1e-6, atol=1e-6) - flag2 = ⪧(der2, der3, rtol=1e-3, atol=1e-6) + flag1 = ⪧(der1, der2, rtol = 1.0e-6, atol = 1.0e-6) + flag2 = ⪧(der2, der3, rtol = 1.0e-3, atol = 1.0e-6) @test flag1 || flag2 end end @@ -1310,7 +1318,7 @@ end for t in LinRange(0, 1, 1500) der1 = DT.twice_differentiate(spl, t) @inferred DT.twice_differentiate(spl, t) - h = 1e-6 + h = 1.0e-6 if 3h < t < 1 - 3h der2 = (spl(t + h) .- 2 .* spl(t) .+ spl(t - h)) ./ (h^2) elseif t < 3h @@ -1320,16 +1328,16 @@ end # h = 1e-2 der2 = (2.0 .* spl(t) .- 5.0 .* spl(t - h) .+ 4.0 .* spl(t - 2h) .- spl(t - 3h)) ./ h^2 end - @test der1 ⪧ der2 rtol = 1e-1 atol = 1e-1 + @test der1 ⪧ der2 rtol = 1.0e-1 atol = 1.0e-1 end end t = LinRange(0, 1, 25000) f = tuple.(sin.(π .* t), cos.(π .* t)) spl = BSpline(f) - for t in t[4:end-4] + for t in t[4:(end - 4)] der = DT.twice_differentiate(spl, t) - @test ⪧(der, (-π^2 * sin(π * t), -π^2 * cos(π * t)); atol=1e-2) + @test ⪧(der, (-π^2 * sin(π * t), -π^2 * cos(π * t)); atol = 1.0e-2) end ## Thrice differentiate @@ -1340,7 +1348,7 @@ end der1 = _der1(t) der2 = DT.thrice_differentiate(spl, t) @inferred DT.thrice_differentiate(spl, t) - h = 1e-4 + h = 1.0e-4 if h < t < 1 - h der3 = (DT.twice_differentiate(spl, t + h) .- DT.twice_differentiate(spl, t - h)) ./ (2h) elseif t < h @@ -1348,8 +1356,8 @@ end else der3 = (DT.twice_differentiate(spl, t) .- DT.twice_differentiate(spl, t - h)) ./ h end - flag1 = ⪧(der1, der2, rtol=1e-6, atol=1e-6) - flag2 = ⪧(der2, der3, rtol=1e-3, atol=1e-6) + flag1 = ⪧(der1, der2, rtol = 1.0e-6, atol = 1.0e-6) + flag2 = ⪧(der2, der3, rtol = 1.0e-3, atol = 1.0e-6) @test flag1 || flag2 end end @@ -1357,9 +1365,9 @@ end t = LinRange(0, 1, 2500) f = tuple.(sin.(π .* t), cos.(π .* t)) spl = BSpline(f) - for t in t[4:end-4] + for t in t[4:(end - 4)] der = DT.thrice_differentiate(spl, t) - @test ⪧(der, (-π^3 * cos(π * t), π^3 * sin(π * t)); atol=1e-2, rtol=1e-2) + @test ⪧(der, (-π^3 * cos(π * t), π^3 * sin(π * t)); atol = 1.0e-2, rtol = 1.0e-2) end ## Closest point @@ -1370,23 +1378,23 @@ end @test q ⪧ spl(t′) _t, _q = closest_point_on_curve(spl, p) if !(spl == periodic_spline || spl == quadratic_periodic_spline) - @test _t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test _t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 elseif t ≠ 0 && t ≠ 1 - @test _t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test _t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 end - @test q ⪧ _q rtol = 1e-1 atol = 1e-1 - @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1e-1 atol = 1e-1 + @test q ⪧ _q rtol = 1.0e-1 atol = 1.0e-1 + @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1.0e-1 atol = 1.0e-1 end for t in LinRange(0, 1, 150) p = spl(t) t′, q = DT.get_closest_point(spl, p) @test q ⪧ spl(t′) if !(spl == periodic_spline || spl == quadratic_periodic_spline) - @test t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 elseif t ≠ 0 && t ≠ 1 - @test t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 end - @test p ⪧ q rtol = 1e-1 atol = 1e-1 + @test p ⪧ q rtol = 1.0e-1 atol = 1.0e-1 end @test DT.get_closest_point(spl, spl(0.0)) == (0.0, spl(0.0)) if spl ∉ (periodic_spline, quadratic_periodic_spline) @@ -1546,18 +1554,18 @@ end ## Arclength for spl in (spline, periodic_spline, longer_spline, quadratic_spline, sextic_spline, quadratic_periodic_spline) - @test DT.arc_length(spl) ≈ slow_arc_length(spl, 0, 1) rtol = 1e-4 + @test DT.arc_length(spl) ≈ slow_arc_length(spl, 0, 1) rtol = 1.0e-4 @inferred DT.arc_length(spl) - @test DT.arc_length(spl, 0.1, 0.15) ≈ slow_arc_length(spl, 0.1, 0.15) rtol = 1e-4 + @test DT.arc_length(spl, 0.1, 0.15) ≈ slow_arc_length(spl, 0.1, 0.15) rtol = 1.0e-4 @test DT.arc_length(spl, 0.0, 0.0) ≈ 0.0 @test DT.arc_length(spl, 1.0, 1.0) ≈ 0.0 - @test DT.arc_length(spl, 0.0, 1.0) ≈ slow_arc_length(spl, 0.0, 1.0) rtol = 1e-3 - @test DT.arc_length(spl, 0.3, 0.9) ≈ slow_arc_length(spl, 0.3, 0.9) rtol = 1e-3 - @test DT.arc_length(spl, 0.2, 0.21) ≈ slow_arc_length(spl, 0.2, 0.21) rtol = 1e-4 + @test DT.arc_length(spl, 0.0, 1.0) ≈ slow_arc_length(spl, 0.0, 1.0) rtol = 1.0e-3 + @test DT.arc_length(spl, 0.3, 0.9) ≈ slow_arc_length(spl, 0.3, 0.9) rtol = 1.0e-3 + @test DT.arc_length(spl, 0.2, 0.21) ≈ slow_arc_length(spl, 0.2, 0.21) rtol = 1.0e-4 for _ in 1:1000 t₁, t₂ = rand(2) t₁, t₂ = minmax(t₁, t₂) - @test DT.arc_length(spl, t₁, t₂) ≈ slow_arc_length(spl, t₁, t₂) rtol = 1e-2 + @test DT.arc_length(spl, t₁, t₂) ≈ slow_arc_length(spl, t₁, t₂) rtol = 1.0e-2 end end @@ -1570,7 +1578,7 @@ end vec2 = [∂²x, ∂²y, 0.0] cur1 = DT.curvature(c, t) cur2 = cross(vec1, vec2)[3] / norm(vec1)^3 - @test cur1 ≈ cur2 rtol = 1e-5 atol = 1e-5 + @test cur1 ≈ cur2 rtol = 1.0e-5 atol = 1.0e-5 end end @@ -1580,13 +1588,13 @@ end TV = DT.total_variation(c) @inferred DT.total_variation(c) TVslow = slow_total_absolute_curvature(c, 0, 1) - @test TV ≈ TVslow rtol = 1e-3 atol = 1e-3 + @test TV ≈ TVslow rtol = 1.0e-3 atol = 1.0e-3 for _ in 1:1000 t1, t2 = minmax(rand(2)...) TV = DT.total_variation(c, t1, t2) @inferred DT.total_variation(c, t1, t2) TVslow = slow_total_absolute_curvature(c, t1, t2) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-1 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-1 end end @@ -1598,9 +1606,9 @@ end t = DT.get_equidistant_split(c, t1, t2) s1 = DT.arc_length(c, t1, t) s2 = DT.arc_length(c, t, t2) - @test s1 ≈ s2 rtol = 1e-1 atol = 1e-1 + @test s1 ≈ s2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 - @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1e-1 + @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1.0e-1 end end @@ -1612,7 +1620,7 @@ end t, T = DT.get_equivariation_split(c, t1, t2) T1 = DT.total_variation(c, t1, t) T2 = DT.total_variation(c, t, t2) - @test T1 ≈ T2 rtol = 1e-1 atol = 1e-1 + @test T1 ≈ T2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 @test T ≈ T1 end @@ -1632,18 +1640,18 @@ end ## get_circle_intersection c = sextic_spline - t₁, t₂, r, = 0.0, 1.0, 1.0 + t₁, t₂, r = 0.0, 1.0, 1.0 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.5096019203840768 && q′ ⪧ (0.47649648275716505, 0.8518859813755716) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 - t₁, t₂, r, = 1.0, 0.0, 1.0 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 + t₁, t₂, r = 1.0, 0.0, 1.0 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.49019803960792163 && q′ ⪧ (0.4997446106449962, 0.8384596166783065) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-2 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-2 t₁, t₂, r = 0.0, 0.1, 0.2 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.04410882176435287 && q′ ⪧ (0.9666126168475349, 0.1970440391610145) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-2 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-2 ## == @test spline == spline @@ -1657,7 +1665,7 @@ end ctrl1 = [(0.0, 1.3), (17.3, 5.0), (-1.0, 2.0), (50.0, 23.0), (17.3, -2.0), (27.3, 50.1)] ctrl2 = [(5.3, 1.3), (17.5, 23.0), (17.3, 200.0), (173.0, 1.3), (0.0, 0.0)] @test BSpline(ctrl1) == BSpline(ctrl1) - @test BSpline(ctrl1) ≠ BSpline(ctrl1, degree=2) + @test BSpline(ctrl1) ≠ BSpline(ctrl1, degree = 2) @test BSpline(ctrl1) ≠ BSpline(ctrl2) end @@ -1684,12 +1692,12 @@ end end end t = LinRange(0, 1, 1500) - fig = Figure(fontsize=44) + fig = Figure(fontsize = 44) for i in 1:3 for j in 1:3 - ax = Axis(fig[i, j], xlabel=L"x", ylabel=L"y", title=L"α = %$(α[i]), τ = %$(τ[j])", titlealign=:left, width=400, height=400) - lines!(ax, spl[i, j].(t), color=:blue, linewidth=6) - scatter!(ax, [p₀, p₁, p₂, p₃], color=[:blue, :black, :red, :green], markersize=16) + ax = Axis(fig[i, j], xlabel = L"x", ylabel = L"y", title = L"α = %$(α[i]), τ = %$(τ[j])", titlealign = :left, width = 400, height = 400) + lines!(ax, spl[i, j].(t), color = :blue, linewidth = 6) + scatter!(ax, [p₀, p₁, p₂, p₃], color = [:blue, :black, :red, :green], markersize = 16) end end resize_to_layout!(fig) @@ -1701,7 +1709,7 @@ end for t in LinRange(0, 1, 15000) @test DT.differentiate(_spl, t) ⪧ 3.0 .* _spl.a .* t^2 .+ 2.0 .* _spl.b .* t .+ _spl.c @inferred DT.differentiate(_spl, t) - @test DT.differentiate(_spl, t) ⪧ (_spl(t + 1e-6) .- _spl(t - 1e-6)) ./ 2e-6 atol = 1e-4 rtol = 1e-4 + @test DT.differentiate(_spl, t) ⪧ (_spl(t + 1.0e-6) .- _spl(t - 1.0e-6)) ./ 2.0e-6 atol = 1.0e-4 rtol = 1.0e-4 @test DT.twice_differentiate(_spl, t) ⪧ 6.0 .* _spl.a .* t .+ 2.0 .* _spl.b @inferred DT.twice_differentiate(_spl, t) @test DT.thrice_differentiate(_spl, t) ⪧ 6.0 .* _spl.a @@ -1714,62 +1722,62 @@ end p₁, p₂, p₃, p₄, x = (2.571, 4.812), (2.05, 17.81), (17.3, -25.3), (0.5, 0.3), 10.0 perms_1234 = [ - 4 3 2 1 - 4 3 1 2 - 4 2 3 1 - 4 2 1 3 - 4 1 3 2 - 4 1 2 3 - 3 4 2 1 - 3 4 1 2 - 3 2 4 1 - 3 2 1 4 - 3 1 4 2 - 3 1 2 4 - 2 4 3 1 - 2 4 1 3 - 2 3 4 1 - 2 3 1 4 - 2 1 4 3 - 2 1 3 4 - 1 4 3 2 - 1 4 2 3 - 1 3 4 2 - 1 3 2 4 - 1 2 4 3 - 1 2 3 4 - ] + 4 3 2 1 + 4 3 1 2 + 4 2 3 1 + 4 2 1 3 + 4 1 3 2 + 4 1 2 3 + 3 4 2 1 + 3 4 1 2 + 3 2 4 1 + 3 2 1 4 + 3 1 4 2 + 3 1 2 4 + 2 4 3 1 + 2 4 1 3 + 2 3 4 1 + 2 3 1 4 + 2 1 4 3 + 2 1 3 4 + 1 4 3 2 + 1 4 2 3 + 1 3 4 2 + 1 3 2 4 + 1 2 4 3 + 1 2 3 4 + ] th4 = [DT.thiele4((p₁, p₂, p₃, p₄)[[i, j, k, ℓ]]..., x)[1] for (i, j, k, ℓ) in eachrow(perms_1234)] th3 = [DT.thiele3((p₁, p₂, p₃, p₄)[[i, j, k]]..., x)[1] for (i, j, k, ℓ) in eachrow(perms_1234)] quad = [DT.quadratic_interp((p₁, p₂, p₃, p₄)[[i, j, k]]..., x)[1] for (i, j, k, ℓ) in eachrow(perms_1234)] th4th3quad = [ - -12.5908 -31.3945 44.1259 - -12.5908 -91.4788 3.2565 - -12.5908 -31.3945 44.1259 - -12.5908 1.95457 -1214.16 - -12.5908 -91.4788 3.2565 - -12.5908 1.95457 -1214.16 - -12.5908 -31.3945 44.1259 - -12.5908 -91.4788 3.2565 - -12.5908 -31.3945 44.1259 - -12.5908 -22.2832 -91.8257 - -12.5908 -91.4788 3.2565 - -12.5908 -22.2832 -91.8257 - -12.5908 -31.3945 44.1259 - -12.5908 1.95457 -1214.16 - -12.5908 -31.3945 44.1259 - -12.5908 -22.2832 -91.8257 - -12.5908 1.95457 -1214.16 - -12.5908 -22.2832 -91.8257 - -12.5908 -91.4788 3.2565 - -12.5908 1.95457 -1214.16 - -12.5908 -91.4788 3.2565 - -12.5908 -22.2832 -91.8257 - -12.5908 1.95457 -1214.16 - -12.5908 -22.2832 -91.8257 - ] - @test [th4 th3 quad] ≈ th4th3quad rtol = 1e-5 + -12.5908 -31.3945 44.1259 + -12.5908 -91.4788 3.2565 + -12.5908 -31.3945 44.1259 + -12.5908 1.95457 -1214.16 + -12.5908 -91.4788 3.2565 + -12.5908 1.95457 -1214.16 + -12.5908 -31.3945 44.1259 + -12.5908 -91.4788 3.2565 + -12.5908 -31.3945 44.1259 + -12.5908 -22.2832 -91.8257 + -12.5908 -91.4788 3.2565 + -12.5908 -22.2832 -91.8257 + -12.5908 -31.3945 44.1259 + -12.5908 1.95457 -1214.16 + -12.5908 -31.3945 44.1259 + -12.5908 -22.2832 -91.8257 + -12.5908 1.95457 -1214.16 + -12.5908 -22.2832 -91.8257 + -12.5908 -91.4788 3.2565 + -12.5908 1.95457 -1214.16 + -12.5908 -91.4788 3.2565 + -12.5908 -22.2832 -91.8257 + -12.5908 1.95457 -1214.16 + -12.5908 -22.2832 -91.8257 + ] + @test [th4 th3 quad] ≈ th4th3quad rtol = 1.0e-5 control_points = [(-9.0, 5.0), (-7.0, 6.0), (-6.0, 4.0), (-3.0, 5.0)] periodic_control_points = [(-2.0, -2.0), (0.0, 0.0), (15.0, 0.0), (13.7, 5.3), (-10.0, 0.0), (-2.0, -2.0)] @@ -1808,16 +1816,16 @@ end alpha = 1 / 2 tension = 0.0 else - spl = CatmullRomSpline(control_points; lookup_steps, _alpha=alpha, _tension=tension) - pspl = CatmullRomSpline(periodic_control_points; lookup_steps, _alpha=alpha, _tension=tension) + spl = CatmullRomSpline(control_points; lookup_steps, _alpha = alpha, _tension = tension) + pspl = CatmullRomSpline(periodic_control_points; lookup_steps, _alpha = alpha, _tension = tension) end knots = zeros(4) pknots = zeros(6) for i in 2:4 - knots[i] = knots[i-1] + norm(control_points[i] .- control_points[i-1])^alpha + knots[i] = knots[i - 1] + norm(control_points[i] .- control_points[i - 1])^alpha end for i in 2:6 - pknots[i] = pknots[i-1] + norm(periodic_control_points[i] .- periodic_control_points[i-1])^alpha + pknots[i] = pknots[i - 1] + norm(periodic_control_points[i] .- periodic_control_points[i - 1])^alpha end left = DT.extend_left_control_point(control_points) right = DT.extend_right_control_point(control_points) @@ -1825,8 +1833,8 @@ end pright = DT.extend_right_control_point(periodic_control_points) knots ./= knots[end] pknots ./= pknots[end] - lookup_table = Vector{NTuple{2,Float64}}(undef, lookup_steps) - plookup_table = Vector{NTuple{2,Float64}}(undef, lookup_steps) + lookup_table = Vector{NTuple{2, Float64}}(undef, lookup_steps) + plookup_table = Vector{NTuple{2, Float64}}(undef, lookup_steps) for i in 1:lookup_steps t = (i - 1) / (lookup_steps - 1) lookup_table[i] = spl(t) @@ -1856,10 +1864,10 @@ end spl = CatmullRomSpline(control_points) pspl = CatmullRomSpline(periodic_control_points) @test DT.is_curve_bounded(spl) - @test spl(0) ⪧ spl(1e-16) ⪧ (-9.0, 5.0) - @test spl(1) ⪧ spl(1 - 1e-16) ⪧ (-9.0, 10.0) - @test pspl(0) ⪧ pspl(1e-16) ⪧ (-2.0, -2.0) - @test pspl(1) ⪧ pspl(1 - 1e-16) ⪧ (-2.0, -2.0) + @test spl(0) ⪧ spl(1.0e-16) ⪧ (-9.0, 5.0) + @test spl(1) ⪧ spl(1 - 1.0e-16) ⪧ (-9.0, 10.0) + @test pspl(0) ⪧ pspl(1.0e-16) ⪧ (-2.0, -2.0) + @test pspl(1) ⪧ pspl(1 - 1.0e-16) ⪧ (-2.0, -2.0) t_vals = LinRange(0.01, 0.99, 50) splt = spl.(t_vals) psplt = pspl.(t_vals) @@ -1915,7 +1923,7 @@ end (-4.82247, 10.6957) (-4.20389, -1.96817) (-6.61471, 10.3812) (-3.16042, -2.07246) (-8.25906, 10.1109) (-2.31858, -2.05861) - ] rtol = 1e-5 + ] rtol = 1.0e-5 for spl in (spl, pspl) for (i, t) in enumerate(spl.knots) @test spl(t) ⪧ spl.control_points[i] @@ -1928,7 +1936,7 @@ end for t in t der1 = DT.differentiate(spl, t) @inferred DT.differentiate(spl, t) - h = 1e-6 + h = 1.0e-6 if h < t < 1 - h der2 = (spl(t + h) .- spl(t - h)) ./ (2h) elseif t < h @@ -1936,7 +1944,7 @@ end else der2 = (spl(t) .- spl(t - h)) ./ h end - @test der1 ⪧ der2 rtol = 1e-4 atol = 1e-4 + @test der1 ⪧ der2 rtol = 1.0e-4 atol = 1.0e-4 end end @@ -1946,7 +1954,7 @@ end for t in t der1 = DT.twice_differentiate(spl, t) @inferred DT.twice_differentiate(spl, t) - h = 1e-6 + h = 1.0e-6 if 3h < t < 1 - 3h der2 = (spl(t + h) .- 2 .* spl(t) .+ spl(t - h)) ./ (h^2) elseif t < 3h @@ -1956,7 +1964,7 @@ end # h = 1e-2 der2 = (2.0 .* spl(t) .- 5.0 .* spl(t - h) .+ 4.0 .* spl(t - 2h) .- spl(t - 3h)) ./ h^2 end - @test der1 ⪧ der2 rtol = 1e-1 atol = 1e-1 + @test der1 ⪧ der2 rtol = 1.0e-1 atol = 1.0e-1 end end @@ -1964,7 +1972,7 @@ end t = LinRange(0, 1, 15000) for spl in (spl, pspl) for t in t - h = 1e-6 + h = 1.0e-6 der1 = DT.thrice_differentiate(spl, t) @inferred DT.thrice_differentiate(spl, t) if h < t < 1 - h @@ -1974,7 +1982,7 @@ end else der2 = (DT.twice_differentiate(spl, t) .- DT.twice_differentiate(spl, t - h)) ./ h end - @test der1 ⪧ der2 rtol = 1e-4 atol = 1e-4 + @test der1 ⪧ der2 rtol = 1.0e-4 atol = 1.0e-4 end end @@ -1987,23 +1995,23 @@ end @test q ⪧ spl(t′) _t, _q = closest_point_on_curve(spl, p) if !(spl == pspl) - @test _t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test _t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 elseif t ≠ 0 && t ≠ 1 && t′ ≠ 0 && t′ ≠ 1 - @test _t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test _t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 end - @test q ⪧ _q rtol = 1e-1 atol = 1e-1 - @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1e-1 atol = 1e-1 + @test q ⪧ _q rtol = 1.0e-1 atol = 1.0e-1 + @test DT.dist(p, _q) ≈ DT.dist(p, q) rtol = 1.0e-1 atol = 1.0e-1 end for t in LinRange(0, 1, 150) p = spl(t) t′, q = DT.get_closest_point(spl, p) @test q ⪧ spl(t′) if !(spl == pspl) - @test t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 elseif t ≠ 0 && t ≠ 1 - @test t ≈ t′ rtol = 1e-1 atol = 1e-1 + @test t ≈ t′ rtol = 1.0e-1 atol = 1.0e-1 end - @test p ⪧ q rtol = 1e-1 atol = 1e-1 + @test p ⪧ q rtol = 1.0e-1 atol = 1.0e-1 end @test DT.get_closest_point(spl, spl.control_points[1]) == (0.0, spl.control_points[1]) if spl ≠ pspl @@ -2088,18 +2096,18 @@ end ## Arclength for spl in (spl, pspl) - @test DT.arc_length(spl) ≈ slow_arc_length(spl, 0, 1) rtol = 1e-4 + @test DT.arc_length(spl) ≈ slow_arc_length(spl, 0, 1) rtol = 1.0e-4 @inferred DT.arc_length(spl) - @test DT.arc_length(spl, 0.1, 0.15) ≈ slow_arc_length(spl, 0.1, 0.15) rtol = 1e-4 + @test DT.arc_length(spl, 0.1, 0.15) ≈ slow_arc_length(spl, 0.1, 0.15) rtol = 1.0e-4 @test DT.arc_length(spl, 0.0, 0.0) ≈ 0.0 @test DT.arc_length(spl, 1.0, 1.0) ≈ 0.0 - @test DT.arc_length(spl, 0.0, 1.0) ≈ slow_arc_length(spl, 0.0, 1.0) rtol = 1e-3 - @test DT.arc_length(spl, 0.3, 0.9) ≈ slow_arc_length(spl, 0.3, 0.9) rtol = 1e-3 - @test DT.arc_length(spl, 0.2, 0.21) ≈ slow_arc_length(spl, 0.2, 0.21) rtol = 1e-4 + @test DT.arc_length(spl, 0.0, 1.0) ≈ slow_arc_length(spl, 0.0, 1.0) rtol = 1.0e-3 + @test DT.arc_length(spl, 0.3, 0.9) ≈ slow_arc_length(spl, 0.3, 0.9) rtol = 1.0e-3 + @test DT.arc_length(spl, 0.2, 0.21) ≈ slow_arc_length(spl, 0.2, 0.21) rtol = 1.0e-4 for _ in 1:1000 t₁, t₂ = rand(2) t₁, t₂ = minmax(t₁, t₂) - @test DT.arc_length(spl, t₁, t₂) ≈ slow_arc_length(spl, t₁, t₂) rtol = 1e-2 + @test DT.arc_length(spl, t₁, t₂) ≈ slow_arc_length(spl, t₁, t₂) rtol = 1.0e-2 end end @@ -2112,7 +2120,7 @@ end vec2 = [∂²x, ∂²y, 0.0] cur1 = DT.curvature(c, t) cur2 = cross(vec1, vec2)[3] / norm(vec1)^3 - @test cur1 ≈ cur2 rtol = 1e-5 atol = 1e-5 + @test cur1 ≈ cur2 rtol = 1.0e-5 atol = 1.0e-5 @inferred DT.curvature(c, t) end end @@ -2123,13 +2131,13 @@ end TV = DT.total_variation(c) @inferred DT.total_variation(c) TVslow = slow_total_absolute_curvature(c, 0, 1) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-3 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-3 for _ in 1:1000 t1, t2 = minmax(rand(2)...) TV = DT.total_variation(c, t1, t2) @inferred DT.total_variation(c, t1, t2) TVslow = slow_total_absolute_curvature(c, t1, t2) - @test TV ≈ TVslow rtol = 1e-1 atol = 1e-1 + @test TV ≈ TVslow rtol = 1.0e-1 atol = 1.0e-1 end end @@ -2141,9 +2149,9 @@ end t = DT.get_equidistant_split(c, t1, t2) s1 = DT.arc_length(c, t1, t) s2 = DT.arc_length(c, t, t2) - @test s1 ≈ s2 rtol = 1e-1 atol = 1e-1 + @test s1 ≈ s2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 - @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1e-1 + @test DT.arc_length(c, t1, t2) ≈ 2s1 rtol = 1.0e-1 end end @@ -2155,7 +2163,7 @@ end t, T = DT.get_equivariation_split(c, t1, t2) T1 = DT.total_variation(c, t1, t) T2 = DT.total_variation(c, t, t2) - @test T1 ≈ T2 rtol = 1e-1 atol = 1e-1 + @test T1 ≈ T2 rtol = 1.0e-1 atol = 1.0e-1 @test t1 ≤ t ≤ t2 @test T ≈ T1 end @@ -2174,31 +2182,31 @@ end for t in LinRange(0, 1, 25000) t′ = DT.get_inverse(c, c(t)) if c ≠ pspl - @test t ≈ t′ rtol = 1e-3 + @test t ≈ t′ rtol = 1.0e-3 else - @test c(t) ⪧ c(t′) rtol = 1e-2 + @test c(t) ⪧ c(t′) rtol = 1.0e-2 end end end ## get_circle_intersection c = spl - t₁, t₂, r, = 0.0, 1.0, 1.0 + t₁, t₂, r = 0.0, 1.0, 1.0 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.03190638127625525 && q′ ⪧ (-8.130630223009339, 5.495953786102033) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 r = 13.0 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.43806261252250456 && q′ ⪧ (1.1435184529348763, -3.13023349324047) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-3 - t₁, t₂, r, = 1.0, 0.0, 1.0 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-3 + t₁, t₂, r = 1.0, 0.0, 1.0 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.9865973255686293 && q′ ⪧ (-7.9932950700471235, 10.152688406611302) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-1 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-1 t₁, t₂, r = 0.0, 0.1, 0.2 t′, q′ = DT.get_circle_intersection(c, t₁, t₂, r) @test t′ ≈ 0.007051410282056411 && q′ ⪧ (-8.812636716331587, 5.071072149949431) - @test DT.dist(c(t₁), q′) ≈ r rtol = 1e-2 + @test DT.dist(c(t₁), q′) ≈ r rtol = 1.0e-2 # == @test spl == spl @@ -2207,8 +2215,8 @@ end @test CatmullRomSpline(ctrl1) == CatmullRomSpline(ctrl1) @test CatmullRomSpline(ctrl1) ≠ CatmullRomSpline(ctrl2) @test CatmullRomSpline(ctrl2) == CatmullRomSpline(ctrl2) - @test CatmullRomSpline(ctrl1, _alpha=0.3) ≠ CatmullRomSpline(ctrl1) - @test CatmullRomSpline(ctrl1, _tension=0.2) ≠ CatmullRomSpline(ctrl1) + @test CatmullRomSpline(ctrl1, _alpha = 0.3) ≠ CatmullRomSpline(ctrl1) + @test CatmullRomSpline(ctrl1, _tension = 0.2) ≠ CatmullRomSpline(ctrl1) end @testset "angle_between" begin @@ -2286,10 +2294,10 @@ end @inferred DT.angle_between(L5, L1) A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V = (14.0, -2.0), (12.0, 2.0), - (0.0, 6.0), (12.0, -2.0), (0.0, -2.0), (2.0, -6.0), (0.0, -8.0), - (4.0, -8.0), (2.0, -4.0), (6.0, -4.0), (6.0, -14.0), (14.0, -14.0), - (8.0, -12.0), (14.0, -12.0), (8.0, -8.0), (16.0, -8.0), (8.0, -4.0), - (16.0, -4.0), (16.0, 6.0), (2.0, 6.0), (8.0, 4.0), (14.0, 4.0) + (0.0, 6.0), (12.0, -2.0), (0.0, -2.0), (2.0, -6.0), (0.0, -8.0), + (4.0, -8.0), (2.0, -4.0), (6.0, -4.0), (6.0, -14.0), (14.0, -14.0), + (8.0, -12.0), (14.0, -12.0), (8.0, -8.0), (16.0, -8.0), (8.0, -4.0), + (16.0, -4.0), (16.0, 6.0), (2.0, 6.0), (8.0, 4.0), (14.0, 4.0) LAB = LineSegment(A, B) LBC = LineSegment(B, C) LCD = LineSegment(C, D) @@ -2403,7 +2411,7 @@ end c₃ = CatmullRomSpline([(12.0, -3.0), (12.0, -4.0), (5.0, -10.0), (0.0, -10.0)]) c₄ = DT.PiecewiseLinear([(0.0, -10.0), (-10.0, -3.0), (-7.0, -3.0), (-5.0, -4.0), (-5.0, 2.0)], [1, 2, 3, 4, 5]) c₅ = BSpline([(-5.0, 2.0), (0.0, 8.0), (0.0, 10.0), (5.0, 1.0), (10.0, 0.0)]) - c₆ = CircularArc((10.0, 0.0), (0.0, 0.0), (5.0, 0.0), positive=false) + c₆ = CircularArc((10.0, 0.0), (0.0, 0.0), (5.0, 0.0), positive = false) θ12 = DT.angle_between(c₁, c₂) |> rad2deg θ23 = DT.angle_between(c₂, c₃) |> rad2deg θ34 = DT.angle_between(c₃, c₄) |> rad2deg @@ -2416,4 +2424,4 @@ end @test θ45 ≈ 360 - 140.19442890773482 @test θ56 ≈ 360 - 101.3099324740202 @test θ61 ≈ 360 - 348.6900675259798 -end \ No newline at end of file +end diff --git a/test/data_structures/graph.jl b/test/data_structures/graph.jl index 61ce12d89..a47e68a3b 100644 --- a/test/data_structures/graph.jl +++ b/test/data_structures/graph.jl @@ -7,19 +7,21 @@ using DataStructures g1 = DT.Graph{Int64}() g2 = DT.Graph{Int32}() @test g1.vertices == Set{Int64}() - @test g1.edges == Set{NTuple{2,Int64}}() - @test g1.neighbours == Dict{Int64,Set{Int64}}() + @test g1.edges == Set{NTuple{2, Int64}}() + @test g1.neighbours == Dict{Int64, Set{Int64}}() @test g2.vertices == Set{Int32}() - @test g2.edges == Set{NTuple{2,Int32}}() - @test g2.neighbours == Dict{Int32,Set{Int32}}() + @test g2.edges == Set{NTuple{2, Int32}}() + @test g2.neighbours == Dict{Int32, Set{Int32}}() end -global sg = [0 0 0 1 0 1 +global sg = [ + 0 0 0 1 0 1 0 0 1 1 0 0 0 1 0 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 - 1 0 1 1 0 0] + 1 0 1 1 0 0 +] global g = _make_graph_from_adjacency(sg) @testset "Getting graph and getting statistics" begin @@ -100,15 +102,17 @@ end DT.add_vertex!(g, bidx, bidx - 1, bidx - 2, bidx - 3, bidx - 4) DT.delete_ghost_vertices_from_graph!(g) @test bidx ∉ g.vertices && bidx - 1 ∉ g.vertices && bidx - 2 ∉ g.vertices && bidx - 3 ∉ g.vertices && - bidx - 4 ∉ g.vertices + bidx - 4 ∉ g.vertices end -global sg = [0 0 0 1 0 1 +global sg = [ + 0 0 0 1 0 1 0 0 1 1 0 0 0 1 0 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 - 1 0 1 1 0 0] + 1 0 1 1 0 0 +] global g = _make_graph_from_adjacency(sg) @testset "Removing empty parts" begin @@ -146,4 +150,4 @@ end @test isempty(get_neighbours(graph)) @test isempty(DT.get_edges(graph)) @test isempty(DT.get_vertices(graph)) -end \ No newline at end of file +end diff --git a/test/data_structures/max_priority_queue.jl b/test/data_structures/max_priority_queue.jl index 06c92e8c3..5f737260c 100644 --- a/test/data_structures/max_priority_queue.jl +++ b/test/data_structures/max_priority_queue.jl @@ -20,14 +20,14 @@ pmax = 1000 for n in [1:10; (11:50:10000)] if n ≠ 11 r = rand(1:pmax, n) - ks, vs = 1:n+1, rand(1:pmax, n) + ks, vs = 1:(n + 1), rand(1:pmax, n) else r = [670, 438, 251, 527, 40, 428, 913, 922, 756, 344, 562] - ks, vs = 1:n+1, [591, 242, 443, 24, 640, 173, 83, 409, 197, 125, 352] + ks, vs = 1:(n + 1), [591, 242, 443, 24, 640, 173, 83, 409, 197, 125, 352] end priorities = Dict(zip(ks, vs)) queue = DT.MaxPriorityQueue(priorities) - dt_queue = PriorityQueue{Int,Int}(Base.Reverse, priorities) + dt_queue = PriorityQueue{Int, Int}(Base.Reverse, priorities) if n == 11 @test sprint(show, MIME"text/plain"(), queue) == "DelaunayTriangulation.MaxPriorityQueue{Int64, Int64} with 11 entries:\n 5 => 640\n 1 => 591\n 3 => 443\n 8 => 409\n 11 => 352\n 2 => 242\n 9 => 197\n 6 => 173\n 10 => 125\n 7 => 83\n 4 => 24" end @@ -49,8 +49,8 @@ for n in [1:10; (11:50:10000)] @test queue[k] == dt_queue[k] end @test queue == dt_queue - pairs = Pair{Int,Int}[] - dt_pairs = Pair{Int,Int}[] + pairs = Pair{Int, Int}[] + dt_pairs = Pair{Int, Int}[] while !isempty(queue) pair = popfirst!(queue) dt_pair = dequeue_pair!(dt_queue) @@ -59,4 +59,4 @@ for n in [1:10; (11:50:10000)] end @test isempty(queue) && isempty(dt_queue) _compare_pairs(pairs, dt_pairs) -end \ No newline at end of file +end diff --git a/test/data_structures/polygon_hierarchy.jl b/test/data_structures/polygon_hierarchy.jl index 00e9b7f1a..800e242fa 100644 --- a/test/data_structures/polygon_hierarchy.jl +++ b/test/data_structures/polygon_hierarchy.jl @@ -30,7 +30,7 @@ for _ in 1:20 # Run many times to make sure the segfault is gone points_II = [ (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), - (0.75, 0.75), (0.25, 0.25) + (0.75, 0.75), (0.25, 0.25), ] curve_III = [[[1, 2, 3, 4, 5], [5, 6, 7, 8, 9], [9, 10, 11, 1]], [[15, 14, 13, 12], [12, 15]]] @@ -38,11 +38,11 @@ for _ in 1:20 # Run many times to make sure the segfault is gone (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), (0.0, 1.0), (0.0, 0.5), - (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75), (0.5, 0.5) + (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75), (0.5, 0.5), ] curve_IV = [CircularArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0))] - points_IV = NTuple{2,Float64}[] + points_IV = NTuple{2, Float64}[] curve_V = [BezierCurve([(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)])] points_V = [(0.0, 0.0), (0.2, 0.25)] @@ -50,13 +50,13 @@ for _ in 1:20 # Run many times to make sure the segfault is gone curve_VI = [ [CircularArc((1.0, 0.0), (0.0, 1.0), (0.0, 0.0))], [BSpline([(0.0, 1.0), (-1.0, 2.0), (-2.0, 0.0), (-2.0, -1.0), (0.0, -2.0)])], - [5, 6, 10] + [5, 6, 10], ] points_VI = [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0)] curve_VII = [ [CircularArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0))], - [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])] + [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])], ] points_VII = [(2.0, 0.0), (0.0, 0.5)] @@ -64,53 +64,55 @@ for _ in 1:20 # Run many times to make sure the segfault is gone [1, 2, 3, 4, 5], [DT.EllipticalArc((0.0, 0.0), (2.0, -2.0), (1.0, -1.0), sqrt(2), sqrt(2), 45.0)], [6, 7, 8, 9, 10], - [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)])] + [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)])], + ] + points_VIII = [ + (10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), + (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, 12.0), (14.0, 0.0), ] - points_VIII = [(10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), - (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, 12.0), (14.0, 0.0)] curve_IX = [ - [ - [1, 2, 3, 4, 5, 6, 7, 1] - ], - [ - [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive=false)] - ], - ] + [ + [1, 2, 3, 4, 5, 6, 7, 1], + ], + [ + [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive = false)], + ], + ] points_IX = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 1.5), (0.0, 1.0), (0.0, 0.5), (0.0, 0.2)] curve_X = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]) - ] + [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]), + ], ] points_X = [ - (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2) + (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2), ] curve_XI = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))] + [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points_XI = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] @@ -241,10 +243,10 @@ for _ in 1:20 # Run many times to make sure the segfault is gone DT.BoundingBox(-10.0, -2.0, -12.0, -4.0), DT.BoundingBox(-8.0, -4.0, -10.0, -6.0), DT.BoundingBox(-9.0, -3.0, -11.0, -5.0), - DT.BoundingBox(-9.0, -2.0, -17.0, -15.0) + DT.BoundingBox(-9.0, -2.0, -17.0, -15.0), ] @test DT.get_polygon_orientations(hierarchy) == [ - false, false, false, false, true, true, true, true, true, true, true, false, false, true, true + false, false, false, false, true, true, true, true, true, true, true, false, false, true, true, ] trees = DT.get_trees(hierarchy) tree6 = trees[6] @@ -290,39 +292,41 @@ for _ in 1:20 # Run many times to make sure the segfault is gone @test DT.get_index(tree15) == 15 && DT.get_height(tree15) == 0 && !DT.has_children(tree15) && !DT.has_parent(tree15) DT.expand_bounds!(hierarchy) @test DT.get_bounding_boxes(hierarchy) ⊢ [ - DT.expand(DT.BoundingBox(-9.0, -2.0, -1.0, 7.0), 0.10), - DT.expand(DT.BoundingBox(0.0, 10.0, -5.0, 6.0), 0.10), - DT.expand(DT.BoundingBox(-1.0, 1.0, 6.0, 7.0), 0.10), - DT.expand(DT.BoundingBox(-20.0, -16.0, 8.0, 10.0), 0.10), - DT.expand(DT.BoundingBox(-22.0, -14.0, -14.0, 4.0), 0.10), - DT.expand(DT.BoundingBox(-22.0, -14.0, 6.0, 12.0), 0.10), - DT.expand(DT.BoundingBox(-12.0, 14.0, -14.0, 12.0), 0.10), - DT.expand(DT.BoundingBox(1.0, 8.0, -4.0, 2.0), 0.10), - DT.expand(DT.BoundingBox(1.0, 8.0, 3.0, 4.0), 0.10), - DT.expand(DT.BoundingBox(-8.0, -3.0, 0.0, 5.0), 0.10), - DT.expand(DT.BoundingBox(-8.0, -3.0, 4.0, 6.0), 0.10), - DT.expand(DT.BoundingBox(-10.0, -2.0, -12.0, -4.0), 0.10), - DT.expand(DT.BoundingBox(-8.0, -4.0, -10.0, -6.0), 0.10), - DT.expand(DT.BoundingBox(-9.0, -3.0, -11.0, -5.0), 0.10), - DT.expand(DT.BoundingBox(-9.0, -2.0, -17.0, -15.0), 0.10) + DT.expand(DT.BoundingBox(-9.0, -2.0, -1.0, 7.0), 0.1), + DT.expand(DT.BoundingBox(0.0, 10.0, -5.0, 6.0), 0.1), + DT.expand(DT.BoundingBox(-1.0, 1.0, 6.0, 7.0), 0.1), + DT.expand(DT.BoundingBox(-20.0, -16.0, 8.0, 10.0), 0.1), + DT.expand(DT.BoundingBox(-22.0, -14.0, -14.0, 4.0), 0.1), + DT.expand(DT.BoundingBox(-22.0, -14.0, 6.0, 12.0), 0.1), + DT.expand(DT.BoundingBox(-12.0, 14.0, -14.0, 12.0), 0.1), + DT.expand(DT.BoundingBox(1.0, 8.0, -4.0, 2.0), 0.1), + DT.expand(DT.BoundingBox(1.0, 8.0, 3.0, 4.0), 0.1), + DT.expand(DT.BoundingBox(-8.0, -3.0, 0.0, 5.0), 0.1), + DT.expand(DT.BoundingBox(-8.0, -3.0, 4.0, 6.0), 0.1), + DT.expand(DT.BoundingBox(-10.0, -2.0, -12.0, -4.0), 0.1), + DT.expand(DT.BoundingBox(-8.0, -4.0, -10.0, -6.0), 0.1), + DT.expand(DT.BoundingBox(-9.0, -3.0, -11.0, -5.0), 0.1), + DT.expand(DT.BoundingBox(-9.0, -2.0, -17.0, -15.0), 0.1), ] - @test all([ - DT.BoundingBox(-9.0, -2.0, -1.0, 7.0), - DT.BoundingBox(0.0, 10.0, -5.0, 6.0), - DT.BoundingBox(-1.0, 1.0, 6.0, 7.0), - DT.BoundingBox(-20.0, -16.0, 8.0, 10.0), - DT.BoundingBox(-22.0, -14.0, -14.0, 4.0), - DT.BoundingBox(-22.0, -14.0, 6.0, 12.0), - DT.BoundingBox(-12.0, 14.0, -14.0, 12.0), - DT.BoundingBox(1.0, 8.0, -4.0, 2.0), - DT.BoundingBox(1.0, 8.0, 3.0, 4.0), - DT.BoundingBox(-8.0, -3.0, 0.0, 5.0), - DT.BoundingBox(-8.0, -3.0, 4.0, 6.0), - DT.BoundingBox(-10.0, -2.0, -12.0, -4.0), - DT.BoundingBox(-8.0, -4.0, -10.0, -6.0), - DT.BoundingBox(-9.0, -3.0, -11.0, -5.0), - DT.BoundingBox(-9.0, -2.0, -17.0, -15.0) - ] .∈ DT.get_bounding_boxes(hierarchy)) + @test all( + [ + DT.BoundingBox(-9.0, -2.0, -1.0, 7.0), + DT.BoundingBox(0.0, 10.0, -5.0, 6.0), + DT.BoundingBox(-1.0, 1.0, 6.0, 7.0), + DT.BoundingBox(-20.0, -16.0, 8.0, 10.0), + DT.BoundingBox(-22.0, -14.0, -14.0, 4.0), + DT.BoundingBox(-22.0, -14.0, 6.0, 12.0), + DT.BoundingBox(-12.0, 14.0, -14.0, 12.0), + DT.BoundingBox(1.0, 8.0, -4.0, 2.0), + DT.BoundingBox(1.0, 8.0, 3.0, 4.0), + DT.BoundingBox(-8.0, -3.0, 0.0, 5.0), + DT.BoundingBox(-8.0, -3.0, 4.0, 6.0), + DT.BoundingBox(-10.0, -2.0, -12.0, -4.0), + DT.BoundingBox(-8.0, -4.0, -10.0, -6.0), + DT.BoundingBox(-9.0, -3.0, -11.0, -5.0), + DT.BoundingBox(-9.0, -2.0, -17.0, -15.0), + ] .∈ DT.get_bounding_boxes(hierarchy), + ) @test traverse_tree(hierarchy.trees[7]) ≠ traverse_tree(hierarchy.trees[15]) @test compare_trees(hierarchy, hierarchy) @test compare_trees(deepcopy(hierarchy), deepcopy(hierarchy)) @@ -348,7 +352,7 @@ for _ in 1:20 # Run many times to make sure the segfault is gone hierarchy = DT.construct_polygon_hierarchy(points, nnew_boundary_nodes, boundary_curves) DT.expand_bounds!(hierarchy, DT.ε) @test DT.get_bounding_boxes(hierarchy) ⊢ [DT.BoundingBox(-1 - 2DT.ε, 1 + 2DT.ε, -1 - 2DT.ε, 1 + 2DT.ε)] && - DT.get_polygon_orientations(hierarchy) ⊢ BitVector([1]) + DT.get_polygon_orientations(hierarchy) ⊢ BitVector([1]) trees = DT.get_trees(hierarchy) @test length(trees) == 1 tree = trees[1] @@ -450,4 +454,4 @@ for _ in 1:20 # Run many times to make sure the segfault is gone tree2 = trees[2] @test DT.get_index(tree2) == 2 && DT.get_height(tree2) == 0 && !DT.has_parent(tree2) && !DT.has_children(tree2) end -end \ No newline at end of file +end diff --git a/test/data_structures/queue.jl b/test/data_structures/queue.jl index a17d29dee..3fa25fbc1 100644 --- a/test/data_structures/queue.jl +++ b/test/data_structures/queue.jl @@ -3,17 +3,17 @@ using ..DelaunayTriangulation const DT = DelaunayTriangulation queue = DT.Queue{Float64}() @test isempty(queue) -@test length(queue) == 0 +@test length(queue) == 0 @test eltype(queue) == Float64 dt_queue = DT.Queue{Float64}() els = Float64[] dt_els = Float64[] -for k in 1:100 +for k in 1:100 r = randn() push!(queue, r) push!(dt_queue, r) end -for k in 1:100 +for k in 1:100 push!(els, popfirst!(queue)) push!(dt_els, popfirst!(dt_queue)) end @@ -23,11 +23,11 @@ end queue = DT.Queue{Int}() points = rand(2, 50) DT.enqueue_all!(queue, DT.each_point_index(points)) -@test queue.data == 1:50 +@test queue.data == 1:50 q1 = DT.Queue{Int}() q2 = DT.Queue{Int}() -@test q1 == q2 +@test q1 == q2 push!(q1, 1) @test q1 ≠ q2 push!(q2, 1) diff --git a/test/data_structures/representative.jl b/test/data_structures/representative.jl index 2136a170d..aa46992b8 100644 --- a/test/data_structures/representative.jl +++ b/test/data_structures/representative.jl @@ -3,9 +3,8 @@ const DT = DelaunayTriangulation using StatsBase - @testset "Initialise" begin - c = DT.RepresentativeCoordinates{Int,Float64}() + c = DT.RepresentativeCoordinates{Int, Float64}() @test c == DT.RepresentativeCoordinates(0.0, 0.0, 0) end @@ -18,7 +17,7 @@ end @testset "Conversion" begin c = DT.RepresentativeCoordinates(0.39182, 0.5919198, 5) - newc = convert(DT.RepresentativeCoordinates{Int32,Float32}, c) + newc = convert(DT.RepresentativeCoordinates{Int32, Float32}, c) @test newc.x isa Float32 @test newc.y isa Float32 @test newc.n isa Int32 @@ -34,7 +33,7 @@ end end @testset "Adding and deleting points to representative coordinates" begin - c = DT.RepresentativeCoordinates{Int,Float64}() + c = DT.RepresentativeCoordinates{Int, Float64}() pts = [15randn(2) for _ in 1:200] foreach(p -> DT.add_point!(c, p), pts) mx, my = mean(pts) @@ -62,8 +61,8 @@ end tri = triangulate(points; boundary_nodes) DT.compute_representative_points!(tri) rep = DT.get_representative_point_list(tri) - @test rep[1].x ≈ 0.5 atol = 1e-12 - @test rep[1].y ≈ 0.5 atol = 1e-12 + @test rep[1].x ≈ 0.5 atol = 1.0e-12 + @test rep[1].y ≈ 0.5 atol = 1.0e-12 @test rep[1].n == 0 x = [[0.0, 1.0], [1.0, 1.0], [1.0, 0.0], [0.0, 0.0]] @@ -72,15 +71,15 @@ end tri = triangulate(points; boundary_nodes) rep = DT.get_representative_point_list(tri) DT.compute_representative_points!(tri) - @test rep[1].x ≈ 0.5 atol = 1e-12 - @test rep[1].y ≈ 0.5 atol = 1e-12 + @test rep[1].x ≈ 0.5 atol = 1.0e-12 + @test rep[1].y ≈ 0.5 atol = 1.0e-12 @test rep[1].n == 0 end @testset "Polylabel, representative points, and distance" begin x, y, x1, x2, x3, x4, x5, y1, y2, y3, y4, y5 = complicated_geometry() boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; boundary_nodes, delete_ghosts=false) + tri = triangulate(points; boundary_nodes, delete_ghosts = false) for i in (1, 2, 3) local x1, y1, x2, y2, x3, y3, x4, y4, x5, y5 if i == 3 @@ -104,16 +103,16 @@ end d4 = DT.distance_to_polygon((x4, y4), tri.points, tri.boundary_nodes[4]) d5 = DT.distance_to_polygon((x5, y5), tri.points, tri.boundary_nodes[5]) @test all(≥(0), (d1, d2, d3, d4, d5)) # all points are inside their respective regions - @test rep[1].x ≈ x1 atol = 1e-14 - @test rep[1].y ≈ y1 atol = 1e-14 - @test rep[2].x ≈ x2 atol = 1e-14 - @test rep[2].y ≈ y2 atol = 1e-14 - @test rep[3].x ≈ x3 atol = 1e-14 - @test rep[3].y ≈ y3 atol = 1e-14 - @test rep[4].x ≈ x4 atol = 1e-14 - @test rep[4].y ≈ y4 atol = 1e-14 - @test rep[5].x ≈ x5 atol = 1e-14 - @test rep[5].y ≈ y5 atol = 1e-14 + @test rep[1].x ≈ x1 atol = 1.0e-14 + @test rep[1].y ≈ y1 atol = 1.0e-14 + @test rep[2].x ≈ x2 atol = 1.0e-14 + @test rep[2].y ≈ y2 atol = 1.0e-14 + @test rep[3].x ≈ x3 atol = 1.0e-14 + @test rep[3].y ≈ y3 atol = 1.0e-14 + @test rep[4].x ≈ x4 atol = 1.0e-14 + @test rep[4].y ≈ y4 atol = 1.0e-14 + @test rep[5].x ≈ x5 atol = 1.0e-14 + @test rep[5].y ≈ y5 atol = 1.0e-14 @test collect(get_point(tri, -1)) ≈ [x1, y1] @test collect(get_point(tri, -2)) ≈ [x1, y1] @test collect(get_point(tri, -3)) ≈ [x1, y1] diff --git a/test/data_structures/rtree.jl b/test/data_structures/rtree.jl index 3defeabd9..b5c687db9 100644 --- a/test/data_structures/rtree.jl +++ b/test/data_structures/rtree.jl @@ -9,7 +9,7 @@ const SI = SpatialIndexing @testset "Expanding a BoundingBox" begin bbox = DT.BoundingBox(2, 5, 13, 20) - tol = 0.10 + tol = 0.1 bbox2 = DT.expand(bbox, tol) @test bbox2 == DT.BoundingBox(2 - 0.3, 5 + 0.3, 13 - 0.7, 20 + 0.7) end @@ -107,7 +107,7 @@ end for _ in 1:50 n = rand(1:1001) points = 5 .* randn(2, n) - tree_si = SI.RTree{Float64,2}(Int, NTuple{2,Int}; variant=SI.RTreeLinear) + tree_si = SI.RTree{Float64, 2}(Int, NTuple{2, Int}; variant = SI.RTreeLinear) tree = DT.RTree() for idx in axes(points, 2) |> shuffle x, y = get_point(points, idx) @@ -118,7 +118,7 @@ end for _ in 1:20 p = Tuple(10 .* randn(2)) - ints = DT.get_intersections(tree, p; cache_id=rand(1:2)) + ints = DT.get_intersections(tree, p; cache_id = rand(1:2)) ints_si = SI.intersects_with(tree_si, SI.Rect(SI.Point(p))) @test ints == ints_si @inferred collect(ints) @@ -147,7 +147,7 @@ end for _ in 1:25 n = rand(1:250) points = 5 .* randn(2, n) - tree_si = SI.RTree{Float64,2}(Int, NTuple{2,Int}; variant=SI.RTreeLinear) + tree_si = SI.RTree{Float64, 2}(Int, NTuple{2, Int}; variant = SI.RTreeLinear) tree = DT.BoundaryRTree(points) ctr = 1 range1 = rand(axes(points, 2), max(isqrt(n), 5)) @@ -168,7 +168,7 @@ end c, d = minmax(c, d) rect = DT.BoundingBox(a, b, c, d) rect_si = SI.Rect((a, c), (b, d)) - int = DT.get_intersections(tree, rect; cache_id=rand(1:2)) + int = DT.get_intersections(tree, rect; cache_id = rand(1:2)) int_si = SI.intersects_with(tree_si, rect_si) @test int == int_si @@ -186,7 +186,7 @@ end @test int == int_si i, j, k = rand(1:n, 3) - int = DT.get_intersections(tree, i, j, k; cache_id=rand(1:2)) + int = DT.get_intersections(tree, i, j, k; cache_id = rand(1:2)) bbox = DT.bounding_box(get_point(points, i, j, k)...) bbox_si = SI.Rect((bbox.x.a, bbox.y.a), (bbox.x.b, bbox.y.b)) int_si = SI.intersects_with(tree_si, bbox_si) @@ -277,4 +277,4 @@ end @test tree1 ≠ tree2 insert!(tree2, 1, 2) @test tree1 == tree2 -end \ No newline at end of file +end diff --git a/test/data_structures/shuffled_polygon_linked_list.jl b/test/data_structures/shuffled_polygon_linked_list.jl index 152396cda..7407c07a8 100644 --- a/test/data_structures/shuffled_polygon_linked_list.jl +++ b/test/data_structures/shuffled_polygon_linked_list.jl @@ -56,4 +56,4 @@ DT.swap_permutation!(list, 1, 2) @test π[2] == _π[1] DT.swap_permutation!(list, 3, 5) @test π[3] == _π[5] -@test π[5] == _π[3] \ No newline at end of file +@test π[5] == _π[3] diff --git a/test/data_structures/statistics.jl b/test/data_structures/statistics.jl index 78ea358d7..2e33711c8 100644 --- a/test/data_structures/statistics.jl +++ b/test/data_structures/statistics.jl @@ -4,33 +4,32 @@ using CairoMakie using ReferenceTests - @testset "Computing statistics" begin _x, _y = complicated_geometry() x = _x y = _y boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_1 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_1 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_1) # 2356 - refine!(tri_1; max_area=1e-3A, use_circumcenter=true) + refine!(tri_1; max_area = 1.0e-3A, use_circumcenter = true) boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) - tri_2 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_2 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_2) - refine!(tri_2; max_area=1e-3A, use_circumcenter=true) + refine!(tri_2; max_area = 1.0e-3A, use_circumcenter = true) boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) - tri_3 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_3 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_3) - refine!(tri_3; max_area=1e-3A, use_circumcenter=true) + refine!(tri_3; max_area = 1.0e-3A, use_circumcenter = true) boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) - tri_4 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_4 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_4) - refine!(tri_4; max_area=1e-3A, use_circumcenter=true) + refine!(tri_4; max_area = 1.0e-3A, use_circumcenter = true) a, b = 0.0, 5.0 c, d = 3.0, 7.0 nx = 3 ny = 3 - tri_5 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=false) - tri_6 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri_5 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = false) + tri_6 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) for (i, tri) in enumerate((tri_1, tri_2, tri_3, tri_4, tri_5, tri_6)) validate_statistics(tri) @inferred statistics(tri) @@ -49,18 +48,18 @@ using ReferenceTests (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), - (1.34, 6.77), (1.24, 4.15) + (1.34, 6.77), (1.24, 4.15), ] boundary_points = [ (0.0, 0.0), (2.0, 1.0), (3.98, 2.85), (6.0, 5.0), (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), - (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0) + (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0), ] - boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points=pts) - uncons_tri = triangulate(pts, delete_ghosts=false) - cons_tri = triangulate(pts; boundary_nodes, delete_ghosts=false) + boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points = pts) + uncons_tri = triangulate(pts, delete_ghosts = false) + cons_tri = triangulate(pts; boundary_nodes, delete_ghosts = false) add_point!(cons_tri, 0.0, 5.0) add_segment!(cons_tri, 40, 26) add_segment!(cons_tri, 39, 27) @@ -184,13 +183,13 @@ end boundary_nodes, points = convert_boundary_points_to_indices(x, y) tri = triangulate(points; boundary_nodes) stats = statistics(tri) - interior_sinks = NTuple{2,Float64}[] + interior_sinks = NTuple{2, Float64}[] for T in each_solid_triangle(tri) is_interior_sink(tri, T) && push!(interior_sinks, DT.get_sink(stats, T)) end @test length(interior_sinks) == 1 == count(T -> is_interior_sink(tri, T), each_solid_triangle(tri)) fig, ax, sc = scatter(get_all_stat(stats, :sink)) - scatter!(ax, interior_sinks, color=:red) + scatter!(ax, interior_sinks, color = :red) triplot!(ax, tri) fig @test_reference "sink_figures.png" fig diff --git a/test/data_structures/triangulation.jl b/test/data_structures/triangulation.jl index 7af7f05ed..97b454e7c 100644 --- a/test/data_structures/triangulation.jl +++ b/test/data_structures/triangulation.jl @@ -14,684 +14,692 @@ using ..DelaunayTriangulation: add_weight!, get_weight, get_weights using ..DelaunayTriangulation: Triangulation global pts = rand(2, 500) -global tri = Triangulation(pts; IntegerType=Int32) +global tri = Triangulation(pts; IntegerType = Int32) @testset "Initialising a triangulation" begin - @test tri ⊢ Triangulation(pts, # points - Set{NTuple{3,Int32}}(), # triangles - Int32[], # boundary_nodes - Set{NTuple{2,Int32}}(), # interior_segments - Set{NTuple{2,Int32}}(), # all_segments - DT.ZeroWeight(), # weights - DT.Adjacent{Int32,NTuple{2,Int32}}(), # adjacent - DT.Adjacent2Vertex{Int32,Set{NTuple{2,Int32}}}(), # adjacent2vertex - DT.Graph{Int32}(), # graph - (), # boundary_curves - Dict{NTuple{2,Int32},Tuple{Vector{Int32},Int32}}(), # boundary_edge_map - Dict{Int32,Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map - Dict{Int32,UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges - DT.ConvexHull(pts, Int32[]), # convex_hull - Dict{Int32,DT.RepresentativeCoordinates{Int32,Float64}}(), # representative_point_coordinate - DT.construct_polygon_hierarchy(pts; IntegerType=Int32), - nothing, - DT.TriangulationCache( - DT.Triangulation( - pts, - Set{NTuple{3,Int32}}(), # triangles - Int32[], # boundary_nodes - Set{NTuple{2,Int32}}(), # interior_segments - Set{NTuple{2,Int32}}(), # all_segments - DT.ZeroWeight(), # weights - DT.Adjacent{Int32,NTuple{2,Int32}}(), # adjacent - DT.Adjacent2Vertex{Int32,Set{NTuple{2,Int32}}}(), # adjacent2vertex - DT.Graph{Int32}(), # graph - (), # boundary_curves - Dict{NTuple{2,Int32},Tuple{Vector{Int32},Int32}}(), # boundary_edge_map - Dict{Int32,Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map - Dict{Int32,UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges - DT.ConvexHull(pts, Int32[]), # convex_hull - Dict{Int32,DT.RepresentativeCoordinates{Int32,Float64}}(), # representative_point_coordinate - DT.construct_polygon_hierarchy(pts; IntegerType=Int32), - nothing, # boundary_enricher - DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing) - ), - DT.Triangulation( - pts, - Set{NTuple{3,Int32}}(), # triangles - Int32[], # boundary_nodes - Set{NTuple{2,Int32}}(), # interior_segments - Set{NTuple{2,Int32}}(), # all_segments - DT.ZeroWeight(), # weights - DT.Adjacent{Int32,NTuple{2,Int32}}(), # adjacent - DT.Adjacent2Vertex{Int32,Set{NTuple{2,Int32}}}(), # adjacent2vertex - DT.Graph{Int32}(), # graph - (), # boundary_curves - Dict{NTuple{2,Int32},Tuple{Vector{Int32},Int32}}(), # boundary_edge_map - Dict{Int32,Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map - Dict{Int32,UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges - DT.ConvexHull(pts, Int32[]), # convex_hull - Dict{Int32,DT.RepresentativeCoordinates{Int32,Float64}}(), # representative_point_coordinate - DT.construct_polygon_hierarchy(pts; IntegerType=Int32), - nothing, # boundary_enricher - DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing) - ), - Int32[], - Set{NTuple{2,Int32}}(), - Vector{Int32}(), - Set{NTuple{3,Int32}}()) - ) + @test tri ⊢ Triangulation( + pts, # points + Set{NTuple{3, Int32}}(), # triangles + Int32[], # boundary_nodes + Set{NTuple{2, Int32}}(), # interior_segments + Set{NTuple{2, Int32}}(), # all_segments + DT.ZeroWeight(), # weights + DT.Adjacent{Int32, NTuple{2, Int32}}(), # adjacent + DT.Adjacent2Vertex{Int32, Set{NTuple{2, Int32}}}(), # adjacent2vertex + DT.Graph{Int32}(), # graph + (), # boundary_curves + Dict{NTuple{2, Int32}, Tuple{Vector{Int32}, Int32}}(), # boundary_edge_map + Dict{Int32, Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map + Dict{Int32, UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges + DT.ConvexHull(pts, Int32[]), # convex_hull + Dict{Int32, DT.RepresentativeCoordinates{Int32, Float64}}(), # representative_point_coordinate + DT.construct_polygon_hierarchy(pts; IntegerType = Int32), + nothing, + DT.TriangulationCache( + DT.Triangulation( + pts, + Set{NTuple{3, Int32}}(), # triangles + Int32[], # boundary_nodes + Set{NTuple{2, Int32}}(), # interior_segments + Set{NTuple{2, Int32}}(), # all_segments + DT.ZeroWeight(), # weights + DT.Adjacent{Int32, NTuple{2, Int32}}(), # adjacent + DT.Adjacent2Vertex{Int32, Set{NTuple{2, Int32}}}(), # adjacent2vertex + DT.Graph{Int32}(), # graph + (), # boundary_curves + Dict{NTuple{2, Int32}, Tuple{Vector{Int32}, Int32}}(), # boundary_edge_map + Dict{Int32, Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map + Dict{Int32, UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges + DT.ConvexHull(pts, Int32[]), # convex_hull + Dict{Int32, DT.RepresentativeCoordinates{Int32, Float64}}(), # representative_point_coordinate + DT.construct_polygon_hierarchy(pts; IntegerType = Int32), + nothing, # boundary_enricher + DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing), + ), + DT.Triangulation( + pts, + Set{NTuple{3, Int32}}(), # triangles + Int32[], # boundary_nodes + Set{NTuple{2, Int32}}(), # interior_segments + Set{NTuple{2, Int32}}(), # all_segments + DT.ZeroWeight(), # weights + DT.Adjacent{Int32, NTuple{2, Int32}}(), # adjacent + DT.Adjacent2Vertex{Int32, Set{NTuple{2, Int32}}}(), # adjacent2vertex + DT.Graph{Int32}(), # graph + (), # boundary_curves + Dict{NTuple{2, Int32}, Tuple{Vector{Int32}, Int32}}(), # boundary_edge_map + Dict{Int32, Vector{Int32}}(DT.𝒢 => Int32[]), # ghost_vertex_map + Dict{Int32, UnitRange{Int32}}(-1 => -1:-1), # ghost_vertex_ranges + DT.ConvexHull(pts, Int32[]), # convex_hull + Dict{Int32, DT.RepresentativeCoordinates{Int32, Float64}}(), # representative_point_coordinate + DT.construct_polygon_hierarchy(pts; IntegerType = Int32), + nothing, # boundary_enricher + DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing), + ), + Int32[], + Set{NTuple{2, Int32}}(), + Vector{Int32}(), + Set{NTuple{3, Int32}}(), + ), + ) end _x, _y = complicated_geometry() global x = _x global y = _y boundary_nodes, points = convert_boundary_points_to_indices(x, y) -global tri = triangulate(points; boundary_nodes, delete_ghosts=false) +global tri = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri) -refine!(tri; max_area=1e-1A, use_circumcenter=true, use_lens=false) +refine!(tri; max_area = 1.0e-1A, use_circumcenter = true, use_lens = false) boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) -global tri_2 = triangulate(points; boundary_nodes, delete_ghosts=false) +global tri_2 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_2) -refine!(tri_2; max_area=1e-1A, use_circumcenter=true, use_lens=false) +refine!(tri_2; max_area = 1.0e-1A, use_circumcenter = true, use_lens = false) boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) -global tri_3 = triangulate(points; boundary_nodes, delete_ghosts=false) +global tri_3 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_3) -refine!(tri_3; max_area=1e-1A, use_circumcenter=true, use_lens=false) +refine!(tri_3; max_area = 1.0e-1A, use_circumcenter = true, use_lens = false) boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) -global tri_4 = triangulate(points; boundary_nodes, delete_ghosts=false) +global tri_4 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_4) -refine!(tri_4; max_area=1e-1A, use_circumcenter=true, use_lens=false) +refine!(tri_4; max_area = 1.0e-1A, use_circumcenter = true, use_lens = false) @testset "Triangulation getters" begin - @test DT.get_points(tri) == tri.points - @test DT.get_triangles(tri) == tri.triangles - @test DT.get_boundary_nodes(tri) == tri.boundary_nodes - @test DT.get_interior_segments(tri) == tri.interior_segments - @test DT.get_all_segments(tri) == tri.all_segments - @test DT.get_weights(tri) == tri.weights - @test DT.get_adjacent(tri) == tri.adjacent - @test DT.get_adjacent2vertex(tri) == tri.adjacent2vertex - @test DT.get_graph(tri) == tri.graph - @test DT.get_boundary_curves(tri) == tri.boundary_curves - @test DT.get_boundary_edge_map(tri) == tri.boundary_edge_map - @test DT.get_ghost_vertex_map(tri) == tri.ghost_vertex_map - @test DT.get_ghost_vertex_ranges(tri) == tri.ghost_vertex_ranges - @test DT.get_convex_hull(tri) == tri.convex_hull - @test DT.get_representative_point_list(tri) == tri.representative_point_list - @test DT.get_exterior_curve_indices(tri) == keys(tri.polygon_hierarchy.trees) - @test DT.get_boundary_enricher(tri) === tri.boundary_enricher - @test compare_trees(DT.get_polygon_hierarchy(tri), DT.construct_polygon_hierarchy(tri.points, tri.boundary_nodes)) - @test compare_edge_vectors(collect(DT.get_all_segments(tri)), collect(tri.all_segments)) - @test compare_edge_vectors(collect(DT.get_all_segments(tri)), collect(DT.merge_segments(get_ghost_vertex_map(tri), get_boundary_nodes(tri), get_interior_segments(tri)))) - @test DT.get_ghost_vertex_map(tri) == tri.ghost_vertex_map == DT.construct_ghost_vertex_map(get_boundary_nodes(tri)) - @test DT.get_ghost_vertex_ranges(tri) == tri.ghost_vertex_ranges == DT.construct_ghost_vertex_ranges(get_boundary_nodes(tri)) - @test DT.get_boundary_edge_map(tri) == tri.boundary_edge_map == DT.construct_boundary_edge_map(get_boundary_nodes(tri)) - @test DT.get_cache(tri) == tri.cache - @inferred DT.get_points(tri) - @inferred DT.get_triangles(tri) - @inferred DT.get_boundary_nodes(tri) - @inferred DT.get_interior_segments(tri) - @inferred DT.get_all_segments(tri) - @inferred DT.get_weights(tri) - @inferred DT.get_adjacent(tri) - @inferred DT.get_adjacent2vertex(tri) - @inferred DT.get_graph(tri) - @inferred DT.get_boundary_curves(tri) - @inferred DT.get_boundary_edge_map(tri) - @inferred DT.get_ghost_vertex_map(tri) - @inferred DT.get_ghost_vertex_ranges(tri) - @inferred DT.get_convex_hull(tri) - @inferred DT.get_representative_point_list(tri) - @inferred DT.get_exterior_curve_indices(tri) + @test DT.get_points(tri) == tri.points + @test DT.get_triangles(tri) == tri.triangles + @test DT.get_boundary_nodes(tri) == tri.boundary_nodes + @test DT.get_interior_segments(tri) == tri.interior_segments + @test DT.get_all_segments(tri) == tri.all_segments + @test DT.get_weights(tri) == tri.weights + @test DT.get_adjacent(tri) == tri.adjacent + @test DT.get_adjacent2vertex(tri) == tri.adjacent2vertex + @test DT.get_graph(tri) == tri.graph + @test DT.get_boundary_curves(tri) == tri.boundary_curves + @test DT.get_boundary_edge_map(tri) == tri.boundary_edge_map + @test DT.get_ghost_vertex_map(tri) == tri.ghost_vertex_map + @test DT.get_ghost_vertex_ranges(tri) == tri.ghost_vertex_ranges + @test DT.get_convex_hull(tri) == tri.convex_hull + @test DT.get_representative_point_list(tri) == tri.representative_point_list + @test DT.get_exterior_curve_indices(tri) == keys(tri.polygon_hierarchy.trees) + @test DT.get_boundary_enricher(tri) === tri.boundary_enricher + @test compare_trees(DT.get_polygon_hierarchy(tri), DT.construct_polygon_hierarchy(tri.points, tri.boundary_nodes)) + @test compare_edge_vectors(collect(DT.get_all_segments(tri)), collect(tri.all_segments)) + @test compare_edge_vectors(collect(DT.get_all_segments(tri)), collect(DT.merge_segments(get_ghost_vertex_map(tri), get_boundary_nodes(tri), get_interior_segments(tri)))) + @test DT.get_ghost_vertex_map(tri) == tri.ghost_vertex_map == DT.construct_ghost_vertex_map(get_boundary_nodes(tri)) + @test DT.get_ghost_vertex_ranges(tri) == tri.ghost_vertex_ranges == DT.construct_ghost_vertex_ranges(get_boundary_nodes(tri)) + @test DT.get_boundary_edge_map(tri) == tri.boundary_edge_map == DT.construct_boundary_edge_map(get_boundary_nodes(tri)) + @test DT.get_cache(tri) == tri.cache + @inferred DT.get_points(tri) + @inferred DT.get_triangles(tri) + @inferred DT.get_boundary_nodes(tri) + @inferred DT.get_interior_segments(tri) + @inferred DT.get_all_segments(tri) + @inferred DT.get_weights(tri) + @inferred DT.get_adjacent(tri) + @inferred DT.get_adjacent2vertex(tri) + @inferred DT.get_graph(tri) + @inferred DT.get_boundary_curves(tri) + @inferred DT.get_boundary_edge_map(tri) + @inferred DT.get_ghost_vertex_map(tri) + @inferred DT.get_ghost_vertex_ranges(tri) + @inferred DT.get_convex_hull(tri) + @inferred DT.get_representative_point_list(tri) + @inferred DT.get_exterior_curve_indices(tri) end @testset "Forwarded methods" begin - @testset "Adjacent" begin - @test DT.get_adjacent(tri, 92, -6) == tri.adjacent.adjacent[(92, -6)] - @test DT.get_adjacent(tri, (723, 1356)) == get(tri.adjacent.adjacent, (723, 1356), DT.∅) - @inferred DT.get_adjacent(tri, (723, 1356)) - DT.add_adjacent!(tri, 101117, 20311, 5) - DT.add_adjacent!(tri, (27311, 50511), 10) - @test DT.get_adjacent(tri, 101117, 20311) == 5 - @inferred DT.get_adjacent(tri, 101117, 20311) - @test DT.get_adjacent(tri, 27311, 50511) == 10 - DT.delete_adjacent!(tri, 101117, 20311) - DT.delete_adjacent!(tri, (27311, 50511)) - @test DT.get_adjacent(tri, 101117, 20311) == DT.∅ - @test DT.get_adjacent(tri, 27311, 50511) == DT.∅ - @test DT.get_adjacent(tri, 711, DT.𝒢) == DT.∅ - end - - @testset "Adjacent2Vertex" begin - @test DT.get_adjacent2vertex(tri, -6) == tri.adjacent2vertex.adjacent2vertex[-6] - @inferred DT.get_adjacent2vertex(tri, -6) - DT.add_adjacent2vertex!(tri, 10005, 23, 27) - DT.add_adjacent2vertex!(tri, 19988, (50, 171)) - @test DT.contains_edge(23, 27, tri.adjacent2vertex.adjacent2vertex[10005]) - @test DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) - @inferred DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) - DT.delete_adjacent2vertex!(tri, 10005, 23, 27) - DT.delete_adjacent2vertex!(tri, 19988, (50, 171)) - @test !DT.contains_edge(23, 27, tri.adjacent2vertex.adjacent2vertex[10005]) - @test !DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) - @test 6 ∈ keys(tri.adjacent2vertex.adjacent2vertex) - DT.delete_adjacent2vertex!(tri, -6) - @test -6 ∉ keys(tri.adjacent2vertex.adjacent2vertex) - end - - @testset "Graph" begin - @test DT.get_edges(tri) == tri.graph.edges == DT.get_edges(tri.graph) - @inferred DT.get_edges(tri) - @test DT.get_neighbours(tri, 3) == tri.graph.neighbours[3] - @inferred DT.get_neighbours(tri, 3) - DT.add_vertex!(tri, 19998, 23721) - DT.add_vertex!(tri, 28371) - @test all(∈(tri.graph.vertices), (19998, 23721, 28371)) - DT.add_neighbour!(tri, 28371, 50912) - DT.add_neighbour!(tri, 28371, 271, 501) - @test all(∈(tri.graph.neighbours[28371]), (50912, 271, 501)) - DT.delete_neighbour!(tri, 28371, 50912) - DT.delete_neighbour!(tri, 28371, 271, 501) - @test all(∉(tri.graph.neighbours[28371]), (50912, 271, 501)) - DT.delete_vertex!(tri, 19998) - DT.delete_vertex!(tri, 28371, 3) - @test all(∉(tri.graph.vertices), (19998, 28371, 3)) - DT.delete_ghost_vertices_from_graph!(tri) - @test all(∉(tri.graph.vertices), -11:-1) - @test DT.get_neighbours(tri) == tri.graph.neighbours - @test DT.get_vertices(tri) == tri.graph.vertices - @test DT.get_vertices(tri) == each_vertex(tri) - @test num_vertices(tri) == length(DT.get_vertices(tri)) - @test all((DT.num_neighbours(tri, u) == DT.num_neighbours(DT.get_graph(tri), u) for u in DT.get_vertices(tri))) - end - - @testset "ConvexHull" begin - @test DT.get_convex_hull(tri) == tri.convex_hull - @test DT.get_convex_hull_vertices(tri) == tri.convex_hull.vertices - _tri = triangulate_rectangle(0.0, 2.0, 5.0, 7.3, 5, 15; single_boundary=true) - points = get_points(_tri) - ch = convex_hull(points) - @test ch.vertices == _tri.boundary_nodes - _indices = deepcopy(ch.vertices) - __indices = DT.get_convex_hull_vertices(_tri) - empty!(__indices) - DT.convex_hull!(_tri; reconstruct=false) - @test length(__indices) == length(_indices) - unique!(__indices) - unique!(ch.vertices) - shift = findfirst(ch.vertices .== first(__indices)) - ch.vertices .= circshift(ch.vertices, 1 - shift) - @test __indices == ch.vertices - DT.convex_hull!(_tri) - @test length(__indices) == length(_indices) - unique!(__indices) - shift = findfirst(ch.vertices .== first(__indices)) - ch.vertices .= circshift(ch.vertices, 1 - shift) - @test __indices == ch.vertices - delete_ghost_triangles!(_tri) - DT.convex_hull!(_tri; reconstruct=false) - @test length(__indices) == length(_indices) - unique!(__indices) - unique!(ch.vertices) - shift = findfirst(ch.vertices .== first(__indices)) - ch.vertices .= circshift(ch.vertices, 1 - shift) - @test __indices == ch.vertices - DT.convex_hull!(_tri) - @test length(__indices) == length(_indices) - unique!(__indices) - shift = findfirst(ch.vertices .== first(__indices)) - ch.vertices .= circshift(ch.vertices, 1 - shift) - @test __indices == ch.vertices - @test !DT.has_ghost_triangles(_tri) - end - - @testset "Boundary nodes" begin - @test DT.has_multiple_curves(tri) - @inferred DT.has_multiple_curves(tri) - @test !DT.has_multiple_curves(tri_2) - @test DT.has_multiple_sections(tri) - @test DT.has_multiple_sections(tri_2) - @test !DT.has_multiple_sections(tri_3) - @inferred DT.has_multiple_sections(tri_2) - @test DT.num_curves(tri) == 5 - @inferred DT.num_curves(tri) - a, b = 0.0, 5.0 - c, d = 3.0, 7.0 - nx = 12 - ny = 15 - @test DT.num_curves(triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 10, 10; delete_ghosts=false, single_boundary=false)) == 1 - @test DT.num_sections(tri_2) == 4 - @inferred DT.num_sections(tri_2) - @test DT.get_boundary_nodes(tri, 1) == tri.boundary_nodes[1] - @test DT.get_boundary_nodes(tri, 1, 3) == tri.boundary_nodes[1][3] - @test DT.get_boundary_nodes(tri, (5, 1)) == tri.boundary_nodes[5][1] - @test DT.get_boundary_nodes(tri_2, 1) == tri_2.boundary_nodes[1] - @test DT.get_boundary_nodes(tri_2, 3) == tri_2.boundary_nodes[3] - @test DT.get_boundary_nodes(tri_3) == tri_3.boundary_nodes - @test DT.get_boundary_nodes(tri_2, 3) == tri_2.boundary_nodes[3] - @test DT.get_curve_index(tri, -1) == 1 - @test DT.get_curve_index(tri, -3) == 1 - @test DT.get_curve_index(tri, -5) == 2 - @test DT.get_curve_index(tri, -11) == 5 - @test DT.get_curve_index(tri_2, -3) == 1 - @test DT.get_curve_index(tri_2, -2) == 1 - @test DT.get_curve_index(tri_3, -1) == 1 - @inferred DT.get_curve_index(tri_3, -1) - end - - @testset "Triangles" begin - rng = StableRNG(9882881) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) - A = get_area(tri) - refine!(tri; max_area=1e-1A, rng, use_circumcenter=true) - @test DT.triangle_type(tri) == NTuple{3,Int} - @inferred DT.triangle_type(tri) - @test DT.num_triangles(tri) == length(tri.triangles) - @test DT.each_triangle(tri) == tri.triangles - @inferred DT.num_triangles(tri) - @test DT.contains_triangle(tri, (68, 67, -6))[2] - @inferred DT.contains_triangle(tri, (68, 67, -6)) - @test !DT.contains_triangle(tri, (1, 1, 5))[2] - @test !DT.contains_triangle(tri, 1, 5, 5)[2] - @inferred DT.contains_triangle(tri, 3, 140, 1126) - @test DT.construct_positively_oriented_triangle(tri, 1, 10, 20) == (10, 1, 20) - @inferred DT.construct_positively_oriented_triangle(tri, 188, 394, 426) - _solid_itr = each_solid_triangle(tri) - @test DelaunayTriangulation.each_triangle(_solid_itr) == _solid_itr - @test Base.IteratorSize(_solid_itr) == Base.HasLength() - @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() - @test Base.eltype(_solid_itr) == NTuple{3,Int} - @test each_solid_triangle(tri) isa DT.EachSolidTriangle - _solid_tri = collect(_solid_itr) - @inferred collect(_solid_itr) - @test all(!DT.is_ghost_triangle, _solid_tri) - _ghost_itr = each_ghost_triangle(tri) - @test Base.IteratorSize(_ghost_itr) == Base.HasLength() - @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() - @test Base.eltype(_ghost_itr) == NTuple{3,Int} - @test each_ghost_triangle(tri) isa DT.EachGhostTriangle - _ghost_tri = collect(_ghost_itr) - @inferred collect(_ghost_itr) - @test DelaunayTriangulation.each_triangle(_ghost_itr) == _ghost_itr - @test all(DT.is_ghost_triangle, _ghost_tri) - @test length(_ghost_tri) + length(_solid_tri) == num_triangles(tri) - @test length(_solid_tri) == DT.num_solid_triangles(tri) == length(_solid_itr) - @test length(_ghost_tri) == DT.num_ghost_triangles(tri) == length(_ghost_itr) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - rng = StableRNG(9882881) - ___tri = triangulate(points; boundary_nodes, delete_ghosts=false, rng) - A = get_area(___tri) - refine!(___tri; max_area=1e-1A, rng, use_circumcenter=true) - DT.delete_ghost_triangles!(___tri) - @test collect(each_triangle(___tri)) == collect(each_solid_triangle(___tri)) - @test length(collect(each_ghost_triangle(___tri))) == 0 - @test sort(collect(filter(!DT.is_ghost_triangle, each_triangle(___tri)))) == sort(collect(each_solid_triangle(___tri))) - @test sort(collect(filter(DT.is_ghost_triangle, each_triangle(___tri)))) == sort(collect(each_ghost_triangle(___tri))) - @test DelaunayTriangulation.triangle_type(_ghost_itr) == DelaunayTriangulation.triangle_type(_ghost_itr) - @test DelaunayTriangulation.triangle_type(_solid_itr) == DelaunayTriangulation.triangle_type(_solid_itr) - end - - @testset "Edges" begin - rng = StableRNG(998871) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) - A = get_area(tri) - refine!(tri; max_area=1e-1A, rng, use_circumcenter=true) - @test DT.edge_type(tri) == NTuple{2,Int} - @inferred DT.edge_type(tri) - @test DT.num_edges(tri) == length(tri.graph.edges) - @inferred DT.num_edges(tri) - @test DT.each_edge(tri) == tri.graph.edges - @inferred DT.each_edge(tri) - _solid_itr = each_solid_edge(tri) - @test DelaunayTriangulation.each_edge(_solid_itr) == _solid_itr - @test Base.IteratorSize(_solid_itr) == Base.HasLength() - @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() - @test Base.eltype(_solid_itr) == NTuple{2,Int} - @test each_solid_edge(tri) isa DT.EachSolidEdge - _solid_tri = collect(_solid_itr) - @inferred collect(_solid_itr) - @test all(!DT.is_ghost_edge, _solid_tri) - _ghost_itr = each_ghost_edge(tri) - @test Base.IteratorSize(_ghost_itr) == Base.HasLength() - @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() - @test Base.eltype(_ghost_itr) == NTuple{2,Int} - @test each_ghost_edge(tri) isa DT.EachGhostEdge - _ghost_tri = collect(_ghost_itr) - @inferred collect(_ghost_itr) - @test DelaunayTriangulation.each_edge(_ghost_itr) == _ghost_itr - @test all(DT.is_ghost_edge, _ghost_tri) - @test length(_ghost_tri) + length(_solid_tri) == num_edges(tri) - rng = StableRNG(998871) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - ___tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) - A = get_area(___tri) - refine!(___tri; max_area=1e-1A, rng, use_circumcenter=true) - DT.delete_ghost_triangles!(___tri) - @test sort(collect(filter(!DT.is_ghost_edge, each_edge(___tri)))) == sort(collect(each_solid_edge(___tri))) - @test sort(collect(filter(DT.is_ghost_edge, each_edge(___tri)))) == sort(collect(each_ghost_edge(___tri))) - @test length(collect(each_ghost_edge(___tri))) == num_edges(___tri) .- length(sort(collect(filter(!DT.is_ghost_edge, each_edge(___tri))))) - @test length(collect(each_ghost_edge(___tri))) == DT.num_ghost_edges(___tri) == length(_ghost_itr) - @test length(collect(each_solid_edge(___tri))) == DT.num_solid_edges(___tri) == length(_solid_itr) - @test DelaunayTriangulation.edge_type(_ghost_itr) == DelaunayTriangulation.edge_type(_ghost_itr) - @test DelaunayTriangulation.edge_type(_solid_itr) == DelaunayTriangulation.edge_type(_solid_itr) - end - - @testset "Points" begin - @test DT.get_point(tri, 2) == Tuple(tri.points[2]) - @inferred DT.get_point(tri, 2) - @test DT.get_point(tri, 17) == Tuple(tri.points[17]) - @test DT.each_point_index(tri) == 1:length(tri.points) - @inferred DT.each_point_index(tri) - @test DT.each_point(tri) == tri.points - @inferred DT.each_point(tri) - @test DT.num_points(tri) == length(tri.points) - @inferred DT.num_points(tri) - @test DT.get_point(tri, 2, 5, 6, 10) == - ntuple(i -> Tuple(tri.points[(2, 5, 6, 10)[i]]), 4) - @inferred DT.get_point(tri, 2, 5, 6, 10) - rep = DT.get_representative_point_list(tri) - rep[1] = DT.RepresentativeCoordinates(0.5, 0.3, 2) - rep[2] = DT.RepresentativeCoordinates(2.5, 7.3, 7) - rep[3] = DT.RepresentativeCoordinates(6.5, -0.6, 13) - rep[4] = DT.RepresentativeCoordinates(6.5, -0.66234, 13) - rep[5] = DT.RepresentativeCoordinates(6.534234, -0.6, 13) - @test DT.get_point(tri, -1) == DT.getxy(rep[1]) - @test DT.get_point(tri, -2) == DT.getxy(rep[1]) - @test DT.get_point(tri, -3) == DT.getxy(rep[1]) - @test DT.get_point(tri, -4) == DT.getxy(rep[1]) - @test DT.get_point(tri, -5) == DT.getxy(rep[2]) - @test DT.get_point(tri, -6) == DT.getxy(rep[3]) - @test DT.get_point(tri, -7) == DT.getxy(rep[4]) - @test DT.get_point(tri, -8) == DT.getxy(rep[4]) - @test DT.get_point(tri, -9) == DT.getxy(rep[4]) - @test DT.get_point(tri, -10) == DT.getxy(rep[4]) - @test DT.get_point(tri, -11) == DT.getxy(rep[5]) - rep = DT.get_representative_point_list(tri_2) - @test DT.get_point(tri_2, -1) == DT.getxy(rep[1]) - @inferred DT.get_point(tri_2, -1) - @test DT.get_point(tri_2, -2) == DT.getxy(rep[1]) - @test DT.get_point(tri_2, -3) == DT.getxy(rep[1]) - @test DT.get_point(tri_2, -4) == DT.getxy(rep[1]) - @test DT.get_point(tri_3, -1) == DT.getxy(DT.get_representative_point_coordinates(tri_3, 1)) - @test_throws KeyError DT.get_point(tri, -12) - @test_throws KeyError DT.get_point(tri_2, -5) - @test_throws KeyError DT.get_point(tri_3, -2) - @test get_point(tri, tri.points[2]) == tri.points[2] - @inferred get_point(tri, tri.points[2]) - @test reverse(sort(collect(DT.all_ghost_vertices(tri)))) == [DT.𝒢, - DT.𝒢 - 1, - DT.𝒢 - 2, - DT.𝒢 - 3, - DT.𝒢 - 4, - DT.𝒢 - 5, - DT.𝒢 - 6, - DT.𝒢 - 7, - DT.𝒢 - 8, - DT.𝒢 - 9, - DT.𝒢 - 10]#(new_point, c′) = (436, (1.8363241117152609, 1.0864161502095007)) - rng = StableRNG(887271) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - _triq = triangulate(points; boundary_nodes, rng) - A = get_area(_triq) - refine!(_triq; max_area=1e-1A, rng, use_circumcenter=true, use_lens=false) - _solid_itr = each_solid_vertex(_triq) - @test DelaunayTriangulation.each_vertex(_solid_itr) == _solid_itr - @test Base.IteratorSize(_solid_itr) == Base.HasLength() - @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() - @test Base.eltype(_solid_itr) == Int - @test each_solid_vertex(_triq) isa DT.EachSolidVertex - _solid_tri = collect(_solid_itr) - @inferred collect(_solid_itr) - @test sort(_solid_tri) == sort(filter(i -> DT.has_vertex(_triq, i) && i ≥ 1, 1:DT.num_points(tri))) - @test all(!DT.is_ghost_vertex, _solid_tri) - _ghost_itr = each_ghost_vertex(_triq) - @test Base.IteratorSize(_ghost_itr) == Base.HasLength() - @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() - @test Base.eltype(_ghost_itr) == Int - @test each_ghost_vertex(_triq) isa DT.EachGhostVertex - _ghost_tri = collect(_ghost_itr) - @inferred collect(_ghost_itr) - @test DelaunayTriangulation.each_vertex(_ghost_itr) == _ghost_itr - @test all(DT.is_ghost_vertex, _ghost_tri) - @test reverse(sort(_ghost_tri)) == [DT.𝒢, - DT.𝒢 - 1, - DT.𝒢 - 2, - DT.𝒢 - 3, - DT.𝒢 - 4, - DT.𝒢 - 5, - DT.𝒢 - 6, - DT.𝒢 - 7, - DT.𝒢 - 8, - DT.𝒢 - 9, - DT.𝒢 - 10] - @test length(_ghost_tri) == length(_ghost_itr) == sum(<(0), keys(_triq.adjacent2vertex.adjacent2vertex)) - @test length(_solid_tri) == length(_solid_itr) == sort(filter(i -> DT.has_vertex(_triq, i) && i ≥ 1, 1:DT.num_points(tri))) |> length - rng = StableRNG(887271) - ___tri = triangulate(points; boundary_nodes, rng) - A = get_area(___tri) - refine!(___tri; max_area=1e-1A, rng, use_circumcenter=true) - DT.delete_ghost_triangles!(___tri) - @test sort(collect(filter(!DT.is_ghost_vertex, each_vertex(___tri)))) == sort(collect(each_solid_vertex(___tri))) - @test sort(collect(filter(DT.is_ghost_vertex, each_vertex(___tri)))) == sort(collect(each_ghost_vertex(___tri))) - @test length(collect(each_ghost_vertex(___tri))) == num_vertices(___tri) .- length(sort(collect(filter(!DT.is_ghost_vertex, each_vertex(___tri))))) - tri1 = Triangulation([[1.0, 2.0], [3.0, 4.0]]) - DT.push_point!(tri1, 13.7, 5.0) - @test get_points(tri1) == [[1.0, 2.0], [3.0, 4.0], [13.7, 5.0]] - @test get_point(tri1, 3) == (13.7, 5.0) - tri1 = Triangulation([(1.0, 2.0), (3.0, 4.0)]) - DT.push_point!(tri1, 13.7, 5.0) - @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0)] - @test get_point(tri1, 3) == (13.7, 5.0) - DT.push_point!(tri1, (19.0, 17.05)) - @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0), (19.0, 17.05)] - DT.pop_point!(tri1) - @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0)] - DT.pop_point!(tri1) - @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0)] - DT.set_point!(tri1, 2, 13.7, 5.0) - @test get_points(tri1) == [(1.0, 2.0), (13.7, 5.0)] - DT.set_point!(tri1, 2, (19.0, 17.05)) - @test get_points(tri1) == [(1.0, 2.0), (19.0, 17.05)] - end - - @testset "Miscellaneous" begin - @test DT.integer_type(tri) == Int - @test DT.number_type(tri) == Float64 - @test DT.edge_type(tri) == NTuple{2,Int} - @test DT.edges_type(tri) == Set{NTuple{2,Int}} - @test DT.triangles_type(tri) == Set{NTuple{3,Int}} - @test DT.triangle_type(tri) == NTuple{3,Int} - @inferred DT.integer_type(tri) - @inferred DT.number_type(tri) - DT.clear_empty_features!(tri) - clean_tri = deepcopy(tri) - get_adjacent(tri, 17, 32) - get_adjacent(tri, 58, 37) - DT.add_adjacent2vertex!(tri, 3, 58, 60) - DT.add_neighbour!(tri, 5, 171) - @test clean_tri ≠ tri - DT.delete_adjacent2vertex!(tri, 3, 58, 60) - DT.delete_neighbour!(tri, 5, 171) - @test clean_tri == tri - _tri = triangulate_rectangle(0.0, 10.0, 0.0, 20.0, 11, 21) - T = (51, 41, 52) - ℓ = (7.0, 3.5) - @test DT.find_edge(_tri, T, ℓ) == (41, 52) - ℓ = (6.5, 4.0) - @test DT.find_edge(_tri, T, ℓ) == (52, 51) - ℓ = (6.5, 3.5) - @test DT.find_edge(_tri, T, ℓ) == (51, 41) - @inferred DT.find_edge(_tri, T, ℓ) - push!(get_all_segments(_tri), (1, 2)) - @test DT.is_constrained(_tri) - empty!(get_all_segments(_tri)) - @test !DT.is_constrained(_tri) - @test reverse(sort(collect(DT.all_ghost_vertices(_tri)))) == - [DT.𝒢, DT.𝒢 - 1, DT.𝒢 - 2, DT.𝒢 - 3] - end + @testset "Adjacent" begin + @test DT.get_adjacent(tri, 92, -6) == tri.adjacent.adjacent[(92, -6)] + @test DT.get_adjacent(tri, (723, 1356)) == get(tri.adjacent.adjacent, (723, 1356), DT.∅) + @inferred DT.get_adjacent(tri, (723, 1356)) + DT.add_adjacent!(tri, 101117, 20311, 5) + DT.add_adjacent!(tri, (27311, 50511), 10) + @test DT.get_adjacent(tri, 101117, 20311) == 5 + @inferred DT.get_adjacent(tri, 101117, 20311) + @test DT.get_adjacent(tri, 27311, 50511) == 10 + DT.delete_adjacent!(tri, 101117, 20311) + DT.delete_adjacent!(tri, (27311, 50511)) + @test DT.get_adjacent(tri, 101117, 20311) == DT.∅ + @test DT.get_adjacent(tri, 27311, 50511) == DT.∅ + @test DT.get_adjacent(tri, 711, DT.𝒢) == DT.∅ + end + + @testset "Adjacent2Vertex" begin + @test DT.get_adjacent2vertex(tri, -6) == tri.adjacent2vertex.adjacent2vertex[-6] + @inferred DT.get_adjacent2vertex(tri, -6) + DT.add_adjacent2vertex!(tri, 10005, 23, 27) + DT.add_adjacent2vertex!(tri, 19988, (50, 171)) + @test DT.contains_edge(23, 27, tri.adjacent2vertex.adjacent2vertex[10005]) + @test DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) + @inferred DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) + DT.delete_adjacent2vertex!(tri, 10005, 23, 27) + DT.delete_adjacent2vertex!(tri, 19988, (50, 171)) + @test !DT.contains_edge(23, 27, tri.adjacent2vertex.adjacent2vertex[10005]) + @test !DT.contains_edge(50, 171, tri.adjacent2vertex.adjacent2vertex[19988]) + @test 6 ∈ keys(tri.adjacent2vertex.adjacent2vertex) + DT.delete_adjacent2vertex!(tri, -6) + @test -6 ∉ keys(tri.adjacent2vertex.adjacent2vertex) + end + + @testset "Graph" begin + @test DT.get_edges(tri) == tri.graph.edges == DT.get_edges(tri.graph) + @inferred DT.get_edges(tri) + @test DT.get_neighbours(tri, 3) == tri.graph.neighbours[3] + @inferred DT.get_neighbours(tri, 3) + DT.add_vertex!(tri, 19998, 23721) + DT.add_vertex!(tri, 28371) + @test all(∈(tri.graph.vertices), (19998, 23721, 28371)) + DT.add_neighbour!(tri, 28371, 50912) + DT.add_neighbour!(tri, 28371, 271, 501) + @test all(∈(tri.graph.neighbours[28371]), (50912, 271, 501)) + DT.delete_neighbour!(tri, 28371, 50912) + DT.delete_neighbour!(tri, 28371, 271, 501) + @test all(∉(tri.graph.neighbours[28371]), (50912, 271, 501)) + DT.delete_vertex!(tri, 19998) + DT.delete_vertex!(tri, 28371, 3) + @test all(∉(tri.graph.vertices), (19998, 28371, 3)) + DT.delete_ghost_vertices_from_graph!(tri) + @test all(∉(tri.graph.vertices), -11:-1) + @test DT.get_neighbours(tri) == tri.graph.neighbours + @test DT.get_vertices(tri) == tri.graph.vertices + @test DT.get_vertices(tri) == each_vertex(tri) + @test num_vertices(tri) == length(DT.get_vertices(tri)) + @test all((DT.num_neighbours(tri, u) == DT.num_neighbours(DT.get_graph(tri), u) for u in DT.get_vertices(tri))) + end + + @testset "ConvexHull" begin + @test DT.get_convex_hull(tri) == tri.convex_hull + @test DT.get_convex_hull_vertices(tri) == tri.convex_hull.vertices + _tri = triangulate_rectangle(0.0, 2.0, 5.0, 7.3, 5, 15; single_boundary = true) + points = get_points(_tri) + ch = convex_hull(points) + @test ch.vertices == _tri.boundary_nodes + _indices = deepcopy(ch.vertices) + __indices = DT.get_convex_hull_vertices(_tri) + empty!(__indices) + DT.convex_hull!(_tri; reconstruct = false) + @test length(__indices) == length(_indices) + unique!(__indices) + unique!(ch.vertices) + shift = findfirst(ch.vertices .== first(__indices)) + ch.vertices .= circshift(ch.vertices, 1 - shift) + @test __indices == ch.vertices + DT.convex_hull!(_tri) + @test length(__indices) == length(_indices) + unique!(__indices) + shift = findfirst(ch.vertices .== first(__indices)) + ch.vertices .= circshift(ch.vertices, 1 - shift) + @test __indices == ch.vertices + delete_ghost_triangles!(_tri) + DT.convex_hull!(_tri; reconstruct = false) + @test length(__indices) == length(_indices) + unique!(__indices) + unique!(ch.vertices) + shift = findfirst(ch.vertices .== first(__indices)) + ch.vertices .= circshift(ch.vertices, 1 - shift) + @test __indices == ch.vertices + DT.convex_hull!(_tri) + @test length(__indices) == length(_indices) + unique!(__indices) + shift = findfirst(ch.vertices .== first(__indices)) + ch.vertices .= circshift(ch.vertices, 1 - shift) + @test __indices == ch.vertices + @test !DT.has_ghost_triangles(_tri) + end + + @testset "Boundary nodes" begin + @test DT.has_multiple_curves(tri) + @inferred DT.has_multiple_curves(tri) + @test !DT.has_multiple_curves(tri_2) + @test DT.has_multiple_sections(tri) + @test DT.has_multiple_sections(tri_2) + @test !DT.has_multiple_sections(tri_3) + @inferred DT.has_multiple_sections(tri_2) + @test DT.num_curves(tri) == 5 + @inferred DT.num_curves(tri) + a, b = 0.0, 5.0 + c, d = 3.0, 7.0 + nx = 12 + ny = 15 + @test DT.num_curves(triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 10, 10; delete_ghosts = false, single_boundary = false)) == 1 + @test DT.num_sections(tri_2) == 4 + @inferred DT.num_sections(tri_2) + @test DT.get_boundary_nodes(tri, 1) == tri.boundary_nodes[1] + @test DT.get_boundary_nodes(tri, 1, 3) == tri.boundary_nodes[1][3] + @test DT.get_boundary_nodes(tri, (5, 1)) == tri.boundary_nodes[5][1] + @test DT.get_boundary_nodes(tri_2, 1) == tri_2.boundary_nodes[1] + @test DT.get_boundary_nodes(tri_2, 3) == tri_2.boundary_nodes[3] + @test DT.get_boundary_nodes(tri_3) == tri_3.boundary_nodes + @test DT.get_boundary_nodes(tri_2, 3) == tri_2.boundary_nodes[3] + @test DT.get_curve_index(tri, -1) == 1 + @test DT.get_curve_index(tri, -3) == 1 + @test DT.get_curve_index(tri, -5) == 2 + @test DT.get_curve_index(tri, -11) == 5 + @test DT.get_curve_index(tri_2, -3) == 1 + @test DT.get_curve_index(tri_2, -2) == 1 + @test DT.get_curve_index(tri_3, -1) == 1 + @inferred DT.get_curve_index(tri_3, -1) + end + + @testset "Triangles" begin + rng = StableRNG(9882881) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) + A = get_area(tri) + refine!(tri; max_area = 1.0e-1A, rng, use_circumcenter = true) + @test DT.triangle_type(tri) == NTuple{3, Int} + @inferred DT.triangle_type(tri) + @test DT.num_triangles(tri) == length(tri.triangles) + @test DT.each_triangle(tri) == tri.triangles + @inferred DT.num_triangles(tri) + @test DT.contains_triangle(tri, (68, 67, -6))[2] + @inferred DT.contains_triangle(tri, (68, 67, -6)) + @test !DT.contains_triangle(tri, (1, 1, 5))[2] + @test !DT.contains_triangle(tri, 1, 5, 5)[2] + @inferred DT.contains_triangle(tri, 3, 140, 1126) + @test DT.construct_positively_oriented_triangle(tri, 1, 10, 20) == (10, 1, 20) + @inferred DT.construct_positively_oriented_triangle(tri, 188, 394, 426) + _solid_itr = each_solid_triangle(tri) + @test DelaunayTriangulation.each_triangle(_solid_itr) == _solid_itr + @test Base.IteratorSize(_solid_itr) == Base.HasLength() + @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() + @test Base.eltype(_solid_itr) == NTuple{3, Int} + @test each_solid_triangle(tri) isa DT.EachSolidTriangle + _solid_tri = collect(_solid_itr) + @inferred collect(_solid_itr) + @test all(!DT.is_ghost_triangle, _solid_tri) + _ghost_itr = each_ghost_triangle(tri) + @test Base.IteratorSize(_ghost_itr) == Base.HasLength() + @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() + @test Base.eltype(_ghost_itr) == NTuple{3, Int} + @test each_ghost_triangle(tri) isa DT.EachGhostTriangle + _ghost_tri = collect(_ghost_itr) + @inferred collect(_ghost_itr) + @test DelaunayTriangulation.each_triangle(_ghost_itr) == _ghost_itr + @test all(DT.is_ghost_triangle, _ghost_tri) + @test length(_ghost_tri) + length(_solid_tri) == num_triangles(tri) + @test length(_solid_tri) == DT.num_solid_triangles(tri) == length(_solid_itr) + @test length(_ghost_tri) == DT.num_ghost_triangles(tri) == length(_ghost_itr) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + rng = StableRNG(9882881) + ___tri = triangulate(points; boundary_nodes, delete_ghosts = false, rng) + A = get_area(___tri) + refine!(___tri; max_area = 1.0e-1A, rng, use_circumcenter = true) + DT.delete_ghost_triangles!(___tri) + @test collect(each_triangle(___tri)) == collect(each_solid_triangle(___tri)) + @test length(collect(each_ghost_triangle(___tri))) == 0 + @test sort(collect(filter(!DT.is_ghost_triangle, each_triangle(___tri)))) == sort(collect(each_solid_triangle(___tri))) + @test sort(collect(filter(DT.is_ghost_triangle, each_triangle(___tri)))) == sort(collect(each_ghost_triangle(___tri))) + @test DelaunayTriangulation.triangle_type(_ghost_itr) == DelaunayTriangulation.triangle_type(_ghost_itr) + @test DelaunayTriangulation.triangle_type(_solid_itr) == DelaunayTriangulation.triangle_type(_solid_itr) + end + + @testset "Edges" begin + rng = StableRNG(998871) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) + A = get_area(tri) + refine!(tri; max_area = 1.0e-1A, rng, use_circumcenter = true) + @test DT.edge_type(tri) == NTuple{2, Int} + @inferred DT.edge_type(tri) + @test DT.num_edges(tri) == length(tri.graph.edges) + @inferred DT.num_edges(tri) + @test DT.each_edge(tri) == tri.graph.edges + @inferred DT.each_edge(tri) + _solid_itr = each_solid_edge(tri) + @test DelaunayTriangulation.each_edge(_solid_itr) == _solid_itr + @test Base.IteratorSize(_solid_itr) == Base.HasLength() + @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() + @test Base.eltype(_solid_itr) == NTuple{2, Int} + @test each_solid_edge(tri) isa DT.EachSolidEdge + _solid_tri = collect(_solid_itr) + @inferred collect(_solid_itr) + @test all(!DT.is_ghost_edge, _solid_tri) + _ghost_itr = each_ghost_edge(tri) + @test Base.IteratorSize(_ghost_itr) == Base.HasLength() + @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() + @test Base.eltype(_ghost_itr) == NTuple{2, Int} + @test each_ghost_edge(tri) isa DT.EachGhostEdge + _ghost_tri = collect(_ghost_itr) + @inferred collect(_ghost_itr) + @test DelaunayTriangulation.each_edge(_ghost_itr) == _ghost_itr + @test all(DT.is_ghost_edge, _ghost_tri) + @test length(_ghost_tri) + length(_solid_tri) == num_edges(tri) + rng = StableRNG(998871) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + ___tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) + A = get_area(___tri) + refine!(___tri; max_area = 1.0e-1A, rng, use_circumcenter = true) + DT.delete_ghost_triangles!(___tri) + @test sort(collect(filter(!DT.is_ghost_edge, each_edge(___tri)))) == sort(collect(each_solid_edge(___tri))) + @test sort(collect(filter(DT.is_ghost_edge, each_edge(___tri)))) == sort(collect(each_ghost_edge(___tri))) + @test length(collect(each_ghost_edge(___tri))) == num_edges(___tri) .- length(sort(collect(filter(!DT.is_ghost_edge, each_edge(___tri))))) + @test length(collect(each_ghost_edge(___tri))) == DT.num_ghost_edges(___tri) == length(_ghost_itr) + @test length(collect(each_solid_edge(___tri))) == DT.num_solid_edges(___tri) == length(_solid_itr) + @test DelaunayTriangulation.edge_type(_ghost_itr) == DelaunayTriangulation.edge_type(_ghost_itr) + @test DelaunayTriangulation.edge_type(_solid_itr) == DelaunayTriangulation.edge_type(_solid_itr) + end + + @testset "Points" begin + @test DT.get_point(tri, 2) == Tuple(tri.points[2]) + @inferred DT.get_point(tri, 2) + @test DT.get_point(tri, 17) == Tuple(tri.points[17]) + @test DT.each_point_index(tri) == 1:length(tri.points) + @inferred DT.each_point_index(tri) + @test DT.each_point(tri) == tri.points + @inferred DT.each_point(tri) + @test DT.num_points(tri) == length(tri.points) + @inferred DT.num_points(tri) + @test DT.get_point(tri, 2, 5, 6, 10) == + ntuple(i -> Tuple(tri.points[(2, 5, 6, 10)[i]]), 4) + @inferred DT.get_point(tri, 2, 5, 6, 10) + rep = DT.get_representative_point_list(tri) + rep[1] = DT.RepresentativeCoordinates(0.5, 0.3, 2) + rep[2] = DT.RepresentativeCoordinates(2.5, 7.3, 7) + rep[3] = DT.RepresentativeCoordinates(6.5, -0.6, 13) + rep[4] = DT.RepresentativeCoordinates(6.5, -0.66234, 13) + rep[5] = DT.RepresentativeCoordinates(6.534234, -0.6, 13) + @test DT.get_point(tri, -1) == DT.getxy(rep[1]) + @test DT.get_point(tri, -2) == DT.getxy(rep[1]) + @test DT.get_point(tri, -3) == DT.getxy(rep[1]) + @test DT.get_point(tri, -4) == DT.getxy(rep[1]) + @test DT.get_point(tri, -5) == DT.getxy(rep[2]) + @test DT.get_point(tri, -6) == DT.getxy(rep[3]) + @test DT.get_point(tri, -7) == DT.getxy(rep[4]) + @test DT.get_point(tri, -8) == DT.getxy(rep[4]) + @test DT.get_point(tri, -9) == DT.getxy(rep[4]) + @test DT.get_point(tri, -10) == DT.getxy(rep[4]) + @test DT.get_point(tri, -11) == DT.getxy(rep[5]) + rep = DT.get_representative_point_list(tri_2) + @test DT.get_point(tri_2, -1) == DT.getxy(rep[1]) + @inferred DT.get_point(tri_2, -1) + @test DT.get_point(tri_2, -2) == DT.getxy(rep[1]) + @test DT.get_point(tri_2, -3) == DT.getxy(rep[1]) + @test DT.get_point(tri_2, -4) == DT.getxy(rep[1]) + @test DT.get_point(tri_3, -1) == DT.getxy(DT.get_representative_point_coordinates(tri_3, 1)) + @test_throws KeyError DT.get_point(tri, -12) + @test_throws KeyError DT.get_point(tri_2, -5) + @test_throws KeyError DT.get_point(tri_3, -2) + @test get_point(tri, tri.points[2]) == tri.points[2] + @inferred get_point(tri, tri.points[2]) + @test reverse(sort(collect(DT.all_ghost_vertices(tri)))) == [ + DT.𝒢, + DT.𝒢 - 1, + DT.𝒢 - 2, + DT.𝒢 - 3, + DT.𝒢 - 4, + DT.𝒢 - 5, + DT.𝒢 - 6, + DT.𝒢 - 7, + DT.𝒢 - 8, + DT.𝒢 - 9, + DT.𝒢 - 10, + ]#(new_point, c′) = (436, (1.8363241117152609, 1.0864161502095007)) + rng = StableRNG(887271) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + _triq = triangulate(points; boundary_nodes, rng) + A = get_area(_triq) + refine!(_triq; max_area = 1.0e-1A, rng, use_circumcenter = true, use_lens = false) + _solid_itr = each_solid_vertex(_triq) + @test DelaunayTriangulation.each_vertex(_solid_itr) == _solid_itr + @test Base.IteratorSize(_solid_itr) == Base.HasLength() + @test Base.IteratorEltype(_solid_itr) == Base.HasEltype() + @test Base.eltype(_solid_itr) == Int + @test each_solid_vertex(_triq) isa DT.EachSolidVertex + _solid_tri = collect(_solid_itr) + @inferred collect(_solid_itr) + @test sort(_solid_tri) == sort(filter(i -> DT.has_vertex(_triq, i) && i ≥ 1, 1:DT.num_points(tri))) + @test all(!DT.is_ghost_vertex, _solid_tri) + _ghost_itr = each_ghost_vertex(_triq) + @test Base.IteratorSize(_ghost_itr) == Base.HasLength() + @test Base.IteratorEltype(_ghost_itr) == Base.HasEltype() + @test Base.eltype(_ghost_itr) == Int + @test each_ghost_vertex(_triq) isa DT.EachGhostVertex + _ghost_tri = collect(_ghost_itr) + @inferred collect(_ghost_itr) + @test DelaunayTriangulation.each_vertex(_ghost_itr) == _ghost_itr + @test all(DT.is_ghost_vertex, _ghost_tri) + @test reverse(sort(_ghost_tri)) == [ + DT.𝒢, + DT.𝒢 - 1, + DT.𝒢 - 2, + DT.𝒢 - 3, + DT.𝒢 - 4, + DT.𝒢 - 5, + DT.𝒢 - 6, + DT.𝒢 - 7, + DT.𝒢 - 8, + DT.𝒢 - 9, + DT.𝒢 - 10, + ] + @test length(_ghost_tri) == length(_ghost_itr) == sum(<(0), keys(_triq.adjacent2vertex.adjacent2vertex)) + @test length(_solid_tri) == length(_solid_itr) == sort(filter(i -> DT.has_vertex(_triq, i) && i ≥ 1, 1:DT.num_points(tri))) |> length + rng = StableRNG(887271) + ___tri = triangulate(points; boundary_nodes, rng) + A = get_area(___tri) + refine!(___tri; max_area = 1.0e-1A, rng, use_circumcenter = true) + DT.delete_ghost_triangles!(___tri) + @test sort(collect(filter(!DT.is_ghost_vertex, each_vertex(___tri)))) == sort(collect(each_solid_vertex(___tri))) + @test sort(collect(filter(DT.is_ghost_vertex, each_vertex(___tri)))) == sort(collect(each_ghost_vertex(___tri))) + @test length(collect(each_ghost_vertex(___tri))) == num_vertices(___tri) .- length(sort(collect(filter(!DT.is_ghost_vertex, each_vertex(___tri))))) + tri1 = Triangulation([[1.0, 2.0], [3.0, 4.0]]) + DT.push_point!(tri1, 13.7, 5.0) + @test get_points(tri1) == [[1.0, 2.0], [3.0, 4.0], [13.7, 5.0]] + @test get_point(tri1, 3) == (13.7, 5.0) + tri1 = Triangulation([(1.0, 2.0), (3.0, 4.0)]) + DT.push_point!(tri1, 13.7, 5.0) + @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0)] + @test get_point(tri1, 3) == (13.7, 5.0) + DT.push_point!(tri1, (19.0, 17.05)) + @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0), (19.0, 17.05)] + DT.pop_point!(tri1) + @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0), (13.7, 5.0)] + DT.pop_point!(tri1) + @test get_points(tri1) == [(1.0, 2.0), (3.0, 4.0)] + DT.set_point!(tri1, 2, 13.7, 5.0) + @test get_points(tri1) == [(1.0, 2.0), (13.7, 5.0)] + DT.set_point!(tri1, 2, (19.0, 17.05)) + @test get_points(tri1) == [(1.0, 2.0), (19.0, 17.05)] + end + + @testset "Miscellaneous" begin + @test DT.integer_type(tri) == Int + @test DT.number_type(tri) == Float64 + @test DT.edge_type(tri) == NTuple{2, Int} + @test DT.edges_type(tri) == Set{NTuple{2, Int}} + @test DT.triangles_type(tri) == Set{NTuple{3, Int}} + @test DT.triangle_type(tri) == NTuple{3, Int} + @inferred DT.integer_type(tri) + @inferred DT.number_type(tri) + DT.clear_empty_features!(tri) + clean_tri = deepcopy(tri) + get_adjacent(tri, 17, 32) + get_adjacent(tri, 58, 37) + DT.add_adjacent2vertex!(tri, 3, 58, 60) + DT.add_neighbour!(tri, 5, 171) + @test clean_tri ≠ tri + DT.delete_adjacent2vertex!(tri, 3, 58, 60) + DT.delete_neighbour!(tri, 5, 171) + @test clean_tri == tri + _tri = triangulate_rectangle(0.0, 10.0, 0.0, 20.0, 11, 21) + T = (51, 41, 52) + ℓ = (7.0, 3.5) + @test DT.find_edge(_tri, T, ℓ) == (41, 52) + ℓ = (6.5, 4.0) + @test DT.find_edge(_tri, T, ℓ) == (52, 51) + ℓ = (6.5, 3.5) + @test DT.find_edge(_tri, T, ℓ) == (51, 41) + @inferred DT.find_edge(_tri, T, ℓ) + push!(get_all_segments(_tri), (1, 2)) + @test DT.is_constrained(_tri) + empty!(get_all_segments(_tri)) + @test !DT.is_constrained(_tri) + @test reverse(sort(collect(DT.all_ghost_vertices(_tri)))) == + [DT.𝒢, DT.𝒢 - 1, DT.𝒢 - 2, DT.𝒢 - 3] + end end @testset "merge_segments" begin - all_bn = get_boundary_nodes(tri) - i = rand(1:100000, 50) - j = rand(1:100000, 50) - all_ce = Set(((i, j) for (i, j) in zip(i, j))) - bn_map = get_ghost_vertex_map(tri) - bn1 = all_bn[1] - bn11 = bn1[1] - bn12 = bn1[2] - bn13 = bn1[3] - bn14 = bn1[4] - bn2 = all_bn[2][1] - bn3 = all_bn[3][1] - bn4 = all_bn[4] - bn41 = bn4[1] - bn42 = bn4[2] - bn43 = bn4[3] - bn44 = bn4[4] - bn5 = all_bn[5][1] - e11 = Set(((bn11[i], bn11[i+1]) for i in 1:(length(bn11)-1))) - e12 = Set(((bn12[i], bn12[i+1]) for i in 1:(length(bn12)-1))) - e13 = Set(((bn13[i], bn13[i+1]) for i in 1:(length(bn13)-1))) - e14 = Set(((bn14[i], bn14[i+1]) for i in 1:(length(bn14)-1))) - e2 = Set(((bn2[i], bn2[i+1]) for i in 1:(length(bn2)-1))) - e3 = Set(((bn3[i], bn3[i+1]) for i in 1:(length(bn3)-1))) - e41 = Set(((bn41[i], bn41[i+1]) for i in 1:(length(bn41)-1))) - e42 = Set(((bn42[i], bn42[i+1]) for i in 1:(length(bn42)-1))) - e43 = Set(((bn43[i], bn43[i+1]) for i in 1:(length(bn43)-1))) - e44 = Set(((bn44[i], bn44[i+1]) for i in 1:(length(bn44)-1))) - e5 = Set(((bn5[i], bn5[i+1]) for i in 1:(length(bn5)-1))) - ace = Set{NTuple{2,Int}}() - for es in (e11, e12, e13, e14, e2, e3, e41, e42, e43, e44, e5) - for e in es - push!(ace, e) - end - end - for e in all_ce - push!(ace, e) - end - @test ace == DT.merge_segments(bn_map, all_bn, all_ce) - - all_bn = get_boundary_nodes(tri_2) - i = rand(1:100000, 50) - j = rand(1:100000, 50) - all_ce = Set(((i, j) for (i, j) in zip(i, j))) - bn_map = get_ghost_vertex_map(tri_2) - bn1 = all_bn[1] - bn2 = all_bn[2] - bn3 = all_bn[3] - bn4 = all_bn[4] - e1 = Set(((bn1[i], bn1[i+1]) for i in 1:(length(bn1)-1))) - e2 = Set(((bn2[i], bn2[i+1]) for i in 1:(length(bn2)-1))) - e3 = Set(((bn3[i], bn3[i+1]) for i in 1:(length(bn3)-1))) - e4 = Set(((bn4[i], bn4[i+1]) for i in 1:(length(bn4)-1))) - ace = Set{NTuple{2,Int}}() - for es in (e1, e2, e3, e4) - for e in es - push!(ace, e) - end - end - for e in all_ce - push!(ace, e) - end - @test ace == DT.merge_segments(bn_map, all_bn, all_ce) - - all_bn = get_boundary_nodes(tri_3) - i = rand(1:100000, 50) - j = rand(1:100000, 50) - all_ce = Set(((i, j) for (i, j) in zip(i, j))) - bn_map = get_ghost_vertex_map(tri_3) - e = Set(((all_bn[i], all_bn[i+1]) for i in 1:(length(all_bn)-1))) - ace = Set{NTuple{2,Int}}() - for e in e + all_bn = get_boundary_nodes(tri) + i = rand(1:100000, 50) + j = rand(1:100000, 50) + all_ce = Set(((i, j) for (i, j) in zip(i, j))) + bn_map = get_ghost_vertex_map(tri) + bn1 = all_bn[1] + bn11 = bn1[1] + bn12 = bn1[2] + bn13 = bn1[3] + bn14 = bn1[4] + bn2 = all_bn[2][1] + bn3 = all_bn[3][1] + bn4 = all_bn[4] + bn41 = bn4[1] + bn42 = bn4[2] + bn43 = bn4[3] + bn44 = bn4[4] + bn5 = all_bn[5][1] + e11 = Set(((bn11[i], bn11[i + 1]) for i in 1:(length(bn11) - 1))) + e12 = Set(((bn12[i], bn12[i + 1]) for i in 1:(length(bn12) - 1))) + e13 = Set(((bn13[i], bn13[i + 1]) for i in 1:(length(bn13) - 1))) + e14 = Set(((bn14[i], bn14[i + 1]) for i in 1:(length(bn14) - 1))) + e2 = Set(((bn2[i], bn2[i + 1]) for i in 1:(length(bn2) - 1))) + e3 = Set(((bn3[i], bn3[i + 1]) for i in 1:(length(bn3) - 1))) + e41 = Set(((bn41[i], bn41[i + 1]) for i in 1:(length(bn41) - 1))) + e42 = Set(((bn42[i], bn42[i + 1]) for i in 1:(length(bn42) - 1))) + e43 = Set(((bn43[i], bn43[i + 1]) for i in 1:(length(bn43) - 1))) + e44 = Set(((bn44[i], bn44[i + 1]) for i in 1:(length(bn44) - 1))) + e5 = Set(((bn5[i], bn5[i + 1]) for i in 1:(length(bn5) - 1))) + ace = Set{NTuple{2, Int}}() + for es in (e11, e12, e13, e14, e2, e3, e41, e42, e43, e44, e5) + for e in es push!(ace, e) - end - for e in all_ce + end + end + for e in all_ce + push!(ace, e) + end + @test ace == DT.merge_segments(bn_map, all_bn, all_ce) + + all_bn = get_boundary_nodes(tri_2) + i = rand(1:100000, 50) + j = rand(1:100000, 50) + all_ce = Set(((i, j) for (i, j) in zip(i, j))) + bn_map = get_ghost_vertex_map(tri_2) + bn1 = all_bn[1] + bn2 = all_bn[2] + bn3 = all_bn[3] + bn4 = all_bn[4] + e1 = Set(((bn1[i], bn1[i + 1]) for i in 1:(length(bn1) - 1))) + e2 = Set(((bn2[i], bn2[i + 1]) for i in 1:(length(bn2) - 1))) + e3 = Set(((bn3[i], bn3[i + 1]) for i in 1:(length(bn3) - 1))) + e4 = Set(((bn4[i], bn4[i + 1]) for i in 1:(length(bn4) - 1))) + ace = Set{NTuple{2, Int}}() + for es in (e1, e2, e3, e4) + for e in es push!(ace, e) - end - @test ace == DT.merge_segments(bn_map, all_bn, all_ce) - - all_bn = get_boundary_nodes(tri_4)[1] - i = rand(1:100000, 50) - j = rand(1:100000, 50) - all_ce = Set(((i, j) for (i, j) in zip(i, j))) - bn_map = get_ghost_vertex_map(tri_4) - e = Set(((all_bn[i], all_bn[i+1]) for i in 1:(length(all_bn)-1))) - ace = Set{NTuple{2,Int}}() - for e in e - push!(ace, e) - end - for e in all_ce - push!(ace, e) - end - @test ace == DT.merge_segments(bn_map, [all_bn], all_ce) + end + end + for e in all_ce + push!(ace, e) + end + @test ace == DT.merge_segments(bn_map, all_bn, all_ce) + + all_bn = get_boundary_nodes(tri_3) + i = rand(1:100000, 50) + j = rand(1:100000, 50) + all_ce = Set(((i, j) for (i, j) in zip(i, j))) + bn_map = get_ghost_vertex_map(tri_3) + e = Set(((all_bn[i], all_bn[i + 1]) for i in 1:(length(all_bn) - 1))) + ace = Set{NTuple{2, Int}}() + for e in e + push!(ace, e) + end + for e in all_ce + push!(ace, e) + end + @test ace == DT.merge_segments(bn_map, all_bn, all_ce) + + all_bn = get_boundary_nodes(tri_4)[1] + i = rand(1:100000, 50) + j = rand(1:100000, 50) + all_ce = Set(((i, j) for (i, j) in zip(i, j))) + bn_map = get_ghost_vertex_map(tri_4) + e = Set(((all_bn[i], all_bn[i + 1]) for i in 1:(length(all_bn) - 1))) + ace = Set{NTuple{2, Int}}() + for e in e + push!(ace, e) + end + for e in all_ce + push!(ace, e) + end + @test ace == DT.merge_segments(bn_map, [all_bn], all_ce) end @testset "sort_edge_by_degree" begin - tri = triangulate(rand(2, 500); delete_ghosts=false) - for e in each_edge(tri) - new_e = DT.sort_edge_by_degree(tri, e) - d1 = DT.num_neighbours(tri, e[1]) - d2 = DT.num_neighbours(tri, e[2]) - if d1 ≤ d2 - @test new_e == e - else - @test new_e == (e[2], e[1]) - end - end + tri = triangulate(rand(2, 500); delete_ghosts = false) + for e in each_edge(tri) + new_e = DT.sort_edge_by_degree(tri, e) + d1 = DT.num_neighbours(tri, e[1]) + d2 = DT.num_neighbours(tri, e[2]) + if d1 ≤ d2 + @test new_e == e + else + @test new_e == (e[2], e[1]) + end + end end @testset "triangle_line_segment_intersection" begin - n = 20 - for _ in 1:10 - n += rand(1:5) - tri1 = triangulate(12randn(2, n), delete_ghosts=false) - tri2 = triangulate(12randn(2, n), delete_ghosts=true) - for tri in (tri1, tri2) - for qi in each_solid_vertex(tri) - for k in each_solid_vertex(tri) - q = get_point(tri, qi) - history = DT.PointLocationHistory{NTuple{3,Int},NTuple{2,Int},Int}() - find_triangle(tri, q; - k, - store_history=true, - history) - visited_triangles = history.triangles - collinear_segments = history.collinear_segments - @test all(T -> DT.is_positively_oriented(DT.triangle_orientation(tri, T...)), visited_triangles) - @test all(!DT.is_none, [DT.triangle_line_segment_intersection(tri, T..., (qi, k)...) for T in visited_triangles]) - @test allunique(visited_triangles) - if !isempty(collinear_segments) - @test all(E -> DT.is_collinear(DT.point_position_relative_to_line(tri, qi, k, E[1])), collinear_segments) - @test all(E -> DT.is_collinear(DT.point_position_relative_to_line(tri, qi, k, E[2])), collinear_segments) - end - end - end + n = 20 + for _ in 1:10 + n += rand(1:5) + tri1 = triangulate(12randn(2, n), delete_ghosts = false) + tri2 = triangulate(12randn(2, n), delete_ghosts = true) + for tri in (tri1, tri2) + for qi in each_solid_vertex(tri) + for k in each_solid_vertex(tri) + q = get_point(tri, qi) + history = DT.PointLocationHistory{NTuple{3, Int}, NTuple{2, Int}, Int}() + find_triangle( + tri, q; + k, + store_history = true, + history, + ) + visited_triangles = history.triangles + collinear_segments = history.collinear_segments + @test all(T -> DT.is_positively_oriented(DT.triangle_orientation(tri, T...)), visited_triangles) + @test all(!DT.is_none, [DT.triangle_line_segment_intersection(tri, T..., (qi, k)...) for T in visited_triangles]) + @test allunique(visited_triangles) + if !isempty(collinear_segments) + @test all(E -> DT.is_collinear(DT.point_position_relative_to_line(tri, qi, k, E[1])), collinear_segments) + @test all(E -> DT.is_collinear(DT.point_position_relative_to_line(tri, qi, k, E[2])), collinear_segments) + end + end end - end + end + end end @testset "point_closest_to_line" begin - tri = fixed_shewchuk_example_constrained() - i, j = 2, 7 - u, v = 9, 8 - @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) - @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) - u, v = 3, 11 - @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) - @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) - i, j = 7, 2 - u, v = 6, 1 - @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) - @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) - u, v = 2, 6 - @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) - @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) - u, v = 7, 4 - @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) - @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) + tri = fixed_shewchuk_example_constrained() + i, j = 2, 7 + u, v = 9, 8 + @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) + @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) + u, v = 3, 11 + @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) + @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) + i, j = 7, 2 + u, v = 6, 1 + @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) + @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) + u, v = 2, 6 + @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) + @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) + u, v = 7, 4 + @test DT.is_closer(DT.point_closest_to_line(tri, i, j, u, v)) + @test DT.is_further(DT.point_closest_to_line(tri, i, j, v, u)) end rng = StableRNG(91928281) @@ -699,751 +707,761 @@ pts = [(rand(rng), rand(rng)) for _ in 1:50] bnd_pts = [(0.3cos(θ), 0.3sin(θ)) .+ 0.5 for θ in LinRange(0, 2π - 1 / 250, 25)] bnd_id = [(51:75)..., 51] append!(pts, bnd_pts) -global tric = triangulate(pts; boundary_nodes=bnd_id, rng) +global tric = triangulate(pts; boundary_nodes = bnd_id, rng) @testset "each_segment" begin - @test each_segment(tric) == each_edge(get_all_segments(tric)) + @test each_segment(tric) == each_edge(get_all_segments(tric)) end @testset "contains_segment" begin - @test !DT.contains_segment(tric, 12, 17) - @test DT.contains_segment(tric, 69, 70) - @test DT.contains_segment(tric, 70, 69) - @test !DT.contains_segment(tric, 32, 41) - @test !DT.contains_segment(tric, 45, 38) - @test DT.contains_segment(tric, 63, 64) - @test !DT.contains_segment(tric, (45, 38)) - @test !DT.contains_segment(tric, 26, 22) - @test DT.contains_segment(tric, 64, 65) - @test DT.contains_segment(tric, 55, 54) - @test DT.contains_segment(tric, 58, 57) - @test DT.contains_segment(tric, 59, 60) - @test !DT.contains_segment(tric, 30, 70) - @test !DT.contains_segment(tric, 56, 37) - @test DT.contains_segment(tric, 73, 74) + @test !DT.contains_segment(tric, 12, 17) + @test DT.contains_segment(tric, 69, 70) + @test DT.contains_segment(tric, 70, 69) + @test !DT.contains_segment(tric, 32, 41) + @test !DT.contains_segment(tric, 45, 38) + @test DT.contains_segment(tric, 63, 64) + @test !DT.contains_segment(tric, (45, 38)) + @test !DT.contains_segment(tric, 26, 22) + @test DT.contains_segment(tric, 64, 65) + @test DT.contains_segment(tric, 55, 54) + @test DT.contains_segment(tric, 58, 57) + @test DT.contains_segment(tric, 59, 60) + @test !DT.contains_segment(tric, 30, 70) + @test !DT.contains_segment(tric, 56, 37) + @test DT.contains_segment(tric, 73, 74) end @testset "get_all_boundary_nodes" begin - x, y = complicated_geometry() - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; rng, boundary_nodes) - A = get_area(tri) - refine!(tri, rng=rng, max_area=1e-1A, use_circumcenter=true, use_lens=false) - all_bn = DT.get_all_boundary_nodes(tri) - @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri)))) - tri2, label_map, index_map = simple_geometry() - all_bn = DT.get_all_boundary_nodes(tri2) - @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri2)))) - tri3 = triangulate_rectangle(0, 1, 0, 1, 50, 50; delete_ghosts=false, single_boundary=false) - all_bn = DT.get_all_boundary_nodes(tri3) - @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri3)))) - tri4 = triangulate_rectangle(0, 1, 0, 1, 50, 50; delete_ghosts=false, single_boundary=true) - all_bn = DT.get_all_boundary_nodes(tri4) - @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri4)))) - tri = triangulate(rand(2, 50)) - @test isempty(DT.get_all_boundary_nodes(tri)) + x, y = complicated_geometry() + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri = triangulate(points; rng, boundary_nodes) + A = get_area(tri) + refine!(tri, rng = rng, max_area = 1.0e-1A, use_circumcenter = true, use_lens = false) + all_bn = DT.get_all_boundary_nodes(tri) + @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri)))) + tri2, label_map, index_map = simple_geometry() + all_bn = DT.get_all_boundary_nodes(tri2) + @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri2)))) + tri3 = triangulate_rectangle(0, 1, 0, 1, 50, 50; delete_ghosts = false, single_boundary = false) + all_bn = DT.get_all_boundary_nodes(tri3) + @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri3)))) + tri4 = triangulate_rectangle(0, 1, 0, 1, 50, 50; delete_ghosts = false, single_boundary = true) + all_bn = DT.get_all_boundary_nodes(tri4) + @test all_bn == Set(reduce(vcat, reduce(vcat, get_boundary_nodes(tri4)))) + tri = triangulate(rand(2, 50)) + @test isempty(DT.get_all_boundary_nodes(tri)) end @testset "get_boundary_edge_map" begin - x, y = complicated_geometry() - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; rng, boundary_nodes) - A = get_area(tri) - refine!(tri, rng=rng, max_area=1e-2A, use_circumcenter=true) - for (e, (s, i)) in tri.boundary_edge_map - @test DT.get_boundary_edge_map(tri, e) == (s, i) - @test DT.get_boundary_edge_map(tri, e...) == (s, i) - @test get_boundary_nodes(DT.get_boundary_nodes(tri, s), i) == e[1] - end + x, y = complicated_geometry() + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri = triangulate(points; rng, boundary_nodes) + A = get_area(tri) + refine!(tri, rng = rng, max_area = 1.0e-2A, use_circumcenter = true) + for (e, (s, i)) in tri.boundary_edge_map + @test DT.get_boundary_edge_map(tri, e) == (s, i) + @test DT.get_boundary_edge_map(tri, e...) == (s, i) + @test get_boundary_nodes(DT.get_boundary_nodes(tri, s), i) == e[1] + end end @testset "split_boundary_edge!" begin - x, y = complicated_geometry() - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_1 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_1) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) - tri_2 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_2) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) - tri_3 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_3) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) - tri_4 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_4) - - DT.split_boundary_edge!(tri_1, (21, 22), 500) - @test tri_1.boundary_nodes[2][1][1:11] == [13, 14, 15, 16, 17, 18, 19, 20, 21, 500, 22] - @test DT.get_boundary_edge_map(tri_1, 21, 500) == ((2, 1), 9) - @test DT.get_boundary_edge_map(tri_1, 500, 22) == ((2, 1), 10) - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 21, 22) - @test !DT.contains_unoriented_edge((21, 22), DT.get_all_segments(tri_1)) - @test DT.contains_unoriented_edge((21, 500), DT.get_all_segments(tri_1)) - @test DT.contains_unoriented_edge((500, 22), DT.get_all_segments(tri_1)) - - DT.split_boundary_edge!(tri_1, (7, 8), 5000) - @test tri_1.boundary_nodes[1][3] == [7, 5000, 8, 9, 10] - @test DT.get_boundary_edge_map(tri_1, 7, 5000) == ((1, 3), 1) - @test DT.get_boundary_edge_map(tri_1, 5000, 8) == ((1, 3), 2) - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 7, 8) - @test !DT.contains_unoriented_edge((7, 8), DT.get_all_segments(tri_1)) - @test DT.contains_unoriented_edge((7, 5000), DT.get_all_segments(tri_1)) - @test DT.contains_unoriented_edge((5000, 8), DT.get_all_segments(tri_1)) - - DT.split_boundary_edge!(tri_2, 8, 9, 300) - @test tri_2.boundary_nodes[3] == [7, 8, 300, 9, 10] - @test DT.get_boundary_edge_map(tri_2, 8, 300) == (3, 2) - @test DT.get_boundary_edge_map(tri_2, 300, 9) == (3, 3) - @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8, 9) - @test !DT.contains_unoriented_edge((8, 9), DT.get_all_segments(tri_2)) - @test DT.contains_unoriented_edge((8, 300), DT.get_all_segments(tri_2)) - @test DT.contains_unoriented_edge((300, 9), DT.get_all_segments(tri_2)) - - DT.split_boundary_edge!(tri_3, 3, 4, 5000) - @test tri_3.boundary_nodes == [1, 2, 3, 5000, 4, 1] - @test DT.get_boundary_edge_map(tri_3, 3, 5000) == (tri_3.boundary_nodes, 3) - @test DT.get_boundary_edge_map(tri_3, 5000, 4) == (tri_3.boundary_nodes, 4) - @test_throws KeyError DT.get_boundary_edge_map(tri_3, 3, 4) - @test !DT.contains_unoriented_edge((3, 4), DT.get_all_segments(tri_3)) - @test DT.contains_unoriented_edge((3, 5000), DT.get_all_segments(tri_3)) - @test DT.contains_unoriented_edge((5000, 4), DT.get_all_segments(tri_3)) - - DT.split_boundary_edge!(tri_4, 6, 7, 1200) - @test DT.get_boundary_edge_map(tri_4, 6, 1200) == (1, 6) - @test DT.get_boundary_edge_map(tri_4, 1200, 7) == (1, 7) - @test_throws KeyError DT.get_boundary_edge_map(tri_4, 6, 7) - @test !DT.contains_unoriented_edge((6, 7), DT.get_all_segments(tri_4)) - @test DT.contains_unoriented_edge((6, 1200), DT.get_all_segments(tri_4)) - @test DT.contains_unoriented_edge((1200, 7), DT.get_all_segments(tri_4)) + x, y = complicated_geometry() + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri_1 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_1) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) + tri_2 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_2) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) + tri_3 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_3) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) + tri_4 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_4) + + DT.split_boundary_edge!(tri_1, (21, 22), 500) + @test tri_1.boundary_nodes[2][1][1:11] == [13, 14, 15, 16, 17, 18, 19, 20, 21, 500, 22] + @test DT.get_boundary_edge_map(tri_1, 21, 500) == ((2, 1), 9) + @test DT.get_boundary_edge_map(tri_1, 500, 22) == ((2, 1), 10) + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 21, 22) + @test !DT.contains_unoriented_edge((21, 22), DT.get_all_segments(tri_1)) + @test DT.contains_unoriented_edge((21, 500), DT.get_all_segments(tri_1)) + @test DT.contains_unoriented_edge((500, 22), DT.get_all_segments(tri_1)) + + DT.split_boundary_edge!(tri_1, (7, 8), 5000) + @test tri_1.boundary_nodes[1][3] == [7, 5000, 8, 9, 10] + @test DT.get_boundary_edge_map(tri_1, 7, 5000) == ((1, 3), 1) + @test DT.get_boundary_edge_map(tri_1, 5000, 8) == ((1, 3), 2) + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 7, 8) + @test !DT.contains_unoriented_edge((7, 8), DT.get_all_segments(tri_1)) + @test DT.contains_unoriented_edge((7, 5000), DT.get_all_segments(tri_1)) + @test DT.contains_unoriented_edge((5000, 8), DT.get_all_segments(tri_1)) + + DT.split_boundary_edge!(tri_2, 8, 9, 300) + @test tri_2.boundary_nodes[3] == [7, 8, 300, 9, 10] + @test DT.get_boundary_edge_map(tri_2, 8, 300) == (3, 2) + @test DT.get_boundary_edge_map(tri_2, 300, 9) == (3, 3) + @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8, 9) + @test !DT.contains_unoriented_edge((8, 9), DT.get_all_segments(tri_2)) + @test DT.contains_unoriented_edge((8, 300), DT.get_all_segments(tri_2)) + @test DT.contains_unoriented_edge((300, 9), DT.get_all_segments(tri_2)) + + DT.split_boundary_edge!(tri_3, 3, 4, 5000) + @test tri_3.boundary_nodes == [1, 2, 3, 5000, 4, 1] + @test DT.get_boundary_edge_map(tri_3, 3, 5000) == (tri_3.boundary_nodes, 3) + @test DT.get_boundary_edge_map(tri_3, 5000, 4) == (tri_3.boundary_nodes, 4) + @test_throws KeyError DT.get_boundary_edge_map(tri_3, 3, 4) + @test !DT.contains_unoriented_edge((3, 4), DT.get_all_segments(tri_3)) + @test DT.contains_unoriented_edge((3, 5000), DT.get_all_segments(tri_3)) + @test DT.contains_unoriented_edge((5000, 4), DT.get_all_segments(tri_3)) + + DT.split_boundary_edge!(tri_4, 6, 7, 1200) + @test DT.get_boundary_edge_map(tri_4, 6, 1200) == (1, 6) + @test DT.get_boundary_edge_map(tri_4, 1200, 7) == (1, 7) + @test_throws KeyError DT.get_boundary_edge_map(tri_4, 6, 7) + @test !DT.contains_unoriented_edge((6, 7), DT.get_all_segments(tri_4)) + @test DT.contains_unoriented_edge((6, 1200), DT.get_all_segments(tri_4)) + @test DT.contains_unoriented_edge((1200, 7), DT.get_all_segments(tri_4)) end @testset "merge_boundary_edge!" begin - x, y = complicated_geometry() - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_1 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_1) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) - tri_2 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_2) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) - tri_3 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_3) - - rng = StableRNG(91818) - boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) - tri_4 = triangulate(points; rng, boundary_nodes) - A = get_area(tri_4) - - orig_bn = deepcopy(get_boundary_nodes(tri_1)) - orig_bnn = deepcopy(get_boundary_edge_map(tri_1)) - DT.split_boundary_edge!(tri_1, (21, 22), 170) - @test get_boundary_nodes(tri_1) ≠ orig_bn - @test get_boundary_edge_map(tri_1) ≠ orig_bnn - DT.merge_boundary_edge!(tri_1, (21, 22), 170) - @test get_boundary_nodes(tri_1) == orig_bn - @test get_boundary_edge_map(tri_1) == orig_bnn - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 21, 170) - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 170, 22) - @test DT.contains_unoriented_edge((21, 22), DT.get_all_segments(tri_1)) - @test !DT.contains_unoriented_edge((21, 170), DT.get_all_segments(tri_1)) - @test !DT.contains_unoriented_edge((170, 22), DT.get_all_segments(tri_1)) - - orig_bn = deepcopy(get_boundary_nodes(tri_1)) - orig_bnn = deepcopy(get_boundary_edge_map(tri_1)) - DT.split_boundary_edge!(tri_1, (7, 8), 5000) - @test get_boundary_nodes(tri_1) ≠ orig_bn - @test get_boundary_edge_map(tri_1) ≠ orig_bnn - DT.merge_boundary_edge!(tri_1, (7, 8), 5000) - @test get_boundary_nodes(tri_1) == orig_bn - @test get_boundary_edge_map(tri_1) == orig_bnn - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 7, 5000) - @test_throws KeyError DT.get_boundary_edge_map(tri_1, 5000, 8) - @test DT.contains_unoriented_edge((7, 8), DT.get_all_segments(tri_1)) - @test !DT.contains_unoriented_edge((7, 5000), DT.get_all_segments(tri_1)) - @test !DT.contains_unoriented_edge((5000, 8), DT.get_all_segments(tri_1)) - - orig_bn = deepcopy(get_boundary_nodes(tri_2)) - orig_bnn = deepcopy(get_boundary_edge_map(tri_2)) - DT.split_boundary_edge!(tri_2, 8, 9, 8182) - @test get_boundary_nodes(tri_2) ≠ orig_bn - @test get_boundary_edge_map(tri_2) ≠ orig_bnn - DT.merge_boundary_edge!(tri_2, 8, 9, 8182) - @test get_boundary_nodes(tri_2) == orig_bn - @test get_boundary_edge_map(tri_2) == orig_bnn - @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8, 8182) - @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8182, 9) - @test DT.contains_unoriented_edge((8, 9), DT.get_all_segments(tri_2)) - @test !DT.contains_unoriented_edge((8, 8182), DT.get_all_segments(tri_2)) - @test !DT.contains_unoriented_edge((8182, 9), DT.get_all_segments(tri_2)) - - orig_bn = deepcopy(get_boundary_nodes(tri_3)) - orig_bnn = deepcopy(get_boundary_edge_map(tri_3)) - DT.split_boundary_edge!(tri_3, 3, 4, 18289) - @test get_boundary_nodes(tri_3) ≠ orig_bn - @test get_boundary_edge_map(tri_3) ≠ orig_bnn - DT.merge_boundary_edge!(tri_3, 3, 4, 18289) - @test get_boundary_nodes(tri_3) == orig_bn - @test get_boundary_edge_map(tri_3) == orig_bnn - @test_throws KeyError DT.get_boundary_edge_map(tri_3, 3, 18289) - @test_throws KeyError DT.get_boundary_edge_map(tri_3, 18289, 4) - @test DT.contains_unoriented_edge((3, 4), DT.get_all_segments(tri_3)) - @test !DT.contains_unoriented_edge((3, 18289), DT.get_all_segments(tri_3)) - @test !DT.contains_unoriented_edge((18289, 4), DT.get_all_segments(tri_3)) - - orig_bn = deepcopy(get_boundary_nodes(tri_4)) - orig_bnn = deepcopy(get_boundary_edge_map(tri_4)) - DT.split_boundary_edge!(tri_4, 6, 7, 1200) - @test get_boundary_nodes(tri_4) ≠ orig_bn - @test get_boundary_edge_map(tri_4) ≠ orig_bnn - DT.merge_boundary_edge!(tri_4, 6, 7, 1200) - @test get_boundary_nodes(tri_4) == orig_bn - @test get_boundary_edge_map(tri_4) == orig_bnn - @test_throws KeyError DT.get_boundary_edge_map(tri_4, 6, 1200) - @test_throws KeyError DT.get_boundary_edge_map(tri_4, 1200, 7) - @test DT.contains_unoriented_edge((6, 7), DT.get_all_segments(tri_4)) - @test !DT.contains_unoriented_edge((6, 1200), DT.get_all_segments(tri_4)) - @test !DT.contains_unoriented_edge((1200, 7), DT.get_all_segments(tri_4)) + x, y = complicated_geometry() + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri_1 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_1) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) + tri_2 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_2) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) + tri_3 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_3) + + rng = StableRNG(91818) + boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) + tri_4 = triangulate(points; rng, boundary_nodes) + A = get_area(tri_4) + + orig_bn = deepcopy(get_boundary_nodes(tri_1)) + orig_bnn = deepcopy(get_boundary_edge_map(tri_1)) + DT.split_boundary_edge!(tri_1, (21, 22), 170) + @test get_boundary_nodes(tri_1) ≠ orig_bn + @test get_boundary_edge_map(tri_1) ≠ orig_bnn + DT.merge_boundary_edge!(tri_1, (21, 22), 170) + @test get_boundary_nodes(tri_1) == orig_bn + @test get_boundary_edge_map(tri_1) == orig_bnn + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 21, 170) + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 170, 22) + @test DT.contains_unoriented_edge((21, 22), DT.get_all_segments(tri_1)) + @test !DT.contains_unoriented_edge((21, 170), DT.get_all_segments(tri_1)) + @test !DT.contains_unoriented_edge((170, 22), DT.get_all_segments(tri_1)) + + orig_bn = deepcopy(get_boundary_nodes(tri_1)) + orig_bnn = deepcopy(get_boundary_edge_map(tri_1)) + DT.split_boundary_edge!(tri_1, (7, 8), 5000) + @test get_boundary_nodes(tri_1) ≠ orig_bn + @test get_boundary_edge_map(tri_1) ≠ orig_bnn + DT.merge_boundary_edge!(tri_1, (7, 8), 5000) + @test get_boundary_nodes(tri_1) == orig_bn + @test get_boundary_edge_map(tri_1) == orig_bnn + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 7, 5000) + @test_throws KeyError DT.get_boundary_edge_map(tri_1, 5000, 8) + @test DT.contains_unoriented_edge((7, 8), DT.get_all_segments(tri_1)) + @test !DT.contains_unoriented_edge((7, 5000), DT.get_all_segments(tri_1)) + @test !DT.contains_unoriented_edge((5000, 8), DT.get_all_segments(tri_1)) + + orig_bn = deepcopy(get_boundary_nodes(tri_2)) + orig_bnn = deepcopy(get_boundary_edge_map(tri_2)) + DT.split_boundary_edge!(tri_2, 8, 9, 8182) + @test get_boundary_nodes(tri_2) ≠ orig_bn + @test get_boundary_edge_map(tri_2) ≠ orig_bnn + DT.merge_boundary_edge!(tri_2, 8, 9, 8182) + @test get_boundary_nodes(tri_2) == orig_bn + @test get_boundary_edge_map(tri_2) == orig_bnn + @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8, 8182) + @test_throws KeyError DT.get_boundary_edge_map(tri_2, 8182, 9) + @test DT.contains_unoriented_edge((8, 9), DT.get_all_segments(tri_2)) + @test !DT.contains_unoriented_edge((8, 8182), DT.get_all_segments(tri_2)) + @test !DT.contains_unoriented_edge((8182, 9), DT.get_all_segments(tri_2)) + + orig_bn = deepcopy(get_boundary_nodes(tri_3)) + orig_bnn = deepcopy(get_boundary_edge_map(tri_3)) + DT.split_boundary_edge!(tri_3, 3, 4, 18289) + @test get_boundary_nodes(tri_3) ≠ orig_bn + @test get_boundary_edge_map(tri_3) ≠ orig_bnn + DT.merge_boundary_edge!(tri_3, 3, 4, 18289) + @test get_boundary_nodes(tri_3) == orig_bn + @test get_boundary_edge_map(tri_3) == orig_bnn + @test_throws KeyError DT.get_boundary_edge_map(tri_3, 3, 18289) + @test_throws KeyError DT.get_boundary_edge_map(tri_3, 18289, 4) + @test DT.contains_unoriented_edge((3, 4), DT.get_all_segments(tri_3)) + @test !DT.contains_unoriented_edge((3, 18289), DT.get_all_segments(tri_3)) + @test !DT.contains_unoriented_edge((18289, 4), DT.get_all_segments(tri_3)) + + orig_bn = deepcopy(get_boundary_nodes(tri_4)) + orig_bnn = deepcopy(get_boundary_edge_map(tri_4)) + DT.split_boundary_edge!(tri_4, 6, 7, 1200) + @test get_boundary_nodes(tri_4) ≠ orig_bn + @test get_boundary_edge_map(tri_4) ≠ orig_bnn + DT.merge_boundary_edge!(tri_4, 6, 7, 1200) + @test get_boundary_nodes(tri_4) == orig_bn + @test get_boundary_edge_map(tri_4) == orig_bnn + @test_throws KeyError DT.get_boundary_edge_map(tri_4, 6, 1200) + @test_throws KeyError DT.get_boundary_edge_map(tri_4, 1200, 7) + @test DT.contains_unoriented_edge((6, 7), DT.get_all_segments(tri_4)) + @test !DT.contains_unoriented_edge((6, 1200), DT.get_all_segments(tri_4)) + @test !DT.contains_unoriented_edge((1200, 7), DT.get_all_segments(tri_4)) end @testset "get_adjacent concurrency" begin # Shouldn't be an issue anymore since we removed DefaultDict, but let's keep this here anyway. The test here is simply that it doesn't error. - tri = triangulate(rand(2, 50), delete_ghosts=false) - Base.Threads.@threads for _ in 1:5000 - get_adjacent(tri, -5, rand(1:1000)) - end + tri = triangulate(rand(2, 50), delete_ghosts = false) + Base.Threads.@threads for _ in 1:5000 + get_adjacent(tri, -5, rand(1:1000)) + end end @testset "has_vertex and has_ghost_vertices" begin - tri = triangulate(rand(2, 50), delete_ghosts=false) - @test DT.has_vertex(tri, 1) - @test !DT.has_vertex(tri, 57) - @test DT.has_ghost_vertices(tri) - @test DT.has_vertex(tri, -1) - DT.delete_ghost_vertices_from_graph!(tri) - @test !DT.has_vertex(tri, -1) - @test !DT.has_ghost_vertices(tri) + tri = triangulate(rand(2, 50), delete_ghosts = false) + @test DT.has_vertex(tri, 1) + @test !DT.has_vertex(tri, 57) + @test DT.has_ghost_vertices(tri) + @test DT.has_vertex(tri, -1) + DT.delete_ghost_vertices_from_graph!(tri) + @test !DT.has_vertex(tri, -1) + @test !DT.has_ghost_vertices(tri) end @testset "Issue #70" begin - points = [(-1.0, -1.0), (1.0, -1.0), (0.0, 1.0)] - tri = triangulate(points) - delete_ghost_triangles!(tri) - DelaunayTriangulation.delete_ghost_vertices_from_graph!(tri) - @test collect(each_solid_vertex(tri)) == collect(each_vertex(tri)) - @test !DelaunayTriangulation.has_ghost_vertices(tri) - @test DelaunayTriangulation.num_ghost_vertices(tri) == 0 - @test DelaunayTriangulation.num_solid_vertices(tri) == 3 - @test isempty(collect(each_ghost_vertex(tri))) + points = [(-1.0, -1.0), (1.0, -1.0), (0.0, 1.0)] + tri = triangulate(points) + delete_ghost_triangles!(tri) + DelaunayTriangulation.delete_ghost_vertices_from_graph!(tri) + @test collect(each_solid_vertex(tri)) == collect(each_vertex(tri)) + @test !DelaunayTriangulation.has_ghost_vertices(tri) + @test DelaunayTriangulation.num_ghost_vertices(tri) == 0 + @test DelaunayTriangulation.num_solid_vertices(tri) == 3 + @test isempty(collect(each_ghost_vertex(tri))) end @testset "Boundary curve orientation" begin - tri = triangulate(rand(2, 500)) - @test DT.is_positively_oriented(tri, 1) - lock_convex_hull!(tri) - @test DT.is_positively_oriented(tri, 1) - - pts = [ - (-7.36, 12.55), (-9.32, 8.59), (-9.0, 3.0), (-6.32, -0.27), - (-4.78, -1.53), (2.78, -1.41), (-5.42, 1.45), (7.86, 0.67), - (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), - (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), - (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), - (1.34, 6.77), (1.24, 4.15) - ] - boundary_points = [ - (0.0, 0.0), (2.0, 1.0), (3.98, 2.85), (6.0, 5.0), - (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), - (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), - (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), - (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0) - ] - boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points=pts) - tri = triangulate(pts; boundary_nodes, delete_ghosts=false) - @test DT.is_positively_oriented(tri, 1) - - points = [ - (2.0, 8.0), (6.0, 4.0), (2.0, 6.0), - (2.0, 4.0), (8.0, 2.0) - ] - segment_1 = [(0.0, 0.0), (14.0, 0.0)] - segment_2 = [(14.0, 0.0), (10.0, 4.0), (4.0, 6.0), (2.0, 12.0), (0.0, 14.0)] - segment_3 = [(0.0, 14.0), (0.0, 0.0)] - boundary_points = [segment_1, segment_2, segment_3] - boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points=points) - tri = triangulate(points; boundary_nodes) - @test DT.is_positively_oriented(tri, 1) - - curve_1 = [[ + tri = triangulate(rand(2, 500)) + @test DT.is_positively_oriented(tri, 1) + lock_convex_hull!(tri) + @test DT.is_positively_oriented(tri, 1) + + pts = [ + (-7.36, 12.55), (-9.32, 8.59), (-9.0, 3.0), (-6.32, -0.27), + (-4.78, -1.53), (2.78, -1.41), (-5.42, 1.45), (7.86, 0.67), + (10.92, 0.23), (9.9, 7.39), (8.14, 4.77), (13.4, 8.61), + (7.4, 12.27), (2.2, 13.85), (-3.48, 10.21), (-4.56, 7.35), + (3.44, 8.99), (3.74, 5.87), (-2.0, 8.0), (-2.52, 4.81), + (1.34, 6.77), (1.24, 4.15), + ] + boundary_points = [ + (0.0, 0.0), (2.0, 1.0), (3.98, 2.85), (6.0, 5.0), + (7.0, 7.0), (7.0, 9.0), (6.0, 11.0), (4.0, 12.0), + (2.0, 12.0), (1.0, 11.0), (0.0, 9.13), (-1.0, 11.0), + (-2.0, 12.0), (-4.0, 12.0), (-6.0, 11.0), (-7.0, 9.0), + (-6.94, 7.13), (-6.0, 5.0), (-4.0, 3.0), (-2.0, 1.0), (0.0, 0.0), + ] + boundary_nodes, pts = convert_boundary_points_to_indices(boundary_points; existing_points = pts) + tri = triangulate(pts; boundary_nodes, delete_ghosts = false) + @test DT.is_positively_oriented(tri, 1) + + points = [ + (2.0, 8.0), (6.0, 4.0), (2.0, 6.0), + (2.0, 4.0), (8.0, 2.0), + ] + segment_1 = [(0.0, 0.0), (14.0, 0.0)] + segment_2 = [(14.0, 0.0), (10.0, 4.0), (4.0, 6.0), (2.0, 12.0), (0.0, 14.0)] + segment_3 = [(0.0, 14.0), (0.0, 0.0)] + boundary_points = [segment_1, segment_2, segment_3] + boundary_nodes, points = convert_boundary_points_to_indices(boundary_points; existing_points = points) + tri = triangulate(points; boundary_nodes) + @test DT.is_positively_oriented(tri, 1) + + curve_1 = [ + [ (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), (-4.0, 0.0), (0.0, 0.0), - ]] - curve_2 = [[ + ], + ] + curve_2 = [ + [ (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), (10.0, 22.0), (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ]] - curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] - curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] - curves = [curve_1, curve_2, curve_3, curve_4] - points = [ - (2.0, 26.0), (2.0, 24.0), (6.0, 24.0), (6.0, 22.0), (8.0, 24.0), (8.0, 22.0), - (2.0, 22.0), (0.0, 26.0), (10.0, 18.0), (8.0, 18.0), (4.0, 18.0), (2.0, 16.0), - (2.0, 12.0), (6.0, 12.0), (2.0, 8.0), (2.0, 4.0), (4.0, 2.0), - (-2.0, 2.0), (4.0, 6.0), (10.0, 2.0), (10.0, 6.0), (8.0, 10.0), (4.0, 10.0), - (10.0, 12.0), (12.0, 12.0), (14.0, 26.0), (16.0, 24.0), (18.0, 28.0), - (16.0, 20.0), (18.0, 12.0), (16.0, 8.0), (14.0, 4.0), (14.0, -2.0), - (6.0, -2.0), (2.0, -4.0), (-4.0, -2.0), (-2.0, 8.0), (-2.0, 16.0), - (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), - (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), - (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] - boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) - tri = triangulate(points; boundary_nodes=boundary_nodes) - @test DT.is_positively_oriented(tri, 1) - @test !DT.is_positively_oriented(tri, 2) - @test !DT.is_positively_oriented(tri, 3) - @test !DT.is_positively_oriented(tri, 4) - - curve_1 = [ - [(0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0)], - [(25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0)], - [(25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0)], - [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)] - ] # outer-most boundary: counter-clockwise - curve_2 = [ - [(4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0)], - [(20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0)], - [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)] - ] # inner boundary: clockwise - curve_3 = [ - [(12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), - (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912)] - ] # this is inside curve_2, so it's counter-clockwise - curves = [curve_1, curve_2, curve_3] - points = [ - (3.0, 23.0), (9.0, 24.0), (9.2, 22.0), (14.8, 22.8), (16.0, 22.0), - (23.0, 23.0), (22.6, 19.0), (23.8, 17.8), (22.0, 14.0), (22.0, 11.0), - (24.0, 6.0), (23.0, 2.0), (19.0, 1.0), (16.0, 3.0), (10.0, 1.0), (11.0, 3.0), - (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), - (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), - (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), - (12.0, 13.0), (19.0, 15.0) - ] - boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) - tri = triangulate(points; boundary_nodes=boundary_nodes) - @test DT.is_positively_oriented(tri, 1) - @test !DT.is_positively_oriented(tri, 2) - @test DT.is_positively_oriented(tri, 3) - - θ = LinRange(0, 2π, 20) |> collect - θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 - xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() - cx = 0.0 - for i in 1:2 - # Make the exterior circle - push!(xy, [[(cx + cos(θ), sin(θ)) for θ in θ]]) - # Now the interior circle - clockwise - push!(xy, [[(cx + 0.5cos(θ), 0.5sin(θ)) for θ in reverse(θ)]]) - cx += 3.0 - end - boundary_nodes, points = convert_boundary_points_to_indices(xy) - tri = triangulate(points; boundary_nodes=boundary_nodes) - @test DT.is_positively_oriented(tri, 1) - @test !DT.is_positively_oriented(tri, 2) - @test DT.is_positively_oriented(tri, 3) - @test !DT.is_positively_oriented(tri, 4) - - C = (15.7109521325776, 33.244486807457) - D = (14.2705719699703, 32.8530791545746) - E = (14.3, 27.2) - F = (14.1, 27.0) - G = (13.7, 27.2) - H = (13.4, 27.5) - I = (13.1, 27.6) - J = (12.7, 27.4) - K = (12.5, 27.1) - L = (12.7, 26.7) - M = (13.1, 26.5) - N = (13.6, 26.4) - O = (14.0, 26.4) - P = (14.6, 26.5) - Q = (15.1983491346581, 26.8128534095401) - R = (15.6, 27.6) - S = (15.6952958264624, 28.2344688505621) - T = (17.8088971520274, 33.1192363585346) - U = (16.3058917649589, 33.0722674401887) - V = (16.3215480710742, 29.7374742376305) - W = (16.3841732955354, 29.393035503094) - Z = (16.6190178872649, 28.9233463196351) - A1 = (17.0417381523779, 28.5319386667527) - B1 = (17.5114273358368, 28.3753756055997) - C1 = (18.1376795804487, 28.3597192994844) - D1 = (18.7169629067146, 28.5632512789833) - E1 = (19.2805899268653, 28.8920337074045) - F1 = (19.26493362075, 28.4536571361762) - G1 = (20.6426885588962, 28.4223445239456) - H1 = (20.689657477242, 33.1035800524193) - I1 = (19.2805899268653, 33.0722674401887) - J1 = (19.2962462329806, 29.7531305437458) - K1 = (19.0614016412512, 29.393035503094) - L1 = (18.7482755189452, 29.236472441941) - M1 = (18.4508057027546, 29.1425346052493) - N1 = (18.1689921926793, 29.3147539725175) - O1 = (17.7932408459121, 29.6278800948235) - P1 = (22.6466957416542, 35.4207133574833) - Q1 = (21.2219718851621, 34.9979930923702) - R1 = (21.2376281912774, 28.4693134422915) - S1 = (22.6780083538847, 28.4380008300609) - T1 = (24.5724213938357, 33.1975178891111) - U1 = (23.3512295168425, 32.8530791545746) - V1 = (23.3199169046119, 28.4380008300609) - W1 = (24.6663592305274, 28.3753756055997) - Z1 = (15.1942940307729, 35.4363696635986) - A2 = (14.7246048473139, 35.3737444391374) - B2 = (14.3645098066621, 35.1858687657538) - C2 = (14.1766341332786, 34.8570863373326) - D2 = (14.1140089088174, 34.3247719294125) - E2 = (14.2705719699703, 33.8394264398383) - F2 = (14.7246048473139, 33.6202381542241) - G2 = (15.4604512347329, 33.6045818481088) - H2 = (16.0, 34.0) - I2 = (15.9771093365377, 34.6848669700643) - J2 = (15.6170142958859, 35.2328376840997) - K2 = (24.1653574348379, 35.4520259697138) - L2 = (23.7739497819555, 35.4363696635986) - M2 = (23.4608236596496, 35.2641502963303) - N2 = (23.272947986266, 34.9040552556785) - O2 = (23.1320412312284, 34.5909291333725) - P2 = (23.1163849251131, 34.2151777866054) - Q2 = (23.2886042923813, 33.8081138276077) - R2 = (23.8209187003014, 33.6045818481088) - S2 = (24.3062641898756, 33.5576129297629) - T2 = (24.7602970672192, 33.8550827459536) - U2 = (25.010797965064, 34.4656786844502) - V2 = (24.8385785977957, 34.9666804801397) - W2 = (24.5254524754898, 35.2641502963303) - Z2 = (25.3708930057158, 37.4716894585871) - A3 = (24.7916096794498, 37.3464390096648) - B3 = (24.4471709449133, 36.9550313567823) - C3 = (24.3062641898756, 36.5636237038999) - D3 = (24.4941398632592, 35.9999966837492) - E3 = (25.0264542711793, 35.5929327247515) - F3 = (25.5587686790994, 35.5929327247515) - F3 = (25.5587686790994, 35.5929327247515) - G3 = (26.0, 36.0) - H3 = (26.1380520053653, 36.5792800100152) - I3 = (26.0, 37.0) - J3 = (25.7466443524829, 37.2838137852036) - K3 = (26.3885529032101, 35.4676822758291) - L3 = (25.9814889442124, 35.3580881330221) - M3 = (25.6840191280217, 35.1858687657538) - N3 = (25.5274560668688, 34.9040552556785) - O3 = (25.4961434546382, 34.5596165211419) - P3 = (25.5274560668688, 34.246490398836) - Q3 = (25.6683628219064, 33.8394264398383) - R3 = (26.0284578625583, 33.6358944603394) - S3 = (26.5451159643631, 33.6202381542241) - T3 = (27.0, 34.0) - U3 = (27.280962351782, 34.5596165211419) - V3 = (27.0304614539373, 35.2171813779844) - W3 = (26.1693646175959, 33.087923746304) - Z3 = (26.0, 33.0) - A4 = (25.5274560668688, 32.7278287056522) - B4 = (25.2612988629087, 32.4147025833463) - C4 = (25.1830173323322, 32.0702638488098) - D4 = (25.2299862506781, 31.7727940326191) - E4 = (25.6527065157911, 31.5222931347744) - F4 = (26.2946150665183, 31.7258251142732) - G4 = (26.5607722704784, 32.5086404200381) - H4 = (27.1557119028596, 32.7434850117675) - I4 = (27.6097447802033, 32.4929841139228) - J4 = (27.6410573924338, 32.1015764610403) - K4 = (27.7193389230103, 31.6005746653509) - L4 = (27.437525412935, 31.4283552980826) - M4 = (26.9834925355914, 31.2561359308143) - N4 = (26.5764285765937, 31.0995728696614) - O4 = (26.0441141686736, 30.7864467473554) - P4 = (25.6527065157911, 30.5672584617413) - Q4 = (25.3239240873699, 30.1915071149741) - R4 = (25.1673610262169, 29.8783809926682) - S4 = (25.1047358017558, 29.6122237887082) - T4 = (25.0890794956405, 29.1895035235952) - U4 = (25.2926114751393, 28.8294084829433) - V4 = (25.6840191280217, 28.5632512789833) - W4 = (26.1537083114806, 28.3753756055997) - Z4 = (26.8269294744384, 28.391031911715) - A5 = (27.4844943312809, 28.6102201973292) - B5 = (27.7342002330051, 28.7239579596219) - C5 = (27.7264126450755, 28.4202565942047) - D5 = (29.1825559185446, 28.3922538389457) - E5 = (29.1545531632856, 32.2146299318021) - F5 = (29.000538009361, 32.5786657501693) - G5 = (28.6785063238822, 32.9006974356481) - H5 = (28.3144705055149, 33.0827153448317) - I5 = (27.9084305542591, 33.2367304987563) - J5 = (27.3343740714492, 33.3207387645334) - K5 = (26.8303244767868, 33.2367304987563) - L5 = (27.6564057569279, 30.786489413592) - M5 = (27.6984098898165, 30.3944508399657) - N5 = (27.6984098898165, 29.7363860913787) - O5 = (27.5863988687804, 29.4143544059) - P5 = (27.2643671833016, 29.2043337414573) - Q5 = (26.9843396307114, 29.1763309861983) - R5 = (26.6903107004917, 29.3163447624934) - S5 = (26.5782996794556, 29.7503874690082) - T5 = (26.7603175886393, 30.3384453294476) - U5 = (27.3203726938197, 30.7024811478149) - J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] - U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] - L_curve = [[P1, Q1, R1, S1, P1]] - I_curve = [[T1, U1, V1, W1, T1]] - A_curve_outline = [[ + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], + ] + curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] + curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] + curves = [curve_1, curve_2, curve_3, curve_4] + points = [ + (2.0, 26.0), (2.0, 24.0), (6.0, 24.0), (6.0, 22.0), (8.0, 24.0), (8.0, 22.0), + (2.0, 22.0), (0.0, 26.0), (10.0, 18.0), (8.0, 18.0), (4.0, 18.0), (2.0, 16.0), + (2.0, 12.0), (6.0, 12.0), (2.0, 8.0), (2.0, 4.0), (4.0, 2.0), + (-2.0, 2.0), (4.0, 6.0), (10.0, 2.0), (10.0, 6.0), (8.0, 10.0), (4.0, 10.0), + (10.0, 12.0), (12.0, 12.0), (14.0, 26.0), (16.0, 24.0), (18.0, 28.0), + (16.0, 20.0), (18.0, 12.0), (16.0, 8.0), (14.0, 4.0), (14.0, -2.0), + (6.0, -2.0), (2.0, -4.0), (-4.0, -2.0), (-2.0, 8.0), (-2.0, 16.0), + (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), + (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), + (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), + (7.0, 7.8), (7.0, 7.4), + ] + boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) + tri = triangulate(points; boundary_nodes = boundary_nodes) + @test DT.is_positively_oriented(tri, 1) + @test !DT.is_positively_oriented(tri, 2) + @test !DT.is_positively_oriented(tri, 3) + @test !DT.is_positively_oriented(tri, 4) + + curve_1 = [ + [(0.0, 0.0), (5.0, 0.0), (10.0, 0.0), (15.0, 0.0), (20.0, 0.0), (25.0, 0.0)], + [(25.0, 0.0), (25.0, 5.0), (25.0, 10.0), (25.0, 15.0), (25.0, 20.0), (25.0, 25.0)], + [(25.0, 25.0), (20.0, 25.0), (15.0, 25.0), (10.0, 25.0), (5.0, 25.0), (0.0, 25.0)], + [(0.0, 25.0), (0.0, 20.0), (0.0, 15.0), (0.0, 10.0), (0.0, 5.0), (0.0, 0.0)], + ] # outer-most boundary: counter-clockwise + curve_2 = [ + [(4.0, 6.0), (4.0, 14.0), (4.0, 20.0), (18.0, 20.0), (20.0, 20.0)], + [(20.0, 20.0), (20.0, 16.0), (20.0, 12.0), (20.0, 8.0), (20.0, 4.0)], + [(20.0, 4.0), (16.0, 4.0), (12.0, 4.0), (8.0, 4.0), (4.0, 4.0), (4.0, 6.0)], + ] # inner boundary: clockwise + curve_3 = [ + [ + (12.906, 10.912), (16.0, 12.0), (16.16, 14.46), (16.29, 17.06), + (13.13, 16.86), (8.92, 16.4), (8.8, 10.9), (12.906, 10.912), + ], + ] # this is inside curve_2, so it's counter-clockwise + curves = [curve_1, curve_2, curve_3] + points = [ + (3.0, 23.0), (9.0, 24.0), (9.2, 22.0), (14.8, 22.8), (16.0, 22.0), + (23.0, 23.0), (22.6, 19.0), (23.8, 17.8), (22.0, 14.0), (22.0, 11.0), + (24.0, 6.0), (23.0, 2.0), (19.0, 1.0), (16.0, 3.0), (10.0, 1.0), (11.0, 3.0), + (6.0, 2.0), (6.2, 3.0), (2.0, 3.0), (2.6, 6.2), (2.0, 8.0), (2.0, 11.0), + (5.0, 12.0), (2.0, 17.0), (3.0, 19.0), (6.0, 18.0), (6.5, 14.5), + (13.0, 19.0), (13.0, 12.0), (16.0, 8.0), (9.8, 8.0), (7.5, 6.0), + (12.0, 13.0), (19.0, 15.0), + ] + boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) + tri = triangulate(points; boundary_nodes = boundary_nodes) + @test DT.is_positively_oriented(tri, 1) + @test !DT.is_positively_oriented(tri, 2) + @test DT.is_positively_oriented(tri, 3) + + θ = LinRange(0, 2π, 20) |> collect + θ[end] = 0 # need to make sure that 2π gives the exact same coordinates as 0 + xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() + cx = 0.0 + for i in 1:2 + # Make the exterior circle + push!(xy, [[(cx + cos(θ), sin(θ)) for θ in θ]]) + # Now the interior circle - clockwise + push!(xy, [[(cx + 0.5cos(θ), 0.5sin(θ)) for θ in reverse(θ)]]) + cx += 3.0 + end + boundary_nodes, points = convert_boundary_points_to_indices(xy) + tri = triangulate(points; boundary_nodes = boundary_nodes) + @test DT.is_positively_oriented(tri, 1) + @test !DT.is_positively_oriented(tri, 2) + @test DT.is_positively_oriented(tri, 3) + @test !DT.is_positively_oriented(tri, 4) + + C = (15.7109521325776, 33.244486807457) + D = (14.2705719699703, 32.8530791545746) + E = (14.3, 27.2) + F = (14.1, 27.0) + G = (13.7, 27.2) + H = (13.4, 27.5) + I = (13.1, 27.6) + J = (12.7, 27.4) + K = (12.5, 27.1) + L = (12.7, 26.7) + M = (13.1, 26.5) + N = (13.6, 26.4) + O = (14.0, 26.4) + P = (14.6, 26.5) + Q = (15.1983491346581, 26.8128534095401) + R = (15.6, 27.6) + S = (15.6952958264624, 28.2344688505621) + T = (17.8088971520274, 33.1192363585346) + U = (16.3058917649589, 33.0722674401887) + V = (16.3215480710742, 29.7374742376305) + W = (16.3841732955354, 29.393035503094) + Z = (16.6190178872649, 28.9233463196351) + A1 = (17.0417381523779, 28.5319386667527) + B1 = (17.5114273358368, 28.3753756055997) + C1 = (18.1376795804487, 28.3597192994844) + D1 = (18.7169629067146, 28.5632512789833) + E1 = (19.2805899268653, 28.8920337074045) + F1 = (19.26493362075, 28.4536571361762) + G1 = (20.6426885588962, 28.4223445239456) + H1 = (20.689657477242, 33.1035800524193) + I1 = (19.2805899268653, 33.0722674401887) + J1 = (19.2962462329806, 29.7531305437458) + K1 = (19.0614016412512, 29.393035503094) + L1 = (18.7482755189452, 29.236472441941) + M1 = (18.4508057027546, 29.1425346052493) + N1 = (18.1689921926793, 29.3147539725175) + O1 = (17.7932408459121, 29.6278800948235) + P1 = (22.6466957416542, 35.4207133574833) + Q1 = (21.2219718851621, 34.9979930923702) + R1 = (21.2376281912774, 28.4693134422915) + S1 = (22.6780083538847, 28.4380008300609) + T1 = (24.5724213938357, 33.1975178891111) + U1 = (23.3512295168425, 32.8530791545746) + V1 = (23.3199169046119, 28.4380008300609) + W1 = (24.6663592305274, 28.3753756055997) + Z1 = (15.1942940307729, 35.4363696635986) + A2 = (14.7246048473139, 35.3737444391374) + B2 = (14.3645098066621, 35.1858687657538) + C2 = (14.1766341332786, 34.8570863373326) + D2 = (14.1140089088174, 34.3247719294125) + E2 = (14.2705719699703, 33.8394264398383) + F2 = (14.7246048473139, 33.6202381542241) + G2 = (15.4604512347329, 33.6045818481088) + H2 = (16.0, 34.0) + I2 = (15.9771093365377, 34.6848669700643) + J2 = (15.6170142958859, 35.2328376840997) + K2 = (24.1653574348379, 35.4520259697138) + L2 = (23.7739497819555, 35.4363696635986) + M2 = (23.4608236596496, 35.2641502963303) + N2 = (23.272947986266, 34.9040552556785) + O2 = (23.1320412312284, 34.5909291333725) + P2 = (23.1163849251131, 34.2151777866054) + Q2 = (23.2886042923813, 33.8081138276077) + R2 = (23.8209187003014, 33.6045818481088) + S2 = (24.3062641898756, 33.5576129297629) + T2 = (24.7602970672192, 33.8550827459536) + U2 = (25.010797965064, 34.4656786844502) + V2 = (24.8385785977957, 34.9666804801397) + W2 = (24.5254524754898, 35.2641502963303) + Z2 = (25.3708930057158, 37.4716894585871) + A3 = (24.7916096794498, 37.3464390096648) + B3 = (24.4471709449133, 36.9550313567823) + C3 = (24.3062641898756, 36.5636237038999) + D3 = (24.4941398632592, 35.9999966837492) + E3 = (25.0264542711793, 35.5929327247515) + F3 = (25.5587686790994, 35.5929327247515) + F3 = (25.5587686790994, 35.5929327247515) + G3 = (26.0, 36.0) + H3 = (26.1380520053653, 36.5792800100152) + I3 = (26.0, 37.0) + J3 = (25.7466443524829, 37.2838137852036) + K3 = (26.3885529032101, 35.4676822758291) + L3 = (25.9814889442124, 35.3580881330221) + M3 = (25.6840191280217, 35.1858687657538) + N3 = (25.5274560668688, 34.9040552556785) + O3 = (25.4961434546382, 34.5596165211419) + P3 = (25.5274560668688, 34.246490398836) + Q3 = (25.6683628219064, 33.8394264398383) + R3 = (26.0284578625583, 33.6358944603394) + S3 = (26.5451159643631, 33.6202381542241) + T3 = (27.0, 34.0) + U3 = (27.280962351782, 34.5596165211419) + V3 = (27.0304614539373, 35.2171813779844) + W3 = (26.1693646175959, 33.087923746304) + Z3 = (26.0, 33.0) + A4 = (25.5274560668688, 32.7278287056522) + B4 = (25.2612988629087, 32.4147025833463) + C4 = (25.1830173323322, 32.0702638488098) + D4 = (25.2299862506781, 31.7727940326191) + E4 = (25.6527065157911, 31.5222931347744) + F4 = (26.2946150665183, 31.7258251142732) + G4 = (26.5607722704784, 32.5086404200381) + H4 = (27.1557119028596, 32.7434850117675) + I4 = (27.6097447802033, 32.4929841139228) + J4 = (27.6410573924338, 32.1015764610403) + K4 = (27.7193389230103, 31.6005746653509) + L4 = (27.437525412935, 31.4283552980826) + M4 = (26.9834925355914, 31.2561359308143) + N4 = (26.5764285765937, 31.0995728696614) + O4 = (26.0441141686736, 30.7864467473554) + P4 = (25.6527065157911, 30.5672584617413) + Q4 = (25.3239240873699, 30.1915071149741) + R4 = (25.1673610262169, 29.8783809926682) + S4 = (25.1047358017558, 29.6122237887082) + T4 = (25.0890794956405, 29.1895035235952) + U4 = (25.2926114751393, 28.8294084829433) + V4 = (25.6840191280217, 28.5632512789833) + W4 = (26.1537083114806, 28.3753756055997) + Z4 = (26.8269294744384, 28.391031911715) + A5 = (27.4844943312809, 28.6102201973292) + B5 = (27.7342002330051, 28.7239579596219) + C5 = (27.7264126450755, 28.4202565942047) + D5 = (29.1825559185446, 28.3922538389457) + E5 = (29.1545531632856, 32.2146299318021) + F5 = (29.000538009361, 32.5786657501693) + G5 = (28.6785063238822, 32.9006974356481) + H5 = (28.3144705055149, 33.0827153448317) + I5 = (27.9084305542591, 33.2367304987563) + J5 = (27.3343740714492, 33.3207387645334) + K5 = (26.8303244767868, 33.2367304987563) + L5 = (27.6564057569279, 30.786489413592) + M5 = (27.6984098898165, 30.3944508399657) + N5 = (27.6984098898165, 29.7363860913787) + O5 = (27.5863988687804, 29.4143544059) + P5 = (27.2643671833016, 29.2043337414573) + Q5 = (26.9843396307114, 29.1763309861983) + R5 = (26.6903107004917, 29.3163447624934) + S5 = (26.5782996794556, 29.7503874690082) + T5 = (26.7603175886393, 30.3384453294476) + U5 = (27.3203726938197, 30.7024811478149) + J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] + U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] + L_curve = [[P1, Q1, R1, S1, P1]] + I_curve = [[T1, U1, V1, W1, T1]] + A_curve_outline = [ + [ K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] - A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] - dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] - dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] - dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] - dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] - curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] - nodes, points = convert_boundary_points_to_indices(curves) - tri = triangulate(points; boundary_nodes=nodes) - @test DT.is_positively_oriented(tri, 1) - @test DT.is_positively_oriented(tri, 2) - @test DT.is_positively_oriented(tri, 3) - @test DT.is_positively_oriented(tri, 4) - @test DT.is_positively_oriented(tri, 5) - @test !DT.is_positively_oriented(tri, 6) - @test DT.is_positively_oriented(tri, 7) - @test DT.is_positively_oriented(tri, 8) - @test DT.is_positively_oriented(tri, 9) - @test DT.is_positively_oriented(tri, 10) - @test DT.num_curves(tri) == 10 + H5, I5, J5, K5, + ], + ] + A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] + dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] + dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] + dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] + dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] + curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] + nodes, points = convert_boundary_points_to_indices(curves) + tri = triangulate(points; boundary_nodes = nodes) + @test DT.is_positively_oriented(tri, 1) + @test DT.is_positively_oriented(tri, 2) + @test DT.is_positively_oriented(tri, 3) + @test DT.is_positively_oriented(tri, 4) + @test DT.is_positively_oriented(tri, 5) + @test !DT.is_positively_oriented(tri, 6) + @test DT.is_positively_oriented(tri, 7) + @test DT.is_positively_oriented(tri, 8) + @test DT.is_positively_oriented(tri, 9) + @test DT.is_positively_oriented(tri, 10) + @test DT.num_curves(tri) == 10 end @testset "Full constructor" begin - # Simple example - tri1 = triangulate(rand(2, 50)) - tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1)) - unlock_convex_hull!(tri2) - @test tri1 == tri2 - - # With boundaries - points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8)] - boundary_nodes = [[[1, 2], [2, 3], [3, 4], [4, 1]], [[8, 7], [7, 6], [6, 5], [5, 8]]] - tri1 = triangulate(points; boundary_nodes) - tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_boundary_nodes(tri1)) - @test tri1 == tri2 - - # Custom types - tri1 = triangulate(rand(2, 50); IntegerType=Int32) - tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1); IntegerType=Int32) - unlock_convex_hull!(tri2) - @test tri1 == tri2 - @test tri1 ⊢ tri2 - - # Delete ghosts works properly - tri1 = triangulate(rand(2, 50), delete_ghosts=true) - tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1), delete_ghosts=true) - unlock_convex_hull!(tri2) - @test tri1 == tri2 - - # Weights work properly - weights = rand(50) - tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1), weights=weights) - @test DT.is_weighted(tri2) && get_weights(tri2) == weights + # Simple example + tri1 = triangulate(rand(2, 50)) + tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1)) + unlock_convex_hull!(tri2) + @test tri1 == tri2 + + # With boundaries + points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8)] + boundary_nodes = [[[1, 2], [2, 3], [3, 4], [4, 1]], [[8, 7], [7, 6], [6, 5], [5, 8]]] + tri1 = triangulate(points; boundary_nodes) + tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_boundary_nodes(tri1)) + @test tri1 == tri2 + + # Custom types + tri1 = triangulate(rand(2, 50); IntegerType = Int32) + tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1); IntegerType = Int32) + unlock_convex_hull!(tri2) + @test tri1 == tri2 + @test tri1 ⊢ tri2 + + # Delete ghosts works properly + tri1 = triangulate(rand(2, 50), delete_ghosts = true) + tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1), delete_ghosts = true) + unlock_convex_hull!(tri2) + @test tri1 == tri2 + + # Weights work properly + weights = rand(50) + tri2 = Triangulation(get_points(tri1), each_solid_triangle(tri1), get_convex_hull_vertices(tri1), weights = weights) + @test DT.is_weighted(tri2) && get_weights(tri2) == weights end @testset "Random sampling of triangles, edges, and vertices" begin - # Get the triangulation - A = (0.0, 0.0) - B = (0.0, 25.0) - C = (5.0, 25.0) - D = (5.0, 5.0) - E = (10.0, 5.0) - F = (10.0, 10.0) - G = (25.0, 10.0) - H = (25.0, 15.0) - I = (10.0, 15.0) - J = (10.0, 25.0) - K = (45.0, 25.0) - L = (45.0, 20.0) - M = (40.0, 20.0) - N = (40.0, 5.0) - O = (45.0, 5.0) - P = (45.0, 0.0) - Q = (10.0, 0.0) - R = (10.0, -5.0) - S = (15.0, -5.0) - T = (15.0, -10.0) - U = (10.0, -10.0) - V = (5.0, -10.0) - W = (5.0, -5.0) - Z = (5.0, 0.0) - A1 = (5.0, 2.5) - B1 = (10.0, 2.5) - C1 = (38.0, 2.5) - D1 = (38.0, 20.0) - E1 = (27.0, 20.0) - F1 = (27.0, 11.0) - G1 = (27.0, 4.0) - H1 = (2.0, 4.0) - I1 = (2.0, 0.0) - pts = [A, I1, H1, G1, F1, E1, D1, C1, B1, A1, Z, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A] - J1 = (17.0603265896789, 7.623652007194) - K1 = (14.8552854162067, 6.5423337394336) - L1 = (16.6998871670921, 6.9875824379232) - M1 = (16.0, 6.0) - N1 = (16.9755173137761, 6.6483453343121) - O1 = (17.0391242707032, 4.8885528593294) - P1 = (17.4207660122657, 6.4575244635308) - Q1 = (17.6327892020226, 4.9945644542079) - R1 = (22.6789411182379, 6.1818943168468) - S1 = (21.8096460402344, 6.4787267825065) - T1 = (26.0, 8.0) - U1 = (15.0673086059636, 9.086612016517) - W1 = (15.0, 8.5) - Z1 = (17.7913089332764, 8.3603005983396) - inner_pts = [Z1, W1, U1, T1, S1, R1, Q1, P1, O1, N1, M1, L1, K1, J1, Z1] - boundary_pts = [[pts], [inner_pts]] - nodes, points = convert_boundary_points_to_indices(boundary_pts) - push!(points, (20.0, 20.0)) - rng = StableRNG(19191919) - C = Set{NTuple{2,Int}}() - for i in 1:50 - θ = 2π * rand(rng) - r = 4sqrt(rand(rng)) - x = 20 + r * cos(θ) - y = 20 + r * sin(θ) - push!(points, (x, y)) - push!(C, (48, 48 + i)) - end - tri = triangulate(points; boundary_nodes=nodes, segments=C, rng) - - # Vertices - ns = 5_000_000 - function test_vertex_sampler(tri, ns) - solid_vertices = DefaultDict{Int,Float64,Float64}(0.0) - ghost_vertices = DefaultDict{Int,Float64,Float64}(0.0) - for _ in 1:ns - sv = rand(each_solid_vertex(tri)) - gv = rand(each_ghost_vertex(tri)) - solid_vertices[sv] += 1 / ns - ghost_vertices[gv] += 1 / ns - end - return solid_vertices, ghost_vertices - end - solid_vertices, ghost_vertices = test_vertex_sampler(tri, ns) - @inferred rand(each_solid_vertex(tri)) - @inferred rand(each_ghost_vertex(tri)) - @test all(!DT.is_ghost_vertex, keys(solid_vertices)) - @test all(DT.is_ghost_vertex, keys(ghost_vertices)) - sm = mean(values(solid_vertices)) # sm for solid mean - gm = mean(values(ghost_vertices)) - @test sm ≈ 1 / DT.num_solid_vertices(tri) - @test gm ≈ 1 / 2 - @test all(y -> isapprox(y, sm, rtol=1e-1), values(solid_vertices)) - @test all(y -> isapprox(y, gm, rtol=1e-1), values(ghost_vertices)) - for i in 1:250 - for f in (each_vertex, each_solid_vertex, each_ghost_vertex) - rng = StableRNG(i) - V1 = rand(rng, f(tri)) - V2 = rand(rng, f(tri)) - V3 = rand(rng, f(tri)) - rng = StableRNG(i) - @test rand(rng, f(tri)) == V1 - @test rand(rng, f(tri)) == V2 - @test rand(rng, f(tri)) == V3 - end - end - - # Triangles - ns = 5_000_000 - function test_triangle_sampler(tri, ns) - solid_triangles = DefaultDict{NTuple{3,Int},Float64,Float64}(0.0) - ghost_triangles = DefaultDict{NTuple{3,Int},Float64,Float64}(0.0) - for _ in 1:ns - st = rand(each_solid_triangle(tri)) - gt = rand(each_ghost_triangle(tri)) - solid_triangles[st] += 1 / ns - ghost_triangles[gt] += 1 / ns - end - return solid_triangles, ghost_triangles - end - solid_triangles, ghost_triangles = test_triangle_sampler(tri, ns) - @inferred rand(each_solid_triangle(tri)) - @inferred rand(each_ghost_triangle(tri)) - @test all(!DT.is_ghost_triangle, keys(solid_triangles)) - @test all(DT.is_ghost_triangle, keys(ghost_triangles)) - sm = mean(values(solid_triangles)) # sm for solid mean - gm = mean(values(ghost_triangles)) - @test sm ≈ 1 / DT.num_solid_triangles(tri) - @test gm ≈ 1 / DT.num_ghost_triangles(tri) - @test all(y -> isapprox(y, sm, rtol=1e-1), values(solid_triangles)) - @test all(y -> isapprox(y, gm, rtol=1e-1), values(ghost_triangles)) - for i in 1:250 - for f in (each_triangle, each_solid_triangle, each_ghost_triangle) - rng = StableRNG(i) - V1 = rand(rng, f(tri)) - V2 = rand(rng, f(tri)) - V3 = rand(rng, f(tri)) - rng = StableRNG(i) - @test rand(rng, f(tri)) == V1 - @test rand(rng, f(tri)) == V2 - @test rand(rng, f(tri)) == V3 - end - end - - # Edges - ns = 5_000_000 - function test_edge_sampler(tri, ns) - solid_edges = DefaultDict{NTuple{2,Int},Float64,Float64}(0.0) - ghost_edges = DefaultDict{NTuple{2,Int},Float64,Float64}(0.0) - for _ in 1:ns - se = rand(each_solid_edge(tri)) - ge = rand(each_ghost_edge(tri)) - solid_edges[se] += 1 / ns - ghost_edges[ge] += 1 / ns - end - return solid_edges, ghost_edges - end - solid_edges, ghost_edges = test_edge_sampler(tri, ns) - @inferred rand(each_solid_edge(tri)) - @inferred rand(each_ghost_edge(tri)) - @test all(!DT.is_ghost_edge, keys(solid_edges)) - @test all(DT.is_ghost_edge, keys(ghost_edges)) - sm = mean(values(solid_edges)) # sm for solid mean - gm = mean(values(ghost_edges)) - @test sm ≈ 1 / DT.num_solid_edges(tri) - @test gm ≈ 1 / DT.num_ghost_edges(tri) - @test all(y -> isapprox(y, sm, rtol=1e-1), values(solid_edges)) - @test all(y -> isapprox(y, gm, rtol=1e-1), values(ghost_edges)) - for i in 1:250 - for f in (each_edge, each_solid_edge, each_ghost_edge) - rng = StableRNG(i) - V1 = rand(rng, f(tri)) - V2 = rand(rng, f(tri)) - rng = StableRNG(i) - @test rand(rng, f(tri)) == V1 - @test rand(rng, f(tri)) == V2 - end - end -end \ No newline at end of file + # Get the triangulation + A = (0.0, 0.0) + B = (0.0, 25.0) + C = (5.0, 25.0) + D = (5.0, 5.0) + E = (10.0, 5.0) + F = (10.0, 10.0) + G = (25.0, 10.0) + H = (25.0, 15.0) + I = (10.0, 15.0) + J = (10.0, 25.0) + K = (45.0, 25.0) + L = (45.0, 20.0) + M = (40.0, 20.0) + N = (40.0, 5.0) + O = (45.0, 5.0) + P = (45.0, 0.0) + Q = (10.0, 0.0) + R = (10.0, -5.0) + S = (15.0, -5.0) + T = (15.0, -10.0) + U = (10.0, -10.0) + V = (5.0, -10.0) + W = (5.0, -5.0) + Z = (5.0, 0.0) + A1 = (5.0, 2.5) + B1 = (10.0, 2.5) + C1 = (38.0, 2.5) + D1 = (38.0, 20.0) + E1 = (27.0, 20.0) + F1 = (27.0, 11.0) + G1 = (27.0, 4.0) + H1 = (2.0, 4.0) + I1 = (2.0, 0.0) + pts = [A, I1, H1, G1, F1, E1, D1, C1, B1, A1, Z, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A] + J1 = (17.0603265896789, 7.623652007194) + K1 = (14.8552854162067, 6.5423337394336) + L1 = (16.6998871670921, 6.9875824379232) + M1 = (16.0, 6.0) + N1 = (16.9755173137761, 6.6483453343121) + O1 = (17.0391242707032, 4.8885528593294) + P1 = (17.4207660122657, 6.4575244635308) + Q1 = (17.6327892020226, 4.9945644542079) + R1 = (22.6789411182379, 6.1818943168468) + S1 = (21.8096460402344, 6.4787267825065) + T1 = (26.0, 8.0) + U1 = (15.0673086059636, 9.086612016517) + W1 = (15.0, 8.5) + Z1 = (17.7913089332764, 8.3603005983396) + inner_pts = [Z1, W1, U1, T1, S1, R1, Q1, P1, O1, N1, M1, L1, K1, J1, Z1] + boundary_pts = [[pts], [inner_pts]] + nodes, points = convert_boundary_points_to_indices(boundary_pts) + push!(points, (20.0, 20.0)) + rng = StableRNG(19191919) + C = Set{NTuple{2, Int}}() + for i in 1:50 + θ = 2π * rand(rng) + r = 4sqrt(rand(rng)) + x = 20 + r * cos(θ) + y = 20 + r * sin(θ) + push!(points, (x, y)) + push!(C, (48, 48 + i)) + end + tri = triangulate(points; boundary_nodes = nodes, segments = C, rng) + + # Vertices + ns = 5_000_000 + function test_vertex_sampler(tri, ns) + solid_vertices = DefaultDict{Int, Float64, Float64}(0.0) + ghost_vertices = DefaultDict{Int, Float64, Float64}(0.0) + for _ in 1:ns + sv = rand(each_solid_vertex(tri)) + gv = rand(each_ghost_vertex(tri)) + solid_vertices[sv] += 1 / ns + ghost_vertices[gv] += 1 / ns + end + return solid_vertices, ghost_vertices + end + solid_vertices, ghost_vertices = test_vertex_sampler(tri, ns) + @inferred rand(each_solid_vertex(tri)) + @inferred rand(each_ghost_vertex(tri)) + @test all(!DT.is_ghost_vertex, keys(solid_vertices)) + @test all(DT.is_ghost_vertex, keys(ghost_vertices)) + sm = mean(values(solid_vertices)) # sm for solid mean + gm = mean(values(ghost_vertices)) + @test sm ≈ 1 / DT.num_solid_vertices(tri) + @test gm ≈ 1 / 2 + @test all(y -> isapprox(y, sm, rtol = 1.0e-1), values(solid_vertices)) + @test all(y -> isapprox(y, gm, rtol = 1.0e-1), values(ghost_vertices)) + for i in 1:250 + for f in (each_vertex, each_solid_vertex, each_ghost_vertex) + rng = StableRNG(i) + V1 = rand(rng, f(tri)) + V2 = rand(rng, f(tri)) + V3 = rand(rng, f(tri)) + rng = StableRNG(i) + @test rand(rng, f(tri)) == V1 + @test rand(rng, f(tri)) == V2 + @test rand(rng, f(tri)) == V3 + end + end + + # Triangles + ns = 5_000_000 + function test_triangle_sampler(tri, ns) + solid_triangles = DefaultDict{NTuple{3, Int}, Float64, Float64}(0.0) + ghost_triangles = DefaultDict{NTuple{3, Int}, Float64, Float64}(0.0) + for _ in 1:ns + st = rand(each_solid_triangle(tri)) + gt = rand(each_ghost_triangle(tri)) + solid_triangles[st] += 1 / ns + ghost_triangles[gt] += 1 / ns + end + return solid_triangles, ghost_triangles + end + solid_triangles, ghost_triangles = test_triangle_sampler(tri, ns) + @inferred rand(each_solid_triangle(tri)) + @inferred rand(each_ghost_triangle(tri)) + @test all(!DT.is_ghost_triangle, keys(solid_triangles)) + @test all(DT.is_ghost_triangle, keys(ghost_triangles)) + sm = mean(values(solid_triangles)) # sm for solid mean + gm = mean(values(ghost_triangles)) + @test sm ≈ 1 / DT.num_solid_triangles(tri) + @test gm ≈ 1 / DT.num_ghost_triangles(tri) + @test all(y -> isapprox(y, sm, rtol = 1.0e-1), values(solid_triangles)) + @test all(y -> isapprox(y, gm, rtol = 1.0e-1), values(ghost_triangles)) + for i in 1:250 + for f in (each_triangle, each_solid_triangle, each_ghost_triangle) + rng = StableRNG(i) + V1 = rand(rng, f(tri)) + V2 = rand(rng, f(tri)) + V3 = rand(rng, f(tri)) + rng = StableRNG(i) + @test rand(rng, f(tri)) == V1 + @test rand(rng, f(tri)) == V2 + @test rand(rng, f(tri)) == V3 + end + end + + # Edges + ns = 5_000_000 + function test_edge_sampler(tri, ns) + solid_edges = DefaultDict{NTuple{2, Int}, Float64, Float64}(0.0) + ghost_edges = DefaultDict{NTuple{2, Int}, Float64, Float64}(0.0) + for _ in 1:ns + se = rand(each_solid_edge(tri)) + ge = rand(each_ghost_edge(tri)) + solid_edges[se] += 1 / ns + ghost_edges[ge] += 1 / ns + end + return solid_edges, ghost_edges + end + solid_edges, ghost_edges = test_edge_sampler(tri, ns) + @inferred rand(each_solid_edge(tri)) + @inferred rand(each_ghost_edge(tri)) + @test all(!DT.is_ghost_edge, keys(solid_edges)) + @test all(DT.is_ghost_edge, keys(ghost_edges)) + sm = mean(values(solid_edges)) # sm for solid mean + gm = mean(values(ghost_edges)) + @test sm ≈ 1 / DT.num_solid_edges(tri) + @test gm ≈ 1 / DT.num_ghost_edges(tri) + @test all(y -> isapprox(y, sm, rtol = 1.0e-1), values(solid_edges)) + @test all(y -> isapprox(y, gm, rtol = 1.0e-1), values(ghost_edges)) + for i in 1:250 + for f in (each_edge, each_solid_edge, each_ghost_edge) + rng = StableRNG(i) + V1 = rand(rng, f(tri)) + V2 = rand(rng, f(tri)) + rng = StableRNG(i) + @test rand(rng, f(tri)) == V1 + @test rand(rng, f(tri)) == V2 + end + end +end diff --git a/test/data_structures/triangulation_cache.jl b/test/data_structures/triangulation_cache.jl index e63855854..0241d9f8a 100644 --- a/test/data_structures/triangulation_cache.jl +++ b/test/data_structures/triangulation_cache.jl @@ -7,7 +7,7 @@ using ..DelaunayTriangulation: add_weight!, get_weight, get_weights @struct_equal DT.TriangulationCache -tri = triangulate(rand(2, 50); weights=DT.ZeroWeight()) +tri = triangulate(rand(2, 50); weights = DT.ZeroWeight()) cache = DT.get_cache(tri) @test get_weights(DT.get_triangulation(DT.get_cache(tri))) === get_weights(tri) DT.unconstrained_triangulation!(DT.get_triangulation(cache)) diff --git a/test/geo_utils.jl b/test/geo_utils.jl index 63a2c312d..936579c03 100644 --- a/test/geo_utils.jl +++ b/test/geo_utils.jl @@ -5,1173 +5,1268 @@ using Random using CairoMakie @testset "Getting polygon features" begin - tri, label_map, index_map = simple_geometry() - pts = get_points(tri) - boundary_nodes = [index_map["a"], + tri, label_map, index_map = simple_geometry() + pts = get_points(tri) + boundary_nodes = [ + index_map["a"], + index_map["b"], + index_map["c"], + index_map["d"], + index_map["e"], + index_map["f"], + index_map["g"], + index_map["h"], + index_map["a"], + ] + a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) + @inferred DT.polygon_features(pts, boundary_nodes) + @test a ≈ 400.0 && cx ≈ 10.0 && cy ≈ 10.0 + boundary_nodes = [ + index_map["j"], + index_map["k"], + index_map["ℓ"], + index_map["i"], + index_map["j"], + ] + a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) + @test a ≈ 40.0 && cx ≈ 6.0 && cy ≈ 11.0 + boundary_nodes = [ + [ + index_map["a"], index_map["b"], index_map["c"], index_map["d"], + ], + [ + index_map["d"], index_map["e"], index_map["f"], index_map["g"], + ], + [ + index_map["g"], index_map["h"], - index_map["a"]] - a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) - @inferred DT.polygon_features(pts, boundary_nodes) - @test a ≈ 400.0 && cx ≈ 10.0 && cy ≈ 10.0 - boundary_nodes = [index_map["j"], + index_map["a"], + ], + ] + a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) + @inferred DT.polygon_features(pts, boundary_nodes) + @test a ≈ 400.0 && cx ≈ 10.0 && cy ≈ 10.0 + boundary_nodes = [ + [ + index_map["j"], + index_map["k"], + ], + [ index_map["k"], index_map["ℓ"], index_map["i"], - index_map["j"]] - a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) - @test a ≈ 40.0 && cx ≈ 6.0 && cy ≈ 11.0 - boundary_nodes = [[index_map["a"], - index_map["b"], - index_map["c"], - index_map["d"]], - [index_map["d"], - index_map["e"], - index_map["f"], - index_map["g"]], - [index_map["g"], - index_map["h"], - index_map["a"]]] - a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) - @inferred DT.polygon_features(pts, boundary_nodes) - @test a ≈ 400.0 && cx ≈ 10.0 && cy ≈ 10.0 - boundary_nodes = [[index_map["j"], - index_map["k"]], - [index_map["k"], - index_map["ℓ"], - index_map["i"]], - [index_map["i"], - index_map["j"]]] - a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) - @test a ≈ 40.0 && cx ≈ 6.0 && cy ≈ 11.0 - a, (cx, cy) = DT.polygon_features(pts, tri.boundary_nodes) - @inferred DT.polygon_features(pts, tri.boundary_nodes) - a1, a2, a3 = 400.0, 32.0, 40.0 - c1, c2, c3 = (10.0, 10.0), (15.58333333333, 7.0), (6.0, 11.0) - @test a ≈ a1 - a2 - a3 - @test cx ≈ (c1[1] * a1 - c2[1] * a2 - c3[1] * a3) / (a1 - a2 - a3) - @test cy ≈ (c1[2] * a1 - c2[2] * a2 - c3[2] * a3) / (a1 - a2 - a3) + ], + [ + index_map["i"], + index_map["j"], + ], + ] + a, (cx, cy) = DT.polygon_features(pts, boundary_nodes) + @test a ≈ 40.0 && cx ≈ 6.0 && cy ≈ 11.0 + a, (cx, cy) = DT.polygon_features(pts, tri.boundary_nodes) + @inferred DT.polygon_features(pts, tri.boundary_nodes) + a1, a2, a3 = 400.0, 32.0, 40.0 + c1, c2, c3 = (10.0, 10.0), (15.58333333333, 7.0), (6.0, 11.0) + @test a ≈ a1 - a2 - a3 + @test cx ≈ (c1[1] * a1 - c2[1] * a2 - c3[1] * a3) / (a1 - a2 - a3) + @test cy ≈ (c1[2] * a1 - c2[2] * a2 - c3[2] * a3) / (a1 - a2 - a3) end @testset "Another test for area" begin - tri = triangulate(rand(2, 50)) - for T in each_solid_triangle(tri) - u, v, w = T - p, q, r = get_point(tri, u, v, w) - a1 = DT.triangle_area(p, q, r) - a2 = DT.polygon_features(get_points(tri), [u, v, w, u])[1] - @test a1 ≈ a2 atol = 1e-4 - end + tri = triangulate(rand(2, 50)) + for T in each_solid_triangle(tri) + u, v, w = T + p, q, r = get_point(tri, u, v, w) + a1 = DT.triangle_area(p, q, r) + a2 = DT.polygon_features(get_points(tri), [u, v, w, u])[1] + @test a1 ≈ a2 atol = 1.0e-4 + end end @testset "Degenerate area calculation" begin #72 - p = (0.007668495f0, 0.7747718f0) - q = (0.0044495463f0, 0.97074896f0) - r = (0.015137732f0, 0.31555605f0) - a1 = DT.triangle_area(p, q, r) - @test a1 isa Float32 - a2 = DT.polygon_features([p, q, r], [1, 2, 3, 1])[1] - @test a1 ≈ a2 atol = 1e-4 + p = (0.007668495f0, 0.7747718f0) + q = (0.0044495463f0, 0.97074896f0) + r = (0.015137732f0, 0.31555605f0) + a1 = DT.triangle_area(p, q, r) + @test a1 isa Float32 + a2 = DT.polygon_features([p, q, r], [1, 2, 3, 1])[1] + @test a1 ≈ a2 atol = 1.0e-4 end @testset "Distance to a segment" begin - p1 = [0.0, 0.0] - p2 = [10.0, 0.0] - q = [0.0, 5.0] - d = DT.squared_distance_to_segment(p1..., p2..., q...) - @test sqrt(d) == q[2] - @inferred DT.squared_distance_to_segment(p1..., p2..., q...) - for _ in 1:10000 - local q - pᵢ = 10randn(2) - pⱼ = 10randn(2) - q = 10randn(2) - pᵢx, pᵢy = pᵢ - pⱼx, pⱼy = pⱼ - qx, qy = q - t = ((pᵢx - pⱼx) * (pᵢx - qx) + (pᵢy - pⱼy) * (pᵢy - qy)) / - ((pᵢx - pⱼx)^2 + (pᵢy - pⱼy)^2) # solve (d/dt)||q - (pᵢ + t(pⱼ - pᵢ))|| = 0 for t - if t < 0 - @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ norm(q - pᵢ)^2 - elseif t > 1 - @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ norm(q - pⱼ)^2 - else - @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ - norm(q - (pᵢ + t * (pⱼ - pᵢ)))^2 - end - end + p1 = [0.0, 0.0] + p2 = [10.0, 0.0] + q = [0.0, 5.0] + d = DT.squared_distance_to_segment(p1..., p2..., q...) + @test sqrt(d) == q[2] + @inferred DT.squared_distance_to_segment(p1..., p2..., q...) + for _ in 1:10000 + local q + pᵢ = 10randn(2) + pⱼ = 10randn(2) + q = 10randn(2) + pᵢx, pᵢy = pᵢ + pⱼx, pⱼy = pⱼ + qx, qy = q + t = ((pᵢx - pⱼx) * (pᵢx - qx) + (pᵢy - pⱼy) * (pᵢy - qy)) / + ((pᵢx - pⱼx)^2 + (pᵢy - pⱼy)^2) # solve (d/dt)||q - (pᵢ + t(pⱼ - pᵢ))|| = 0 for t + if t < 0 + @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ norm(q - pᵢ)^2 + elseif t > 1 + @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ norm(q - pⱼ)^2 + else + @test DT.squared_distance_to_segment(pᵢ..., pⱼ..., q...) ≈ + norm(q - (pᵢ + t * (pⱼ - pᵢ)))^2 + end + end end @testset "Distance to a polygon" begin - tri, label_map, index_map = simple_geometry() - pts = get_points(tri) - @testset "Single boundary" begin - boundary_nodes = [index_map["a"], - index_map["b"], - index_map["c"], - index_map["d"], - index_map["e"], - index_map["f"], - index_map["g"], - index_map["h"], - index_map["a"]] - q = (28.0, 18.0) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ -8.0 - @inferred DT.distance_to_polygon(q, pts, boundary_nodes) - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (26.9116654358588, 23.0120339025522) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ -7.5394606788132 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (9.5687897994641, 11.7840765682329) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ 20.0 - q[2] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ q[1] - 8.0 - q = (2.0, 2.0) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ 2.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (-2.0, 0.0) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ -2.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (0.0, 0.0) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ 0.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (10.0, 0.0) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @inferred DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ 0.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (4.6998638334488, 13.8273575177129) - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ q[1] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ -(q[1] - 4.0) - q = [-0.181375963606, 9.9696497047896] - dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) - @test dist ≈ q[1] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - end + tri, label_map, index_map = simple_geometry() + pts = get_points(tri) + @testset "Single boundary" begin + boundary_nodes = [ + index_map["a"], + index_map["b"], + index_map["c"], + index_map["d"], + index_map["e"], + index_map["f"], + index_map["g"], + index_map["h"], + index_map["a"], + ] + q = (28.0, 18.0) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ -8.0 + @inferred DT.distance_to_polygon(q, pts, boundary_nodes) + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (26.9116654358588, 23.0120339025522) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ -7.5394606788132 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (9.5687897994641, 11.7840765682329) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ 20.0 - q[2] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ q[1] - 8.0 + q = (2.0, 2.0) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ 2.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (-2.0, 0.0) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ -2.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (0.0, 0.0) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ 0.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (10.0, 0.0) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @inferred DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ 0.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (4.6998638334488, 13.8273575177129) + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ q[1] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ -(q[1] - 4.0) + q = [-0.181375963606, 9.9696497047896] + dist = DT.distance_to_polygon_single_segment(q, pts, boundary_nodes) + @test dist ≈ q[1] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + end - @testset "Multiple boundary segments" begin - boundary_nodes = [[index_map["a"], - index_map["b"], - index_map["c"], - index_map["d"]], - [index_map["d"], - index_map["e"], - index_map["f"], - index_map["g"]], - [index_map["g"], - index_map["h"], - index_map["a"]]] - q = (28.0, 18.0) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ -8.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (26.9116654358588, 23.0120339025522) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ -7.5394606788132 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (9.5687897994641, 11.7840765682329) - @inferred DT.distance_to_polygon(q, pts, boundary_nodes) - @inferred DT.distance_to_polygon(q, pts, tri.boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ 20.0 - q[2] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - q = (2.0, 2.0) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ 2.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (-2.0, 0.0) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ -2.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (0.0, 0.0) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ 0.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (10.0, 0.0) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @inferred DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ 0.0 - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == - DT.distance_to_polygon(q, pts, tri.boundary_nodes) - q = (4.6998638334488, 13.8273575177129) - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ q[1] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - q = [-0.181375963606, 9.9696497047896] - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ q[1] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - q = [14.2840577995064, 9.7320720329939] - dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) - @test dist ≈ 20.0 - q[1] - @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) - @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ -(q[1] - 14.0) - end + @testset "Multiple boundary segments" begin + boundary_nodes = [ + [ + index_map["a"], + index_map["b"], + index_map["c"], + index_map["d"], + ], + [ + index_map["d"], + index_map["e"], + index_map["f"], + index_map["g"], + ], + [ + index_map["g"], + index_map["h"], + index_map["a"], + ], + ] + q = (28.0, 18.0) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ -8.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (26.9116654358588, 23.0120339025522) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ -7.5394606788132 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (9.5687897994641, 11.7840765682329) + @inferred DT.distance_to_polygon(q, pts, boundary_nodes) + @inferred DT.distance_to_polygon(q, pts, tri.boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ 20.0 - q[2] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + q = (2.0, 2.0) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ 2.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (-2.0, 0.0) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ -2.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (0.0, 0.0) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ 0.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (10.0, 0.0) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @inferred DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ 0.0 + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) == + DT.distance_to_polygon(q, pts, tri.boundary_nodes) + q = (4.6998638334488, 13.8273575177129) + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ q[1] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + q = [-0.181375963606, 9.9696497047896] + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ q[1] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + q = [14.2840577995064, 9.7320720329939] + dist = DT.distance_to_polygon_multiple_segments(q, pts, boundary_nodes) + @test dist ≈ 20.0 - q[1] + @test dist == DT.distance_to_polygon(q, pts, boundary_nodes) + @test DT.distance_to_polygon(q, pts, tri.boundary_nodes) ≈ -(q[1] - 14.0) + end end @testset "Bounding box of a polygon" begin - tri, label_map, index_map = simple_geometry() - pts = get_points(tri) - boundary_nodes = [index_map["a"], + tri, label_map, index_map = simple_geometry() + pts = get_points(tri) + boundary_nodes = [ + index_map["a"], + index_map["b"], + index_map["c"], + index_map["d"], + index_map["e"], + index_map["f"], + index_map["g"], + index_map["h"], + index_map["a"], + ] + @test DT.polygon_bounds(pts, boundary_nodes) == (0.0, 20.0, 0.0, 20.0) + @inferred DT.polygon_bounds(pts, boundary_nodes) + boundary_nodes = [ + [ + index_map["a"], index_map["b"], index_map["c"], index_map["d"], + ], + [ + index_map["d"], index_map["e"], index_map["f"], index_map["g"], + ], + [ + index_map["g"], index_map["h"], - index_map["a"]] - @test DT.polygon_bounds(pts, boundary_nodes) == (0.0, 20.0, 0.0, 20.0) - @inferred DT.polygon_bounds(pts, boundary_nodes) - boundary_nodes = [[index_map["a"], - index_map["b"], - index_map["c"], - index_map["d"]], - [index_map["d"], - index_map["e"], - index_map["f"], - index_map["g"]], - [index_map["g"], - index_map["h"], - index_map["a"]]] - @test DT.polygon_bounds(pts, boundary_nodes) == (0.0, 20.0, 0.0, 20.0) - @inferred DT.polygon_bounds(pts, boundary_nodes) - @test DT.polygon_bounds(pts, tri.boundary_nodes) == (0.0, 20.0, 0.0, 20.0) - @inferred DT.polygon_bounds(pts, tri.boundary_nodes) + index_map["a"], + ], + ] + @test DT.polygon_bounds(pts, boundary_nodes) == (0.0, 20.0, 0.0, 20.0) + @inferred DT.polygon_bounds(pts, boundary_nodes) + @test DT.polygon_bounds(pts, tri.boundary_nodes) == (0.0, 20.0, 0.0, 20.0) + @inferred DT.polygon_bounds(pts, tri.boundary_nodes) - # this example used to give ymin = ∞! - pts = - [ - (0.42128834958962136, 0.33007028464908217) - (0.11356454007618466, 0.7448537954874419) - (0.7546603355923669, 0.9543777463196534) - (0.4891168285858787, 0.633382367024488) - (0.6747495735823583, 0.45029401396930835) - (0.4974345692650808, 0.5149317175333161) - (0.5484553916212294, 0.5711900118327666) - (0.11175023541896634, 0.990159314424705) - (0.4879170832093027, 0.08984797306499748) - (0.1335657114656048, 0.35758096957091445) - (0.7400877461824955, 0.8325280694798072) - (0.3299481327824305, 0.3440909795000966) - (0.1962438207259194, 0.6775012296614791) - (0.3403201981957973, 0.012234115125469014) - (0.39090662279892596, 0.6232084829209825) - (0.05180909728733263, 0.008306644625064141) - (0.4469104766158789, 0.5039047194497466) - (0.33193129503638996, 0.1768246437543215) - (0.24763476605581736, 0.9547830758766014) - (0.8626957317918005, 0.8901670309728742) - (0.16962017427458131, 0.8788693051101659) - (0.6974737865767218, 0.3655018057608477) - (0.5781761692908192, 0.49368701064930676) - (0.802284945950765, 0.6391848231098498) - (0.24014031334952324, 0.03642844544263135) - (0.29635836817046646, 0.49234998547822206) - (0.6537526603197776, 0.9534202877086324) - (0.22033649109831877, 0.6097719755673441) - (0.5794841917252405, 0.6525875695433809) - (0.48634161888118377, 0.7185107690604786) - (0.5345141678719951, 0.5951779828559485) - (0.07485448974139897, 0.3652052168490376) - (0.9456233879280223, 0.20388899534798632) - (0.27834285268176084, 0.8083123815440214) - (0.6267933326859505, 0.39246432872096704) - (0.7616653549409313, 0.6567908542485912) - (0.7064053508954178, 0.5295025690789412) - (0.6402160832134494, 0.7577312997966936) - (0.3919353829681529, 0.8457590619098538) - (0.9716293296512977, 0.5682387373301687) - ] - boundary_nodes = [16, 14, 33, 40, 20, 3, 8, 16] - _pts = pts[boundary_nodes] - xmin = minimum(getindex.(_pts, 1)) - xmax = maximum(getindex.(_pts, 1)) - ymin = minimum(getindex.(_pts, 2)) - ymax = maximum(getindex.(_pts, 2)) - _xmin, _xmax, _ymin, _ymax = DT.polygon_bounds(pts, boundary_nodes) - @test xmin == _xmin - @test ymin == _ymin - @test xmax == _xmax - @test ymax == _ymax + # this example used to give ymin = ∞! + pts = + [ + (0.42128834958962136, 0.33007028464908217) + (0.11356454007618466, 0.7448537954874419) + (0.7546603355923669, 0.9543777463196534) + (0.4891168285858787, 0.633382367024488) + (0.6747495735823583, 0.45029401396930835) + (0.4974345692650808, 0.5149317175333161) + (0.5484553916212294, 0.5711900118327666) + (0.11175023541896634, 0.990159314424705) + (0.4879170832093027, 0.08984797306499748) + (0.1335657114656048, 0.35758096957091445) + (0.7400877461824955, 0.8325280694798072) + (0.3299481327824305, 0.3440909795000966) + (0.1962438207259194, 0.6775012296614791) + (0.3403201981957973, 0.012234115125469014) + (0.39090662279892596, 0.6232084829209825) + (0.05180909728733263, 0.008306644625064141) + (0.4469104766158789, 0.5039047194497466) + (0.33193129503638996, 0.1768246437543215) + (0.24763476605581736, 0.9547830758766014) + (0.8626957317918005, 0.8901670309728742) + (0.16962017427458131, 0.8788693051101659) + (0.6974737865767218, 0.3655018057608477) + (0.5781761692908192, 0.49368701064930676) + (0.802284945950765, 0.6391848231098498) + (0.24014031334952324, 0.03642844544263135) + (0.29635836817046646, 0.49234998547822206) + (0.6537526603197776, 0.9534202877086324) + (0.22033649109831877, 0.6097719755673441) + (0.5794841917252405, 0.6525875695433809) + (0.48634161888118377, 0.7185107690604786) + (0.5345141678719951, 0.5951779828559485) + (0.07485448974139897, 0.3652052168490376) + (0.9456233879280223, 0.20388899534798632) + (0.27834285268176084, 0.8083123815440214) + (0.6267933326859505, 0.39246432872096704) + (0.7616653549409313, 0.6567908542485912) + (0.7064053508954178, 0.5295025690789412) + (0.6402160832134494, 0.7577312997966936) + (0.3919353829681529, 0.8457590619098538) + (0.9716293296512977, 0.5682387373301687) + ] + boundary_nodes = [16, 14, 33, 40, 20, 3, 8, 16] + _pts = pts[boundary_nodes] + xmin = minimum(getindex.(_pts, 1)) + xmax = maximum(getindex.(_pts, 1)) + ymin = minimum(getindex.(_pts, 2)) + ymax = maximum(getindex.(_pts, 2)) + _xmin, _xmax, _ymin, _ymax = DT.polygon_bounds(pts, boundary_nodes) + @test xmin == _xmin + @test ymin == _ymin + @test xmax == _xmax + @test ymax == _ymax end @testset "Cell data structure" begin - tri, label_map, index_map = simple_geometry() - pts = get_points(tri) - @testset "Constructor and operations" begin - p = DT.Cell(10.0, 10.0, 10.0, pts, tri.boundary_nodes) - @test p.dist == DT.distance_to_polygon((10.0, 10.0), pts, tri.boundary_nodes) - @test p.max_dist ≈ p.dist + 10.0 * sqrt(2) - q = DT.Cell(7.0, 17.0, 0.3, pts, tri.boundary_nodes) - @test (p < q) == (p.max_dist < q.max_dist) - @test (p > q) == (p.max_dist > q.max_dist) - @test (p == q) == (p.max_dist == q.max_dist) - @test (p ≤ q) == (p.max_dist ≤ q.max_dist) - @test (p ≥ q) == (p.max_dist ≥ q.max_dist) - @test p.x == 10.0 - @test p.y == 10.0 - @test p.half_width == 10.0 - @test q.x == 7.0 - @test q.y == 17.0 - @test q.half_width == 0.3 - @inferred p < q - end + tri, label_map, index_map = simple_geometry() + pts = get_points(tri) + @testset "Constructor and operations" begin + p = DT.Cell(10.0, 10.0, 10.0, pts, tri.boundary_nodes) + @test p.dist == DT.distance_to_polygon((10.0, 10.0), pts, tri.boundary_nodes) + @test p.max_dist ≈ p.dist + 10.0 * sqrt(2) + q = DT.Cell(7.0, 17.0, 0.3, pts, tri.boundary_nodes) + @test (p < q) == (p.max_dist < q.max_dist) + @test (p > q) == (p.max_dist > q.max_dist) + @test (p == q) == (p.max_dist == q.max_dist) + @test (p ≤ q) == (p.max_dist ≤ q.max_dist) + @test (p ≥ q) == (p.max_dist ≥ q.max_dist) + @test p.x == 10.0 + @test p.y == 10.0 + @test p.half_width == 10.0 + @test q.x == 7.0 + @test q.y == 17.0 + @test q.half_width == 0.3 + @inferred p < q + end - @testset "CellQueue" begin - boundary_nodes = [[index_map["a"], - index_map["b"], - index_map["c"], - index_map["d"]], - [index_map["d"], - index_map["e"], - index_map["f"], - index_map["g"]], - [index_map["g"], - index_map["h"], - index_map["a"]]] - q = DT.CellQueue{Float64}() - @test isempty(q) - c = DT.Cell(DT.polygon_features(pts, boundary_nodes)[2]..., 10.0, pts, boundary_nodes) - DT.insert_cell!(q, c) - @test q.queue[c] == c.max_dist - @inferred DT.get_next_cell!(q) - end + @testset "CellQueue" begin + boundary_nodes = [ + [ + index_map["a"], + index_map["b"], + index_map["c"], + index_map["d"], + ], + [ + index_map["d"], + index_map["e"], + index_map["f"], + index_map["g"], + ], + [ + index_map["g"], + index_map["h"], + index_map["a"], + ], + ] + q = DT.CellQueue{Float64}() + @test isempty(q) + c = DT.Cell(DT.polygon_features(pts, boundary_nodes)[2]..., 10.0, pts, boundary_nodes) + DT.insert_cell!(q, c) + @test q.queue[c] == c.max_dist + @inferred DT.get_next_cell!(q) + end end @testset "Pole of inaccessibility" begin - pts = [(0.0, 10.0), (0.0, 8.0), (0.0, 6.0), (0.0, 4.0), (0.0, 2.0), - (0.0, 0.0), (2.0, 0.0), (4.0, 0.0), (6.0, 0.0), (8.0, 0.0), (10.0, 0.0), - (10.0, 2.0), (10.0, 4.0), (8.0, 4.0), (6.0, 4.0), - (4.0, 4.0), (4.0, 6.0), (4.0, 8.0), (4.0, 10.0), (2.0, 10.0), - (0.0, 10.0)] - @testset "Single segment" begin - boundary_nodes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @inferred DT.pole_of_inaccessibility(pts, boundary_nodes) - @test x == 2.5 && y == 2.5 - end + pts = [ + (0.0, 10.0), (0.0, 8.0), (0.0, 6.0), (0.0, 4.0), (0.0, 2.0), + (0.0, 0.0), (2.0, 0.0), (4.0, 0.0), (6.0, 0.0), (8.0, 0.0), (10.0, 0.0), + (10.0, 2.0), (10.0, 4.0), (8.0, 4.0), (6.0, 4.0), + (4.0, 4.0), (4.0, 6.0), (4.0, 8.0), (4.0, 10.0), (2.0, 10.0), + (0.0, 10.0), + ] + @testset "Single segment" begin + boundary_nodes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @inferred DT.pole_of_inaccessibility(pts, boundary_nodes) + @test x == 2.5 && y == 2.5 + end - @testset "Multiple segments" begin - push!(pts, - (2.4988557436664, 2.4749992804628), - (1.258244761794, 3.494679539536), - (1.2242554198249, 1.4553190213896), - (3.3825786348632, 1.2683776405595), - (3.3825786348632, 3.4097061846133), - (2.0, 4.0)) - boundary_nodes = [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 1]], - [reverse([21, 22, 23, 24, 25, 21])]] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @inferred DT.pole_of_inaccessibility(pts, boundary_nodes) - @test (x ≈ 8.125 || x ≈ 5.625) && y ≈ 1.875 - end + @testset "Multiple segments" begin + push!( + pts, + (2.4988557436664, 2.4749992804628), + (1.258244761794, 3.494679539536), + (1.2242554198249, 1.4553190213896), + (3.3825786348632, 1.2683776405595), + (3.3825786348632, 3.4097061846133), + (2.0, 4.0), + ) + boundary_nodes = [ + [ + [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, + ], + ], + [reverse([21, 22, 23, 24, 25, 21])], + ] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @inferred DT.pole_of_inaccessibility(pts, boundary_nodes) + @test (x ≈ 8.125 || x ≈ 5.625) && y ≈ 1.875 + end - @testset "Multiply connected" begin - push!(pts, - (7.4103156582024, 2.4749992804628), - (7.0, 1.0), - (8.8548626918894, 0.8775002079148), - (9.2797294665033, 2.2370738866791)) - boundary_nodes = [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 1]], - [reverse([21, 22, 23, 24, 25, 21])], - [reverse([26, 27, 28, 29, 26])]] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @test x ≈ 2.5 && y ≈ 7.5 - end + @testset "Multiply connected" begin + push!( + pts, + (7.4103156582024, 2.4749992804628), + (7.0, 1.0), + (8.8548626918894, 0.8775002079148), + (9.2797294665033, 2.2370738866791), + ) + boundary_nodes = [ + [ + [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, + ], + ], + [reverse([21, 22, 23, 24, 25, 21])], + [reverse([26, 27, 28, 29, 26])], + ] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @test x ≈ 2.5 && y ≈ 7.5 + end - @testset "More complicated examples" begin - pts = [0.0 8.0 - 2.0 5.0 - 3.0 7.0 - 1.8190689042843 8.1342247183191 - 3.2296265960022 8.864995570655 - 4.2493068550754 7.7433472856744 - 4.5042269198437 5.8739334773735 - 3.6714880416006 4.3784024307328 - 2.7367811374502 2.6279513193238 - 5.5069125079324 1.3873403374514 - 8.4299959172756 2.7469140162157 - 9.7045962411171 5.5340400576824 - 8.565953285152 7.7943312986281 - 6.7135341478357 9.0349422805005 - 4.1303441581835 9.663745106929 - 2.7537758084347 10.3775212882802 - 1.0882980519485 10.4964839851721 - -1.1380038470281 9.8336918167745 - -2.2596521320086 8.4571234670257 - -2.7864869325298 5.9419121613117 - -1.3929239117964 3.647631578397 - 0.3235378576436 4.9732159151922 - -0.9000784532443 6.6216990006939 - 0.9863300260411 9.6807397779135 - 0.153591147798 9.5447824100371 - 0.2725538446899 8.6610595188403 - 2.9067278472957 8.1852087312728 - 2.1249729820062 9.4258197131452]' - A = Dict('a':'z' .=> 1:26) - boundary_nodes = [[[A['a'], A['d'], A['c'], A['b']], - [A['b'], A['i'], A['j'], A['k'], A['h'], A['g'], A['l']], - [A['l'], A['f'], A['m'], A['e'], A['n'], A['o'], A['p'], A['q'], A['p']], - [A['p'], A['q'], A['r'], A['s'], A['t'], A['u'], A['v'], A['w'], A['a']]], - [[28 - 2, 27 - 2, 26 - 2], - [26 - 2, 30 - 2, 29 - 2, 28 - 2]]] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @testset "More complicated examples" begin + pts = [ + 0.0 8.0 + 2.0 5.0 + 3.0 7.0 + 1.8190689042843 8.1342247183191 + 3.2296265960022 8.864995570655 + 4.2493068550754 7.7433472856744 + 4.5042269198437 5.8739334773735 + 3.6714880416006 4.3784024307328 + 2.7367811374502 2.6279513193238 + 5.5069125079324 1.3873403374514 + 8.4299959172756 2.7469140162157 + 9.7045962411171 5.5340400576824 + 8.565953285152 7.7943312986281 + 6.7135341478357 9.0349422805005 + 4.1303441581835 9.663745106929 + 2.7537758084347 10.3775212882802 + 1.0882980519485 10.4964839851721 + -1.1380038470281 9.8336918167745 + -2.2596521320086 8.4571234670257 + -2.7864869325298 5.9419121613117 + -1.3929239117964 3.647631578397 + 0.3235378576436 4.9732159151922 + -0.9000784532443 6.6216990006939 + 0.9863300260411 9.6807397779135 + 0.153591147798 9.5447824100371 + 0.2725538446899 8.6610595188403 + 2.9067278472957 8.1852087312728 + 2.1249729820062 9.4258197131452 + ]' + A = Dict('a':'z' .=> 1:26) + boundary_nodes = [ + [ + [A['a'], A['d'], A['c'], A['b']], + [A['b'], A['i'], A['j'], A['k'], A['h'], A['g'], A['l']], + [A['l'], A['f'], A['m'], A['e'], A['n'], A['o'], A['p'], A['q'], A['p']], + [A['p'], A['q'], A['r'], A['s'], A['t'], A['u'], A['v'], A['w'], A['a']], + ], + [ + [28 - 2, 27 - 2, 26 - 2], + [26 - 2, 30 - 2, 29 - 2, 28 - 2], + ], + ] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @test x ≈ 4.6146922812432685 && y ≈ 3.0953047713990314 - len = size(pts, 2) - pts = hcat(pts, [7.274358290326 3.0 5.3369657980869; 2.7978980291693 4.0 1.8801857960034]) - boundary_nodes = [[[A['a'], A['d'], A['c'], A['b']], - [A['b'], A['i'], A['j'], A['k'], A['h'], A['g'], A['l']], - [A['l'], A['f'], A['m'], A['e'], A['n'], A['o'], A['p'], A['q'], A['p']], - [A['p'], A['q'], A['r'], A['s'], A['t'], A['u'], A['v'], A['w'], A['a']]], - [[28 - 2, 27 - 2, 26 - 2], - [26 - 2, 30 - 2, 29 - 2, 28 - 2]], - [[len + 1, len + 2, len + 3, len + 1]]] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @test x ≈ -1.0785224985822 && y ≈ 5.3725906833292 - end + @test x ≈ 4.6146922812432685 && y ≈ 3.0953047713990314 + len = size(pts, 2) + pts = hcat(pts, [7.274358290326 3.0 5.3369657980869; 2.7978980291693 4.0 1.8801857960034]) + boundary_nodes = [ + [ + [A['a'], A['d'], A['c'], A['b']], + [A['b'], A['i'], A['j'], A['k'], A['h'], A['g'], A['l']], + [A['l'], A['f'], A['m'], A['e'], A['n'], A['o'], A['p'], A['q'], A['p']], + [A['p'], A['q'], A['r'], A['s'], A['t'], A['u'], A['v'], A['w'], A['a']], + ], + [ + [28 - 2, 27 - 2, 26 - 2], + [26 - 2, 30 - 2, 29 - 2, 28 - 2], + ], + [[len + 1, len + 2, len + 3, len + 1]], + ] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @test x ≈ -1.0785224985822 && y ≈ 5.3725906833292 + end end @testset "Making a figure" begin - pts = [0.0 8.0 - 2.0 5.0 - 3.0 7.0 - 1.81907 8.13422 - 3.22963 8.865 - 4.24931 7.74335 - 4.50423 5.87393 - 3.67149 4.3784 - 2.73678 2.62795 - 5.50691 1.38734 - 8.43 2.74691 - 9.7046 5.53404 - 8.56595 7.79433 - 6.71353 9.03494 - 4.13034 9.66375 - 2.75378 10.3775 - 1.0883 10.4965 - -1.138 9.83369 - -2.25965 8.45712 - -2.78649 5.94191 - -1.39292 3.64763 - 0.323538 4.97322 - -0.900078 6.6217 - 0.98633 9.68074 - 0.153591 9.54478 - 0.272554 8.66106 - 2.90673 8.18521 - 2.12497 9.42582 - 7.27436 2.7979 - 3.0 4.0 - 5.33697 1.88019]' - boundary_nodes = [ - [[1, 4, 3, 2], [2, 9, 10, 11, 8, 7, 12], [12, 6, 13, 5, 14, 15, 16, 17, 16], [16, 17, 18, 19, 20, 21, 22, 23, 1]], - [[26, 25, 24], [24, 28, 27, 26]], - [[29,31,30,29]] - ] - x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) - @test x ≈ -1.0785225000000000003 - @test y ≈ 5.37259749999999999999 + pts = [ + 0.0 8.0 + 2.0 5.0 + 3.0 7.0 + 1.81907 8.13422 + 3.22963 8.865 + 4.24931 7.74335 + 4.50423 5.87393 + 3.67149 4.3784 + 2.73678 2.62795 + 5.50691 1.38734 + 8.43 2.74691 + 9.7046 5.53404 + 8.56595 7.79433 + 6.71353 9.03494 + 4.13034 9.66375 + 2.75378 10.3775 + 1.0883 10.4965 + -1.138 9.83369 + -2.25965 8.45712 + -2.78649 5.94191 + -1.39292 3.64763 + 0.323538 4.97322 + -0.900078 6.6217 + 0.98633 9.68074 + 0.153591 9.54478 + 0.272554 8.66106 + 2.90673 8.18521 + 2.12497 9.42582 + 7.27436 2.7979 + 3.0 4.0 + 5.33697 1.88019 + ]' + boundary_nodes = [ + [[1, 4, 3, 2], [2, 9, 10, 11, 8, 7, 12], [12, 6, 13, 5, 14, 15, 16, 17, 16], [16, 17, 18, 19, 20, 21, 22, 23, 1]], + [[26, 25, 24], [24, 28, 27, 26]], + [[29, 31, 30, 29]], + ] + x, y = DT.pole_of_inaccessibility(pts, boundary_nodes) + @test x ≈ -1.0785225000000000003 + @test y ≈ 5.37259749999999999999 - tri = triangulate(pts; boundary_nodes) - @test collect(DT.getxy(DT.get_representative_point_coordinates(tri, 1))) ≈ [x, y] + tri = triangulate(pts; boundary_nodes) + @test collect(DT.getxy(DT.get_representative_point_coordinates(tri, 1))) ≈ [x, y] end @testset "A previously broken example" begin - PT = [-3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, - 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, - 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, - 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, - 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, - 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, - -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, - -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, - -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, - -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, - 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, - 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, - 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, - 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, - 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, - -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, - -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, - -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, - -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, - 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, - 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, - 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, - 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, - 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, - -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, - -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, - -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, - -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, - -4.927587132008278, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, - -3.304869996725775, -3.304869996725775, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, - -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, - -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, - 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, - 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, - 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, - 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, - 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, - 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, - 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, - 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, - 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, - 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, - 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, - 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, - 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, - 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, - 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, - 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, - 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, - 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, - 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929, - 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929] - PT = [PT[1:216]'; PT[217:end]'] - BN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 27, 36, 45, 54, 63, 72, - 81, 90, 99, 108, 117, 126, 135, 144, 153, 162, 171, 180, 189, - 198, 207, 216, 215, 214, 213, 212, 211, 210, 209, 208, 199, - 190, 181, 172, 163, 154, 145, 136, 127, 118, 109, 100, 91, 82, - 73, 64, 55, 46, 37, 28, 19, 10, 1] - pc = DT.pole_of_inaccessibility(PT, BN) - @test collect(pc) ≈ collect(DT.polygon_features(PT, BN)[2]) + PT = [ + -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, + 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, + 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, + 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, + 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, + 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, + -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, + -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, + -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, + -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, + 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, + 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, + 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, + 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, + 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, + -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, + -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, + -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, + -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, + 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, + 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, + 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, + 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, -0.569282706070557, + 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, -1.4572528434350467, + -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, -2.3452229807995364, + -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, -3.233193118164026, + -2.3452229807995364, -1.4572528434350467, -0.569282706070557, 0.31868743129393273, 1.2066575686584224, 2.094627706022912, 2.982597843387402, 3.8705679807518916, + -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, -4.927587132008278, + -4.927587132008278, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, -3.304869996725775, + -3.304869996725775, -3.304869996725775, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, + -1.6821528614432721, -1.6821528614432721, -1.6821528614432721, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, + -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, -0.05943572616076942, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, + 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 1.5632814091217337, 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, + 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, 3.185998544404236, 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, + 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, 4.808715679686739, 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, + 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, 6.431432814969242, 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, + 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, 8.054149950251745, 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, + 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, 9.676867085534248, 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, + 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, 11.299584220816751, 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, + 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, 12.922301356099254, 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, + 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, 14.545018491381757, 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, + 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, 16.16773562666426, 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, + 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, 17.790452761946764, 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, + 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, 19.413169897229267, 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, + 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, 21.03588703251177, 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, + 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, 22.658604167794273, 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, + 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, 24.281321303076776, 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, + 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, 25.90403843835928, 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, + 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, 27.52675557364178, 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, + 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, 29.149472708924286, 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, + 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, 30.772189844206785, 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929, + 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929, 32.39490697948929, + ] + PT = [PT[1:216]'; PT[217:end]'] + BN = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 27, 36, 45, 54, 63, 72, + 81, 90, 99, 108, 117, 126, 135, 144, 153, 162, 171, 180, 189, + 198, 207, 216, 215, 214, 213, 212, 211, 210, 209, 208, 199, + 190, 181, 172, 163, 154, 145, 136, 127, 118, 109, 100, 91, 82, + 73, 64, 55, 46, 37, 28, 19, 10, 1, + ] + pc = DT.pole_of_inaccessibility(PT, BN) + @test collect(pc) ≈ collect(DT.polygon_features(PT, BN)[2]) end @testset "Bounding box for a multiple polygon" begin - C = (15.7109521325776, 33.244486807457) - D = (14.2705719699703, 32.8530791545746) - E = (14.3, 27.2) - F = (14.1, 27.0) - G = (13.7, 27.2) - H = (13.4, 27.5) - I = (13.1, 27.6) - J = (12.7, 27.4) - K = (12.5, 27.1) - L = (12.7, 26.7) - M = (13.1, 26.5) - N = (13.6, 26.4) - O = (14.0, 26.4) - P = (14.6, 26.5) - Q = (15.1983491346581, 26.8128534095401) - R = (15.6, 27.6) - S = (15.6952958264624, 28.2344688505621) - T = (17.8088971520274, 33.1192363585346) - U = (16.3058917649589, 33.0722674401887) - V = (16.3215480710742, 29.7374742376305) - W = (16.3841732955354, 29.393035503094) - Z = (16.6190178872649, 28.9233463196351) - A1 = (17.0417381523779, 28.5319386667527) - B1 = (17.5114273358368, 28.3753756055997) - C1 = (18.1376795804487, 28.3597192994844) - D1 = (18.7169629067146, 28.5632512789833) - E1 = (19.2805899268653, 28.8920337074045) - F1 = (19.26493362075, 28.4536571361762) - G1 = (20.6426885588962, 28.4223445239456) - H1 = (20.689657477242, 33.1035800524193) - I1 = (19.2805899268653, 33.0722674401887) - J1 = (19.2962462329806, 29.7531305437458) - K1 = (19.0614016412512, 29.393035503094) - L1 = (18.7482755189452, 29.236472441941) - M1 = (18.4508057027546, 29.1425346052493) - N1 = (18.1689921926793, 29.3147539725175) - O1 = (17.7932408459121, 29.6278800948235) - P1 = (22.6466957416542, 35.4207133574833) - Q1 = (21.2219718851621, 34.9979930923702) - R1 = (21.2376281912774, 28.4693134422915) - S1 = (22.6780083538847, 28.4380008300609) - T1 = (24.5724213938357, 33.1975178891111) - U1 = (23.3512295168425, 32.8530791545746) - V1 = (23.3199169046119, 28.4380008300609) - W1 = (24.6663592305274, 28.3753756055997) - Z1 = (15.1942940307729, 35.4363696635986) - A2 = (14.7246048473139, 35.3737444391374) - B2 = (14.3645098066621, 35.1858687657538) - C2 = (14.1766341332786, 34.8570863373326) - D2 = (14.1140089088174, 34.3247719294125) - E2 = (14.2705719699703, 33.8394264398383) - F2 = (14.7246048473139, 33.6202381542241) - G2 = (15.4604512347329, 33.6045818481088) - H2 = (16.0, 34.0) - I2 = (15.9771093365377, 34.6848669700643) - J2 = (15.6170142958859, 35.2328376840997) - K2 = (24.1653574348379, 35.4520259697138) - L2 = (23.7739497819555, 35.4363696635986) - M2 = (23.4608236596496, 35.2641502963303) - N2 = (23.272947986266, 34.9040552556785) - O2 = (23.1320412312284, 34.5909291333725) - P2 = (23.1163849251131, 34.2151777866054) - Q2 = (23.2886042923813, 33.8081138276077) - R2 = (23.8209187003014, 33.6045818481088) - S2 = (24.3062641898756, 33.5576129297629) - T2 = (24.7602970672192, 33.8550827459536) - U2 = (25.010797965064, 34.4656786844502) - V2 = (24.8385785977957, 34.9666804801397) - W2 = (24.5254524754898, 35.2641502963303) - Z2 = (25.3708930057158, 37.4716894585871) - A3 = (24.7916096794498, 37.3464390096648) - B3 = (24.4471709449133, 36.9550313567823) - C3 = (24.3062641898756, 36.5636237038999) - D3 = (24.4941398632592, 35.9999966837492) - E3 = (25.0264542711793, 35.5929327247515) - F3 = (25.5587686790994, 35.5929327247515) - F3 = (25.5587686790994, 35.5929327247515) - G3 = (26.0, 36.0) - H3 = (26.1380520053653, 36.5792800100152) - I3 = (26.0, 37.0) - J3 = (25.7466443524829, 37.2838137852036) - K3 = (26.3885529032101, 35.4676822758291) - L3 = (25.9814889442124, 35.3580881330221) - M3 = (25.6840191280217, 35.1858687657538) - N3 = (25.5274560668688, 34.9040552556785) - O3 = (25.4961434546382, 34.5596165211419) - P3 = (25.5274560668688, 34.246490398836) - Q3 = (25.6683628219064, 33.8394264398383) - R3 = (26.0284578625583, 33.6358944603394) - S3 = (26.5451159643631, 33.6202381542241) - T3 = (27.0, 34.0) - U3 = (27.280962351782, 34.5596165211419) - V3 = (27.0304614539373, 35.2171813779844) - W3 = (26.1693646175959, 33.087923746304) - Z3 = (26.0, 33.0) - A4 = (25.5274560668688, 32.7278287056522) - B4 = (25.2612988629087, 32.4147025833463) - C4 = (25.1830173323322, 32.0702638488098) - D4 = (25.2299862506781, 31.7727940326191) - E4 = (25.6527065157911, 31.5222931347744) - F4 = (26.2946150665183, 31.7258251142732) - G4 = (26.5607722704784, 32.5086404200381) - H4 = (27.1557119028596, 32.7434850117675) - I4 = (27.6097447802033, 32.4929841139228) - J4 = (27.6410573924338, 32.1015764610403) - K4 = (27.7193389230103, 31.6005746653509) - L4 = (27.437525412935, 31.4283552980826) - M4 = (26.9834925355914, 31.2561359308143) - N4 = (26.5764285765937, 31.0995728696614) - O4 = (26.0441141686736, 30.7864467473554) - P4 = (25.6527065157911, 30.5672584617413) - Q4 = (25.3239240873699, 30.1915071149741) - R4 = (25.1673610262169, 29.8783809926682) - S4 = (25.1047358017558, 29.6122237887082) - T4 = (25.0890794956405, 29.1895035235952) - U4 = (25.2926114751393, 28.8294084829433) - V4 = (25.6840191280217, 28.5632512789833) - W4 = (26.1537083114806, 28.3753756055997) - Z4 = (26.8269294744384, 28.391031911715) - A5 = (27.4844943312809, 28.6102201973292) - B5 = (27.7342002330051, 28.7239579596219) - C5 = (27.7264126450755, 28.4202565942047) - D5 = (29.1825559185446, 28.3922538389457) - E5 = (29.1545531632856, 32.2146299318021) - F5 = (29.000538009361, 32.5786657501693) - G5 = (28.6785063238822, 32.9006974356481) - H5 = (28.3144705055149, 33.0827153448317) - I5 = (27.9084305542591, 33.2367304987563) - J5 = (27.3343740714492, 33.3207387645334) - K5 = (26.8303244767868, 33.2367304987563) - L5 = (27.6564057569279, 30.786489413592) - M5 = (27.6984098898165, 30.3944508399657) - N5 = (27.6984098898165, 29.7363860913787) - O5 = (27.5863988687804, 29.4143544059) - P5 = (27.2643671833016, 29.2043337414573) - Q5 = (26.9843396307114, 29.1763309861983) - R5 = (26.6903107004917, 29.3163447624934) - S5 = (26.5782996794556, 29.7503874690082) - T5 = (26.7603175886393, 30.3384453294476) - U5 = (27.3203726938197, 30.7024811478149) - J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] - U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] - L_curve = [[P1, Q1, R1, S1, P1]] - I_curve = [[T1, U1, V1, W1, T1]] - A_curve_outline = [[ + C = (15.7109521325776, 33.244486807457) + D = (14.2705719699703, 32.8530791545746) + E = (14.3, 27.2) + F = (14.1, 27.0) + G = (13.7, 27.2) + H = (13.4, 27.5) + I = (13.1, 27.6) + J = (12.7, 27.4) + K = (12.5, 27.1) + L = (12.7, 26.7) + M = (13.1, 26.5) + N = (13.6, 26.4) + O = (14.0, 26.4) + P = (14.6, 26.5) + Q = (15.1983491346581, 26.8128534095401) + R = (15.6, 27.6) + S = (15.6952958264624, 28.2344688505621) + T = (17.8088971520274, 33.1192363585346) + U = (16.3058917649589, 33.0722674401887) + V = (16.3215480710742, 29.7374742376305) + W = (16.3841732955354, 29.393035503094) + Z = (16.6190178872649, 28.9233463196351) + A1 = (17.0417381523779, 28.5319386667527) + B1 = (17.5114273358368, 28.3753756055997) + C1 = (18.1376795804487, 28.3597192994844) + D1 = (18.7169629067146, 28.5632512789833) + E1 = (19.2805899268653, 28.8920337074045) + F1 = (19.26493362075, 28.4536571361762) + G1 = (20.6426885588962, 28.4223445239456) + H1 = (20.689657477242, 33.1035800524193) + I1 = (19.2805899268653, 33.0722674401887) + J1 = (19.2962462329806, 29.7531305437458) + K1 = (19.0614016412512, 29.393035503094) + L1 = (18.7482755189452, 29.236472441941) + M1 = (18.4508057027546, 29.1425346052493) + N1 = (18.1689921926793, 29.3147539725175) + O1 = (17.7932408459121, 29.6278800948235) + P1 = (22.6466957416542, 35.4207133574833) + Q1 = (21.2219718851621, 34.9979930923702) + R1 = (21.2376281912774, 28.4693134422915) + S1 = (22.6780083538847, 28.4380008300609) + T1 = (24.5724213938357, 33.1975178891111) + U1 = (23.3512295168425, 32.8530791545746) + V1 = (23.3199169046119, 28.4380008300609) + W1 = (24.6663592305274, 28.3753756055997) + Z1 = (15.1942940307729, 35.4363696635986) + A2 = (14.7246048473139, 35.3737444391374) + B2 = (14.3645098066621, 35.1858687657538) + C2 = (14.1766341332786, 34.8570863373326) + D2 = (14.1140089088174, 34.3247719294125) + E2 = (14.2705719699703, 33.8394264398383) + F2 = (14.7246048473139, 33.6202381542241) + G2 = (15.4604512347329, 33.6045818481088) + H2 = (16.0, 34.0) + I2 = (15.9771093365377, 34.6848669700643) + J2 = (15.6170142958859, 35.2328376840997) + K2 = (24.1653574348379, 35.4520259697138) + L2 = (23.7739497819555, 35.4363696635986) + M2 = (23.4608236596496, 35.2641502963303) + N2 = (23.272947986266, 34.9040552556785) + O2 = (23.1320412312284, 34.5909291333725) + P2 = (23.1163849251131, 34.2151777866054) + Q2 = (23.2886042923813, 33.8081138276077) + R2 = (23.8209187003014, 33.6045818481088) + S2 = (24.3062641898756, 33.5576129297629) + T2 = (24.7602970672192, 33.8550827459536) + U2 = (25.010797965064, 34.4656786844502) + V2 = (24.8385785977957, 34.9666804801397) + W2 = (24.5254524754898, 35.2641502963303) + Z2 = (25.3708930057158, 37.4716894585871) + A3 = (24.7916096794498, 37.3464390096648) + B3 = (24.4471709449133, 36.9550313567823) + C3 = (24.3062641898756, 36.5636237038999) + D3 = (24.4941398632592, 35.9999966837492) + E3 = (25.0264542711793, 35.5929327247515) + F3 = (25.5587686790994, 35.5929327247515) + F3 = (25.5587686790994, 35.5929327247515) + G3 = (26.0, 36.0) + H3 = (26.1380520053653, 36.5792800100152) + I3 = (26.0, 37.0) + J3 = (25.7466443524829, 37.2838137852036) + K3 = (26.3885529032101, 35.4676822758291) + L3 = (25.9814889442124, 35.3580881330221) + M3 = (25.6840191280217, 35.1858687657538) + N3 = (25.5274560668688, 34.9040552556785) + O3 = (25.4961434546382, 34.5596165211419) + P3 = (25.5274560668688, 34.246490398836) + Q3 = (25.6683628219064, 33.8394264398383) + R3 = (26.0284578625583, 33.6358944603394) + S3 = (26.5451159643631, 33.6202381542241) + T3 = (27.0, 34.0) + U3 = (27.280962351782, 34.5596165211419) + V3 = (27.0304614539373, 35.2171813779844) + W3 = (26.1693646175959, 33.087923746304) + Z3 = (26.0, 33.0) + A4 = (25.5274560668688, 32.7278287056522) + B4 = (25.2612988629087, 32.4147025833463) + C4 = (25.1830173323322, 32.0702638488098) + D4 = (25.2299862506781, 31.7727940326191) + E4 = (25.6527065157911, 31.5222931347744) + F4 = (26.2946150665183, 31.7258251142732) + G4 = (26.5607722704784, 32.5086404200381) + H4 = (27.1557119028596, 32.7434850117675) + I4 = (27.6097447802033, 32.4929841139228) + J4 = (27.6410573924338, 32.1015764610403) + K4 = (27.7193389230103, 31.6005746653509) + L4 = (27.437525412935, 31.4283552980826) + M4 = (26.9834925355914, 31.2561359308143) + N4 = (26.5764285765937, 31.0995728696614) + O4 = (26.0441141686736, 30.7864467473554) + P4 = (25.6527065157911, 30.5672584617413) + Q4 = (25.3239240873699, 30.1915071149741) + R4 = (25.1673610262169, 29.8783809926682) + S4 = (25.1047358017558, 29.6122237887082) + T4 = (25.0890794956405, 29.1895035235952) + U4 = (25.2926114751393, 28.8294084829433) + V4 = (25.6840191280217, 28.5632512789833) + W4 = (26.1537083114806, 28.3753756055997) + Z4 = (26.8269294744384, 28.391031911715) + A5 = (27.4844943312809, 28.6102201973292) + B5 = (27.7342002330051, 28.7239579596219) + C5 = (27.7264126450755, 28.4202565942047) + D5 = (29.1825559185446, 28.3922538389457) + E5 = (29.1545531632856, 32.2146299318021) + F5 = (29.000538009361, 32.5786657501693) + G5 = (28.6785063238822, 32.9006974356481) + H5 = (28.3144705055149, 33.0827153448317) + I5 = (27.9084305542591, 33.2367304987563) + J5 = (27.3343740714492, 33.3207387645334) + K5 = (26.8303244767868, 33.2367304987563) + L5 = (27.6564057569279, 30.786489413592) + M5 = (27.6984098898165, 30.3944508399657) + N5 = (27.6984098898165, 29.7363860913787) + O5 = (27.5863988687804, 29.4143544059) + P5 = (27.2643671833016, 29.2043337414573) + Q5 = (26.9843396307114, 29.1763309861983) + R5 = (26.6903107004917, 29.3163447624934) + S5 = (26.5782996794556, 29.7503874690082) + T5 = (26.7603175886393, 30.3384453294476) + U5 = (27.3203726938197, 30.7024811478149) + J_curve = [[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, C]] + U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] + L_curve = [[P1, Q1, R1, S1, P1]] + I_curve = [[T1, U1, V1, W1, T1]] + A_curve_outline = [ + [ K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] - A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] - dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] - dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] - dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] - dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] - curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] - nodes, points = convert_boundary_points_to_indices(curves) - xmin, xmax, ymin, ymax = DelaunayTriangulation.polygon_bounds(points, nodes, Val(true)) # Val(true) => check all parts of the polygon - @test xmin ≈ 12.5 && xmax ≈ 29.1825559185446 && ymin ≈ 26.4 && ymax ≈ 37.4716894585871 + H5, I5, J5, K5, + ], + ] + A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] + dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] + dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] + dot_3 = [[K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, K2]] + dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] + curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] + nodes, points = convert_boundary_points_to_indices(curves) + xmin, xmax, ymin, ymax = DelaunayTriangulation.polygon_bounds(points, nodes, Val(true)) # Val(true) => check all parts of the polygon + @test xmin ≈ 12.5 && xmax ≈ 29.1825559185446 && ymin ≈ 26.4 && ymax ≈ 37.4716894585871 end @testset "segment_intersection_coordinates" begin - a, b, c, d = (0.5, 4.0), (1.5, 3.5), (2.0, 4.0), (0.5, 3.0) - u, v = DT.segment_intersection_coordinates(a, b, c, d) - @test u ≈ 1.3571428571429 && v ≈ 3.57142857 - a, b, c, d = (0.5, 3.5), (1.5, 3.5), (1.0, 4.0), (1.0, 3.0) - u, v = DT.segment_intersection_coordinates(a, b, c, d) - @test u ≈ 1.0 && v ≈ 3.5 - a, b, c, d = (0.5, 4.0), (1.5, 4.0), (1.0, 4.0), (1.0, 3.0) - u, v = DT.segment_intersection_coordinates(a, b, c, d) - @test u ≈ 1.0 && v ≈ 4.0 + a, b, c, d = (0.5, 4.0), (1.5, 3.5), (2.0, 4.0), (0.5, 3.0) + u, v = DT.segment_intersection_coordinates(a, b, c, d) + @test u ≈ 1.3571428571429 && v ≈ 3.57142857 + a, b, c, d = (0.5, 3.5), (1.5, 3.5), (1.0, 4.0), (1.0, 3.0) + u, v = DT.segment_intersection_coordinates(a, b, c, d) + @test u ≈ 1.0 && v ≈ 3.5 + a, b, c, d = (0.5, 4.0), (1.5, 4.0), (1.0, 4.0), (1.0, 3.0) + u, v = DT.segment_intersection_coordinates(a, b, c, d) + @test u ≈ 1.0 && v ≈ 4.0 end @testset "intersection_of_edge_and_bisector_ray" begin - a = (-7.0, 3.0) - b = (-5.0, 7.0) - c = (-10.0, 7.0) - cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) - @test all(isnan, m) - c = (-4.86, 4.47) - cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) - @test m == (-6.0, 5.0) - c = (-4.0, 4.0) - cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) - @test m == (-6.0, 5.0) - p = (0.0, 3.0) - q = (3.0, 3.0) - r = (1.5, 2.9) - @test DT.intersection_of_edge_and_bisector_ray(p, q, r)[2] == (1.5, 3.0) - a = (-5.0, 3.0) - b = (-5.0, 7.0) - c = (-5.0, 5.0) - @test DT.intersection_of_edge_and_bisector_ray(a, b, c)[2] == (-5.0, 5.0) - @test DT.is_collinear(DT.intersection_of_edge_and_bisector_ray(a, b, c)[1]) - c = (-5.0, 4.5) - @test DT.intersection_of_edge_and_bisector_ray(a, b, c)[2] == (-5.0, 5.0) + a = (-7.0, 3.0) + b = (-5.0, 7.0) + c = (-10.0, 7.0) + cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) + @test all(isnan, m) + c = (-4.86, 4.47) + cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) + @test m == (-6.0, 5.0) + c = (-4.0, 4.0) + cert, m = DT.intersection_of_edge_and_bisector_ray(a, b, c) + @test m == (-6.0, 5.0) + p = (0.0, 3.0) + q = (3.0, 3.0) + r = (1.5, 2.9) + @test DT.intersection_of_edge_and_bisector_ray(p, q, r)[2] == (1.5, 3.0) + a = (-5.0, 3.0) + b = (-5.0, 7.0) + c = (-5.0, 5.0) + @test DT.intersection_of_edge_and_bisector_ray(a, b, c)[2] == (-5.0, 5.0) + @test DT.is_collinear(DT.intersection_of_edge_and_bisector_ray(a, b, c)[1]) + c = (-5.0, 4.5) + @test DT.intersection_of_edge_and_bisector_ray(a, b, c)[2] == (-5.0, 5.0) end @testset "classify_and_compute_segment_intersection" begin - a = (-2.0, 3.0) - b = (-2.0, 5.0) - c = (-4.97, 4.82) - d = (-4.0, 4.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.is_none(cert) - @test DT.is_left(cert_c) - @test DT.is_left(cert_d) - @test all(isnan, p) - d = (2.0, -1.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.is_none(cert) - @test DT.is_left(cert_c) - @test DT.is_right(cert_d) - c = (-5.0, 4.0) - d = (1.0, 4.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.has_one_intersection(cert) - @test DT.is_left(cert_c) - @test DT.is_right(cert_d) - @test p == (-2.0, 4.0) - a = (0.0, 5.0) - b = (0.0, 7.0) - c = (-5.0, 4.0) - d = (0.0, 6.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.is_touching(cert) - @test DT.is_left(cert_c) - @test DT.is_collinear(cert_d) - @test p == (0.0, 6.0) - c = (2.0, 6.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.is_touching(cert) - @test DT.is_right(cert_c) - @test DT.is_collinear(cert_d) - @test p == (0.0, 6.0) - d = (1.0, 5.0) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) - @test DT.is_none(cert) - @test DT.is_right(cert_c) - @test DT.is_right(cert_d) - @test all(isnan, p) + a = (-2.0, 3.0) + b = (-2.0, 5.0) + c = (-4.97, 4.82) + d = (-4.0, 4.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.is_none(cert) + @test DT.is_left(cert_c) + @test DT.is_left(cert_d) + @test all(isnan, p) + d = (2.0, -1.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.is_none(cert) + @test DT.is_left(cert_c) + @test DT.is_right(cert_d) + c = (-5.0, 4.0) + d = (1.0, 4.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.has_one_intersection(cert) + @test DT.is_left(cert_c) + @test DT.is_right(cert_d) + @test p == (-2.0, 4.0) + a = (0.0, 5.0) + b = (0.0, 7.0) + c = (-5.0, 4.0) + d = (0.0, 6.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.is_touching(cert) + @test DT.is_left(cert_c) + @test DT.is_collinear(cert_d) + @test p == (0.0, 6.0) + c = (2.0, 6.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.is_touching(cert) + @test DT.is_right(cert_c) + @test DT.is_collinear(cert_d) + @test p == (0.0, 6.0) + d = (1.0, 5.0) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, d) + @test DT.is_none(cert) + @test DT.is_right(cert_c) + @test DT.is_right(cert_d) + @test all(isnan, p) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection((NaN, NaN), b, c, d) - @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, (Inf, Inf), c, d) - @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, (NaN, NaN), d) - @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) - cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, (Inf, Inf)) - @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection((NaN, NaN), b, c, d) + @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, (Inf, Inf), c, d) + @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, (NaN, NaN), d) + @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) + cert, cert_c, cert_d, p = DT.classify_and_compute_segment_intersection(a, b, c, (Inf, Inf)) + @test DT.is_none(cert) && DT.is_none(cert_c) && DT.is_none(cert_d) && all(isnan, p) end @testset "sort_convex_polygon!" begin - for _ in 1:50 - tri = triangulate(rand(2, 500)) - ch = get_convex_hull(tri) - pts = get_points(ch) - verts = DT.get_vertices(ch) - orig_verts = deepcopy(verts) - pop!(verts) - shuffle!(verts) - DT.sort_convex_polygon!(verts, pts) - push!(verts, verts[begin]) - @test DT.circular_equality(verts, orig_verts) - A = DT.polygon_features(pts, verts)[1] - @test A ≥ 0.0 - end + for _ in 1:50 + tri = triangulate(rand(2, 500)) + ch = get_convex_hull(tri) + pts = get_points(ch) + verts = DT.get_vertices(ch) + orig_verts = deepcopy(verts) + pop!(verts) + shuffle!(verts) + DT.sort_convex_polygon!(verts, pts) + push!(verts, verts[begin]) + @test DT.circular_equality(verts, orig_verts) + A = DT.polygon_features(pts, verts)[1] + @test A ≥ 0.0 + end end @testset "Degenerate pole_of_inaccessibility" begin - points = [(0.0, 0.0), (0.0, 1.0), (0.0, 2.0), (0.0, 3.0)] - boundary_nodes = [1, 2, 3, 4, 1] - @test DT.pole_of_inaccessibility(points, boundary_nodes) == (0.0, 1.5) - points = [(2.0, 0.0), (3.5, 0.0), (5.0, 0.0)] - boundary_nodes = [1, 2, 3, 1] - @test DT.pole_of_inaccessibility(points, boundary_nodes) == (3.5, 0.0) + points = [(0.0, 0.0), (0.0, 1.0), (0.0, 2.0), (0.0, 3.0)] + boundary_nodes = [1, 2, 3, 4, 1] + @test DT.pole_of_inaccessibility(points, boundary_nodes) == (0.0, 1.5) + points = [(2.0, 0.0), (3.5, 0.0), (5.0, 0.0)] + boundary_nodes = [1, 2, 3, 1] + @test DT.pole_of_inaccessibility(points, boundary_nodes) == (3.5, 0.0) end @testset "identify_side and intersection_of_ray_with_bounding_box" begin - a, b, c, d = 0.5, 1.3, 2.7, 5.8 - p = (0.7378963231985, 4.6758264584035) - q = (2.17804800057, 3.5917562397227) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (1.3, 4.252704459932) - @test collect(r) ≈ collect(rtrue) - p = (1.0, 4.5) - q = (2.0, 4.5) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (1.3, 4.5) - @test collect(r) ≈ collect(rtrue) + a, b, c, d = 0.5, 1.3, 2.7, 5.8 + p = (0.7378963231985, 4.6758264584035) + q = (2.17804800057, 3.5917562397227) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (1.3, 4.252704459932) + @test collect(r) ≈ collect(rtrue) + p = (1.0, 4.5) + q = (2.0, 4.5) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (1.3, 4.5) + @test collect(r) ≈ collect(rtrue) - a, b, c, d = 0.0, 1.0, 0.0, 1.0 - p = (0.5, 0.5) - q = (2.5, 0.5) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (1.0, 0.5) - @test collect(r) ≈ collect(rtrue) - q = (0.5, 1.5) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.5, 1.0) - @test collect(r) ≈ collect(rtrue) - q = (0.202587350495, 1.5151867707735) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.353517464218, 1.0) - @test collect(r) ≈ collect(rtrue) rtol = 1e-6 - q = (-0.5, 1.5) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.0, 1.0) - @test collect(r) ≈ collect(rtrue) - q = (-1.0, 0.5) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.0, 0.5) - @test collect(r) ≈ collect(rtrue) - q = (-1.5, 0.0) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.0, 0.375) - @test collect(r) ≈ collect(rtrue) - q = (-1.0, -1.0) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.0, 0.0) - @test collect(r) ≈ collect(rtrue) atol = 1e-6 - q = (0.0, -1.0) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (1 / 3, 0.0) - @test collect(r) ≈ collect(rtrue) - q = (0.5, -1.0) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.5, 0.0) - @test collect(r) ≈ collect(rtrue) - q = (2.0, -1.0) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (1.0, 0.0) - @test collect(r) ≈ collect(rtrue) - q = (0.4026485332004, 0.7749544176151) - r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) - rtrue = (0.3229679893052, 1.0) - @test collect(r) ≈ collect(rtrue) - u, v = (a, d), (b, d) - newr = DT.segment_intersection_coordinates(p, r, u, v) - @test collect(newr) ≈ collect(r) - cert = DT.line_segment_intersection_type(p, r, u, v) - @test DT.is_touching(cert) + a, b, c, d = 0.0, 1.0, 0.0, 1.0 + p = (0.5, 0.5) + q = (2.5, 0.5) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (1.0, 0.5) + @test collect(r) ≈ collect(rtrue) + q = (0.5, 1.5) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.5, 1.0) + @test collect(r) ≈ collect(rtrue) + q = (0.202587350495, 1.5151867707735) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.353517464218, 1.0) + @test collect(r) ≈ collect(rtrue) rtol = 1.0e-6 + q = (-0.5, 1.5) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.0, 1.0) + @test collect(r) ≈ collect(rtrue) + q = (-1.0, 0.5) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.0, 0.5) + @test collect(r) ≈ collect(rtrue) + q = (-1.5, 0.0) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.0, 0.375) + @test collect(r) ≈ collect(rtrue) + q = (-1.0, -1.0) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.0, 0.0) + @test collect(r) ≈ collect(rtrue) atol = 1.0e-6 + q = (0.0, -1.0) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (1 / 3, 0.0) + @test collect(r) ≈ collect(rtrue) + q = (0.5, -1.0) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.5, 0.0) + @test collect(r) ≈ collect(rtrue) + q = (2.0, -1.0) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (1.0, 0.0) + @test collect(r) ≈ collect(rtrue) + q = (0.4026485332004, 0.7749544176151) + r = DT.intersection_of_ray_with_bounding_box(p, q, a, b, c, d) + rtrue = (0.3229679893052, 1.0) + @test collect(r) ≈ collect(rtrue) + u, v = (a, d), (b, d) + newr = DT.segment_intersection_coordinates(p, r, u, v) + @test collect(newr) ≈ collect(r) + cert = DT.line_segment_intersection_type(p, r, u, v) + @test DT.is_touching(cert) end @testset "Polygon" begin - verts = [1, 11, 18, 26, 32, 72] - _verts = [verts; 1] - points = [rand(2) for _ in 1:maximum(verts)] - for verts in (verts, _verts) - poly = DT.Polygon(verts, points) - @test length(poly) == 6 - @test size(poly) == (6,) - @test poly[1] == Tuple(points[1]) - @test poly[2] == Tuple(points[11]) - @test poly[3] == Tuple(points[18]) - @test poly[4] == Tuple(points[26]) - @test poly[5] == Tuple(points[32]) - @test poly[6] == Tuple(points[72]) - @test eachindex(poly) == 1:6 - @test collect(poly) == Tuple.(getindex.(Ref(points), [1, 11, 18, 26, 32, 72])) - @test poly[begin:end] == [poly[i] for i in 1:6] - @inferred poly[1] - @inferred poly[5] - end + verts = [1, 11, 18, 26, 32, 72] + _verts = [verts; 1] + points = [rand(2) for _ in 1:maximum(verts)] + for verts in (verts, _verts) + poly = DT.Polygon(verts, points) + @test length(poly) == 6 + @test size(poly) == (6,) + @test poly[1] == Tuple(points[1]) + @test poly[2] == Tuple(points[11]) + @test poly[3] == Tuple(points[18]) + @test poly[4] == Tuple(points[26]) + @test poly[5] == Tuple(points[32]) + @test poly[6] == Tuple(points[72]) + @test eachindex(poly) == 1:6 + @test collect(poly) == Tuple.(getindex.(Ref(points), [1, 11, 18, 26, 32, 72])) + @test poly[begin:end] == [poly[i] for i in 1:6] + @inferred poly[1] + @inferred poly[5] + end end @testset "Sutherland-Hodgman algorithm" begin - # rectangular - verts = [1, 2, 3, 4, 5, 6, 7, 8, 9] - points = [(50.0, 150.0), (200.0, 50.0), (350.0, 150.0), (350.0, 300.0), - (250.0, 300.0), (200.0, 250.0), (150.0, 350.0), (100.0, 250.0), (100.0, 200.0)] - clip_verts = [1, 2, 3, 4] - clip_points = [(100.0, 100.0), (300.0, 100.0), (300.0, 300.0), (100.0, 300.0)] - spoly = DT.Polygon(verts, points) - cpoly = DT.Polygon(clip_verts, clip_points) - result = DT.clip_polygon(spoly, cpoly) - @inferred DT.clip_polygon(spoly, cpoly) - @test collect.(result) ≈ [ - [100.0, 116 + 2 / 3], - [125, 100], - [275, 100], - [300, 116 + 2 / 3], - [300, 300], - [250, 300], - [200, 250], - [175, 300], - [125, 300], - [100, 250], - [100.0, 116 + 2 / 3] - ] - @test DT.clip_polygon(verts, points, clip_verts, clip_points) == result - @test DT.polygon_features(result, eachindex(result))[1] > 0 + # rectangular + verts = [1, 2, 3, 4, 5, 6, 7, 8, 9] + points = [ + (50.0, 150.0), (200.0, 50.0), (350.0, 150.0), (350.0, 300.0), + (250.0, 300.0), (200.0, 250.0), (150.0, 350.0), (100.0, 250.0), (100.0, 200.0), + ] + clip_verts = [1, 2, 3, 4] + clip_points = [(100.0, 100.0), (300.0, 100.0), (300.0, 300.0), (100.0, 300.0)] + spoly = DT.Polygon(verts, points) + cpoly = DT.Polygon(clip_verts, clip_points) + result = DT.clip_polygon(spoly, cpoly) + @inferred DT.clip_polygon(spoly, cpoly) + @test collect.(result) ≈ [ + [100.0, 116 + 2 / 3], + [125, 100], + [275, 100], + [300, 116 + 2 / 3], + [300, 300], + [250, 300], + [200, 250], + [175, 300], + [125, 300], + [100, 250], + [100.0, 116 + 2 / 3], + ] + @test DT.clip_polygon(verts, points, clip_verts, clip_points) == result + @test DT.polygon_features(result, eachindex(result))[1] > 0 - # bigger example - function to_rand_point_verts(___points) - _points = [Tuple(rand(2)) for _ in 1:500] - _points = [_points; ___points] - shuffle!(_points) - vertices = identity.(indexin(___points, _points)) # identity to convert eltype from Union{Nothing, Int} - return _points, vertices - end - a = (-4.0, 4.0) - b = (-1.0, 6.0) - c = (3.0, 6.0) - d = (4.0, 4.0) - e = (4.0, -1.0) - f = (2.0, -3.0) - g = (-2.94, -1.32) - points = [g, f, e, d, c, b, a] # ccw - npoints, nvertices = to_rand_point_verts(deepcopy(points)) - h = (-2.0, 7.0) - i = (-5.0, 6.0) - j = (-5.0, 2.0) - k = (-4.0, -2.0) - ℓ = (-1.0, -3.0) - m = (2.0, 2.0) - n = (1.0, 5.0) - clip_points = [h, i, j, k, ℓ, m, n] - nclip_points, nclip_vertices = to_rand_point_verts(deepcopy(clip_points)) - result = DT.clip_polygon(nvertices, npoints, nclip_vertices, nclip_points) - @test DT.circular_equality(collect.(result), collect.([ - g, - (-0.4915938130464, -2.1526563550773), - m, - n, - (-0.5, 6.0), - b, - a, - g - ]), ≈) + # bigger example + function to_rand_point_verts(___points) + _points = [Tuple(rand(2)) for _ in 1:500] + _points = [_points; ___points] + shuffle!(_points) + vertices = identity.(indexin(___points, _points)) # identity to convert eltype from Union{Nothing, Int} + return _points, vertices + end + a = (-4.0, 4.0) + b = (-1.0, 6.0) + c = (3.0, 6.0) + d = (4.0, 4.0) + e = (4.0, -1.0) + f = (2.0, -3.0) + g = (-2.94, -1.32) + points = [g, f, e, d, c, b, a] # ccw + npoints, nvertices = to_rand_point_verts(deepcopy(points)) + h = (-2.0, 7.0) + i = (-5.0, 6.0) + j = (-5.0, 2.0) + k = (-4.0, -2.0) + ℓ = (-1.0, -3.0) + m = (2.0, 2.0) + n = (1.0, 5.0) + clip_points = [h, i, j, k, ℓ, m, n] + nclip_points, nclip_vertices = to_rand_point_verts(deepcopy(clip_points)) + result = DT.clip_polygon(nvertices, npoints, nclip_vertices, nclip_points) + @test DT.circular_equality( + collect.(result), collect.( + [ + g, + (-0.4915938130464, -2.1526563550773), + m, + n, + (-0.5, 6.0), + b, + a, + g, + ], + ), ≈, + ) end @testset "Liang-Barsky algorithm" begin - p, q = (-7.0, 5.0), (1.0, 8.0) - a, b, c, d = 0.0, 8.0, 0.0, 4.0 - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test all(isnan, u) && all(isnan, v) - p, q = (-3.0, 1.0), (10.0, 5.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [0, 1.9230769230769] - @test collect(v) ≈ [6.75, 4.0] - p, q = (0.0, -2.0), (0.0, 6.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [0, 0] - @test collect(v) ≈ [0, 4] - p, q = (2.0, 6.0), (-2.0, 2.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test u == v && (collect(u) ≈ [0, 4]) - p, q = (10.0, 6.0), (-2.0, 6.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test all(isnan, u) && all(isnan, v) - p, q = (4.0, 6.0), (4.0, -2.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [4.0, 4.0] - @test collect(v) ≈ [4.0, 0.0] - p, q = (2.0, 6.0), (10.0, -2.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [4.0, 4.0] - @test collect(v) ≈ [8.0, 0.0] - a, b, c, d = 4, 10, 2, 8 - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [4.0, 4.0] - @test collect(v) ≈ [6.0, 2.0] - p, q = (2.0, 6.0), (14.0, 8.0) - u, v = DT.liang_barsky(a, b, c, d, p, q) - @test collect(u) ≈ [4, 6 + 1 / 3] - @test collect(v) ≈ [10, 7 + 1 / 3] + p, q = (-7.0, 5.0), (1.0, 8.0) + a, b, c, d = 0.0, 8.0, 0.0, 4.0 + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test all(isnan, u) && all(isnan, v) + p, q = (-3.0, 1.0), (10.0, 5.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [0, 1.9230769230769] + @test collect(v) ≈ [6.75, 4.0] + p, q = (0.0, -2.0), (0.0, 6.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [0, 0] + @test collect(v) ≈ [0, 4] + p, q = (2.0, 6.0), (-2.0, 2.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test u == v && (collect(u) ≈ [0, 4]) + p, q = (10.0, 6.0), (-2.0, 6.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test all(isnan, u) && all(isnan, v) + p, q = (4.0, 6.0), (4.0, -2.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [4.0, 4.0] + @test collect(v) ≈ [4.0, 0.0] + p, q = (2.0, 6.0), (10.0, -2.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [4.0, 4.0] + @test collect(v) ≈ [8.0, 0.0] + a, b, c, d = 4, 10, 2, 8 + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [4.0, 4.0] + @test collect(v) ≈ [6.0, 2.0] + p, q = (2.0, 6.0), (14.0, 8.0) + u, v = DT.liang_barsky(a, b, c, d, p, q) + @test collect(u) ≈ [4, 6 + 1 / 3] + @test collect(v) ≈ [10, 7 + 1 / 3] end @testset "get_plane_through_three_points" begin - @static if VERSION ≥ v"1.10" - _plane_mat(p, q, r) = + @static if VERSION ≥ v"1.10" + _plane_mat(p, q, r) = let c = (p .+ q .+ r) ./ 3 - [c... 1; p... 1; q... 1; r... 1] - end - else - _plane_mat(p, q, r) = - let c = (p .+ q .+ r) ./ 3 - vcat([c... 1], [p... 1], [q... 1], [r... 1]) - end - end - _plane_norm(p, q, r) = begin - x = q .- p - y = r .- p - nv = cross(x |> collect, y |> collect) - return nv ./ norm(nv) - end - for _ in 1:10000 - p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - @inferred DT.get_plane_through_three_points(p, q, r) - @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1e-14 - n = _plane_norm(p, q, r) - @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) + [c... 1; p... 1; q... 1; r... 1] + end + else + _plane_mat(p, q, r) = + let c = (p .+ q .+ r) ./ 3 + vcat([c... 1], [p... 1], [q... 1], [r... 1]) + end + end + _plane_norm(p, q, r) = begin + x = q .- p + y = r .- p + nv = cross(x |> collect, y |> collect) + return nv ./ norm(nv) + end + for _ in 1:10000 + p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + @inferred DT.get_plane_through_three_points(p, q, r) + @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1.0e-14 + n = _plane_norm(p, q, r) + @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) - p, q, r = (rand(2)..., 0.0), (rand(2)..., 0.0), (rand(2)..., 0.0) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1e-14 - n = [0, 0, 1] - @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) - p, q, r = (rand(), 2.0, rand()), (rand(), 2.0, rand()), (rand(), 2.0, rand()) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1e-14 - n = [0, 1, 0] - @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) - p, q, r = (2.0, rand(), rand()), (2.0, rand(), rand()), (2.0, rand(), rand()) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1e-14 - n = [1, 0, 0] - @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) - end - p, q, r = (1.3, 0.5, 5.5), (2.5, 2.22, 3.86), (5.3, 1.39, 2.85) - a, b, c, d = DT.get_plane_through_three_points(p, q, r) - @test a ≈ -3.0984 - @test b ≈ -3.38 - @test c ≈ -5.812 - @test d ≈ 37.68392 + p, q, r = (rand(2)..., 0.0), (rand(2)..., 0.0), (rand(2)..., 0.0) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1.0e-14 + n = [0, 0, 1] + @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) + p, q, r = (rand(), 2.0, rand()), (rand(), 2.0, rand()), (rand(), 2.0, rand()) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1.0e-14 + n = [0, 1, 0] + @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) + p, q, r = (2.0, rand(), rand()), (2.0, rand(), rand()), (2.0, rand(), rand()) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + @test det(_plane_mat(p, q, r)) ≈ 0.0 atol = 1.0e-14 + n = [1, 0, 0] + @test n ≈ [α, β, γ] / norm([α, β, γ]) || n ≈ -[α, β, γ] / norm([α, β, γ]) + end + p, q, r = (1.3, 0.5, 5.5), (2.5, 2.22, 3.86), (5.3, 1.39, 2.85) + a, b, c, d = DT.get_plane_through_three_points(p, q, r) + @test a ≈ -3.0984 + @test b ≈ -3.38 + @test c ≈ -5.812 + @test d ≈ 37.68392 end @testset "get_steepest_descent_direction" begin - for _ in 1:10000 - p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - x, y = DT.get_steepest_descent_direction(p, q, r) - @inferred DT.get_steepest_descent_direction(p, q, r) - @test x ≈ sign(γ) * α && sign(γ) * y ≈ β - p1 = DT.get_steepest_descent_direction(p, q, r) |> collect - p2 = DT.get_steepest_descent_direction(q, r, p) |> collect - p3 = DT.get_steepest_descent_direction(r, p, q) |> collect - p4 = DT.get_steepest_descent_direction(r, q, p) |> collect - @test p1 ≈ p2 ≈ p3 ≈ p4 - end - p, q, r = (1.3, 0.5, 5.5), (2.5, 2.22, 3.86), (5.3, 1.39, 2.9) - x, y = DT.get_steepest_descent_direction(p, q, r) - @test x ≈ 3.0124 && y ≈ 3.44 + for _ in 1:10000 + p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + x, y = DT.get_steepest_descent_direction(p, q, r) + @inferred DT.get_steepest_descent_direction(p, q, r) + @test x ≈ sign(γ) * α && sign(γ) * y ≈ β + p1 = DT.get_steepest_descent_direction(p, q, r) |> collect + p2 = DT.get_steepest_descent_direction(q, r, p) |> collect + p3 = DT.get_steepest_descent_direction(r, p, q) |> collect + p4 = DT.get_steepest_descent_direction(r, q, p) |> collect + @test p1 ≈ p2 ≈ p3 ≈ p4 + end + p, q, r = (1.3, 0.5, 5.5), (2.5, 2.22, 3.86), (5.3, 1.39, 2.9) + x, y = DT.get_steepest_descent_direction(p, q, r) + @test x ≈ 3.0124 && y ≈ 3.44 end @testset "get_distance_to_plane" begin - for _ in 1:10000 - p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) - s = Tuple(rand(3)) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - d = DT.get_vertical_distance_to_plane(p, q, r, s) - @inferred DT.get_vertical_distance_to_plane(p, q, r, s) - @test d ≈ s[3] + (α * s[1] + β * s[2] + δ) / γ + for _ in 1:10000 + p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) + s = Tuple(rand(3)) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + d = DT.get_vertical_distance_to_plane(p, q, r, s) + @inferred DT.get_vertical_distance_to_plane(p, q, r, s) + @test d ≈ s[3] + (α * s[1] + β * s[2] + δ) / γ - p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) - s = Tuple(rand(3)) - α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) - n = [α, β, γ] / norm([α, β, γ]) - x, y, z = s - z₀ = -(α * x + β * y + δ) / γ - Q = [x, y, z₀] - P = [x, y, z] - v = Q - P - δ = dot(v, n) - d = DT.get_distance_to_plane(p, q, r, s) - @inferred DT.get_distance_to_plane(p, q, r, s) - @test abs(d) ≈ abs(δ) - @test sign(d) == sign(DT.get_vertical_distance_to_plane(p, q, r, s)) - end + p, q, r = Tuple(rand(3)), Tuple(rand(3)), Tuple(rand(3)) + s = Tuple(rand(3)) + α, β, γ, δ = DT.get_plane_through_three_points(p, q, r) + n = [α, β, γ] / norm([α, β, γ]) + x, y, z = s + z₀ = -(α * x + β * y + δ) / γ + Q = [x, y, z₀] + P = [x, y, z] + v = Q - P + δ = dot(v, n) + d = DT.get_distance_to_plane(p, q, r, s) + @inferred DT.get_distance_to_plane(p, q, r, s) + @test abs(d) ≈ abs(δ) + @test sign(d) == sign(DT.get_vertical_distance_to_plane(p, q, r, s)) + end - for _ in 1:1000 - p, q, r = (rand(), rand(), 2.0), (rand(), rand(), 2.0), (rand(), rand(), 2.0) - s = (rand(), rand(), 10 * randn()) - d = DT.get_distance_to_plane(p, q, r, s) - @test d ≈ s[3] - 2 ≈ DT.get_vertical_distance_to_plane(p, q, r, s) - if s[3] > 2.0 - @test d > 0.0 - else - @test d ≤ 0.0 - end - end + for _ in 1:1000 + p, q, r = (rand(), rand(), 2.0), (rand(), rand(), 2.0), (rand(), rand(), 2.0) + s = (rand(), rand(), 10 * randn()) + d = DT.get_distance_to_plane(p, q, r, s) + @test d ≈ s[3] - 2 ≈ DT.get_vertical_distance_to_plane(p, q, r, s) + if s[3] > 2.0 + @test d > 0.0 + else + @test d ≤ 0.0 + end + end end @testset "angle_between" begin - p = (2.0, 9.0) - q = (2.0, -5.0) - θ = DT.angle_between(p, q) - @test rad2deg(θ) ≈ 145.6697828044967 rtol = 1e-4 - θ = DT.angle_between(q, p) - @test rad2deg(θ) ≈ 214.3302171955033 rtol = 1e-4 - p = (7.0, 1.0) - q = (2.0, -5.0) - θ = DT.angle_between(p, q) - @test rad2deg(θ) ≈ 76.3286928678042 - θ = DT.angle_between(q, p) - @test rad2deg(θ) ≈ 283.6713071321958 - p = (0.0, 9.0) - q = (0.0, -4.0) - θ = DT.angle_between(p, q) - @test rad2deg(θ) ≈ 180.0 - θ = DT.angle_between(q, p) - @test rad2deg(θ) ≈ 180.0 - p = (0.0, -5.0) - q = (0.0, -4.0) - θ = DT.angle_between(p, q) - @test rad2deg(θ) ≈ 0.0 - θ = DT.angle_between(q, p) - @test rad2deg(θ) ≈ 0.0 - p = (-0.27, -4.96) - q = (0.0, -4.0) - θ = DT.angle_between(p, q) - @test rad2deg(θ) ≈ 356.8841517402107 rtol = 1e-4 - θ = DT.angle_between(q, p) - @test rad2deg(θ) ≈ 3.1158482597894 rtol = 1e-4 -end \ No newline at end of file + p = (2.0, 9.0) + q = (2.0, -5.0) + θ = DT.angle_between(p, q) + @test rad2deg(θ) ≈ 145.6697828044967 rtol = 1.0e-4 + θ = DT.angle_between(q, p) + @test rad2deg(θ) ≈ 214.3302171955033 rtol = 1.0e-4 + p = (7.0, 1.0) + q = (2.0, -5.0) + θ = DT.angle_between(p, q) + @test rad2deg(θ) ≈ 76.3286928678042 + θ = DT.angle_between(q, p) + @test rad2deg(θ) ≈ 283.6713071321958 + p = (0.0, 9.0) + q = (0.0, -4.0) + θ = DT.angle_between(p, q) + @test rad2deg(θ) ≈ 180.0 + θ = DT.angle_between(q, p) + @test rad2deg(θ) ≈ 180.0 + p = (0.0, -5.0) + q = (0.0, -4.0) + θ = DT.angle_between(p, q) + @test rad2deg(θ) ≈ 0.0 + θ = DT.angle_between(q, p) + @test rad2deg(θ) ≈ 0.0 + p = (-0.27, -4.96) + q = (0.0, -4.0) + θ = DT.angle_between(p, q) + @test rad2deg(θ) ≈ 356.8841517402107 rtol = 1.0e-4 + θ = DT.angle_between(q, p) + @test rad2deg(θ) ≈ 3.1158482597894 rtol = 1.0e-4 +end diff --git a/test/helper_function_tests.jl b/test/helper_function_tests.jl index c0ef9134c..518e0e38c 100644 --- a/test/helper_function_tests.jl +++ b/test/helper_function_tests.jl @@ -13,33 +13,33 @@ const DT = DelaunayTriangulation g = [2.0, -2.0] h = [6.0, 4.0] pts = [a, b, c, d, e, f, g, h] - tri = triangulate(pts; delete_ghosts=false) - @test validate_triangulation(tri; print_result=false) + tri = triangulate(pts; delete_ghosts = false) + @test validate_triangulation(tri; print_result = false) DT.delete_triangle!(tri, 6, 2, 3) - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) DT.add_triangle!(tri, 6, 3, 2) @test !test_state(test_triangle_orientation(tri)) - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) tri.points[7] = [2, -0.5] - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) tri.points[7] = [2.0, -2.0] tri.adjacent.adjacent[(6, 3)] = DT.∅ @test !test_state(test_each_edge_has_two_incident_triangles(tri)) - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) tri.adjacent.adjacent[(6, 3)] = 2 tri.adjacent.adjacent[(6, 17)] = 10 @test !test_state(test_adjacent2vertex_map_matches_adjacent_map(tri)) @test !test_state(test_adjacent_map_matches_adjacent2vertex_map(tri)) - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) DT.delete_vertex!(tri, 3) - @test !validate_triangulation(tri; print_result=false) - tri = triangulate(pts; delete_ghosts=false) + @test !validate_triangulation(tri; print_result = false) + tri = triangulate(pts; delete_ghosts = false) push!(tri.triangles, (11, 17, 20)) @test any(!test_state, test_iterators(tri)) - tri = triangulate(pts; delete_ghosts=true) + tri = triangulate(pts; delete_ghosts = true) push!(tri.triangles, (11, 17, -20)) @test any(!test_state, test_iterators(tri)) - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) push!(tri.triangles, (11, 17, 20000)) @test any(!test_state, test_iterators(tri)) end @@ -52,29 +52,29 @@ end boundary_nodes, points = convert_boundary_points_to_indices(x, y) tri_1 = triangulate(points; boundary_nodes) A = get_area(tri_1) - refine!(tri_1; max_area=1e-3A, use_circumcenter=true) + refine!(tri_1; max_area = 1.0e-3A, use_circumcenter = true) @test validate_triangulation(tri_1) boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) - tri_2 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_2 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_2) - refine!(tri_2; max_area=1e-3A, use_circumcenter=true) + refine!(tri_2; max_area = 1.0e-3A, use_circumcenter = true) @test validate_triangulation(tri_2) x = [0.0, 2.0, 2.0, 0.0, 0.0] y = [0.0, 0.0, 2.0, 2.0, 0.0] boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_3 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_3 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_3) - refine!(tri_3; max_area=1e-3A, use_circumcenter=true) + refine!(tri_3; max_area = 1.0e-3A, use_circumcenter = true) @test validate_triangulation(tri_3) x = reverse(reverse.(_x[2])) y = reverse(reverse.(_y[2])) boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_4 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_4 = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(tri_4) - refine!(tri_4; max_area=1e-3A, use_circumcenter=true) + refine!(tri_4; max_area = 1.0e-3A, use_circumcenter = true) @test validate_triangulation(tri_4) end @@ -92,9 +92,7 @@ end @testset "test_visibility" begin points = [(0.0, 0.0), (6.0, 0.0), (6.0, 6.0), (0.0, 6.0), (1.0, 1.0), (3.5, 5.5), (4.5, 4.0)] boundary_nodes = [1, 2, 3, 4, 1] - tri = triangulate(points; boundary_nodes, segments=Set([(2, 4)])) + tri = triangulate(points; boundary_nodes, segments = Set([(2, 4)])) @test DT.is_visible(DT.test_visibility(tri, 4, 2, 3)) @test DT.is_invisible(DT.test_visibility(tri, 5, 1, 7)) end - - diff --git a/test/helper_functions.jl b/test/helper_functions.jl index ff15f5081..17021c70c 100644 --- a/test/helper_functions.jl +++ b/test/helper_functions.jl @@ -17,14 +17,18 @@ const DT = DelaunayTriangulation using DelaunayTriangulation: validate_triangulation function complicated_geometry() - x1 = [collect(LinRange(0, 2, 4)), + x1 = [ + collect(LinRange(0, 2, 4)), collect(LinRange(2, 2, 4)), collect(LinRange(2, 0, 4)), - collect(LinRange(0, 0, 4))] - y1 = [collect(LinRange(0, 0, 4)), + collect(LinRange(0, 0, 4)), + ] + y1 = [ + collect(LinRange(0, 0, 4)), collect(LinRange(0, 6, 4)), collect(LinRange(6, 6, 4)), - collect(LinRange(6, 0, 4))] + collect(LinRange(6, 0, 4)), + ] r = 0.5 h = k = 0.6 θ = LinRange(2π, 0, 50) @@ -35,14 +39,26 @@ function complicated_geometry() k = 0.5 x3 = [h .+ r .* cos.(θ)] y3 = [k .+ r .* sin.(θ)] - x4 = reverse(reverse.([collect(LinRange(1, 1.5, 4)), - collect(LinRange(1.5, 1.5, 4)), - collect(LinRange(1.5, 1, 4)), - collect(LinRange(1, 1, 4))])) - y4 = reverse(reverse.([collect(LinRange(2, 2, 4)), - collect(LinRange(2, 5, 4)), - collect(LinRange(5, 5, 4)), - collect(LinRange(5, 2, 4))])) + x4 = reverse( + reverse.( + [ + collect(LinRange(1, 1.5, 4)), + collect(LinRange(1.5, 1.5, 4)), + collect(LinRange(1.5, 1, 4)), + collect(LinRange(1, 1, 4)), + ], + ), + ) + y4 = reverse( + reverse.( + [ + collect(LinRange(2, 2, 4)), + collect(LinRange(2, 5, 4)), + collect(LinRange(5, 5, 4)), + collect(LinRange(5, 2, 4)), + ], + ), + ) x5 = [reverse([0.2, 0.5, 0.75, 0.75, 0.2, 0.2])] y5 = [reverse([2.0, 2.0, 3.0, 4.0, 5.0, 2.0])] x = [x1, x2, x3, x4, x5] @@ -77,9 +93,12 @@ function simple_geometry() z = (18.0, 16.0) a1 = (4.0, 18.0) b1 = (2.0, 12.0) - pts = [a, b, c, d, e, f, g, h, i, j, k, ℓ, - m, n, o, p, q, r, s, t, u, v, w, z, a1, b1] - T = [h a s + pts = [ + a, b, c, d, e, f, g, h, i, j, k, ℓ, + m, n, o, p, q, r, s, t, u, v, w, z, a1, b1, + ] + T = [ + h a s h s j b1 h j i b1 j @@ -114,20 +133,29 @@ function simple_geometry() p b c q p c d q c - r q d] + r q d + ] T = indexin(T, pts) - T = Set{NTuple{3,Int}}((Tuple(T) for T in eachrow(T))) + T = Set{NTuple{3, Int}}((Tuple(T) for T in eachrow(T))) outer = [[indexin([a, b, c, d, e, f, g, h, a], pts)...]] inner1 = [[indexin([ℓ, k, j, i, ℓ], pts)...]] inner2 = [[indexin([r, q, p], pts)...], [indexin([p, o, n, m, r], pts)...]] boundary_nodes = [outer, inner1, inner2] - label_map = Dict(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "ℓ", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "z", "a1", - "b1"] .=> pts) - index_map = Dict(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "ℓ", - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "z", "a1", - "b1"] .=> DT.each_point_index(pts)) - return DT.Triangulation(pts, T, boundary_nodes, delete_ghosts=true), label_map, index_map + label_map = Dict( + [ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "ℓ", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "z", "a1", + "b1", + ] .=> pts, + ) + index_map = Dict( + [ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "ℓ", + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "z", "a1", + "b1", + ] .=> DT.each_point_index(pts), + ) + return DT.Triangulation(pts, T, boundary_nodes, delete_ghosts = true), label_map, index_map end macro _adj(i, j, k) @@ -145,13 +173,15 @@ function example_triangulation() p7 = @SVector[2.0, 1.0] p8 = @SVector[5.0, 1.0] pts = [p1, p2, p3, p4, p5, p6, p7, p8] - T = Set{NTuple{3,Int}}([ - (6, 3, 1), - (3, 2, 5), - (4, 1, 5), - (4, 6, 1), - (5, 1, 3) - ]) + T = Set{NTuple{3, Int}}( + [ + (6, 3, 1), + (3, 2, 5), + (4, 1, 5), + (4, 6, 1), + (5, 1, 3), + ], + ) A = [ 0 0 1 1 1 1 1 0 0 0 1 1 1 1 @@ -172,24 +202,30 @@ function example_triangulation() (5, 1) => 3, (1, 3) => 5, (3, 5) => 1, (4, 5) => DT.𝒢, (5, 2) => DT.𝒢, (2, 3) => DT.𝒢, (3, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (6, 4) => DT.𝒢, + ), ) - adj2v = DT.Adjacent2Vertex(Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(5, 4), (3, 5), (6, 3), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3)]), - 3 => Set{NTuple{2,Int}}([(1, 6), (5, 1), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(1, 4), (3, 1)]) - )) - rep = Dict{Int,DT.RepresentativeCoordinates{Int,Float64}}() - tri = DT.Triangulation(pts, T, Int[], Set{NTuple{2,Int}}(), Set{NTuple{2,Int}}(), + adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(5, 4), (3, 5), (6, 3), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3)]), + 3 => Set{NTuple{2, Int}}([(1, 6), (5, 1), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(1, 4), (3, 1)]), + ), + ) + rep = Dict{Int, DT.RepresentativeCoordinates{Int, Float64}}() + tri = DT.Triangulation( + pts, T, Int[], Set{NTuple{2, Int}}(), Set{NTuple{2, Int}}(), DT.ZeroWeight(), adj, adj2v, DG, (), DT.construct_boundary_edge_map(Int[]), - Dict{Int,Vector{Int}}(), Dict{Int,UnitRange{Int}}(), DT.ConvexHull(pts, [2, 6, 4, 5, 2]), rep, DT.construct_polygon_hierarchy(pts), nothing, - DT._build_cache(pts, Int, NTuple{2,Int}, NTuple{3,Int}, - Set{NTuple{2,Int}}, Set{NTuple{3,Int}}, DT.ZeroWeight(), Val(true))) + Dict{Int, Vector{Int}}(), Dict{Int, UnitRange{Int}}(), DT.ConvexHull(pts, [2, 6, 4, 5, 2]), rep, DT.construct_polygon_hierarchy(pts), nothing, + DT._build_cache( + pts, Int, NTuple{2, Int}, NTuple{3, Int}, + Set{NTuple{2, Int}}, Set{NTuple{3, Int}}, DT.ZeroWeight(), Val(true), + ), + ) DT.compute_representative_points!(tri) return tri end @@ -199,18 +235,22 @@ function example_empty_triangulation() p2 = @SVector[3.0, -1.0] p3 = @SVector[2.0, 0.0] pts = [p1, p2, p3] - T = Set{NTuple{3,Int}}() + T = Set{NTuple{3, Int}}() A = zeros(Int, 0, 0) DG = SimpleGraphs.relabel(SimpleGraphs.UndirectedGraph(A), Dict(1:7 .=> [-1, (1:6)...])) DG = DT.Graph(DG.V, DG.E, DG.N) - adj = DT.Adjacent(Dict{NTuple{2,Int},Int}()) - adj2v = DT.Adjacent2Vertex(Dict(DT.𝒢 => Set{NTuple{2,Int}}())) - rep = Dict{Int,DT.RepresentativeCoordinates{Int,Float64}}() - tri = DT.Triangulation(pts, T, Int[], Set{NTuple{2,Int}}(), Set{NTuple{2,Int}}(), + adj = DT.Adjacent(Dict{NTuple{2, Int}, Int}()) + adj2v = DT.Adjacent2Vertex(Dict(DT.𝒢 => Set{NTuple{2, Int}}())) + rep = Dict{Int, DT.RepresentativeCoordinates{Int, Float64}}() + tri = DT.Triangulation( + pts, T, Int[], Set{NTuple{2, Int}}(), Set{NTuple{2, Int}}(), DT.ZeroWeight(), adj, adj2v, DG, (), DT.construct_boundary_edge_map(Int[]), - Dict{Int,Vector{Int}}(), Dict{Int,UnitRange{Int}}(), DT.ConvexHull(pts, [1, 2, 3, 1]), rep, DT.construct_polygon_hierarchy(pts), nothing, - DT._build_cache(pts, Int, NTuple{2,Int}, NTuple{3,Int}, - Set{NTuple{2,Int}}, Set{NTuple{3,Int}}, DT.ZeroWeight(), Val(true))) + Dict{Int, Vector{Int}}(), Dict{Int, UnitRange{Int}}(), DT.ConvexHull(pts, [1, 2, 3, 1]), rep, DT.construct_polygon_hierarchy(pts), nothing, + DT._build_cache( + pts, Int, NTuple{2, Int}, NTuple{3, Int}, + Set{NTuple{2, Int}}, Set{NTuple{3, Int}}, DT.ZeroWeight(), Val(true), + ), + ) DT.compute_representative_points!(tri) return tri end @@ -236,7 +276,7 @@ function example_with_special_corners() r = [3.0, 8.0] pts = [a, b, c, d, e, f, g, h, i, j, k, ℓ, m, n, o, p, q, r] rng = StableRNG(29292929292) - tri = triangulate(pts; rng, delete_ghosts=false, randomise=false) + tri = triangulate(pts; rng, delete_ghosts = false, randomise = false) return tri end @@ -254,7 +294,7 @@ function shewchuk_example_constrained() k = [8.0, 4.0] pts = [a, b, c, d, e, f, g, h, i, j, k] rng = StableRNG(213) - tri = triangulate(pts; rng, delete_ghosts=false, randomise=false) + tri = triangulate(pts; rng, delete_ghosts = false, randomise = false) return tri end @@ -272,7 +312,7 @@ function fixed_shewchuk_example_constrained() k = [8.0, 2.5] pts = [a, b, c, d, e, f, g, h, i, j, k] rng = StableRNG(213) - tri = triangulate(pts; rng, delete_ghosts=false, randomise=false) + tri = triangulate(pts; rng, delete_ghosts = false, randomise = false) return tri end @@ -341,12 +381,12 @@ function test_segment_triangle_intersections(tri, edge, true_triangles, true_col !isnothing(current_constrained_edges) && @test compare_edge_vectors(constrained_edges, current_constrained_edges) end -function get_random_vertices_and_constrained_edges(nverts1, nverts2, nedges, rng=Random.default_rng()) +function get_random_vertices_and_constrained_edges(nverts1, nverts2, nedges, rng = Random.default_rng()) ## To generate a random set of constrained edges, we get a random small triangulation, ## and we just take the edges from that triangulation. points = [Tuple(rand(rng, 2)) for _ in 1:nverts1] tri = triangulate(points; rng) - edges = Set{NTuple{2,Int}}() + edges = Set{NTuple{2, Int}}() all_edges = collect(each_solid_edge(tri)) iter = 0 while length(edges) < nedges && iter < 10000 @@ -355,7 +395,7 @@ function get_random_vertices_and_constrained_edges(nverts1, nverts2, nedges, rng iter += 1 end ## Now get the rest of the points - append!(points, [Tuple(rand(rng, 2)) for _ in 1:(nverts2-nverts1)]) + append!(points, [Tuple(rand(rng, 2)) for _ in 1:(nverts2 - nverts1)]) return points, edges, vec(hcat(getindex.(edges, 1), getindex.(edges, 2))') end @@ -404,11 +444,13 @@ function second_shewchuk_example_constrained() (21, 22), (23, 24), (25, 26), - (27, 28) + (27, 28), ] - pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, + pts = [ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, - p25, p26, p27, p28] + p25, p26, p27, p28, + ] return pts, Set(C) end @@ -431,11 +473,11 @@ function example_for_testing_add_point_on_constrained_triangulation() return P, Set([(1, 2)]) end -function validate_statistics(tri::DT.Triangulation, stats=statistics(tri)) +function validate_statistics(tri::DT.Triangulation, stats = statistics(tri)) ## Build up the array (see also test_iterators) I = DT.integer_type(tri) - T = NTuple{3,I} - E = NTuple{2,I} + T = NTuple{3, I} + E = NTuple{2, I} solid_triangles = T[] ghost_triangles = T[] all_triangles = T[] @@ -500,19 +542,19 @@ function validate_statistics(tri::DT.Triangulation, stats=statistics(tri)) sort!(ghost_vertices) ## Build up the individual statistics - areas = Dict{T,Float64}() - lengths = Dict{T,NTuple{3,Float64}}() - circumcenters = Dict{T,NTuple{2,Float64}}() - circumradii = Dict{T,Float64}() - angles = Dict{T,NTuple{3,Float64}}() - radius_edge_ratio = Dict{T,Float64}() - edge_midpoints = Dict{T,NTuple{3,NTuple{2,Float64}}}() - aspect_ratio = Dict{T,Float64}() - inradius = Dict{T,Float64}() - perimeter = Dict{T,Float64}() - centroid = Dict{T,NTuple{2,Float64}}() - offcenters = Dict{T,NTuple{2,Float64}}() - sinks = Dict{T,NTuple{2,Float64}}() + areas = Dict{T, Float64}() + lengths = Dict{T, NTuple{3, Float64}}() + circumcenters = Dict{T, NTuple{2, Float64}}() + circumradii = Dict{T, Float64}() + angles = Dict{T, NTuple{3, Float64}}() + radius_edge_ratio = Dict{T, Float64}() + edge_midpoints = Dict{T, NTuple{3, NTuple{2, Float64}}}() + aspect_ratio = Dict{T, Float64}() + inradius = Dict{T, Float64}() + perimeter = Dict{T, Float64}() + centroid = Dict{T, NTuple{2, Float64}}() + offcenters = Dict{T, NTuple{2, Float64}}() + sinks = Dict{T, NTuple{2, Float64}}() total_A = 0.0 for T in each_solid_triangle(tri) u, v, w = DT.triangle_vertices(T) @@ -537,8 +579,8 @@ function validate_statistics(tri::DT.Triangulation, stats=statistics(tri)) circumcenters[triangle_vertices(T)] = (ox, oy) circumradii[triangle_vertices(T)] = norm(r - collect(circumcenters[triangle_vertices(T)])) all_angles = [(norm(p - r)^2 + norm(q - r)^2 - norm(p - q)^2) / (2norm(p - r) * norm(q - r)) for (p, q, r) in ((p, q, r), (q, r, p), (r, p, q))] - all_angles[all_angles.<-1.0] .= -1.0 - all_angles[all_angles.>1.0] .= 1.0 + all_angles[all_angles .< -1.0] .= -1.0 + all_angles[all_angles .> 1.0] .= 1.0 all_angles = acos.(all_angles) sort!(all_angles) radius_edge_ratio[triangle_vertices(T)] = circumradii[triangle_vertices(T)] / ℓ1 @@ -558,35 +600,35 @@ function validate_statistics(tri::DT.Triangulation, stats=statistics(tri)) ## Now compare the statistics for T in each_solid_triangle(tri) - @test areas[triangle_vertices(T)] ≈ DT.get_area(stats, T) rtol = 1e-4 atol = 1e-4 - @test collect(lengths[triangle_vertices(T)]) ≈ collect(DT.get_lengths(stats, T)) rtol = 1e-4 atol = 1e-4 - @test collect(circumcenters[triangle_vertices(T)]) ≈ collect(DT.get_circumcenter(stats, T)) rtol = 1e-4 atol = 1e-4 - @test circumradii[triangle_vertices(T)] ≈ DT.get_circumradius(stats, T) rtol = 1e-4 atol = 1e-4 - @test radius_edge_ratio[triangle_vertices(T)] ≈ DT.get_radius_edge_ratio(stats, T) rtol = 1e-4 atol = 1e-4 - @test collect(collect.(edge_midpoints[triangle_vertices(T)])) ≈ collect(collect.(DT.get_edge_midpoints(stats, T))) rtol = 1e-4 atol = 1e-4 - @test aspect_ratio[triangle_vertices(T)] ≈ DT.get_aspect_ratio(stats, T) rtol = 1e-4 atol = 1e-4 - @test inradius[triangle_vertices(T)] ≈ DT.get_inradius(stats, T) rtol = 1e-4 atol = 1e-4 - @test perimeter[triangle_vertices(T)] ≈ DT.get_perimeter(stats, T) rtol = 1e-4 atol = 1e-4 - @test radius_edge_ratio[triangle_vertices(T)] ≈ 1 / (2sin(angles[triangle_vertices(T)][1])) rtol = 1e-4 atol = 1e-4 + @test areas[triangle_vertices(T)] ≈ DT.get_area(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test collect(lengths[triangle_vertices(T)]) ≈ collect(DT.get_lengths(stats, T)) rtol = 1.0e-4 atol = 1.0e-4 + @test collect(circumcenters[triangle_vertices(T)]) ≈ collect(DT.get_circumcenter(stats, T)) rtol = 1.0e-4 atol = 1.0e-4 + @test circumradii[triangle_vertices(T)] ≈ DT.get_circumradius(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test radius_edge_ratio[triangle_vertices(T)] ≈ DT.get_radius_edge_ratio(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test collect(collect.(edge_midpoints[triangle_vertices(T)])) ≈ collect(collect.(DT.get_edge_midpoints(stats, T))) rtol = 1.0e-4 atol = 1.0e-4 + @test aspect_ratio[triangle_vertices(T)] ≈ DT.get_aspect_ratio(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test inradius[triangle_vertices(T)] ≈ DT.get_inradius(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test perimeter[triangle_vertices(T)] ≈ DT.get_perimeter(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test radius_edge_ratio[triangle_vertices(T)] ≈ 1 / (2sin(angles[triangle_vertices(T)][1])) rtol = 1.0e-4 atol = 1.0e-4 @test (2sin(DT.get_minimum_angle(stats, T) / 2)^2 - 0.1 ≤ DT.get_aspect_ratio(stats, T) ≤ 2tan(DT.get_minimum_angle(stats, T) / 2) + 0.1) - @test DT.get_radius_edge_ratio(stats, T) ≈ 1 / (2(sin(DT.get_minimum_angle(stats, T)))) rtol = 1e-4 atol = 1e-4 - @test areas[triangle_vertices(T)] ≈ inradius[triangle_vertices(T)] * 0.5perimeter[triangle_vertices(T)] rtol = 1e-4 atol = 1e-4 - @test DT.get_area(stats, T) ≈ DT.get_inradius(stats, T) * 0.5DT.get_perimeter(stats, T) rtol = 1e-4 atol = 1e-4 - @test collect(centroid[triangle_vertices(T)]) ≈ collect(DT.get_centroid(stats, T)) rtol = 1e-4 atol = 1e-4 - @test DT.get_angles(stats, T)[1] ≈ angles[triangle_vertices(T)][1] rtol = 1e-4 atol = 1e-4 - @test DT.get_angles(stats, T)[2] ≈ angles[triangle_vertices(T)][2] rtol = 1e-4 atol = 1e-4 - @test DT.get_angles(stats, T)[3] ≈ angles[triangle_vertices(T)][3] rtol = 1e-4 atol = 1e-4 - @test sum(DT.get_angles(stats, T)) ≈ π rtol = 1e-4 atol = 1e-4 - @test DT.get_minimum_angle(stats, T) ≈ angles[triangle_vertices(T)][1] rtol = 1e-4 atol = 1e-4 - @test DT.get_maximum_angle(stats, T) ≈ angles[triangle_vertices(T)][3] rtol = 1e-4 atol = 1e-4 - @test DT.get_minimum_angle(stats, T) ≈ DT.get_angles(stats, T)[1] rtol = 1e-4 atol = 1e-4 - @test DT.get_maximum_angle(stats, T) ≈ DT.get_angles(stats, T)[3] rtol = 1e-4 atol = 1e-4 - @test collect(offcenters[triangle_vertices(T)]) ≈ collect(DT.get_offcenter(stats, T)) rtol = 1e-4 atol = 1e-2 - @test collect(sinks[triangle_vertices(T)]) ≈ collect(DT.get_sink(stats, T)) rtol = 1e-4 atol = 1e-4 + @test DT.get_radius_edge_ratio(stats, T) ≈ 1 / (2(sin(DT.get_minimum_angle(stats, T)))) rtol = 1.0e-4 atol = 1.0e-4 + @test areas[triangle_vertices(T)] ≈ inradius[triangle_vertices(T)] * 0.5perimeter[triangle_vertices(T)] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_area(stats, T) ≈ DT.get_inradius(stats, T) * 0.5DT.get_perimeter(stats, T) rtol = 1.0e-4 atol = 1.0e-4 + @test collect(centroid[triangle_vertices(T)]) ≈ collect(DT.get_centroid(stats, T)) rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_angles(stats, T)[1] ≈ angles[triangle_vertices(T)][1] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_angles(stats, T)[2] ≈ angles[triangle_vertices(T)][2] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_angles(stats, T)[3] ≈ angles[triangle_vertices(T)][3] rtol = 1.0e-4 atol = 1.0e-4 + @test sum(DT.get_angles(stats, T)) ≈ π rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_minimum_angle(stats, T) ≈ angles[triangle_vertices(T)][1] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_maximum_angle(stats, T) ≈ angles[triangle_vertices(T)][3] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_minimum_angle(stats, T) ≈ DT.get_angles(stats, T)[1] rtol = 1.0e-4 atol = 1.0e-4 + @test DT.get_maximum_angle(stats, T) ≈ DT.get_angles(stats, T)[3] rtol = 1.0e-4 atol = 1.0e-4 + @test collect(offcenters[triangle_vertices(T)]) ≈ collect(DT.get_offcenter(stats, T)) rtol = 1.0e-4 atol = 1.0e-2 + @test collect(sinks[triangle_vertices(T)]) ≈ collect(DT.get_sink(stats, T)) rtol = 1.0e-4 atol = 1.0e-4 end @test stats.individual_statistics == DT.get_individual_statistics(stats) - @test stats.area ≈ DT.get_area(stats) rtol = 1e-4 atol = 1e-4 - @test stats.area ≈ total_A rtol = 1e-4 atol = 1e-4 + @test stats.area ≈ DT.get_area(stats) rtol = 1.0e-4 atol = 1.0e-4 + @test stats.area ≈ total_A rtol = 1.0e-4 atol = 1.0e-4 ## Test the number statistics @test DT.num_vertices(stats) == length(all_vertices) == stats.num_vertices @@ -610,12 +652,12 @@ function validate_statistics(tri::DT.Triangulation, stats=statistics(tri)) largest_area = maximum([areas[triangle_vertices(T)] for T in each_solid_triangle(tri)]) smallest_radius_edge_ratio = minimum([radius_edge_ratio[triangle_vertices(T)] for T in each_solid_triangle(tri)]) largest_radius_edge_ratio = maximum([radius_edge_ratio[triangle_vertices(T)] for T in each_solid_triangle(tri)]) - @test DT.get_smallest_angle(stats) ≈ smallest_angle rtol = 1e-2 - @test DT.get_largest_angle(stats) ≈ largest_angle rtol = 1e-2 - @test DT.get_smallest_area(stats) ≈ smallest_area rtol = 1e-2 - @test DT.get_largest_area(stats) ≈ largest_area rtol = 1e-2 - @test DT.get_smallest_radius_edge_ratio(stats) ≈ smallest_radius_edge_ratio rtol = 1e-2 - @test DT.get_largest_radius_edge_ratio(stats) ≈ largest_radius_edge_ratio rtol = 1e-2 + @test DT.get_smallest_angle(stats) ≈ smallest_angle rtol = 1.0e-2 + @test DT.get_largest_angle(stats) ≈ largest_angle rtol = 1.0e-2 + @test DT.get_smallest_area(stats) ≈ smallest_area rtol = 1.0e-2 + @test DT.get_largest_area(stats) ≈ largest_area rtol = 1.0e-2 + @test DT.get_smallest_radius_edge_ratio(stats) ≈ smallest_radius_edge_ratio rtol = 1.0e-2 + @test DT.get_largest_radius_edge_ratio(stats) ≈ largest_radius_edge_ratio rtol = 1.0e-2 @test DT.get_smallest_radius_edge_ratio(stats) ≥ 1 / sqrt(3) - 0.1 @test DT.get_smallest_angle(stats) ≤ deg2rad(60) + 0.01 end @@ -623,7 +665,7 @@ end function slow_encroachment_test(tri::DT.Triangulation) E = DT.edge_type(tri) I = DT.integer_type(tri) - ch = Channel{Pair{E,Tuple{Bool,I}}}(Inf) # https://discourse.julialang.org/t/can-dicts-be-threadsafe/27172/17 + ch = Channel{Pair{E, Tuple{Bool, I}}}(Inf) # https://discourse.julialang.org/t/can-dicts-be-threadsafe/27172/17 @sync for i in collect(each_solid_vertex(tri)) Base.Threads.@spawn begin for j in each_solid_vertex(tri) @@ -650,8 +692,8 @@ function slow_encroachment_test(tri::DT.Triangulation) end end end - not_in_dt_encroached_edges = Dict{E,Tuple{Bool,I}}() - in_dt_encroached_edges = Dict{E,Tuple{Bool,I}}() + not_in_dt_encroached_edges = Dict{E, Tuple{Bool, I}}() + in_dt_encroached_edges = Dict{E, Tuple{Bool, I}}() while !isempty(ch) e, (b, k) = take!(ch) if DT.edge_exists(tri, e) || DT.edge_exists(tri, DT.reverse_edge(e)) @@ -666,7 +708,7 @@ end function slow_encroachment_test_diametral_lens(tri::DT.Triangulation, lens_angle) E = DT.edge_type(tri) I = DT.integer_type(tri) - ch = Channel{Pair{E,Tuple{Bool,I}}}(Inf) # https://discourse.julialang.org/t/can-dicts-be-threadsafe/27172/17 + ch = Channel{Pair{E, Tuple{Bool, I}}}(Inf) # https://discourse.julialang.org/t/can-dicts-be-threadsafe/27172/17 @sync for i in collect(each_solid_vertex(tri)) Base.Threads.@spawn begin for j in each_solid_vertex(tri) @@ -698,8 +740,8 @@ function slow_encroachment_test_diametral_lens(tri::DT.Triangulation, lens_angle end end end - not_in_dt_encroached_edges = Dict{E,Tuple{Bool,I}}() - in_dt_encroached_edges = Dict{E,Tuple{Bool,I}}() + not_in_dt_encroached_edges = Dict{E, Tuple{Bool, I}}() + in_dt_encroached_edges = Dict{E, Tuple{Bool, I}}() while !isempty(ch) e, (b, k) = take!(ch) if DT.edge_exists(tri, e) || DT.edge_exists(tri, DT.reverse_edge(e)) @@ -785,7 +827,7 @@ end ## TODO: Implement a brute-force DT.VoronoiTessellation that we can compare with -function validate_tessellation(vorn::DT.VoronoiTessellation; check_convex=true, check_adjacent=true) +function validate_tessellation(vorn::DT.VoronoiTessellation; check_convex = true, check_adjacent = true) tri = DT.get_triangulation(vorn) for (i, p) in DT.get_generators(vorn) flag = get_point(tri, i) == get_generator(vorn, i) == p @@ -887,7 +929,7 @@ function validate_tessellation(vorn::DT.VoronoiTessellation; check_convex=true, if i ∉ DT.get_unbounded_polygons(vorn) verts = get_polygon(vorn, i) poly_points = get_polygon_point.(Ref(vorn), verts) - flag = @views allunique(poly_points[begin:end-1]) + flag = @views allunique(poly_points[begin:(end - 1)]) if !flag println("Polygon $i has repeated vertices.") return false @@ -909,12 +951,12 @@ function validate_tessellation(vorn::DT.VoronoiTessellation; check_convex=true, for i in each_polygon_index(vorn) A += get_area(vorn, i) end - @test isapprox(A, get_area(vorn.triangulation), rtol=1e-4) + @test isapprox(A, get_area(vorn.triangulation), rtol = 1.0e-4) end return true end -function _make_graph_from_adjacency(A, labels=Dict(axes(A, 1) .=> axes(A, 1))) +function _make_graph_from_adjacency(A, labels = Dict(axes(A, 1) .=> axes(A, 1))) g = DT.Graph{Int}() foreach(axes(A, 1)) do i push!(g.vertices, labels[i]) @@ -967,7 +1009,7 @@ function _validate_offcenter(p, q, r, β) m = (p .+ q) ./ 2 # Check orientations - @test _orient(m, c, offcenter) ≈ 0.0 atol = 1e-6 + @test _orient(m, c, offcenter) ≈ 0.0 atol = 1.0e-6 @test _orient(p, q, offcenter) > 0 # Check the radius-edge ratios @@ -1052,7 +1094,7 @@ function compute_diametral_lens(p, q, lens_angle) end function get_points_in_diametral_circle(p, q) tri = triangulate(rand(2, 50)) - args = DT.RefinementArguments(tri; use_lens=false) + args = DT.RefinementArguments(tri; use_lens = false) θ = LinRange(0, 2π, 250) r = LinRange(0, norm(p .- q) / 2, 250) m = (p .+ q) ./ 2 @@ -1062,7 +1104,7 @@ function get_points_in_diametral_circle(p, q) end function get_points_in_diametral_lens(p, q, lens_angle) tri = triangulate(rand(2, 50)) - args = DT.RefinementArguments(tri; use_lens=true, min_angle=lens_angle) + args = DT.RefinementArguments(tri; use_lens = true, min_angle = lens_angle) θ = LinRange(0, 2π, 250) r = LinRange(0, norm(p .- q) / 2, 250) m = (p .+ q) ./ 2 @@ -1088,7 +1130,7 @@ function _lexicographically_sort_pair_vector(pairs) return key_x < key_y end end - return sort(pairs, lt=lt) + return sort(pairs, lt = lt) end function _compare_pairs(pairs, dt_pairs) @test length(pairs) == length(dt_pairs) @@ -1164,7 +1206,7 @@ function validate_insertion_event_history(tri::Triangulation, orig_tri::Triangul @test DT.compare_unoriented_edge_collections(manual_history.added_boundary_segments, history.added_boundary_segments) end -_approx_ispow2(x) = ispow2(x) || isapprox(log2(x), round(log2(x)), atol=1e-9, rtol=1e-9) +_approx_ispow2(x) = ispow2(x) || isapprox(log2(x), round(log2(x)), atol = 1.0e-9, rtol = 1.0e-9) function compare_encroach_queues(args::DT.RefinementArguments, manual_enqueue) _manual_enqueue_pairs = collect(manual_enqueue) @@ -1200,7 +1242,7 @@ function is_conformal(tri::Triangulation) insert!(segment_tree, i, j) end for r in each_solid_vertex(tri) - intersects = DT.get_intersections(segment_tree, r, cache_id=1) # can't use multithreading here + intersects = DT.get_intersections(segment_tree, r, cache_id = 1) # can't use multithreading here c = get_point(tri, r) for box in intersects i, j = DT.get_edge(box) @@ -1222,8 +1264,8 @@ function is_conformal(tri::Triangulation) end function slow_triangle_assess(tri, args) - good_T = NTuple{3,Int}[] - bad_T = NTuple{3,Int}[] + good_T = NTuple{3, Int}[] + bad_T = NTuple{3, Int}[] for T in each_solid_triangle(tri) u, v, w = T p, q, r = get_point(tri, u, v, w) @@ -1249,7 +1291,7 @@ end function slow_triangle_assess_queue(tri, args) good_T, bad_T = slow_triangle_assess(tri, args) - queue = PriorityQueue{NTuple{3,Int},Float64}(Base.Order.Reverse) + queue = PriorityQueue{NTuple{3, Int}, Float64}(Base.Order.Reverse) for T in bad_T queue[T] = DT.triangle_radius_edge_ratio(get_point(tri, T...)...) end @@ -1305,7 +1347,7 @@ function compute_φmin(tri) return φmin end -function validate_refinement(tri, args; check_conformal=true, warn=true) +function validate_refinement(tri, args; check_conformal = true, warn = true) ## Things to check: ## 1. All angle constraints are met, except for seditious and nestled triangles. ## 2. If !use_lens, the triangulation is conformal. @@ -1353,7 +1395,7 @@ function validate_refinement(tri, args; check_conformal=true, warn=true) show_print && println("Triangle $T has maximum angle $(max(t1, t2, t3)), which is greater than the maximum angle constraint $(args.constraints.max_angle).") return false end - flag = args.constraints.min_area - 1e-16 ≤ A ≤ args.constraints.max_area + flag = args.constraints.min_area - 1.0e-16 ≤ A ≤ args.constraints.max_area if !flag show_print && println("Triangle $T has area $A, which is not in the range $(args.constraints.min_area) to $(args.constraints.max_area).") DT.is_none(_flag) && return false @@ -1366,7 +1408,7 @@ function validate_refinement(tri, args; check_conformal=true, warn=true) if !args.use_lens flag = DT.dist(tri, steiner_point) > -eps(Float64) if !flag - show_print && println("The Steiner point associated with the triangle $T is a distance $(-DT.dist(tri,steiner_point)) away from the domain.") + show_print && println("The Steiner point associated with the triangle $T is a distance $(-DT.dist(tri, steiner_point)) away from the domain.") DT.is_none(_flag) && return false end end @@ -1430,7 +1472,7 @@ function validate_refinement(tri, args; check_conformal=true, warn=true) end return true end -validate_refinement(tri; check_conformal=true, warn=true, kwargs...) = validate_refinement(tri, DT.RefinementArguments(tri; kwargs...); warn, check_conformal) +validate_refinement(tri; check_conformal = true, warn = true, kwargs...) = validate_refinement(tri, DT.RefinementArguments(tri; kwargs...); warn, check_conformal) function why_not_equal(tri1, tri2) !DT.has_ghost_triangles(tri1) && DT.has_ghost_triangles(tri2) && println("!has_ghost_triangles(tri1) && has_ghost_triangles(tri2)") @@ -1579,7 +1621,7 @@ function get_weighted_example(i) num_pts = Int(mat[1, 1]) points = mat[2:num_pts, 1:2] weights = mat[2:num_pts, 3] - triangles = Int.(mat[num_pts+1:end, :]) + triangles = Int.(mat[(num_pts + 1):end, :]) triangles = Set([Tuple(tri) for tri in eachrow(triangles)]) _triangles = empty(triangles) for T in triangles @@ -1598,7 +1640,7 @@ function get_weighted_example(i) # since some of the vertices might be submerged, we can't just get the # convex hull of points to find the boundary (in cases of collinear points). instead, let's find # all the edges which have only one adjoining triangle, and then sort them. - d = Dict{NTuple{2,Int},Int}() + d = Dict{NTuple{2, Int}, Int}() for T in triangles i, j, k = T d[(i, j)] = k @@ -1630,7 +1672,7 @@ function get_weighted_example(i) # return tri = Triangulation(points, triangles, boundary_nodes; weights) unlock_convex_hull!(tri) - return (tri=tri, submerged_vertices=submerged_vertices, nonsubmerged_vertices=nonsubmerged_vertices, weights=weights) + return (tri = tri, submerged_vertices = submerged_vertices, nonsubmerged_vertices = nonsubmerged_vertices, weights = weights) end get_unstructured_weighted_example(i) = get_weighted_example(i) function get_convex_polygon_weighted_example(i) @@ -1639,11 +1681,11 @@ function get_convex_polygon_weighted_example(i) representative_point_list = DT.get_representative_point_list(tri) cx, cy = DT.mean_points(get_points(tri), S) representative_point_list[1] = DT.RepresentativeCoordinates(cx, cy, length(S)) - return (tri=tri, submerged_vertices=submerged_vertices, nonsubmerged_vertices=nonsubmerged_vertices, weights=weights, S=S) + return (tri = tri, submerged_vertices = submerged_vertices, nonsubmerged_vertices = nonsubmerged_vertices, weights = weights, S = S) end function get_all_distances_to_witness_planes(tri, i) - distances = Dict{NTuple{3,Int},Float64}() + distances = Dict{NTuple{3, Int}, Float64}() for T in each_solid_triangle(tri) T = DT.sort_triangle(T) δ = DT.get_distance_to_witness_plane(tri, i, T) @@ -1653,7 +1695,7 @@ function get_all_distances_to_witness_planes(tri, i) end function get_nearest_power_point(tri, i) - all_dists = Dict{Int,Float64}() + all_dists = Dict{Int, Float64}() for j in each_solid_vertex(tri) p = DT.get_point(tri, i) q = DT.get_point(tri, j) @@ -1663,7 +1705,7 @@ function get_nearest_power_point(tri, i) end ⪧(a::Vector{Tuple}, b::Vector{Tuple}; kwargs...) = ⪧(collect.(a), collect.(b); kwargs...) -⪧(a::Vector{<:Union{Vector,Number}}, b::Vector; kwargs...) = isapprox(a, b; kwargs...) +⪧(a::Vector{<:Union{Vector, Number}}, b::Vector; kwargs...) = isapprox(a, b; kwargs...) ⪧(a, b; kwargs...) = isapprox(collect(collect.(a)), collect(collect.(b)); kwargs...) function closest_point_on_curve(c, p) @@ -1678,8 +1720,8 @@ end function slow_arc_length(c, t₁, t₂) t = LinRange(t₁, t₂, 15000) s = 0.0 - for i in 1:(length(t)-1) - s += norm(c(t[i+1]) .- c(t[i])) + for i in 1:(length(t) - 1) + s += norm(c(t[i + 1]) .- c(t[i])) end return s end @@ -1687,9 +1729,9 @@ end function slow_total_absolute_curvature(c, t₁, t₂) t = LinRange(t₁, t₂, 1500) s = 0.0 - for i in 1:(length(t)-1) + for i in 1:(length(t) - 1) T₁ = DT.differentiate(c, t[i]) - T₂ = DT.differentiate(c, t[i+1]) + T₂ = DT.differentiate(c, t[i + 1]) _rat = dot(T₁, T₂) / (norm(T₁) * norm(T₂)) _dot = _rat > 1 ? 1 : _rat < -1 ? -1 : _rat θ = acos(_dot) @@ -1701,32 +1743,32 @@ end function slow_get_segment(control_points, knots, alpha, tension, t) L = 0.0 for i in 2:lastindex(control_points) - L += norm(control_points[i] .- control_points[i-1])^alpha + L += norm(control_points[i] .- control_points[i - 1])^alpha end is_closed = control_points[begin] == control_points[end] s = 0 for outer s in eachindex(knots) - knots[s] ≤ t ≤ knots[s+1] && break + knots[s] ≤ t ≤ knots[s + 1] && break end - points = NTuple{2,Float64}[] + points = NTuple{2, Float64}[] if s == 1 if is_closed - push!(points, control_points[end-1]) + push!(points, control_points[end - 1]) else push!(points, DT.extend_left_control_point(control_points)) end else - push!(points, control_points[s-1]) + push!(points, control_points[s - 1]) end - push!(points, control_points[s], control_points[s+1]) + push!(points, control_points[s], control_points[s + 1]) if s == length(knots) - 1 if is_closed - push!(points, control_points[begin+1]) + push!(points, control_points[begin + 1]) else push!(points, DT.extend_right_control_point(control_points)) end else - push!(points, control_points[s+2]) + push!(points, control_points[s + 2]) end return DT.catmull_rom_spline_segment(points..., alpha, tension), s end @@ -1739,7 +1781,7 @@ function slow_eval_bspline(control_points, knots, t) end val = Real[0, 0] order = length(knots) - length(control_points) - a, b = knots[order], knots[length(control_points)+1] + a, b = knots[order], knots[length(control_points) + 1] t = a + (b - a) * t for i in eachindex(control_points) val = val .+ control_points[i] .* slow_eval_bspline_basis(knots, i, order, t) @@ -1748,10 +1790,10 @@ function slow_eval_bspline(control_points, knots, t) end function slow_eval_bspline_basis(knots, i, order, t) if order == 1 - return (knots[i] ≤ t < knots[i+1]) ? 1.0 : 0.0 + return (knots[i] ≤ t < knots[i + 1]) ? 1.0 : 0.0 else - coeff1 = (t - knots[i]) / (knots[i+order-1] - knots[i]) - coeff2 = (knots[i+order] - t) / (knots[i+order] - knots[i+1]) + coeff1 = (t - knots[i]) / (knots[i + order - 1] - knots[i]) + coeff2 = (knots[i + order] - t) / (knots[i + order] - knots[i + 1]) coeff1 = isfinite(coeff1) ? coeff1 : 0.0 coeff2 = isfinite(coeff2) ? coeff2 : 0.0 return coeff1 * slow_eval_bspline_basis(knots, i, order - 1, t) + coeff2 * slow_eval_bspline_basis(knots, i + 1, order - 1, t) @@ -1761,11 +1803,11 @@ end function slow_bezier_eval(points, t) points = collect.(points) n = length(points) - 1 - return collect(sum([binomial(n, i) .* (1 - t)^(n - i) .* t^i .* points[i+1] for i in 0:n])) + return collect(sum([binomial(n, i) .* (1 - t)^(n - i) .* t^i .* points[i + 1] for i in 0:n])) end -function flatten_boundary_nodes(points, boundary_nodes, segments=nothing) - _points = NTuple{2,Float64}[] +function flatten_boundary_nodes(points, boundary_nodes, segments = nothing) + _points = NTuple{2, Float64}[] if DT.has_multiple_curves(boundary_nodes) nc = DT.num_curves(boundary_nodes) for i in 1:nc @@ -1775,7 +1817,7 @@ function flatten_boundary_nodes(points, boundary_nodes, segments=nothing) __boundary_nodes = get_boundary_nodes(_boundary_nodes, j) if !(get_boundary_nodes(__boundary_nodes, 1) isa DT.AbstractParametricCurve) n = DT.num_boundary_edges(__boundary_nodes) - for k in 1:(n+1) + for k in 1:(n + 1) push!(_points, get_point(points, get_boundary_nodes(__boundary_nodes, k))) end else @@ -1901,8 +1943,8 @@ end to_lines(rect::DT.BoundingBox) = [(rect.x.a, rect.y.a), (rect.x.b, rect.y.a), (rect.x.b, rect.y.b), (rect.x.a, rect.y.b), (rect.x.a, rect.y.a)] to_lines(rect::SI.Rect) = let a = rect.low[1], c = rect.low[2], b = rect.high[1], d = rect.high[2] - [(a, c), (b, c), (b, d), (a, d), (a, c)] - end + [(a, c), (b, c), (b, d), (a, d), (a, c)] +end to_lines(rect::DT.DiametralBoundingBox) = to_lines(DT.get_bounding_box(rect)) to_lines(rect::SI.SpatialElem) = to_lines(rect.mbr) to_edge(rect::DT.DiametralBoundingBox) = DT.get_edge(rect) @@ -1913,9 +1955,9 @@ function get_plot_data(tree, points) else bounding_rectangles, id_rectangles = get_si_rectangles(tree) end - _lines = NTuple{2,Float64}[] - id_rectangle_lines = NTuple{2,Float64}[] - bounding_rectangle_lines = NTuple{2,Float64}[] + _lines = NTuple{2, Float64}[] + id_rectangle_lines = NTuple{2, Float64}[] + bounding_rectangle_lines = NTuple{2, Float64}[] for rect in id_rectangles i, j = to_edge(rect) p, q = get_point(points, i, j) @@ -1931,9 +1973,9 @@ function get_plot_data(tree, points) end function plot_tree(tree, points) _lines, _id_rectangle_lines, _bounding_rectangle_lines = get_plot_data(tree, points) - fig, ax, sc = lines(_id_rectangle_lines, color=:blue) - linesegments!(ax, _lines, color=:black) - lines!(ax, _bounding_rectangle_lines, color=:red) + fig, ax, sc = lines(_id_rectangle_lines, color = :blue) + linesegments!(ax, _lines, color = :black) + lines!(ax, _bounding_rectangle_lines, color = :red) display(fig) return fig, ax, sc end @@ -1972,7 +2014,7 @@ function traverse_tree(tree::DT.PolygonTree) parent_index = DT.has_parent(tree) ? DT.get_index(DT.get_parent(tree)) : 0 tup = (height, index, parent_index) children = DT.get_children(tree) - schildren = sort(OrderedSet(children), by=x -> DT.get_index(x)) + schildren = sort(OrderedSet(children), by = x -> DT.get_index(x)) for child in schildren tup = (tup..., traverse_tree(child)) end @@ -1981,7 +2023,7 @@ end function traverse_tree(hierarchy::DT.PolygonHierarchy) dict = Dict() trees = DT.get_trees(hierarchy) - strees = sort(OrderedDict(trees), by=x -> x[1]) + strees = sort(OrderedDict(trees), by = x -> x[1]) for (index, tree) in strees dict[index] = traverse_tree(tree) end @@ -1996,7 +2038,7 @@ function compare_trees(hierarchy1::DT.PolygonHierarchy, hierarchy2::DT.PolygonHi return true end -function plot_boundary_and_diametral_circles(points, boundary_nodes, segments=nothing) +function plot_boundary_and_diametral_circles(points, boundary_nodes, segments = nothing) fpoints = flatten_boundary_nodes(points, boundary_nodes, segments) fig, ax, sc = lines(fpoints) scatter!(ax, points) @@ -2009,7 +2051,7 @@ function plot_boundary_and_diametral_circles(points, boundary_nodes, segments=no u, v = get_boundary_nodes(section_nodes, k), get_boundary_nodes(section_nodes, k + 1) p, q = get_point(points, u, v) c, r = DT.diametral_circle(p, q) - arc!(ax, c, r, 0, 2π, color=:red, linestyle=:dash) + arc!(ax, c, r, 0, 2π, color = :red, linestyle = :dash) end end end @@ -2020,7 +2062,7 @@ function plot_boundary_and_diametral_circles(points, boundary_nodes, segments=no u, v = get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, j + 1) p, q = get_point(points, u, v) c, r = DT.diametral_circle(p, q) - arc!(ax, c, r, 0, 2π, color=:red, linestyle=:dash) + arc!(ax, c, r, 0, 2π, color = :red, linestyle = :dash) end end else @@ -2028,7 +2070,7 @@ function plot_boundary_and_diametral_circles(points, boundary_nodes, segments=no u, v = get_boundary_nodes(boundary_nodes, i), get_boundary_nodes(boundary_nodes, i + 1) p, q = get_point(points, u, v) c, r = DT.diametral_circle(p, q) - arc!(ax, c, r, 0, 2π, color=:red, linestyle=:dash) + arc!(ax, c, r, 0, 2π, color = :red, linestyle = :dash) end end if !isnothing(segments) @@ -2036,7 +2078,7 @@ function plot_boundary_and_diametral_circles(points, boundary_nodes, segments=no i, j = DT.edge_vertices(e) p, q = get_point(points, i, j) c, r = DT.diametral_circle(p, q) - arc!(ax, c, r, 0, 2π, color=:red, linestyle=:dash) + arc!(ax, c, r, 0, 2π, color = :red, linestyle = :dash) end end display(fig) @@ -2045,7 +2087,7 @@ end plot_boundary_and_diametral_circles(enricher::DT.BoundaryEnricher) = plot_boundary_and_diametral_circles( get_points(enricher), get_boundary_nodes(enricher), - DT.get_segments(enricher) + DT.get_segments(enricher), ) function maximum_total_variation(points, boundary_nodes, boundary_curves) @@ -2159,7 +2201,7 @@ function all_points_are_inside(enricher::DT.BoundaryEnricher, orig_points, orig_ hierarchy = DT.get_polygon_hierarchy(enricher) for p in DT.each_point(points) δ = DT.distance_to_polygon(p, new_points, new_boundary_nodes) - δ < -1e-4 && return false + δ < -1.0e-4 && return false end return true end @@ -2167,7 +2209,7 @@ end function plot_small_angle_complexes(enricher) points, boundary_nodes, boundary_curves = get_points(enricher), get_boundary_nodes(enricher), DT.get_boundary_curves(enricher) complexes = DT.get_small_angle_complexes(points, boundary_nodes, boundary_curves) - _points, _boundary_nodes = DT.polygonise(points, boundary_nodes, boundary_curves; n=2^10) + _points, _boundary_nodes = DT.polygonise(points, boundary_nodes, boundary_curves; n = 2^10) fpoints = flatten_boundary_nodes(_points, _boundary_nodes) fig, ax, sc = lines(fpoints) colors = [:red, :green, :blue, :orange, :purple, :cyan, :magenta, :yellow] @@ -2180,18 +2222,18 @@ function plot_small_angle_complexes(enricher) curve = boundary_curves[parent_curve] p, q = get_point(points, apex, next_edge) if DT.is_piecewise_linear(curve) - lines!(ax, [p, q], linewidth=4, color=colors[color_ctr]) + lines!(ax, [p, q], linewidth = 4, color = colors[color_ctr]) else t₁ = DT.get_inverse(curve, p) t₂ = DT.get_inverse(curve, q) t = LinRange(t₁, t₂, 1000) - lines!(ax, curve.(t), linewidth=4, color=colors[color_ctr]) + lines!(ax, curve.(t), linewidth = 4, color = colors[color_ctr]) end end color_ctr = mod1(color_ctr + 1, length(colors)) end p = get_point(points, apex) - scatter!(ax, [p], color=colors[1], markersize=17) + scatter!(ax, [p], color = colors[1], markersize = 17) end display(fig) return fig @@ -2207,9 +2249,9 @@ using DelaunayTriangulation: USE_INEXACTPREDICATES, USE_EXACTPREDICATES using Preferences -if USE_INEXACTPREDICATES +if USE_INEXACTPREDICATES @test load_preference(DelaunayTriangulation, "PREDICATES", "EXACT") == "INEXACT" -elseif USE_EXACTPREDICATES +elseif USE_EXACTPREDICATES @test load_preference(DelaunayTriangulation, "PREDICATES", "EXACT") == "EXACT" end @@ -2281,4 +2323,4 @@ export test_adjacent_map_matches_adjacent2vertex_map export test_each_edge_has_two_incident_triangles export test_triangle_orientation export test_iterators -end \ No newline at end of file +end diff --git a/test/interfaces/boundary_nodes.jl b/test/interfaces/boundary_nodes.jl index f8bdaeea8..418ff6e63 100644 --- a/test/interfaces/boundary_nodes.jl +++ b/test/interfaces/boundary_nodes.jl @@ -5,10 +5,11 @@ using DataStructures using StaticArraysCore - -global bn1 = [[[1, 2], [3, 4], [5, 6], [10, 12]], - [[13, 25, 50], [75, 17, 5, 10]], - [[17, 293, 101], [29, 23]]] +global bn1 = [ + [[1, 2], [3, 4], [5, 6], [10, 12]], + [[13, 25, 50], [75, 17, 5, 10]], + [[17, 293, 101], [29, 23]], +] global bn2 = [[13, 25, 50], [75, 17, 5, 10]] global bn3 = [17, 293, 101, 29, 23] global map1 = DT.construct_ghost_vertex_map(bn1) @@ -17,200 +18,212 @@ global map3 = DT.construct_ghost_vertex_map(bn3) global idx = DT.𝒢 @testset "Testing number of sections/curves" begin - @test DT.has_multiple_curves(bn1) - @test !DT.has_multiple_curves(bn2) - @test !DT.has_multiple_curves(bn3) - @test !DT.has_multiple_curves(Int[]) - @test !DT.has_multiple_sections(Int[]) - @test DT.has_multiple_sections(bn1) - @test DT.has_multiple_sections(bn2) - @test !DT.has_multiple_sections(bn3) + @test DT.has_multiple_curves(bn1) + @test !DT.has_multiple_curves(bn2) + @test !DT.has_multiple_curves(bn3) + @test !DT.has_multiple_curves(Int[]) + @test !DT.has_multiple_sections(Int[]) + @test DT.has_multiple_sections(bn1) + @test DT.has_multiple_sections(bn2) + @test !DT.has_multiple_sections(bn3) end @testset "Getting number of sections/curves" begin - @test DT.num_curves(bn1) == 3 - @test DT.num_curves(bn2) == 1 - @test DT.num_curves(bn3) == 1 - @test DT.num_sections(bn2) == 2 + @test DT.num_curves(bn1) == 3 + @test DT.num_curves(bn2) == 1 + @test DT.num_curves(bn3) == 1 + @test DT.num_sections(bn2) == 2 end @testset "Number of boundary edges" begin - @test DT.num_boundary_edges(bn3) == 4 - @test DT.num_boundary_edges(bn1[1][1]) == 1 - @test DT.num_boundary_edges(bn2[2]) == 3 - @test DT.num_boundary_edges(Int[]) == 0 + @test DT.num_boundary_edges(bn3) == 4 + @test DT.num_boundary_edges(bn1[1][1]) == 1 + @test DT.num_boundary_edges(bn2[2]) == 3 + @test DT.num_boundary_edges(Int[]) == 0 end @testset "Getting boundary nodes" begin - @test get_boundary_nodes(bn1, 1) == bn1[1] - @test get_boundary_nodes(bn1, 2) == bn1[2] - @test get_boundary_nodes(bn2, 2) == bn2[2] - @test get_boundary_nodes(bn3, 4) == bn3[4] - @test get_boundary_nodes(bn1, (1, 2)) == bn1[1][2] - @test get_boundary_nodes(bn3, bn3) == bn3 + @test get_boundary_nodes(bn1, 1) == bn1[1] + @test get_boundary_nodes(bn1, 2) == bn1[2] + @test get_boundary_nodes(bn2, 2) == bn2[2] + @test get_boundary_nodes(bn3, 4) == bn3[4] + @test get_boundary_nodes(bn1, (1, 2)) == bn1[1][2] + @test get_boundary_nodes(bn3, bn3) == bn3 end @testset "Getting each boundary node" begin - @test DT.each_boundary_node(bn3) == bn3 + @test DT.each_boundary_node(bn3) == bn3 end @testset "Constructing the ghost vertex map" begin - map1 = DT.construct_ghost_vertex_map(bn1) - map2 = DT.construct_ghost_vertex_map(bn2) - map3 = DT.construct_ghost_vertex_map(bn3) - idx = DT.𝒢 - @test map1 == - Dict(idx => (1, 1), idx - 1 => (1, 2), idx - 2 => (1, 3), idx - 3 => (1, 4), - idx - 4 => (2, 1), idx - 5 => (2, 2), - idx - 6 => (3, 1), idx - 7 => (3, 2)) - @test map2 == Dict(idx => 1, idx - 1 => 2) - @test map3 == Dict(idx => bn3) + map1 = DT.construct_ghost_vertex_map(bn1) + map2 = DT.construct_ghost_vertex_map(bn2) + map3 = DT.construct_ghost_vertex_map(bn3) + idx = DT.𝒢 + @test map1 == + Dict( + idx => (1, 1), idx - 1 => (1, 2), idx - 2 => (1, 3), idx - 3 => (1, 4), + idx - 4 => (2, 1), idx - 5 => (2, 2), + idx - 6 => (3, 1), idx - 7 => (3, 2), + ) + @test map2 == Dict(idx => 1, idx - 1 => 2) + @test map3 == Dict(idx => bn3) end @testset "Getting a curve index" begin - @test DT.get_curve_index(map1, idx - 4) == 2 - @test DT.get_curve_index(map2, idx - 1) == 1 - @test DT.get_curve_index(3) == 1 - @test DT.get_curve_index((5, 7)) == 5 - @test DT.get_curve_index(map3, idx) == 1 + @test DT.get_curve_index(map1, idx - 4) == 2 + @test DT.get_curve_index(map2, idx - 1) == 1 + @test DT.get_curve_index(3) == 1 + @test DT.get_curve_index((5, 7)) == 5 + @test DT.get_curve_index(map3, idx) == 1 end @testset "Getting a section index" begin - @test DT.get_section_index(map1, idx - 4) == 1 - @test DT.get_section_index(map2, idx - 1) == 2 - @test DT.get_section_index(3) == 3 - @test DT.get_section_index((5, 7)) == 7 - @test DT.get_section_index(map3, idx) == 1 + @test DT.get_section_index(map1, idx - 4) == 1 + @test DT.get_section_index(map2, idx - 1) == 2 + @test DT.get_section_index(3) == 3 + @test DT.get_section_index((5, 7)) == 7 + @test DT.get_section_index(map3, idx) == 1 end @testset "Getting ghost vertex ranges" begin - for r in 1:500 # this example used to StackOverflow randomly, so let's just be sure it doesn't come back - d1 = DT.construct_ghost_vertex_ranges(bn1) - d2 = DT.construct_ghost_vertex_ranges(bn2) - d3 = DT.construct_ghost_vertex_ranges(bn3) - boundary_nodes = [[[1, 2, 3, 4], [4, 5, 6, 1]], - [[18, 19, 20, 25, 26, 30]], - [[50, 51, 52, 53, 54, 55], [55, 56, 57, 58], - [58, 101, 103, 105, 107, 120], - [120, 121, 122, 50]]] - d4 = DT.construct_ghost_vertex_ranges(boundary_nodes) - @test d4 == Dict(-1 => -2:-1, - -2 => -2:-1, - -3 => -3:-3, - -4 => -7:-4, - -5 => -7:-4, - -6 => -7:-4, - -7 => -7:-4) - @test d1 == Dict(-1 => -4:-1, - -2 => -4:-1, - -3 => -4:-1, - -4 => -4:-1, - -5 => -6:-5, - -6 => -6:-5, - -7 => -8:-7, - -8 => -8:-7) - @test d2 == Dict(-1 => -2:-1, -2 => -2:-1) - @test d3 == Dict(-1 => -1:-1) - - x, y = complicated_geometry() - boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; boundary_nodes) - @test tri.ghost_vertex_ranges == Dict(-1 => -4:-1, - -2 => -4:-1, - -3 => -4:-1, - -4 => -4:-1, - -5 => -5:-5, - -6 => -6:-6, - -7 => -10:-7, - -8 => -10:-7, - -9 => -10:-7, - -10 => -10:-7, - -11 => -11:-11) - end + for r in 1:500 # this example used to StackOverflow randomly, so let's just be sure it doesn't come back + d1 = DT.construct_ghost_vertex_ranges(bn1) + d2 = DT.construct_ghost_vertex_ranges(bn2) + d3 = DT.construct_ghost_vertex_ranges(bn3) + boundary_nodes = [ + [[1, 2, 3, 4], [4, 5, 6, 1]], + [[18, 19, 20, 25, 26, 30]], + [ + [50, 51, 52, 53, 54, 55], [55, 56, 57, 58], + [58, 101, 103, 105, 107, 120], + [120, 121, 122, 50], + ], + ] + d4 = DT.construct_ghost_vertex_ranges(boundary_nodes) + @test d4 == Dict( + -1 => -2:-1, + -2 => -2:-1, + -3 => -3:-3, + -4 => -7:-4, + -5 => -7:-4, + -6 => -7:-4, + -7 => -7:-4, + ) + @test d1 == Dict( + -1 => -4:-1, + -2 => -4:-1, + -3 => -4:-1, + -4 => -4:-1, + -5 => -6:-5, + -6 => -6:-5, + -7 => -8:-7, + -8 => -8:-7, + ) + @test d2 == Dict(-1 => -2:-1, -2 => -2:-1) + @test d3 == Dict(-1 => -1:-1) + + x, y = complicated_geometry() + boundary_nodes, points = convert_boundary_points_to_indices(x, y) + tri = triangulate(points; boundary_nodes) + @test tri.ghost_vertex_ranges == Dict( + -1 => -4:-1, + -2 => -4:-1, + -3 => -4:-1, + -4 => -4:-1, + -5 => -5:-5, + -6 => -6:-6, + -7 => -10:-7, + -8 => -10:-7, + -9 => -10:-7, + -10 => -10:-7, + -11 => -11:-11, + ) + end end @testset "construct_boundary_edge_map" begin - bn = [1, 2, 3, 4, 5, 6, 7, 1] - bn_map = DT.construct_boundary_edge_map(bn) - for (ij, (index, k)) in bn_map - S = get_boundary_nodes(bn, index) - @test get_boundary_nodes(S, k) == ij[1] - @test get_boundary_nodes(S, k + 1) == ij[2] - end - bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] - bn_map = DT.construct_boundary_edge_map(bn) - for (ij, (index, k)) in bn_map - S = get_boundary_nodes(bn, index) - @test get_boundary_nodes(S, k) == ij[1] - @test get_boundary_nodes(S, k + 1) == ij[2] - end - bn = [ - [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], - [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]] - ] - bn_map = DT.construct_boundary_edge_map(bn) - for (ij, (index, k)) in bn_map - S = get_boundary_nodes(bn, index) - @test get_boundary_nodes(S, k) == ij[1] - @test get_boundary_nodes(S, k + 1) == ij[2] - end - bn = Int[] - bn_map = DT.construct_boundary_edge_map(bn) - @test bn_map == Dict{Tuple{Int32,Int32},Tuple{Vector{Int},Int}}() + bn = [1, 2, 3, 4, 5, 6, 7, 1] + bn_map = DT.construct_boundary_edge_map(bn) + for (ij, (index, k)) in bn_map + S = get_boundary_nodes(bn, index) + @test get_boundary_nodes(S, k) == ij[1] + @test get_boundary_nodes(S, k + 1) == ij[2] + end + bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] + bn_map = DT.construct_boundary_edge_map(bn) + for (ij, (index, k)) in bn_map + S = get_boundary_nodes(bn, index) + @test get_boundary_nodes(S, k) == ij[1] + @test get_boundary_nodes(S, k + 1) == ij[2] + end + bn = [ + [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], + [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]], + ] + bn_map = DT.construct_boundary_edge_map(bn) + for (ij, (index, k)) in bn_map + S = get_boundary_nodes(bn, index) + @test get_boundary_nodes(S, k) == ij[1] + @test get_boundary_nodes(S, k + 1) == ij[2] + end + bn = Int[] + bn_map = DT.construct_boundary_edge_map(bn) + @test bn_map == Dict{Tuple{Int32, Int32}, Tuple{Vector{Int}, Int}}() end @testset "insert_boundary_node!" begin - bn = [1, 2, 3, 4, 5, 6, 7, 1] - DT.insert_boundary_node!(bn, (bn, 5), 17) - DT.insert_boundary_node!(bn, (bn, 1), 13) - @test bn == [13, 1, 2, 3, 4, 17, 5, 6, 7, 1] - bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] - DT.insert_boundary_node!(bn, (1, 2), 9) - DT.insert_boundary_node!(bn, (1, 4), 18) - DT.insert_boundary_node!(bn, (2, 4), 23) - DT.insert_boundary_node!(bn, (3, 1), 5) - @test bn == [[1, 9, 2, 18, 3, 4], [4, 5, 6, 23, 7, 8], [5, 8, 9, 10, 1]] - bn = [ - [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], - [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]] - ] - DT.insert_boundary_node!(bn, ((1, 1), 1), 17) - DT.insert_boundary_node!(bn, ((1, 2), 3), 38) - DT.insert_boundary_node!(bn, ((1, 3), 2), 50) - DT.insert_boundary_node!(bn, ((1, 4), 3), 67) - DT.insert_boundary_node!(bn, ((2, 1), 3), 500) - DT.insert_boundary_node!(bn, ((2, 2), 3), 87) - DT.insert_boundary_node!(bn, ((2, 3), 2), 671) - @test bn == [ - [[17, 1, 2, 3, 4, 5], [5, 6, 38, 7], [7, 50, 8], [8, 9, 67, 10, 1]], - [[13, 14, 500, 15, 16, 17], [17, 18, 87, 19, 20], [20, 671, 13]] - ] + bn = [1, 2, 3, 4, 5, 6, 7, 1] + DT.insert_boundary_node!(bn, (bn, 5), 17) + DT.insert_boundary_node!(bn, (bn, 1), 13) + @test bn == [13, 1, 2, 3, 4, 17, 5, 6, 7, 1] + bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] + DT.insert_boundary_node!(bn, (1, 2), 9) + DT.insert_boundary_node!(bn, (1, 4), 18) + DT.insert_boundary_node!(bn, (2, 4), 23) + DT.insert_boundary_node!(bn, (3, 1), 5) + @test bn == [[1, 9, 2, 18, 3, 4], [4, 5, 6, 23, 7, 8], [5, 8, 9, 10, 1]] + bn = [ + [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], + [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]], + ] + DT.insert_boundary_node!(bn, ((1, 1), 1), 17) + DT.insert_boundary_node!(bn, ((1, 2), 3), 38) + DT.insert_boundary_node!(bn, ((1, 3), 2), 50) + DT.insert_boundary_node!(bn, ((1, 4), 3), 67) + DT.insert_boundary_node!(bn, ((2, 1), 3), 500) + DT.insert_boundary_node!(bn, ((2, 2), 3), 87) + DT.insert_boundary_node!(bn, ((2, 3), 2), 671) + @test bn == [ + [[17, 1, 2, 3, 4, 5], [5, 6, 38, 7], [7, 50, 8], [8, 9, 67, 10, 1]], + [[13, 14, 500, 15, 16, 17], [17, 18, 87, 19, 20], [20, 671, 13]], + ] end @testset "delete_boundary_node!" begin - bn = [1, 2, 3, 4, 5, 6, 7, 1] - DT.delete_boundary_node!(bn, (bn, 5)) - DT.delete_boundary_node!(bn, (bn, 1)) - @test bn == [2, 3, 4, 6, 7, 1] - bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] - DT.delete_boundary_node!(bn, (1, 2)) - DT.delete_boundary_node!(bn, (1, 2)) - DT.delete_boundary_node!(bn, (2, 4)) - DT.delete_boundary_node!(bn, (3, 1)) - @test bn == [[1, 4], [4, 5, 6, 8], [9, 10, 1]] - bn = [ - [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], - [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]] - ] - DT.delete_boundary_node!(bn, ((1, 1), 1)) - DT.delete_boundary_node!(bn, ((1, 2), 3)) - DT.delete_boundary_node!(bn, ((1, 3), 2)) - DT.delete_boundary_node!(bn, ((1, 4), 3)) - DT.delete_boundary_node!(bn, ((2, 1), 3)) - DT.delete_boundary_node!(bn, ((2, 2), 3)) - DT.delete_boundary_node!(bn, ((2, 3), 2)) - @test bn == [ - [[2, 3, 4, 5], [5, 6], [7], [8, 9, 1]], - [[13, 14, 16, 17], [17, 18, 20], [20]] - ] -end \ No newline at end of file + bn = [1, 2, 3, 4, 5, 6, 7, 1] + DT.delete_boundary_node!(bn, (bn, 5)) + DT.delete_boundary_node!(bn, (bn, 1)) + @test bn == [2, 3, 4, 6, 7, 1] + bn = [[1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 1]] + DT.delete_boundary_node!(bn, (1, 2)) + DT.delete_boundary_node!(bn, (1, 2)) + DT.delete_boundary_node!(bn, (2, 4)) + DT.delete_boundary_node!(bn, (3, 1)) + @test bn == [[1, 4], [4, 5, 6, 8], [9, 10, 1]] + bn = [ + [[1, 2, 3, 4, 5], [5, 6, 7], [7, 8], [8, 9, 10, 1]], + [[13, 14, 15, 16, 17], [17, 18, 19, 20], [20, 13]], + ] + DT.delete_boundary_node!(bn, ((1, 1), 1)) + DT.delete_boundary_node!(bn, ((1, 2), 3)) + DT.delete_boundary_node!(bn, ((1, 3), 2)) + DT.delete_boundary_node!(bn, ((1, 4), 3)) + DT.delete_boundary_node!(bn, ((2, 1), 3)) + DT.delete_boundary_node!(bn, ((2, 2), 3)) + DT.delete_boundary_node!(bn, ((2, 3), 2)) + @test bn == [ + [[2, 3, 4, 5], [5, 6], [7], [8, 9, 1]], + [[13, 14, 16, 17], [17, 18, 20], [20]], + ] +end diff --git a/test/interfaces/edges.jl b/test/interfaces/edges.jl index 5e6404509..754391977 100644 --- a/test/interfaces/edges.jl +++ b/test/interfaces/edges.jl @@ -8,7 +8,7 @@ global i = 17 global j = 5 global e1 = (i, j) global e2 = [i, j] -global e3 = SVector{2,Int32}((i, j)) +global e3 = SVector{2, Int32}((i, j)) @testset "Individual edges" begin @testset "Constructing an edge" begin @@ -45,11 +45,15 @@ end global es1 = Set{typeof(e1)}(((1, 3), (4, 1), (10, 1), (3, 9), (5, 3))) global es2 = Set{typeof(e2)}(([1, 3], [4, 1], [10, 1], [3, 9], [5, 3])) -global es3 = Set{typeof(e3)}((SVector{2,Int32}((1, 3)), - SVector{2,Int32}((4, 1)), - SVector{2,Int32}((10, 1)), - SVector{2,Int32}((3, 9)), - SVector{2,Int32}((5, 3)))) +global es3 = Set{typeof(e3)}( + ( + SVector{2, Int32}((1, 3)), + SVector{2, Int32}((4, 1)), + SVector{2, Int32}((10, 1)), + SVector{2, Int32}((3, 9)), + SVector{2, Int32}((5, 3)), + ), +) @testset "Collection of edges" begin @testset "Getting the type of edges in a collection" begin @@ -57,7 +61,7 @@ global es3 = Set{typeof(e3)}((SVector{2,Int32}((1, 3)), F = eltype(es) @test DT.edge_type(typeof(es)) == F end - @test DT.edge_type(Vector{NTuple{2,Int}}) == NTuple{2,Int} + @test DT.edge_type(Vector{NTuple{2, Int}}) == NTuple{2, Int} end @testset "Number of edges" begin @@ -159,4 +163,4 @@ end @test !DT.edges_are_disjoint(e, e′) e′ = (3, 2) @test !DT.edges_are_disjoint(e, e′) -end \ No newline at end of file +end diff --git a/test/interfaces/points.jl b/test/interfaces/points.jl index fc609e339..55d28e3be 100644 --- a/test/interfaces/points.jl +++ b/test/interfaces/points.jl @@ -7,7 +7,7 @@ import GeometryBasics: Point2f global p1 = [1.3, 2.5] global p2 = (1.3, 2.5) -global p3 = SVector{2,Float32}((1.3, 2.5)) +global p3 = SVector{2, Float32}((1.3, 2.5)) @testset "Individual points" begin @testset "Getting coordinates" begin @@ -52,9 +52,9 @@ global pts4 = ((2.0, 3.5), (1.7, 23.3), (-1.0, 0.0)) @test DT.get_point(pts, (2.0, 5.3), (17.0, 5.3)) == ((2.0, 5.3), (17.0, 5.3)) @inferred DT.get_point(pts, (2.0, 5.3), (17.0, 5.3)) == ((2.0, 5.3), (17.0, 5.3)) @test DT.get_point(pts, 1, 2, (17.0, -2.0), (57.0, 23.0)) == - ((2.0, 3.5), (1.7, 23.3), (17.0, -2.0), (57.0, 23.0)) + ((2.0, 3.5), (1.7, 23.3), (17.0, -2.0), (57.0, 23.0)) @inferred DT.get_point(pts, 1, 2, (17.0, -2.0), (57.0, 23.0)) == - ((2.0, 3.5), (1.7, 23.3), (17.0, -2.0), (57.0, 23.0)) + ((2.0, 3.5), (1.7, 23.3), (17.0, -2.0), (57.0, 23.0)) end end @@ -94,18 +94,22 @@ global pts4 = ((2.0, 3.5), (1.7, 23.3), (-1.0, 0.0)) end @testset "Sorting points lexicographically" begin - A = [2.0 5.0 1.0 10.0 17.0 23.0 5.0 5.0 - 7.0 2.0 0.0 7.5 2.0 -2.5 3.5 3.0] + A = [ + 2.0 5.0 1.0 10.0 17.0 23.0 5.0 5.0 + 7.0 2.0 0.0 7.5 2.0 -2.5 3.5 3.0 + ] idx = DT.lexicographic_order(A) @test idx == [3, 1, 2, 8, 7, 4, 5, 6] - A = [(2.0, 7.0), + A = [ + (2.0, 7.0), (5.0, 2.0), (1.0, 0.0), (10.0, 7.5), (17.0, 2.0), (23.0, -2.5), (5.0, 3.5), - (5.0, 3.0)] + (5.0, 3.0), + ] idx = DT.lexicographic_order(A) @test idx == [3, 1, 2, 8, 7, 4, 5, 6] end @@ -162,9 +166,9 @@ global pts4 = ((2.0, 3.5), (1.7, 23.3), (-1.0, 0.0)) DT.set_point!(points, 2, 3.4, 6.7) @test points == [[1.0, 5.0], [3.4, 6.7]] - points = [SVector{2,Float64}(1.0, 5.4), SVector{2,Float64}(6.5, 2.3)] + points = [SVector{2, Float64}(1.0, 5.4), SVector{2, Float64}(6.5, 2.3)] DT.set_point!(points, 2, 3.4, 6.7) - @test points == [SVector{2,Float64}(1.0, 5.4), SVector{2,Float64}(3.4, 6.7)] + @test points == [SVector{2, Float64}(1.0, 5.4), SVector{2, Float64}(3.4, 6.7)] points = [Float32[1.0, 5.0], Float32[2.3, -6.7]] DT.set_point!(points, 1, 2.3, 6.9) @@ -180,7 +184,7 @@ end points1 = [(1.0, 2.0), (5.0, 9.0), (3.0, 4.0)] points2 = [1.0 5.0 3.0; 2.0 9.0 4.0] points3 = rand(2, 75) - points4 = [SVector{2,Float32}((1.0, 2.0)), SVector{2,Float32}((5.0, 9.0)), SVector{2,Float32}((3.0, 4.0))] + points4 = [SVector{2, Float32}((1.0, 2.0)), SVector{2, Float32}((5.0, 9.0)), SVector{2, Float32}((3.0, 4.0))] points5 = [Point2f(1.0, 2.0), Point2f(5.0, 9.0), Point2f(3.0, 4.0)] points6 = [Float32[1.0, 2.0], Float32[5.0, 9.0], Float32[3.0, 4.0]] @test DT.find_point_index(points1, 1.0, 2.0) == 1 @@ -225,13 +229,13 @@ end (17.5, 17.5), (0.0, 0.0), (0.0, 0.0), - (20.0, 20.0) + (20.0, 20.0), ] dict = DT.find_duplicate_points(points) @test dict == Dict( (1.0, 2.0) => [1, 4], (17.5, 17.5) => [3, 6], - (0.0, 0.0) => [7, 8] + (0.0, 0.0) => [7, 8], ) end @@ -241,8 +245,8 @@ end r = [1.0f0, 4.0f0, 5.0f0] s = @SVector [3, 7, 5] t = [5.0, 13.0, -5.0] - - @test DT.getz(p) === 3.0 + + @test DT.getz(p) === 3.0 @test DT._getz(p) === 3.0 @test DT.getxyz(p) === (1.0, 2.0, 3.0) @test DT._getxyz(p) === (1.0, 2.0, 3.0) @@ -266,4 +270,4 @@ end @test DT._getz(t) === -5.0 @test DT.getxyz(t) === (5.0, 13.0, -5.0) @test DT._getxyz(t) === (5.0, 13.0, -5.0) -end \ No newline at end of file +end diff --git a/test/interfaces/triangles.jl b/test/interfaces/triangles.jl index c00e45c83..c0626a106 100644 --- a/test/interfaces/triangles.jl +++ b/test/interfaces/triangles.jl @@ -8,15 +8,15 @@ global j = 5 global k = 10 global T1 = (i, j, k) global T2 = [i, j, k] -global T3 = SVector{3,Int32}((i, j, k)) +global T3 = SVector{3, Int32}((i, j, k)) @testset "Individual triangles" begin @testset "Constructing a triangle" begin @test_throws MethodError DT.construct_triangle(String, i, j, k) - @test DT.construct_triangle(NTuple{3,Int}, i, j, k) == T1 + @test DT.construct_triangle(NTuple{3, Int}, i, j, k) == T1 @test DT.construct_triangle(Vector{Int}, i, j, k) == T2 - @test DT.construct_triangle(SVector{3,Int32}, i, j, k) == T3 - @inferred DT.construct_triangle(NTuple{3,Int}, i, j, k) + @test DT.construct_triangle(SVector{3, Int32}, i, j, k) == T3 + @inferred DT.construct_triangle(NTuple{3, Int}, i, j, k) end @testset "Getting indices" begin @@ -42,10 +42,10 @@ global T3 = SVector{3,Int32}((i, j, k)) @testset "Edges of a triangle" begin @test DT.triangle_edges(T1) == - DT.triangle_edges(T2) == - DT.triangle_edges(T3) == - DT.triangle_edges(i, j, k) == - ((i, j), (j, k), (k, i)) + DT.triangle_edges(T2) == + DT.triangle_edges(T3) == + DT.triangle_edges(i, j, k) == + ((i, j), (j, k), (k, i)) @inferred DT.triangle_edges(T1) end @@ -53,7 +53,7 @@ global T3 = SVector{3,Int32}((i, j, k)) for T in (T1, T2, T3) for r in 0:2 @test DT.rotate_triangle(T, r) == - DT.construct_triangle(typeof(T), ((i, j, k), (j, k, i), (k, i, j))[r+1]...) + DT.construct_triangle(typeof(T), ((i, j, k), (j, k, i), (k, i, j))[r + 1]...) @inferred DT.rotate_triangle(T, r) end end @@ -84,10 +84,10 @@ global T3 = SVector{3,Int32}((i, j, k)) i = 1 j = (0.3, 0.5) k = 5 - P = NTuple{2,Float64} + P = NTuple{2, Float64} I = Int - types = Union{Tuple{I,I,P},Tuple{I,P,I},Tuple{P,I,I}} - types2 = Union{Tuple{P,P,I},Tuple{P,I,P},Tuple{P,P,I}} + types = Union{Tuple{I, I, P}, Tuple{I, P, I}, Tuple{P, I, I}} + types2 = Union{Tuple{P, P, I}, Tuple{P, I, P}, Tuple{P, P, I}} @test DT.sort_triangle(i, j, k) == (i, j, k) @inferred types DT.sort_triangle(i, j, k) @test DT.sort_triangle(5, 7, (0.9, 0.2)) == (5, 7, (0.9, 0.2)) @@ -105,19 +105,23 @@ end global Ts1 = Set{typeof(T1)}(((1, 2, 3), (4, 6, 1), (10, 6, 1), (3, 10, 9), (5, 10, 3))) global Ts2 = Set{typeof(T2)}(([1, 2, 3], [4, 6, 1], [10, 6, 1], [3, 10, 9], [5, 10, 3])) -global Ts3 = Set{typeof(T3)}((SVector{3,Int32}((1, 2, 3)), - SVector{3,Int32}((4, 6, 1)), - SVector{3,Int32}((10, 6, 1)), - SVector{3,Int32}((3, 10, 9)), - SVector{3,Int32}((5, 10, 3)))) +global Ts3 = Set{typeof(T3)}( + ( + SVector{3, Int32}((1, 2, 3)), + SVector{3, Int32}((4, 6, 1)), + SVector{3, Int32}((10, 6, 1)), + SVector{3, Int32}((3, 10, 9)), + SVector{3, Int32}((5, 10, 3)), + ), +) @testset "Collection of triangles" begin @testset "Getting the eltype of a collection of triangles" begin for (T, Ts) in zip((T1, T2, T3), (Ts1, Ts2, Ts3)) @test DT.triangle_type(typeof(Ts)) == typeof(T) end - @test DT.triangle_type(Vector{NTuple{3,Int}}) == NTuple{3,Int} - @inferred DT.triangle_type(Vector{NTuple{3,Int}}) + @test DT.triangle_type(Vector{NTuple{3, Int}}) == NTuple{3, Int} + @inferred DT.triangle_type(Vector{NTuple{3, Int}}) end @testset "Number of triangles" begin @@ -169,7 +173,7 @@ global Ts3 = Set{typeof(T3)}((SVector{3,Int32}((1, 2, 3)), V5 = DT.construct_triangle(V, 20, 25, 50) V6 = [17, 23, 507] V7 = (1, 100, 500) - V8 = SVector{3,Int32}(100, 50, 901) + V8 = SVector{3, Int32}(100, 50, 901) G6 = DT.construct_triangle(V, V6...) G7 = DT.construct_triangle(V, V7...) G8 = DT.construct_triangle(V, V8...) @@ -185,7 +189,7 @@ global Ts3 = Set{typeof(T3)}((SVector{3,Int32}((1, 2, 3)), end @test length(Ts) == 13 end - T = Vector{NTuple{3,Int}}() + T = Vector{NTuple{3, Int}}() DT.add_triangle!(T, (1, 2, 3)) DT.add_triangle!(T, (5, 6, 8), (9, 10, 12)) DT.add_triangle!(T, [13, 14, 15]) @@ -230,67 +234,91 @@ global Ts3 = Set{typeof(T3)}((SVector{3,Int32}((1, 2, 3)), @testset "Getting a positively oriented triangle" begin points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)] - @test DT.construct_positively_oriented_triangle(NTuple{3,Int}, 1, 2, 3, points) == - (1, 2, 3) - @test DT.construct_positively_oriented_triangle(NTuple{3,Int}, 2, 1, 3, points) == - (1, 2, 3) - @inferred DT.construct_positively_oriented_triangle(NTuple{3,Int}, 2, 1, 3, points) + @test DT.construct_positively_oriented_triangle(NTuple{3, Int}, 1, 2, 3, points) == + (1, 2, 3) + @test DT.construct_positively_oriented_triangle(NTuple{3, Int}, 2, 1, 3, points) == + (1, 2, 3) + @inferred DT.construct_positively_oriented_triangle(NTuple{3, Int}, 2, 1, 3, points) end @testset "Comparing collections of triangles" begin - T = Set{NTuple{3,Int}}(((1, 2, 3), - (2, 3, 4), - (4, 5, 6), - (6, 9, 11))) - V = Set{NTuple{3,Int}}(((1, 2, 3), - (2, 3, 4), - (4, 5, 6), - (6, 9, 11))) + T = Set{NTuple{3, Int}}( + ( + (1, 2, 3), + (2, 3, 4), + (4, 5, 6), + (6, 9, 11), + ), + ) + V = Set{NTuple{3, Int}}( + ( + (1, 2, 3), + (2, 3, 4), + (4, 5, 6), + (6, 9, 11), + ), + ) @test DT.compare_triangle_collections(T, V) - V = Set{NTuple{3,Int}}(((1, 2, 3), - (2, 3, 4), - (4, 5, 6))) + V = Set{NTuple{3, Int}}( + ( + (1, 2, 3), + (2, 3, 4), + (4, 5, 6), + ), + ) @test !DT.compare_triangle_collections(T, V) - V = Set{NTuple{3,Int}}(((3, 1, 2), - (3, 4, 2), - (6, 4, 5), - (6, 9, 11))) + V = Set{NTuple{3, Int}}( + ( + (3, 1, 2), + (3, 4, 2), + (6, 4, 5), + (6, 9, 11), + ), + ) @test DT.compare_triangle_collections(T, V) - V = Set{NTuple{3,Int}}(((3, 1, 2), - (3, 4, 2), - (6, 4, 5), - (6, 11, 9))) + V = Set{NTuple{3, Int}}( + ( + (3, 1, 2), + (3, 4, 2), + (6, 4, 5), + (6, 11, 9), + ), + ) @test !DT.compare_triangle_collections(T, V) @inferred DT.compare_triangle_collections(T, V) end @testset "Sorting a collection of triangles" begin - T = Set{NTuple{3,Int}}([ - (1, 2, 3), - (10, 9, 3), - (11, 5, 1), - (193, 12, 10), - (5, 3, 1), - (19, 18, 17), - (17, 5, 23), - (20, 50, 72), - (30, 31, 32), - (20, 13, 37) - ]) + T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), + (10, 9, 3), + (11, 5, 1), + (193, 12, 10), + (5, 3, 1), + (19, 18, 17), + (17, 5, 23), + (20, 50, 72), + (30, 31, 32), + (20, 13, 37), + ], + ) V = DT.sort_triangles(T) @inferred DT.sort_triangles(T) - @test V == Set{NTuple{3,Int}}([ - (2, 3, 1), - (10, 9, 3), - (11, 5, 1), - (193, 12, 10), - (5, 3, 1), - (19, 18, 17), - (23, 17, 5), - (50, 72, 20), - (31, 32, 30), - (37, 20, 13) - ]) + @test V == Set{NTuple{3, Int}}( + [ + (2, 3, 1), + (10, 9, 3), + (11, 5, 1), + (193, 12, 10), + (5, 3, 1), + (19, 18, 17), + (23, 17, 5), + (50, 72, 20), + (31, 32, 30), + (37, 20, 13), + ], + ) @test DT.compare_triangle_collections(T, V) end -end \ No newline at end of file +end diff --git a/test/operations/add_ghost_triangles.jl b/test/operations/add_ghost_triangles.jl index acdc2e801..4d57282e3 100644 --- a/test/operations/add_ghost_triangles.jl +++ b/test/operations/add_ghost_triangles.jl @@ -7,24 +7,30 @@ using StaticArrays tri, label_map, index_map = simple_geometry() DT.add_ghost_triangles!(tri) - outer_edges = [("a", "b") => DT.𝒢, + outer_edges = [ + ("a", "b") => DT.𝒢, ("b", "c") => DT.𝒢, ("c", "d") => DT.𝒢, ("d", "e") => DT.𝒢, ("e", "f") => DT.𝒢, ("f", "g") => DT.𝒢, ("g", "h") => DT.𝒢, - ("h", "a") => DT.𝒢] - inner_edges_1 = [("k", "j") => DT.𝒢 - 1, + ("h", "a") => DT.𝒢, + ] + inner_edges_1 = [ + ("k", "j") => DT.𝒢 - 1, ("j", "i") => DT.𝒢 - 1, ("i", "ℓ") => DT.𝒢 - 1, - ("ℓ", "k") => DT.𝒢 - 1] - inner_edges_2 = [("r", "q") => DT.𝒢 - 2, + ("ℓ", "k") => DT.𝒢 - 1, + ] + inner_edges_2 = [ + ("r", "q") => DT.𝒢 - 2, ("q", "p") => DT.𝒢 - 2, ("p", "o") => DT.𝒢 - 3, ("o", "n") => DT.𝒢 - 3, ("n", "m") => DT.𝒢 - 3, - ("m", "r") => DT.𝒢 - 3] + ("m", "r") => DT.𝒢 - 3, + ] for ((a, b), k) in outer_edges i = index_map[a] @@ -39,4 +45,4 @@ using StaticArrays @test DT.contains_edge(i, k, DT.get_adjacent2vertex(tri, j)) @test DT.contains_edge(k, j, DT.get_adjacent2vertex(tri, i)) end -end \ No newline at end of file +end diff --git a/test/operations/add_point.jl b/test/operations/add_point.jl index d560acdc8..709e65db1 100644 --- a/test/operations/add_point.jl +++ b/test/operations/add_point.jl @@ -10,13 +10,13 @@ rng = StableRNG(8888) @testset "Adding a point" begin for _ in 1:150 pts = tuple.(rand(50), rand(50)) - tri = DT.triangulate(pts, delete_ghosts=false, skip_points=4:50) + tri = DT.triangulate(pts, delete_ghosts = false, skip_points = 4:50) for i in setdiff(DT.each_point_index(pts), DT.get_vertices(tri)) add_point!(tri, i) @test validate_triangulation(tri) end @test num_solid_vertices(tri) == DT.num_points(tri) - DT.convex_hull!(tri; reconstruct=false) + DT.convex_hull!(tri; reconstruct = false) DT.clear_empty_features!(tri) _tri = triangulate(pts; rng) DT.compute_representative_points!(tri) @@ -45,7 +45,7 @@ end tri = triangulate(pts) _tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) - add_point!(tri, 0.4, 0.4, store_event_history=Val(true), event_history=history, peek=Val(true)) + add_point!(tri, 0.4, 0.4, store_event_history = Val(true), event_history = history, peek = Val(true)) @test DT.compare_triangle_collections(get_triangles(_tri), get_triangles(tri)) DT.clear_empty_features!(tri) @test get_adjacent(tri) == get_adjacent(_tri) @@ -62,20 +62,22 @@ end end @test get_points(tri) == get_points(_tri) - tri = triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 11, 6, delete_ghosts=false) + tri = triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 11, 6, delete_ghosts = false) _tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) - for (x, y) in [(0.0, 0.23), (0.0, 0.8), (1.0, 1.0), (0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (0.39881, 0.0), (0.5, 1.0), (0.0, 0.4), (1.0, 0.881), - [(0.0, rand()) for _ in 1:50]..., [(rand(), 0.0) for _ in 1:50]..., [(rand(), 1.0) for _ in 1:50]..., [(1.0, rand()) for _ in 1:50]..., - [(rand(), rand()) for _ in 1:500]...] + for (x, y) in [ + (0.0, 0.23), (0.0, 0.8), (1.0, 1.0), (0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (0.39881, 0.0), (0.5, 1.0), (0.0, 0.4), (1.0, 0.881), + [(0.0, rand()) for _ in 1:50]..., [(rand(), 0.0) for _ in 1:50]..., [(rand(), 1.0) for _ in 1:50]..., [(1.0, rand()) for _ in 1:50]..., + [(rand(), rand()) for _ in 1:500]..., + ] empty!(history) if rand() < 1 / 2 - add_point!(tri, x, y, store_event_history=Val(true), event_history=history, peek=Val(true)) + add_point!(tri, x, y, store_event_history = Val(true), event_history = history, peek = Val(true)) else - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history, peek=Val(true)) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history, peek = Val(true)) end DT.clear_empty_features!(tri) - @test tri ==_tri + @test tri == _tri @test length(history.added_triangles) > 0 @test length(history.deleted_triangles) > 0 for T in DT.each_added_triangle(history) @@ -91,10 +93,10 @@ end @testset "Peeking concurrency" begin pts = [(rand(), rand()) for _ in 1:50] - tri = triangulate(pts, delete_ghosts=false) + tri = triangulate(pts, delete_ghosts = false) Base.Threads.@threads for _ in 1:500 history = DT.InsertionEventHistory(tri) - add_point!(tri, rand(2), store_event_history=Val(true), event_history=history, peek=Val(true)) + add_point!(tri, rand(2), store_event_history = Val(true), event_history = history, peek = Val(true)) end @test DT.num_points(tri) == 50 end diff --git a/test/operations/add_triangle.jl b/test/operations/add_triangle.jl index 7c7936fe0..f1164250a 100644 --- a/test/operations/add_triangle.jl +++ b/test/operations/add_triangle.jl @@ -10,339 +10,370 @@ global x = _x global y = _y boundary_nodes, points = convert_boundary_points_to_indices(x, y) rng = StableRNG(9881) -global tri = triangulate(points; boundary_nodes, rng, delete_ghosts=false) +global tri = triangulate(points; boundary_nodes, rng, delete_ghosts = false) A = get_area(tri) -refine!(tri; max_area=1e-3A, rng, use_circumcenter=true) +refine!(tri; max_area = 1.0e-3A, rng, use_circumcenter = true) boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) rng = StableRNG(9881) -global tri_2 = triangulate(points; boundary_nodes, rng, delete_ghosts=false) +global tri_2 = triangulate(points; boundary_nodes, rng, delete_ghosts = false) A = get_area(tri_2) -refine!(tri_2; max_area=1e-3A, rng, use_circumcenter=true) +refine!(tri_2; max_area = 1.0e-3A, rng, use_circumcenter = true) global i, j, k = 451, 307, 227 global u, v, w = 420, 417, 418 global T = (u, v, w) @testset "Simple add, no connections" begin - DT.add_triangle!(tri, i, j, k) - DT.add_triangle!(tri, T) - for ((a, b, c)) in ((i, j, k), (u, v, w)) - @test DT.get_adjacent(tri, a, b) == c - @test DT.get_adjacent(tri, b, c) == a - @test DT.get_adjacent(tri, c, a) == b - @test (a, b) ∈ DT.get_adjacent2vertex(tri, c) - @test (b, c) ∈ DT.get_adjacent2vertex(tri, a) - @test (c, a) ∈ DT.get_adjacent2vertex(tri, b) - @test a ∈ DT.get_neighbours(tri, b) && a ∈ DT.get_neighbours(tri, c) - @test b ∈ DT.get_neighbours(tri, a) && b ∈ DT.get_neighbours(tri, c) - @test c ∈ DT.get_neighbours(tri, a) && c ∈ DT.get_neighbours(tri, b) - @test (a, b, c) ∈ tri.triangles - end + DT.add_triangle!(tri, i, j, k) + DT.add_triangle!(tri, T) + for ((a, b, c)) in ((i, j, k), (u, v, w)) + @test DT.get_adjacent(tri, a, b) == c + @test DT.get_adjacent(tri, b, c) == a + @test DT.get_adjacent(tri, c, a) == b + @test (a, b) ∈ DT.get_adjacent2vertex(tri, c) + @test (b, c) ∈ DT.get_adjacent2vertex(tri, a) + @test (c, a) ∈ DT.get_adjacent2vertex(tri, b) + @test a ∈ DT.get_neighbours(tri, b) && a ∈ DT.get_neighbours(tri, c) + @test b ∈ DT.get_neighbours(tri, a) && b ∈ DT.get_neighbours(tri, c) + @test c ∈ DT.get_neighbours(tri, a) && c ∈ DT.get_neighbours(tri, b) + @test (a, b, c) ∈ tri.triangles + end end @testset "Adding to empty triangulation, ghost edges included" begin - pts = rand(2, 500) - u, v, w = 37, 38, 73 - pts[:, u] .= 0.0 - pts[:, v] .= [1.0, 0.0] - pts[:, w] .= [0.0, 1.0] - tri = Triangulation(pts) - DT.add_triangle!(tri, (u, v, w); update_ghost_edges=true) - BI = DT.𝒢 - @test get_triangles(tri) == Set(((u, v, w), (w, v, BI), (v, u, BI), (u, w, BI))) - @test get_adjacent(get_adjacent(tri)) == Dict((u, v) => w, - (v, w) => u, - (w, u) => v, - (w, v) => BI, - (v, BI) => w, - (BI, w) => v, - (v, u) => BI, - (u, BI) => v, - (BI, v) => u, - (u, w) => BI, - (w, BI) => u, - (BI, u) => w) - @test get_adjacent2vertex(get_adjacent2vertex(tri)) == - Dict(BI => Set{NTuple{2,Int}}([(w, v), (v, u), (u, w)]), - u => Set{NTuple{2,Int}}([(v, w), (BI, v), (w, BI)]), - v => Set{NTuple{2,Int}}([(w, u), (BI, w), (u, BI)]), - w => Set{NTuple{2,Int}}([(u, v), (v, BI), (BI, u)])) - @test get_graph(tri).edges == - Set([(BI, v), (u, w), (u, v), (BI, w), (BI, u), (v, w)]) - @test get_graph(tri).vertices == Set([u, v, w, BI]) + pts = rand(2, 500) + u, v, w = 37, 38, 73 + pts[:, u] .= 0.0 + pts[:, v] .= [1.0, 0.0] + pts[:, w] .= [0.0, 1.0] + tri = Triangulation(pts) + DT.add_triangle!(tri, (u, v, w); update_ghost_edges = true) + BI = DT.𝒢 + @test get_triangles(tri) == Set(((u, v, w), (w, v, BI), (v, u, BI), (u, w, BI))) + @test get_adjacent(get_adjacent(tri)) == Dict( + (u, v) => w, + (v, w) => u, + (w, u) => v, + (w, v) => BI, + (v, BI) => w, + (BI, w) => v, + (v, u) => BI, + (u, BI) => v, + (BI, v) => u, + (u, w) => BI, + (w, BI) => u, + (BI, u) => w, + ) + @test get_adjacent2vertex(get_adjacent2vertex(tri)) == + Dict( + BI => Set{NTuple{2, Int}}([(w, v), (v, u), (u, w)]), + u => Set{NTuple{2, Int}}([(v, w), (BI, v), (w, BI)]), + v => Set{NTuple{2, Int}}([(w, u), (BI, w), (u, BI)]), + w => Set{NTuple{2, Int}}([(u, v), (v, BI), (BI, u)]), + ) + @test get_graph(tri).edges == + Set([(BI, v), (u, w), (u, v), (BI, w), (BI, u), (v, w)]) + @test get_graph(tri).vertices == Set([u, v, w, BI]) end @testset "Smaller example" begin - tri = example_triangulation() - i, j, k = 1, 3, 7 - DT.add_triangle!(tri, i, j, k) + tri = example_triangulation() + i, j, k = 1, 3, 7 + DT.add_triangle!(tri, i, j, k) - @testset "Adding an interior triangle" begin - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 3, 7), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3) - ]) + @testset "Adding an interior triangle" begin + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 3, 7), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + ], + ) + true_adj = + Dict( + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (4, 5) => DT.𝒢, (5, 2) => DT.𝒢, + (2, 3) => DT.𝒢, (3, 6) => DT.𝒢, + (6, 4) => DT.𝒢, + ) + true_adj2v = Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (7, 1), (1, 6)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 3)]), + ) + true_DG = [ + 0 0 1 1 1 1 1 0 + 0 0 0 1 1 1 1 1 + 1 0 0 1 0 1 0 0 + 1 1 1 0 0 1 1 1 + 1 1 0 0 0 1 1 0 + 1 1 1 1 1 0 0 0 + 1 1 0 1 1 0 0 0 + 0 1 0 1 0 0 0 0 + ] + true_DG = _make_graph_from_adjacency(true_DG, Dict(1:8 .=> [-1, (1:7)...])) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v + @test get_graph(tri) == true_DG + end + + @testset "Adding a boundary triangle with one boundary edge" begin + for (i, j, k) in ((5, 2, 8), (2, 8, 5), (8, 5, 2)) + local true_T, true_adj, true_adj2v, true_DG + _tri = deepcopy(tri) + DT.add_triangle!(_tri, i, j, k) + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 3, 7), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + (i, j, k), + ], + ) true_adj = - Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (4, 5) => DT.𝒢, (5, 2) => DT.𝒢, - (2, 3) => DT.𝒢, (3, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + Dict( + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, + (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, + (8, 2) => DT.𝒢, (2, 3) => DT.𝒢, + (3, 6) => DT.𝒢, (6, 4) => DT.𝒢, + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (7, 1), (1, 6)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 3)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 3), (3, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (8, 5)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (7, 1), (1, 6)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 3)]), + 8 => Set{NTuple{2, Int}}([(5, 2)]), ) - true_DG = [0 0 1 1 1 1 1 0 - 0 0 0 1 1 1 1 1 - 1 0 0 1 0 1 0 0 - 1 1 1 0 0 1 1 1 - 1 1 0 0 0 1 1 0 - 1 1 1 1 1 0 0 0 - 1 1 0 1 1 0 0 0 - 0 1 0 1 0 0 0 0] - true_DG = _make_graph_from_adjacency(true_DG, Dict(1:8 .=> [-1, (1:7)...])) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v - @test get_graph(tri) == true_DG - end - - @testset "Adding a boundary triangle with one boundary edge" begin - for (i, j, k) in ((5, 2, 8), (2, 8, 5), (8, 5, 2)) - local true_T, true_adj, true_adj2v, true_DG - _tri = deepcopy(tri) - DT.add_triangle!(_tri, i, j, k) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 3, 7), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3), - (i, j, k) - ]) - true_adj = - Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, - (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, - (8, 2) => DT.𝒢, (2, 3) => DT.𝒢, - (3, 6) => DT.𝒢, (6, 4) => DT.𝒢 - ) - true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 3), (3, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (8, 5)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (7, 1), (1, 6)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 3)]), - 8 => Set{NTuple{2,Int}}([(5, 2)]) - ) - true_DG = _make_graph_from_adjacency([ - 0 0 1 1 1 1 1 0 1 - 0 0 0 1 1 1 1 1 0 - 1 0 0 1 0 1 0 0 1 - 1 1 1 0 0 1 1 1 0 - 1 1 0 0 0 1 1 0 0 - 1 1 1 1 1 0 0 0 1 - 1 1 0 1 1 0 0 0 0 - 0 1 0 1 0 0 0 0 0 - 1 0 1 0 0 1 0 0 0 - ], Dict(1:9 .=> [-1, (1:8)...])) - DT.clear_empty_features!(_tri) - @test get_triangles(_tri) == true_T - @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(_tri) == true_adj2v - @test get_graph(_tri) == true_DG - end - DT.add_triangle!(tri, 5, 2, 8) # Get an actual copy for later, test is above - end + true_DG = _make_graph_from_adjacency( + [ + 0 0 1 1 1 1 1 0 1 + 0 0 0 1 1 1 1 1 0 + 1 0 0 1 0 1 0 0 1 + 1 1 1 0 0 1 1 1 0 + 1 1 0 0 0 1 1 0 0 + 1 1 1 1 1 0 0 0 1 + 1 1 0 1 1 0 0 0 0 + 0 1 0 1 0 0 0 0 0 + 1 0 1 0 0 1 0 0 0 + ], Dict(1:9 .=> [-1, (1:8)...]), + ) + DT.clear_empty_features!(_tri) + @test get_triangles(_tri) == true_T + @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(_tri) == true_adj2v + @test get_graph(_tri) == true_DG + end + DT.add_triangle!(tri, 5, 2, 8) # Get an actual copy for later, test is above + end - @testset "Adding a boundary triangle with two boundary edges" begin - for (i, j, k) in ((3, 6, 2), (6, 2, 3), (2, 3, 6)) - local true_T, true_adj, true_adj2v, true_DG - _tri = deepcopy(tri) - DT.add_triangle!(_tri, i, j, k) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 3, 7), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3), - (5, 2, 8), - (i, j, k) - ]) - true_adj = - Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, - (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, - (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, - (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) - true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (8, 5), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (7, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4), (2, 3)]), - 7 => Set{NTuple{2,Int}}([(1, 3)]), - 8 => Set{NTuple{2,Int}}([(5, 2)]) - ) - true_DG = _make_graph_from_adjacency([ - 0 0 1 0 1 1 1 0 1 - 0 0 0 1 1 1 1 1 0 - 1 0 0 1 0 1 1 0 1 - 0 1 1 0 0 1 1 1 0 - 1 1 0 0 0 1 1 0 0 - 1 1 1 1 1 0 0 0 1 - 1 1 1 1 1 0 0 0 0 - 0 1 0 1 0 0 0 0 0 - 1 0 1 0 0 1 0 0 0 - ], Dict(1:9 .=> [-1, (1:8)...])) - DT.clear_empty_features!(_tri) - @test get_triangles(_tri) == true_T - @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(_tri) == true_adj2v - @test get_graph(_tri) == true_DG - end - end + @testset "Adding a boundary triangle with two boundary edges" begin + for (i, j, k) in ((3, 6, 2), (6, 2, 3), (2, 3, 6)) + local true_T, true_adj, true_adj2v, true_DG + _tri = deepcopy(tri) + DT.add_triangle!(_tri, i, j, k) + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 3, 7), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + (5, 2, 8), + (i, j, k), + ], + ) + true_adj = + Dict( + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, + (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, + (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, + (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, + (6, 4) => DT.𝒢, + ) + true_adj2v = Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 7), (3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (8, 5), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (7, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4), (2, 3)]), + 7 => Set{NTuple{2, Int}}([(1, 3)]), + 8 => Set{NTuple{2, Int}}([(5, 2)]), + ) + true_DG = _make_graph_from_adjacency( + [ + 0 0 1 0 1 1 1 0 1 + 0 0 0 1 1 1 1 1 0 + 1 0 0 1 0 1 1 0 1 + 0 1 1 0 0 1 1 1 0 + 1 1 0 0 0 1 1 0 0 + 1 1 1 1 1 0 0 0 1 + 1 1 1 1 1 0 0 0 0 + 0 1 0 1 0 0 0 0 0 + 1 0 1 0 0 1 0 0 0 + ], Dict(1:9 .=> [-1, (1:8)...]), + ) + DT.clear_empty_features!(_tri) + @test get_triangles(_tri) == true_T + @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(_tri) == true_adj2v + @test get_graph(_tri) == true_DG + end + end end @testset "Empty triangulation" begin - tri = example_empty_triangulation() - true_T = Set{NTuple{3,Int}}([(1, 2, 3)]) - true_adj = - Dict((1, 2) => 3, (2, 3) => 1, (3, 1) => 2, - (3, 2) => DT.𝒢, (2, 1) => DT.𝒢, (1, 3) => DT.𝒢) - true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(3, 2), (2, 1), (1, 3)]), - 1 => Set{NTuple{2,Int}}([(2, 3)]), - 2 => Set{NTuple{2,Int}}([(3, 1)]), - 3 => Set{NTuple{2,Int}}([(1, 2)]) - ) - true_DG = _make_graph_from_adjacency([ - 0 1 1 1 - 1 0 1 1 - 1 1 0 1 - 1 1 1 0 - ], Dict(1:4 .=> [-1, 1, 2, 3])) - DT.add_triangle!(tri, 1, 2, 3) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v - @test get_graph(tri) == true_DG + tri = example_empty_triangulation() + true_T = Set{NTuple{3, Int}}([(1, 2, 3)]) + true_adj = + Dict( + (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, + (3, 2) => DT.𝒢, (2, 1) => DT.𝒢, (1, 3) => DT.𝒢, + ) + true_adj2v = Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(3, 2), (2, 1), (1, 3)]), + 1 => Set{NTuple{2, Int}}([(2, 3)]), + 2 => Set{NTuple{2, Int}}([(3, 1)]), + 3 => Set{NTuple{2, Int}}([(1, 2)]), + ) + true_DG = _make_graph_from_adjacency( + [ + 0 1 1 1 + 1 0 1 1 + 1 1 0 1 + 1 1 1 0 + ], Dict(1:4 .=> [-1, 1, 2, 3]), + ) + DT.add_triangle!(tri, 1, 2, 3) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v + @test get_graph(tri) == true_DG end @testset "Testing the boundary addition cases for updating ghost edges" begin - p1 = @SVector[0.0, 0.0] - p2 = @SVector[1.0, 0.0] - p3 = @SVector[0.0, 1.0] - pts = [p1, p2, p3] - tri = Triangulation(pts) - DT.add_triangle!(tri, 1, 2, 3; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([(1, 2, 3), + p1 = @SVector[0.0, 0.0] + p2 = @SVector[1.0, 0.0] + p3 = @SVector[0.0, 1.0] + pts = [p1, p2, p3] + tri = Triangulation(pts) + DT.add_triangle!(tri, 1, 2, 3; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), (2, 1, DT.𝒢), (1, 3, DT.𝒢), - (3, 2, DT.𝒢)]) - true_adj = DT.Adjacent( - Dict( - (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, - (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, - (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, - (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2 - )) - true_adj2v = DT.Adjacent2Vertex( - Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(2, 1), (1, 3), (3, 2)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 3)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (DT.𝒢, 1), (2, DT.𝒢)]) - ) - ) - true_DG = DT.Graph{Int}() - DT.add_neighbour!(true_DG, DT.𝒢, [1, 2, 3]...) - DT.add_neighbour!(true_DG, 1, [2, 3]...) - DT.add_neighbour!(true_DG, 2, [1, 3]...) - DT.add_neighbour!(true_DG, 3, [1, 2]...) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex - @test get_graph(tri) == true_DG - p4 = @SVector[1.7, 1.7] - push!(pts, p4) - DT.add_triangle!(tri, 3, 2, 4; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([(1, 2, 3), + (3, 2, DT.𝒢), + ], + ) + true_adj = DT.Adjacent( + Dict( + (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, + (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, + (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, + (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2, + ), + ) + true_adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(2, 1), (1, 3), (3, 2)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 3)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (DT.𝒢, 1), (2, DT.𝒢)]), + ), + ) + true_DG = DT.Graph{Int}() + DT.add_neighbour!(true_DG, DT.𝒢, [1, 2, 3]...) + DT.add_neighbour!(true_DG, 1, [2, 3]...) + DT.add_neighbour!(true_DG, 2, [1, 3]...) + DT.add_neighbour!(true_DG, 3, [1, 2]...) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex + @test get_graph(tri) == true_DG + p4 = @SVector[1.7, 1.7] + push!(pts, p4) + DT.add_triangle!(tri, 3, 2, 4; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), (2, 1, DT.𝒢), (1, 3, DT.𝒢), (3, 4, DT.𝒢), (4, 2, DT.𝒢), - (3, 2, 4)]) - true_adj = DT.Adjacent( - Dict( - (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, - (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, - (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, - (3, 4) => DT.𝒢, (4, DT.𝒢) => 3, (DT.𝒢, 3) => 4, - (4, 2) => DT.𝒢, (2, DT.𝒢) => 4, (DT.𝒢, 4) => 2, - (3, 2) => 4, (2, 4) => 3, (4, 3) => 2 - )) - true_adj2v = DT.Adjacent2Vertex( - Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(2, 1), (1, 3), (3, 4), (4, 2)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 4), (4, 3)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (DT.𝒢, 1), (4, DT.𝒢), (2, 4)]), - 4 => Set{NTuple{2,Int}}([(DT.𝒢, 3), (2, DT.𝒢), (3, 2)]) - ) - ) - true_DG = DT.Graph{Int}() - DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 4, 2]...) - DT.add_neighbour!(true_DG, 1, [2, 3]...) - DT.add_neighbour!(true_DG, 2, [1, 3, 4]...) - DT.add_neighbour!(true_DG, 3, [1, 2, 4]...) - DT.add_neighbour!(true_DG, 4, [2, 3]...) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex - @test get_graph(tri) == true_DG - p5 = @SVector[1.0, 3.0] - p6 = @SVector[3.0, 1.0] - push!(pts, p5, p6) - DT.add_triangle!(tri, 3, 4, 5; update_ghost_edges=true) - DT.add_triangle!(tri, 4, 2, 6; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([ + (3, 2, 4), + ], + ) + true_adj = DT.Adjacent( + Dict( + (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, + (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, + (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, + (3, 4) => DT.𝒢, (4, DT.𝒢) => 3, (DT.𝒢, 3) => 4, + (4, 2) => DT.𝒢, (2, DT.𝒢) => 4, (DT.𝒢, 4) => 2, + (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, + ), + ) + true_adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(2, 1), (1, 3), (3, 4), (4, 2)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 4), (4, 3)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (DT.𝒢, 1), (4, DT.𝒢), (2, 4)]), + 4 => Set{NTuple{2, Int}}([(DT.𝒢, 3), (2, DT.𝒢), (3, 2)]), + ), + ) + true_DG = DT.Graph{Int}() + DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 4, 2]...) + DT.add_neighbour!(true_DG, 1, [2, 3]...) + DT.add_neighbour!(true_DG, 2, [1, 3, 4]...) + DT.add_neighbour!(true_DG, 3, [1, 2, 4]...) + DT.add_neighbour!(true_DG, 4, [2, 3]...) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex + @test get_graph(tri) == true_DG + p5 = @SVector[1.0, 3.0] + p6 = @SVector[3.0, 1.0] + push!(pts, p5, p6) + DT.add_triangle!(tri, 3, 4, 5; update_ghost_edges = true) + DT.add_triangle!(tri, 4, 2, 6; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ (1, 2, 3), (3, 2, 4), (3, 4, 5), @@ -352,46 +383,49 @@ end (3, 5, DT.𝒢), (5, 4, DT.𝒢), (4, 6, DT.𝒢), - (6, 2, DT.𝒢) - ]) - true_adj = DT.Adjacent( - Dict( - (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, - (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, - (3, 4) => 5, (4, 5) => 3, (5, 3) => 4, - (4, 2) => 6, (2, 6) => 4, (6, 4) => 2, - (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, - (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, - (3, 5) => DT.𝒢, (5, DT.𝒢) => 3, (DT.𝒢, 3) => 5, - (5, 4) => DT.𝒢, (4, DT.𝒢) => 5, (DT.𝒢, 5) => 4, - (4, 6) => DT.𝒢, (6, DT.𝒢) => 4, (DT.𝒢, 4) => 6, - (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2 - )) - true_adj2v = DT.Adjacent2Vertex( - Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 4), (4, 6), (6, 2), (2, 1)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), - 4 => Set{NTuple{2,Int}}([(3, 2), (5, 3), (2, 6), (DT.𝒢, 5), (6, DT.𝒢)]), - 5 => Set{NTuple{2,Int}}([(3, 4), (DT.𝒢, 3), (4, DT.𝒢)]), - 6 => Set{NTuple{2,Int}}([(4, 2), (DT.𝒢, 4), (2, DT.𝒢)]) - ) - ) - true_DG = DT.Graph{Int}() - DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 5, 4, 6, 2]...) - DT.add_neighbour!(true_DG, 1, [2, 3]...) - DT.add_neighbour!(true_DG, 2, [1, 3, 4, 6]...) - DT.add_neighbour!(true_DG, 3, [1, 2, 4, 5]...) - DT.add_neighbour!(true_DG, 4, [2, 3, 5, 6]...) - DT.add_neighbour!(true_DG, 5, [3, 4]...) - DT.add_neighbour!(true_DG, 6, [2, 4]...) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex - @test get_graph(tri) == true_DG - DT.add_triangle!(tri, 5, 4, 6; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([ + (6, 2, DT.𝒢), + ], + ) + true_adj = DT.Adjacent( + Dict( + (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, + (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, + (3, 4) => 5, (4, 5) => 3, (5, 3) => 4, + (4, 2) => 6, (2, 6) => 4, (6, 4) => 2, + (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, + (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, + (3, 5) => DT.𝒢, (5, DT.𝒢) => 3, (DT.𝒢, 3) => 5, + (5, 4) => DT.𝒢, (4, DT.𝒢) => 5, (DT.𝒢, 5) => 4, + (4, 6) => DT.𝒢, (6, DT.𝒢) => 4, (DT.𝒢, 4) => 6, + (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2, + ), + ) + true_adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 4), (4, 6), (6, 2), (2, 1)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), + 4 => Set{NTuple{2, Int}}([(3, 2), (5, 3), (2, 6), (DT.𝒢, 5), (6, DT.𝒢)]), + 5 => Set{NTuple{2, Int}}([(3, 4), (DT.𝒢, 3), (4, DT.𝒢)]), + 6 => Set{NTuple{2, Int}}([(4, 2), (DT.𝒢, 4), (2, DT.𝒢)]), + ), + ) + true_DG = DT.Graph{Int}() + DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 5, 4, 6, 2]...) + DT.add_neighbour!(true_DG, 1, [2, 3]...) + DT.add_neighbour!(true_DG, 2, [1, 3, 4, 6]...) + DT.add_neighbour!(true_DG, 3, [1, 2, 4, 5]...) + DT.add_neighbour!(true_DG, 4, [2, 3, 5, 6]...) + DT.add_neighbour!(true_DG, 5, [3, 4]...) + DT.add_neighbour!(true_DG, 6, [2, 4]...) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex + @test get_graph(tri) == true_DG + DT.add_triangle!(tri, 5, 4, 6; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ (1, 2, 3), (3, 2, 4), (3, 4, 5), @@ -401,64 +435,66 @@ end (1, 3, DT.𝒢), (3, 5, DT.𝒢), (5, 6, DT.𝒢), - (6, 2, DT.𝒢) - ]) - true_adj = DT.Adjacent( - Dict( - (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, - (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, - (3, 4) => 5, (4, 5) => 3, (5, 3) => 4, - (4, 2) => 6, (2, 6) => 4, (6, 4) => 2, - (5, 4) => 6, (4, 6) => 5, (6, 5) => 4, - (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, - (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, - (3, 5) => DT.𝒢, (5, DT.𝒢) => 3, (DT.𝒢, 3) => 5, - (5, 6) => DT.𝒢, (6, DT.𝒢) => 5, (DT.𝒢, 5) => 6, - (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2 - )) - true_adj2v = DT.Adjacent2Vertex( - Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 6), (6, 2), (2, 1)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), - 4 => Set{NTuple{2,Int}}([(3, 2), (2, 6), (6, 5), (5, 3)]), - 5 => Set{NTuple{2,Int}}([(3, 4), (4, 6), (6, DT.𝒢), (DT.𝒢, 3)]), - 6 => Set{NTuple{2,Int}}([(4, 2), (5, 4), (DT.𝒢, 5), (2, DT.𝒢)]) - ) - ) - true_DG = DT.Graph{Int}() - DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 5, 6, 2]...) - DT.add_neighbour!(true_DG, 1, [2, 3]...) - DT.add_neighbour!(true_DG, 2, [1, 3, 4, 6]...) - DT.add_neighbour!(true_DG, 3, [1, 2, 4, 5]...) - DT.add_neighbour!(true_DG, 4, [2, 3, 5, 6]...) - DT.add_neighbour!(true_DG, 5, [3, 4, 6]...) - DT.add_neighbour!(true_DG, 6, [2, 4, 5]...) - @test get_triangles(tri) == true_T - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex - @test get_graph(tri) == true_DG - DT.convex_hull!(tri; reconstruct=false) - DT.compute_representative_points!(tri) - @test validate_triangulation(tri) + (6, 2, DT.𝒢), + ], + ) + true_adj = DT.Adjacent( + Dict( + (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, + (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, + (3, 4) => 5, (4, 5) => 3, (5, 3) => 4, + (4, 2) => 6, (2, 6) => 4, (6, 4) => 2, + (5, 4) => 6, (4, 6) => 5, (6, 5) => 4, + (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, + (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, + (3, 5) => DT.𝒢, (5, DT.𝒢) => 3, (DT.𝒢, 3) => 5, + (5, 6) => DT.𝒢, (6, DT.𝒢) => 5, (DT.𝒢, 5) => 6, + (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2, + ), + ) + true_adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 6), (6, 2), (2, 1)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), + 4 => Set{NTuple{2, Int}}([(3, 2), (2, 6), (6, 5), (5, 3)]), + 5 => Set{NTuple{2, Int}}([(3, 4), (4, 6), (6, DT.𝒢), (DT.𝒢, 3)]), + 6 => Set{NTuple{2, Int}}([(4, 2), (5, 4), (DT.𝒢, 5), (2, DT.𝒢)]), + ), + ) + true_DG = DT.Graph{Int}() + DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 5, 6, 2]...) + DT.add_neighbour!(true_DG, 1, [2, 3]...) + DT.add_neighbour!(true_DG, 2, [1, 3, 4, 6]...) + DT.add_neighbour!(true_DG, 3, [1, 2, 4, 5]...) + DT.add_neighbour!(true_DG, 4, [2, 3, 5, 6]...) + DT.add_neighbour!(true_DG, 5, [3, 4, 6]...) + DT.add_neighbour!(true_DG, 6, [2, 4, 5]...) + @test get_triangles(tri) == true_T + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex + @test get_graph(tri) == true_DG + DT.convex_hull!(tri; reconstruct = false) + DT.compute_representative_points!(tri) + @test validate_triangulation(tri) end @testset "Larger example" begin - p1 = @SVector[-3.32, 3.53] - p2 = @SVector[-5.98, 2.17] - p3 = @SVector[-6.36, -1.55] - p4 = @SVector[-2.26, -4.31] - p5 = @SVector[6.34, -3.23] - p6 = @SVector[-3.24, 1.01] - p7 = @SVector[0.14, -1.51] - p8 = @SVector[0.2, 1.25] - p9 = @SVector[1.0, 4.0] - p10 = @SVector[4.74, 2.21] - p11 = @SVector[2.32, -0.27] - pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] - tri = Triangulation(pts) - for (i, j, k) in ( + p1 = @SVector[-3.32, 3.53] + p2 = @SVector[-5.98, 2.17] + p3 = @SVector[-6.36, -1.55] + p4 = @SVector[-2.26, -4.31] + p5 = @SVector[6.34, -3.23] + p6 = @SVector[-3.24, 1.01] + p7 = @SVector[0.14, -1.51] + p8 = @SVector[0.2, 1.25] + p9 = @SVector[1.0, 4.0] + p10 = @SVector[4.74, 2.21] + p11 = @SVector[2.32, -0.27] + pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] + tri = Triangulation(pts) + for (i, j, k) in ( (1, 2, 6), (1, 6, 8), (9, 1, 8), @@ -471,11 +507,12 @@ end (6, 4, 7), (7, 4, 5), (11, 7, 5), - (10, 11, 5) - ) - DT.add_triangle!(tri, i, j, k; update_ghost_edges=true) - end - true_T = Set{NTuple{3,Int}}([ + (10, 11, 5), + ) + DT.add_triangle!(tri, i, j, k; update_ghost_edges = true) + end + true_T = Set{NTuple{3, Int}}( + [ (1, 6, 8), (1, 8, 9), (9, 8, 10), @@ -495,54 +532,55 @@ end (10, 5, DT.𝒢), (5, 4, DT.𝒢), (4, 3, DT.𝒢), - (3, 2, DT.𝒢) - ]) - true_adj = DT.Adjacent( - Dict( - (1, 6) => 8, (6, 8) => 1, (8, 1) => 6, - (1, 8) => 9, (8, 9) => 1, (9, 1) => 8, - (9, 8) => 10, (8, 10) => 9, (10, 9) => 8, - (10, 8) => 11, (8, 11) => 10, (11, 10) => 8, - (10, 11) => 5, (11, 5) => 10, (5, 10) => 11, - (11, 7) => 5, (7, 5) => 11, (5, 11) => 7, - (7, 4) => 5, (4, 5) => 7, (5, 7) => 4, - (7, 6) => 4, (6, 4) => 7, (4, 7) => 6, - (6, 3) => 4, (3, 4) => 6, (4, 6) => 3, - (6, 2) => 3, (2, 3) => 6, (3, 6) => 2, - (1, 2) => 6, (2, 6) => 1, (6, 1) => 2, - (8, 6) => 7, (6, 7) => 8, (7, 8) => 6, - (8, 7) => 11, (7, 11) => 8, (11, 8) => 7, - (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, - (1, 9) => DT.𝒢, (9, DT.𝒢) => 1, (DT.𝒢, 1) => 9, - (9, 10) => DT.𝒢, (10, DT.𝒢) => 9, (DT.𝒢, 9) => 10, - (10, 5) => DT.𝒢, (5, DT.𝒢) => 10, (DT.𝒢, 10) => 5, - (5, 4) => DT.𝒢, (4, DT.𝒢) => 5, (DT.𝒢, 5) => 4, - (4, 3) => DT.𝒢, (3, DT.𝒢) => 4, (DT.𝒢, 4) => 3, - (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2 - ) - ) - true_adj2v = DT.Adjacent2Vertex{Int,Set{NTuple{2,Int}}}() - for (ij, k) in true_adj.adjacent - DT.add_adjacent2vertex!(true_adj2v, k, ij) - end - true_DG = DT.Graph{Int}() - DT.add_neighbour!(true_DG, DT.𝒢, 1, 9, 10, 5, 4, 3, 2) - DT.add_neighbour!(true_DG, 1, 2, 6, 8, 9) - DT.add_neighbour!(true_DG, 2, 1, 6, 3) - DT.add_neighbour!(true_DG, 3, 2, 6, 4) - DT.add_neighbour!(true_DG, 4, 6, 3, 7, 5) - DT.add_neighbour!(true_DG, 5, 10, 11, 7, 4) - DT.add_neighbour!(true_DG, 6, 1, 2, 3, 4, 7, 8) - DT.add_neighbour!(true_DG, 7, 8, 6, 4, 5, 11) - DT.add_neighbour!(true_DG, 8, 1, 6, 7, 11, 10, 9) - DT.add_neighbour!(true_DG, 9, 1, 8, 10) - DT.add_neighbour!(true_DG, 10, 9, 8, 11, 5) - DT.add_neighbour!(true_DG, 11, 10, 8, 7, 5) - @test DT.compare_triangle_collections(get_triangles(tri), true_T) - @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent - @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex - @test get_graph(tri) == true_DG - DT.convex_hull!(tri; reconstruct=false) - DT.compute_representative_points!(tri) - @test validate_triangulation(tri) -end \ No newline at end of file + (3, 2, DT.𝒢), + ], + ) + true_adj = DT.Adjacent( + Dict( + (1, 6) => 8, (6, 8) => 1, (8, 1) => 6, + (1, 8) => 9, (8, 9) => 1, (9, 1) => 8, + (9, 8) => 10, (8, 10) => 9, (10, 9) => 8, + (10, 8) => 11, (8, 11) => 10, (11, 10) => 8, + (10, 11) => 5, (11, 5) => 10, (5, 10) => 11, + (11, 7) => 5, (7, 5) => 11, (5, 11) => 7, + (7, 4) => 5, (4, 5) => 7, (5, 7) => 4, + (7, 6) => 4, (6, 4) => 7, (4, 7) => 6, + (6, 3) => 4, (3, 4) => 6, (4, 6) => 3, + (6, 2) => 3, (2, 3) => 6, (3, 6) => 2, + (1, 2) => 6, (2, 6) => 1, (6, 1) => 2, + (8, 6) => 7, (6, 7) => 8, (7, 8) => 6, + (8, 7) => 11, (7, 11) => 8, (11, 8) => 7, + (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, + (1, 9) => DT.𝒢, (9, DT.𝒢) => 1, (DT.𝒢, 1) => 9, + (9, 10) => DT.𝒢, (10, DT.𝒢) => 9, (DT.𝒢, 9) => 10, + (10, 5) => DT.𝒢, (5, DT.𝒢) => 10, (DT.𝒢, 10) => 5, + (5, 4) => DT.𝒢, (4, DT.𝒢) => 5, (DT.𝒢, 5) => 4, + (4, 3) => DT.𝒢, (3, DT.𝒢) => 4, (DT.𝒢, 4) => 3, + (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2, + ), + ) + true_adj2v = DT.Adjacent2Vertex{Int, Set{NTuple{2, Int}}}() + for (ij, k) in true_adj.adjacent + DT.add_adjacent2vertex!(true_adj2v, k, ij) + end + true_DG = DT.Graph{Int}() + DT.add_neighbour!(true_DG, DT.𝒢, 1, 9, 10, 5, 4, 3, 2) + DT.add_neighbour!(true_DG, 1, 2, 6, 8, 9) + DT.add_neighbour!(true_DG, 2, 1, 6, 3) + DT.add_neighbour!(true_DG, 3, 2, 6, 4) + DT.add_neighbour!(true_DG, 4, 6, 3, 7, 5) + DT.add_neighbour!(true_DG, 5, 10, 11, 7, 4) + DT.add_neighbour!(true_DG, 6, 1, 2, 3, 4, 7, 8) + DT.add_neighbour!(true_DG, 7, 8, 6, 4, 5, 11) + DT.add_neighbour!(true_DG, 8, 1, 6, 7, 11, 10, 9) + DT.add_neighbour!(true_DG, 9, 1, 8, 10) + DT.add_neighbour!(true_DG, 10, 9, 8, 11, 5) + DT.add_neighbour!(true_DG, 11, 10, 8, 7, 5) + @test DT.compare_triangle_collections(get_triangles(tri), true_T) + @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent + @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex + @test get_graph(tri) == true_DG + DT.convex_hull!(tri; reconstruct = false) + DT.compute_representative_points!(tri) + @test validate_triangulation(tri) +end diff --git a/test/operations/delete_ghost_triangles.jl b/test/operations/delete_ghost_triangles.jl index 0b4d963ff..39b150f78 100644 --- a/test/operations/delete_ghost_triangles.jl +++ b/test/operations/delete_ghost_triangles.jl @@ -17,19 +17,19 @@ end @testset "Making sure the ghost triangles are correctly adjusted on disjoint sets" begin θ = LinRange(0, 2π, 100) |> collect θ[end] = 0 - xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() + xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() cx = 0.0 for i in 1:2 - push!(xy, [[(cx + cos(θ) + 1e-3rand(), sin(θ) + 1e-3rand()) for θ in θ]]) # use perturbations to also do this check without ExactPredicates loaded. iszero makes the boundary closed - push!(xy, [[(cx + 0.5cos(θ) + 1e-3rand(), 0.5sin(θ) + 1e-3rand()) for θ in reverse(θ)]]) + push!(xy, [[(cx + cos(θ) + 1.0e-3rand(), sin(θ) + 1.0e-3rand()) for θ in θ]]) # use perturbations to also do this check without ExactPredicates loaded. iszero makes the boundary closed + push!(xy, [[(cx + 0.5cos(θ) + 1.0e-3rand(), 0.5sin(θ) + 1.0e-3rand()) for θ in reverse(θ)]]) cx += 3.0 end xy[1][1][end] = xy[1][1][1] - xy[2][1][end] = xy[2][1][1] + xy[2][1][end] = xy[2][1][1] xy[3][1][end] = xy[3][1][1] - xy[4][1][end] = xy[4][1][1] + xy[4][1][end] = xy[4][1][1] boundary_nodes, points = convert_boundary_points_to_indices(xy) - tri = triangulate(points; boundary_nodes=boundary_nodes) + tri = triangulate(points; boundary_nodes = boundary_nodes) @test validate_triangulation(tri) validate_statistics(tri) -end \ No newline at end of file +end diff --git a/test/operations/delete_holes.jl b/test/operations/delete_holes.jl index 91fd648e3..71152d609 100644 --- a/test/operations/delete_holes.jl +++ b/test/operations/delete_holes.jl @@ -13,43 +13,45 @@ using Preferences rng = StableRNG(1919) existing_pts = [(rand(rng), rand(rng)) for _ in 1:15] push!(existing_pts, (0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)) - nodes, points = convert_boundary_points_to_indices([p1, p2, p3, p4, p1], existing_points=existing_pts) - tri = triangulate(points; boundary_nodes=nodes, delete_holes=false, delete_ghosts=false, rng) + nodes, points = convert_boundary_points_to_indices([p1, p2, p3, p4, p1], existing_points = existing_pts) + tri = triangulate(points; boundary_nodes = nodes, delete_holes = false, delete_ghosts = false, rng) points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((17, 1, DT.𝒢, 19, 12, 3, 8, 16, 15, 5, 11, 18, 9, 4)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - true_triangles_to_delete = Set(( - (1, 22, 4), - (1, 4, 19), - (1, 19, 17), - (1, 17, 12), - (1, 12, 22), - (3, 8, 23), - (3, 23, 17), - (3, 17, 8), - (4, 11, 19), - (4, 22, 21), - (4, 21, 11), - (5, 18, 11), - (5, 11, 21), - (5, 21, 9), - (5, 9, 15), - (5, 15, 16), - (8, 16, 20), - (8, 17, 16), - (8, 20, 23), - (9, 20, 15), - (9, 21, 20), - (5, 16, 18), - (11, 18, 19), - (12, 23, 22), - (12, 17, 23), - (15, 20, 16), - (17, 19, DT.𝒢), - (19, 18, DT.𝒢), - (18, 16, DT.𝒢), - (16, 17, DT.𝒢) - )) + true_triangles_to_delete = Set( + ( + (1, 22, 4), + (1, 4, 19), + (1, 19, 17), + (1, 17, 12), + (1, 12, 22), + (3, 8, 23), + (3, 23, 17), + (3, 17, 8), + (4, 11, 19), + (4, 22, 21), + (4, 21, 11), + (5, 18, 11), + (5, 11, 21), + (5, 21, 9), + (5, 9, 15), + (5, 15, 16), + (8, 16, 20), + (8, 17, 16), + (8, 20, 23), + (9, 20, 15), + (9, 21, 20), + (5, 16, 18), + (11, 18, 19), + (12, 23, 22), + (12, 17, 23), + (15, 20, 16), + (17, 19, DT.𝒢), + (19, 18, DT.𝒢), + (18, 16, DT.𝒢), + (16, 17, DT.𝒢), + ), + ) @test DT.compare_triangle_collections(triangles_to_delete, true_triangles_to_delete) p1 = (0.2, 0.2) @@ -59,8 +61,8 @@ using Preferences rng = StableRNG(1919) existing_pts = [(rand(rng), rand(rng)) for _ in 1:15] push!(existing_pts, (0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)) - nodes, points = convert_boundary_points_to_indices([p1, p2, p3, p4, p1], existing_points=existing_pts) - tri = triangulate(points; boundary_nodes=nodes, rng) + nodes, points = convert_boundary_points_to_indices([p1, p2, p3, p4, p1], existing_points = existing_pts) + tri = triangulate(points; boundary_nodes = nodes, rng) @test validate_triangulation(tri) validate_statistics(tri) end @@ -98,46 +100,48 @@ end f1 = (5.0, 4.3) pts = [[[d, e, f, a, b, f1, e1, c1, d1, c, d]], [[g, h, i, ℓ, k, j, g]]] existing_points = [m, n, o, p, q, r, s, t, u, v, w, z, a1, b1] - nodes, points = convert_boundary_points_to_indices(pts; existing_points=existing_points) - tri = triangulate(points; boundary_nodes=nodes, delete_holes=false, delete_ghosts=false) + nodes, points = convert_boundary_points_to_indices(pts; existing_points = existing_points) + tri = triangulate(points; boundary_nodes = nodes, delete_holes = false, delete_ghosts = false) points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((12, 11, 14, 3, 13, 4, 6, 7, DT.𝒢)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - true_triangles_to_delete = Set(( - (15, 17, 12), - (12, 17, 11), - (12, 11, 16), - (11, 17, 16), - (25, 30, 29), - (29, 28, 6), - (25, 29, 6), - (25, 6, 26), - (6, 7, 26), - (6, 28, 7), - (7, 28, 27), - (26, 7, 27), - (20, 19, 13), - (13, 19, 14), - (13, 14, 3), - (20, 13, 3), - (20, 3, 4), - (21, 20, 4), - (24, 23, 22), - (24, 22, 21), - (24, 21, 4), - (15, 24, DT.𝒢), - (24, 4, DT.𝒢), - (4, 3, DT.𝒢), - (3, 14, DT.𝒢), - (14, 19, DT.𝒢), - (19, 18, DT.𝒢), - (18, 17, DT.𝒢), - (17, 15, DT.𝒢), - (12, 16, 15) - )) + true_triangles_to_delete = Set( + ( + (15, 17, 12), + (12, 17, 11), + (12, 11, 16), + (11, 17, 16), + (25, 30, 29), + (29, 28, 6), + (25, 29, 6), + (25, 6, 26), + (6, 7, 26), + (6, 28, 7), + (7, 28, 27), + (26, 7, 27), + (20, 19, 13), + (13, 19, 14), + (13, 14, 3), + (20, 13, 3), + (20, 3, 4), + (21, 20, 4), + (24, 23, 22), + (24, 22, 21), + (24, 21, 4), + (15, 24, DT.𝒢), + (24, 4, DT.𝒢), + (4, 3, DT.𝒢), + (3, 14, DT.𝒢), + (14, 19, DT.𝒢), + (19, 18, DT.𝒢), + (18, 17, DT.𝒢), + (17, 15, DT.𝒢), + (12, 16, 15), + ), + ) @test DT.compare_triangle_collections(triangles_to_delete, true_triangles_to_delete) - tri = triangulate(points; boundary_nodes=nodes) + tri = triangulate(points; boundary_nodes = nodes) @test validate_triangulation(tri) validate_statistics(tri) end @@ -152,50 +156,62 @@ if !USE_INEXACTPREDICATES p6 = (0.8, 0.2) p7 = (0.8, 0.8) pts = [p1, p2, p3, p4, p5, p6, p7] - tri = triangulate(pts, boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]], delete_holes=false, delete_ghosts=false) + tri = triangulate(pts, boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]], delete_holes = false, delete_ghosts = false) @test num_ghost_triangles(tri) == 4 @test num_ghost_edges(tri) == 4 points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((DT.𝒢,)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - @test DT.compare_triangle_collections(triangles_to_delete, Set(( - (1, 4, DT.𝒢), - (4, 3, DT.𝒢), - (3, 2, DT.𝒢), - (2, 1, DT.𝒢), - (5, 6, 7) - ))) - tri = triangulate(pts; boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]]) + @test DT.compare_triangle_collections( + triangles_to_delete, Set( + ( + (1, 4, DT.𝒢), + (4, 3, DT.𝒢), + (3, 2, DT.𝒢), + (2, 1, DT.𝒢), + (5, 6, 7), + ), + ), + ) + tri = triangulate(pts; boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]]) @test validate_triangulation(tri) validate_statistics(tri) - tri = triangulate(pts, boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7], [7, 6, 5]]], delete_holes=false, delete_ghosts=false) + tri = triangulate(pts, boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7], [7, 6, 5]]], delete_holes = false, delete_ghosts = false) points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((DT.𝒢,)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - @test DT.compare_triangle_collections(triangles_to_delete, Set(( - (1, 4, DT.𝒢), - (4, 3, DT.𝒢), - (3, 2, DT.𝒢), - (2, 1, DT.𝒢), - (5, 6, 7) - ))) - tri = triangulate(pts; boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7], [7, 6, 5]]]) + @test DT.compare_triangle_collections( + triangles_to_delete, Set( + ( + (1, 4, DT.𝒢), + (4, 3, DT.𝒢), + (3, 2, DT.𝒢), + (2, 1, DT.𝒢), + (5, 6, 7), + ), + ), + ) + tri = triangulate(pts; boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7], [7, 6, 5]]]) @test validate_triangulation(tri) validate_statistics(tri) - tri = triangulate(pts, boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]], delete_holes=false, delete_ghosts=false) + tri = triangulate(pts, boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]], delete_holes = false, delete_ghosts = false) points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((DT.𝒢,)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - @test DT.compare_triangle_collections(triangles_to_delete, Set(( - (1, 4, DT.𝒢), - (4, 3, DT.𝒢), - (3, 2, DT.𝒢), - (2, 1, DT.𝒢), - (5, 6, 7) - ))) - tri = triangulate(pts; boundary_nodes=[[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]]) + @test DT.compare_triangle_collections( + triangles_to_delete, Set( + ( + (1, 4, DT.𝒢), + (4, 3, DT.𝒢), + (3, 2, DT.𝒢), + (2, 1, DT.𝒢), + (5, 6, 7), + ), + ), + ) + tri = triangulate(pts; boundary_nodes = [[[1, 2, 3, 4, 1]], [[5, 7, 6, 5]]]) @test validate_triangulation(tri) validate_statistics(tri) end @@ -208,30 +224,32 @@ end y = @. a * (2sin(t) - sin(2t)) points = [2.4 -0.152786404500042 -1.047213595499958 -1.047213595499958 -0.1527864045000426; 0.0 1.051462224238267 1.70130161670408 -1.70130161670408 -1.051462224238268] bn_nodes = [1, 2, 3, 4, 5, 1] - tri = triangulate(points; boundary_nodes=bn_nodes, delete_ghosts=false, delete_holes=false) + tri = triangulate(points; boundary_nodes = bn_nodes, delete_ghosts = false, delete_holes = false) points_to_process = DT.find_all_points_to_delete(tri) @test points_to_process == Set((DT.𝒢,)) triangles_to_delete = DT.find_all_triangles_to_delete(tri, points_to_process) - true_triangles_to_delete = Set(( - (3, 2, 1), - (4, 1, 5), - (3, 1, DT.𝒢), - (1, 4, DT.𝒢), - (4, 3, DT.𝒢) - )) + true_triangles_to_delete = Set( + ( + (3, 2, 1), + (4, 1, 5), + (3, 1, DT.𝒢), + (1, 4, DT.𝒢), + (4, 3, DT.𝒢), + ), + ) @test DT.compare_triangle_collections(triangles_to_delete, true_triangles_to_delete) - tri = triangulate(points; boundary_nodes=bn_nodes) + tri = triangulate(points; boundary_nodes = bn_nodes) @test validate_triangulation(tri) validate_statistics(tri) a = 4 / 5 t = LinRange(0, 2π, 100) x = @. a * (2cos(t) + cos(2t)) - y = @. a * (2sin(t) - sin(2t)) + y = @. a * (2sin(t) - sin(2t)) points = [2.4 2.390342532619651 2.361486661646358 2.313780262033189 2.247797423889998 2.16432999441036 2.064375923309772 1.949124594926212 1.819939377400058 1.678337662931399 1.525968712312314 1.364589651123909 1.196039993627106 1.022215093005981 0.8450389328830836 0.6664366846599798 0.4883074580921845 0.3124976685434042 0.1407754336467903 -0.02519360519360872 -0.1838686646186263 -0.333854062108855 -0.473917012361638 -0.6030027096667079 -0.7202464727404799 -0.824982776042241 -0.9167510419119772 -0.9952981201288541 -1.060577434849961 -1.112744832492037 -1.152151217102105 -1.179332111274063 -1.194994329879372 -1.2 -1.19534820274028 -1.182154550372295 -1.161629044931084 -1.13505259139796 -1.103752559560399 -1.069077803180918 -1.032373553014235 -0.994956601357817 -0.958091190190919 -0.9229660026456057 -0.8906726387622712 -0.8621859315182511 -0.8383464283873544 -0.8198453276894746 -0.8072121183067701 -0.8008051266355886 -0.8008051266355887 -0.8072121183067701 -0.8198453276894746 -0.8383464283873544 -0.8621859315182508 -0.890672638762271 -0.9229660026456055 -0.9580911901909194 -0.9949566013578169 -1.032373553014235 -1.069077803180918 -1.103752559560399 -1.135052591397961 -1.161629044931084 -1.182154550372295 -1.19534820274028 -1.2 -1.194994329879372 -1.179332111274063 -1.152151217102105 -1.112744832492038 -1.060577434849961 -0.9952981201288543 -0.9167510419119774 -0.8249827760422405 -0.7202464727404799 -0.6030027096667084 -0.473917012361639 -0.3338540621088567 -0.1838686646186263 -0.02519360519360934 0.1407754336467914 0.3124976685434047 0.4883074580921845 0.6664366846599791 0.8450389328830821 1.022215093005981 1.196039993627106 1.364589651123908 1.525968712312312 1.678337662931397 1.819939377400058 1.949124594926211 2.064375923309773 2.16432999441036 2.247797423889998 2.313780262033188 2.361486661646357 2.390342532619651 0.3170611563256605 0.3222593190661471 -0.6183519451946706 -0.6497375598908914 -0.03601883360826612 0.6813132651727021 -0.6442990922286358 0.677301056434819 -0.03212472989883586 1.049402030184789 -0.6932272745230642 -0.3561747556617257 1.050855112561903 -0.3586613134669976 -0.6921937990949052 -0.7738275096391242 1.420372082515759 -0.6465445728766354 -0.7401785386842585 -0.8130282799705698 1.553206818654827 -0.4939148325245979 -0.5486837455157717 -0.3610262116797264 -0.73633174592415 -0.5446205627063301 -0.5160523518705824 1.230246578448748 1.093304308222101 0.8980444010246713 1.226019949979472 -0.4997667391156656 -0.726253210863807 -0.6697924507551998 -0.4891744968539103 -0.4634488008923348 -0.301600826224346 -0.2783275986241442 -0.1177692287900377 -0.09393337228059367 -0.2546427830837441 -0.0703514373220399 0.08836743861011277 -0.2313237479039875 0.1137973151090641 0.2724811315356115 0.2996278178466897 0.4682688930880384 0.1380153936605681 0.406551246715369 0.6046552182453121 -0.426784127732563 -0.3923263038801806 -0.208465408072328 -0.3607313375439971 -0.1857892526190982 0.4960419968524275 -0.1415763437967015 0.03591030790050782 0.8685411342185969 -0.1926902902309472 -0.8592155035553608 1.716817787430798 -0.8576022838754369 -0.1921452564055306 -0.6683334786985783 0.8654953794762578 0.6952267131341282 -0.6287806122165458 0.4999252549098672 0.3218569037134379 -0.5986272435711641 0.1449039324769594 2.203335189185611 -1.101667594592808 -1.101667594592807 -0.0286998603756622 -0.3499716813694415 -0.4450559779573338 -0.04783795748406422 0.09480479796065325 2.114352958860066 -1.054192316972474 -1.054192316972475 -0.3317870997991825 1.39665732177026 -0.6206155967973439 -0.7760417249729167 0.4988340023743217 0.1461550962121355 0.3242397406248529 0.9036042833648704 -0.5300851339677813 -0.3652221764727946 -0.9373851776825108 1.875039225311675 -0.9376540476291644 -0.5066666554551625 0.2368123037070368 -0.02440461564986861 0.150646683235148 1.991415825682697 -0.9957149117466657 -0.9957009139360333 0.5336878756578392 0.7210970221965526 -0.1928809320498361 0.7689122343492278 -0.6467071096582683 1.285560087566004 -0.6388529779077368 -0.1969978949942105 0.1875732054682595 -0.4975220279896986 -0.7186754363850769 1.577166091039188 -0.8584906546541111; 0.0 0.000204308591503799 0.001629535973135443 0.005472026448394285 0.01287939060935179 0.02492716987386698 0.04259671987083449 0.06675468790926908 0.09813443380113843 0.1373197116453414 0.1847308933321656 0.2406139730886964 0.3050325470249727 0.3778629130904994 0.4587923858949879 0.5473208683088024 0.6427656684861544 0.7442694978083142 0.8508115330838226 0.9612213760111374 1.074195695220302 1.188317291935738 1.302076290158998 1.413893116908774 1.522142908049466 1.625180951076655 1.721368758301788 1.809100352482636 1.886828342268937 1.953089366954632 2.006528498919954 2.04592220767042 2.070199511290803 2.078460969082653 2.069995202699299 2.044292671697285 2.001056472471559 1.94020997634528 1.86190117239507 1.766503632611802 1.654614070392519 1.527046517275516 1.384823196404126 1.229162223576608 1.061462317070302 0.8832847449107668 0.6963327821298029 0.5024289901161495 0.3034906647750211 0.1015038293221599 -0.1015038293221605 -0.3034906647750203 -0.50242899011615 -0.6963327821298022 -0.8832847449107647 -1.061462317070301 -1.229162223576608 -1.384823196404126 -1.527046517275515 -1.654614070392518 -1.766503632611802 -1.86190117239507 -1.940209976345281 -2.001056472471559 -2.044292671697285 -2.069995202699299 -2.078460969082653 -2.070199511290803 -2.04592220767042 -2.006528498919954 -1.953089366954633 -1.886828342268938 -1.809100352482636 -1.721368758301788 -1.625180951076654 -1.522142908049467 -1.413893116908775 -1.302076290158999 -1.18831729193574 -1.074195695220302 -0.9612213760111378 -0.8508115330838222 -0.7442694978083139 -0.6427656684861544 -0.5473208683088027 -0.4587923858949887 -0.3778629130904991 -0.3050325470249729 -0.2406139730886968 -0.184730893332166 -0.137319711645342 -0.09813443380113851 -0.06675468790926926 -0.04259671987083431 -0.02492716987386698 -0.01287939060935179 -0.005472026448394374 -0.001629535973135488 -0.000204308591503799 -0.5473096449852685 0.5447620596126443 0.01428450391194042 -0.4309321583994598 0.7536074241825893 0.3536290172290472 0.4171992061645116 -0.354274248521617 -0.7697113089269275 0.1945973624956351 0.8115101356751746 -1.00610749817081 -0.1925650703607583 1.006349758355742 -0.8137846879949843 1.19333488738332 0.07348683780306886 -1.266821725186389 1.366146471157314 -1.324086653415268 -0.04174935346989145 1.135404524959176 0.9456563651429131 0.8229544359251958 -0.995445054751826 -0.9480022448317108 -0.741992356781049 -0.13995947020735 0.002345879688797254 -0.08111410706343182 0.130762025431598 -1.127145434944549 0.9963834095129508 0.6153059195085407 0.5329795234649529 0.3351323238863241 0.4528041803207281 0.2552428653861011 0.3751002341424148 0.1760741054849401 0.05622243244883154 -0.02310920543998908 0.0916097709503603 -0.1431517599572751 -0.1033611549989752 0.01112539166303821 -0.1796378655622734 -0.06423821903495724 -0.2933071885887684 0.1346998725151015 0.06389662809144629 -0.06697977586584479 -0.263147702667072 -0.3418086892373844 -0.4602230597841197 -0.5395791962871652 -0.260267079463506 0.5739282454666178 0.5007002518322551 0.2757413735876992 -0.8939205770864943 -1.486342121175829 0.0009313928164653013 1.487273513992295 0.8909822595409715 -0.6270118467477362 -0.2692763527002932 -0.1472140205276644 0.2179450297267495 0.4510351900656056 0.3329413377177828 -0.2182665505265999 -0.6631900778915942 0.0 1.908144246886934 -1.908144246886936 -0.4106426344765784 -0.6482825657476072 0.1353078965823503 -0.2192301054498285 0.3004465131589842 4.336808689942018e-17 1.825914653945082 -1.825914653945081 0.6415639095768699 -0.08968357289590935 1.254408379505216 -1.164673062563948 -0.4517076066327135 0.6541117112279523 -0.36426907951982 0.09997393244042915 0.731016147780223 -0.8325312305826258 1.623909218280243 0.0001552321360775167 -1.623753986144165 -0.5474230356714256 0.1741645772010534 -0.5950229828132197 -0.4758032489975526 8.081639737527319e-6 -1.724612653719712 1.724620735359448 0.2655807939077015 0.1867114129881211 -0.717357771233564 0.01594342553679897 -1.111060401383298 -0.004534585080420719 1.115594986463718 0.7308601982314702 0.4541306336569979 -0.3789760643386818 -1.406227077779554 0.08072235390443261 1.325504723875121] bn_nodes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 1] - tri = triangulate(points; boundary_nodes=bn_nodes) + tri = triangulate(points; boundary_nodes = bn_nodes) @test validate_triangulation(tri) validate_statistics(tri) -end \ No newline at end of file +end diff --git a/test/operations/delete_point.jl b/test/operations/delete_point.jl index e783b0225..457b32a8a 100644 --- a/test/operations/delete_point.jl +++ b/test/operations/delete_point.jl @@ -10,17 +10,17 @@ using StaticArrays rng1 = StableRNG(j) n = rand(rng1, 50:1000) points = 20randn(rng1, 2, n) - tri = triangulate(points; delete_ghosts=false, rng=rng1) + tri = triangulate(points; delete_ghosts = false, rng = rng1) deleted_pts = Int[] - for k in 1:(n÷10) + for k in 1:(n ÷ 10) rng2 = StableRNG(j + k * n) i = rand(rng2, each_solid_vertex(tri) |> collect) while DT.is_boundary_node(tri, i)[1] i = rand(rng2, each_solid_vertex(tri) |> collect) end - delete_point!(tri, i; rng=rng2) + delete_point!(tri, i; rng = rng2) push!(deleted_pts, i) - _tri = triangulate(points; delete_ghosts=false, skip_points=deleted_pts, rng=rng2) + _tri = triangulate(points; delete_ghosts = false, skip_points = deleted_pts, rng = rng2) DT.clear_empty_features!(tri) DT.clear_empty_features!(_tri) @test DT.compare_triangle_collections(get_triangles(_tri), get_triangles(tri)) @@ -42,7 +42,7 @@ using StaticArrays while DT.is_boundary_node(tri, i)[1] i = rand(rng, each_solid_vertex(tri)) end - delete_point!(tri, i, rng=rng) + delete_point!(tri, i, rng = rng) @test validate_triangulation(tri) end end @@ -56,20 +56,20 @@ using StaticArrays c, d = sort(15randn(rng1, 2)) nx = rand(rng1, 5:25) ny = rand(rng1, 5:25) - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) points = get_points(tri) n = nx * ny - for k in 1:(n÷10) + for k in 1:(n ÷ 10) rng2 = StableRNG(j + k * n) i = rand(rng2, each_solid_vertex(tri) |> collect) while DT.is_boundary_node(tri, i)[1] i = rand(rng2, each_solid_vertex(tri) |> collect) end - delete_point!(tri, i; rng=rng2) + delete_point!(tri, i; rng = rng2) @test validate_triangulation(tri) end end - tri = triangulate_rectangle(0, 1, 0, 1, 25, 25; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(0, 1, 0, 1, 25, 25; delete_ghosts = false, single_boundary = true) add_segment!(tri, 7, 7 + 25) @test_throws DT.InvalidVertexDeletionError delete_point!(tri, 2) @test_throws DT.InvalidVertexDeletionError delete_point!(tri, 7) @@ -83,16 +83,16 @@ using StaticArrays c, d = sort(15randn(rng1, 2)) nx = rand(rng1, 5:25) ny = rand(rng1, 5:25) - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=false) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = false) points = get_points(tri) n = nx * ny - for k in 1:(n÷10) + for k in 1:(n ÷ 10) rng2 = StableRNG(j + k * n) i = rand(rng2, each_solid_vertex(tri) |> collect) while DT.is_boundary_node(tri, i)[1] i = rand(rng2, each_solid_vertex(tri) |> collect) end - delete_point!(tri, i; rng=rng2) + delete_point!(tri, i; rng = rng2) @test validate_triangulation(tri) end end @@ -133,7 +133,7 @@ end 5 4 1 ] for T in eachrow(true_T) - add_triangle!(_tri, T; update_ghost_edges=true) + add_triangle!(_tri, T; update_ghost_edges = true) end convex_hull!(tri) DT.compute_representative_points!(tri) @@ -143,7 +143,7 @@ end @test get_adjacent(tri) == get_adjacent(_tri) @test get_adjacent2vertex(tri) == get_adjacent2vertex(_tri) @test get_graph(tri) == get_graph(_tri) - _tri = triangulate(get_points(tri); skip_points=16, delete_ghosts=false) + _tri = triangulate(get_points(tri); skip_points = 16, delete_ghosts = false) DT.clear_empty_features!(_tri) @test DT.compare_triangle_collections(get_triangles(_tri), get_triangles(tri)) @test get_adjacent(tri) == get_adjacent(_tri) @@ -174,7 +174,7 @@ end delete_point!(tri, point; rng) convex_hull!(tri) DT.compute_representative_points!(tri) - _tri = triangulate(get_points(tri); skip_points=_deleted_points, delete_ghosts=false, rng) + _tri = triangulate(get_points(tri); skip_points = _deleted_points, delete_ghosts = false, rng) @test validate_triangulation(tri) rng = StableRNG(ctr) ctr += 1 @@ -198,9 +198,9 @@ end k = 19 rng = StableRNG(k) i = 183 - delete_point!(tri, i, rng=rng) + delete_point!(tri, i, rng = rng) @test validate_triangulation(tri) - add_point!(tri, i, rng=rng) + add_point!(tri, i, rng = rng) @test tri == orig_tri @test validate_triangulation(tri) -end \ No newline at end of file +end diff --git a/test/operations/delete_triangle.jl b/test/operations/delete_triangle.jl index e4e8edea0..eb31da62a 100644 --- a/test/operations/delete_triangle.jl +++ b/test/operations/delete_triangle.jl @@ -10,17 +10,19 @@ global tri, label_map, index_map = simple_geometry() add_ghost_triangles!(tri) @testset "Deleting a triangle" begin - all_i = Set{NTuple{3,Int}}() - for (a, b, c) in [("a1", "f", "g"), - ("a1", "g", "i"), - ("a1", "i", "f"), - ("f", "i", "ℓ"), - ("f", "v", "e"), - ("f", "w", "v"), - ("e", "v", "z")] + all_i = Set{NTuple{3, Int}}() + for (a, b, c) in [ + ("a1", "f", "g"), + ("a1", "g", "i"), + ("a1", "i", "f"), + ("f", "i", "ℓ"), + ("f", "v", "e"), + ("f", "w", "v"), + ("e", "v", "z"), + ] i, j, k = index_map[a], index_map[b], index_map[c] push!(all_i, (i, j, k)) - DT.delete_triangle!(tri, i, j, k; protect_boundary=true, update_ghost_edges=false) + DT.delete_triangle!(tri, i, j, k; protect_boundary = true, update_ghost_edges = false) @test !DT.contains_triangle(tri, i, j, k)[2] @test !DT.contains_triangle(tri, j, k, i)[2] @test !DT.contains_triangle(tri, k, i, j)[2] @@ -56,38 +58,40 @@ end @testset "Deleting an interior triangle" begin i, j, k = 1, 3, 7 DT.delete_triangle!(tri, i, j, k) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3), - (5, 2, 8), - (6, 2, 3) - ]) + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + (5, 2, 8), + (6, 2, 3), + ], + ) true_adj = Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, - (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, - (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, - (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (5, 2) => 8, (2, 8) => 5, (8, 5) => 2, + (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, + (4, 5) => DT.𝒢, (5, 8) => DT.𝒢, + (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, + (6, 4) => DT.𝒢, + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (8, 5), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4), (2, 3)]), - 7 => Set{NTuple{2,Int}}([]), - 8 => Set{NTuple{2,Int}}([(5, 2)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (8, 5), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2), (2, 8)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4), (2, 3)]), + 7 => Set{NTuple{2, Int}}([]), + 8 => Set{NTuple{2, Int}}([(5, 2)]), ) true_DG = _make_graph_from_adjacency( [ @@ -100,7 +104,8 @@ end 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 - ], Dict(1:9 .=> [-1, (1:8)...])) + ], Dict(1:9 .=> [-1, (1:8)...]), + ) @test get_triangles(tri) == true_T @test (get_adjacent ∘ get_adjacent)(tri) == true_adj @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v @@ -112,34 +117,36 @@ end local true_T, true_adj, true_adj2v, true_DG _tri = deepcopy(tri) DT.delete_triangle!(_tri, i, j, k) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3), - (6, 2, 3) - ]) + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + (6, 2, 3), + ], + ) true_adj = Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, - (4, 5) => DT.𝒢, - (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (2, 3) => 6, (3, 6) => 2, (6, 2) => 3, + (4, 5) => DT.𝒢, + (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, + (6, 4) => DT.𝒢, + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4), (2, 3)]), + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4), (2, 3)]), ) true_DG = _make_graph_from_adjacency( [ @@ -150,7 +157,8 @@ end 1 1 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 - ], Dict(1:7 .=> [-1, (1:6)...])) + ], Dict(1:7 .=> [-1, (1:6)...]), + ) DT.clear_empty_features!(_tri) @test get_triangles(_tri) == true_T @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj @@ -166,33 +174,35 @@ end local true_T, true_adj, true_adj2v, true_DG _tri = deepcopy(tri) DT.delete_triangle!(_tri, i, j, k) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (6, 3, 1), - (4, 6, 1), - (5, 1, 3), - ]) + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (6, 3, 1), + (4, 6, 1), + (5, 1, 3), + ], + ) true_adj = Dict( - (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, - (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, - (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, - (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, - (5, 1) => 3, (3, 5) => 1, - (4, 5) => DT.𝒢, - (5, 2) => DT.𝒢, - (6, 4) => DT.𝒢, - (2, 3) => DT.𝒢, (3, 6) => DT.𝒢, - ) + (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, + (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, + (6, 3) => 1, (3, 1) => 6, (1, 6) => 3, + (4, 6) => 1, (6, 1) => 4, (1, 4) => 6, + (5, 1) => 3, (3, 5) => 1, + (4, 5) => DT.𝒢, + (5, 2) => DT.𝒢, + (6, 4) => DT.𝒢, + (2, 3) => DT.𝒢, (3, 6) => DT.𝒢, + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 1), (1, 6)]), - 4 => Set{NTuple{2,Int}}([(1, 5), (6, 1)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(3, 1), (1, 4)]), + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 3), (3, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(3, 5), (6, 3), (5, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 1), (1, 6)]), + 4 => Set{NTuple{2, Int}}([(1, 5), (6, 1)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(3, 1), (1, 4)]), ) true_DG = _make_graph_from_adjacency( [ @@ -203,7 +213,8 @@ end 1 1 0 0 0 1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 0 - ], Dict(1:7 .=> [-1, (1:6)...])) + ], Dict(1:7 .=> [-1, (1:6)...]), + ) DT.clear_empty_features!(_tri) @test get_triangles(_tri) == true_T @test (get_adjacent ∘ get_adjacent)(_tri) == true_adj @@ -216,13 +227,13 @@ end @testset "Deleting the only triangle of a triangulation" begin tri = example_empty_triangulation() DT.add_triangle!(tri, 1, 2, 3) - true_T = Set{NTuple{3,Int}}([]) + true_T = Set{NTuple{3, Int}}([]) true_adj = DefaultDict(DT.∅, Dict()) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}(), - 1 => Set{NTuple{2,Int}}(), - 2 => Set{NTuple{2,Int}}(), - 3 => Set{NTuple{2,Int}}() + DT.𝒢 => Set{NTuple{2, Int}}(), + 1 => Set{NTuple{2, Int}}(), + 2 => Set{NTuple{2, Int}}(), + 3 => Set{NTuple{2, Int}}(), ) true_DG = _make_graph_from_adjacency([0 0 0 0; 0 0 0 0; 0 0 0 0; 0 0 0 0], Dict(1:4 .=> [-1, 1, 2, 3])) DT.delete_triangle!(tri, 1, 2, 3) @@ -238,29 +249,31 @@ end p3 = @SVector[0.0, 1.0] pts = [p1, p2, p3] tri = Triangulation(pts) - DT.add_triangle!(tri, 1, 2, 3; update_ghost_edges=true) + DT.add_triangle!(tri, 1, 2, 3; update_ghost_edges = true) p4 = @SVector[1.7, 1.7] push!(pts, p4) - DT.add_triangle!(tri, 3, 2, 4; update_ghost_edges=true) + DT.add_triangle!(tri, 3, 2, 4; update_ghost_edges = true) p5 = @SVector[1.0, 3.0] p6 = @SVector[3.0, 1.0] push!(pts, p5, p6) - DT.add_triangle!(tri, 3, 4, 5; update_ghost_edges=true) - DT.add_triangle!(tri, 4, 2, 6; update_ghost_edges=true) - DT.add_triangle!(tri, 5, 4, 6; update_ghost_edges=true) - DT.delete_triangle!(tri, 5, 4, 6; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([ - (1, 2, 3), - (3, 2, 4), - (3, 4, 5), - (4, 2, 6), - (2, 1, DT.𝒢), - (1, 3, DT.𝒢), - (3, 5, DT.𝒢), - (5, 4, DT.𝒢), - (4, 6, DT.𝒢), - (6, 2, DT.𝒢) - ]) + DT.add_triangle!(tri, 3, 4, 5; update_ghost_edges = true) + DT.add_triangle!(tri, 4, 2, 6; update_ghost_edges = true) + DT.add_triangle!(tri, 5, 4, 6; update_ghost_edges = true) + DT.delete_triangle!(tri, 5, 4, 6; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), + (3, 2, 4), + (3, 4, 5), + (4, 2, 6), + (2, 1, DT.𝒢), + (1, 3, DT.𝒢), + (3, 5, DT.𝒢), + (5, 4, DT.𝒢), + (4, 6, DT.𝒢), + (6, 2, DT.𝒢), + ], + ) true_adj = DT.Adjacent( Dict( (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, @@ -272,18 +285,19 @@ end (3, 5) => DT.𝒢, (5, DT.𝒢) => 3, (DT.𝒢, 3) => 5, (5, 4) => DT.𝒢, (4, DT.𝒢) => 5, (DT.𝒢, 5) => 4, (4, 6) => DT.𝒢, (6, DT.𝒢) => 4, (DT.𝒢, 4) => 6, - (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2 - )) + (6, 2) => DT.𝒢, (2, DT.𝒢) => 6, (DT.𝒢, 6) => 2, + ), + ) true_adj2v = DT.Adjacent2Vertex( Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 4), (4, 6), (6, 2), (2, 1)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), - 4 => Set{NTuple{2,Int}}([(3, 2), (5, 3), (2, 6), (DT.𝒢, 5), (6, DT.𝒢)]), - 5 => Set{NTuple{2,Int}}([(3, 4), (DT.𝒢, 3), (4, DT.𝒢)]), - 6 => Set{NTuple{2,Int}}([(4, 2), (DT.𝒢, 4), (2, DT.𝒢)]) - ) + DT.𝒢 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 4), (4, 6), (6, 2), (2, 1)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (3, DT.𝒢), (DT.𝒢, 2)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (4, 3), (6, 4), (1, DT.𝒢), (DT.𝒢, 6)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (2, 4), (4, 5), (DT.𝒢, 1), (5, DT.𝒢)]), + 4 => Set{NTuple{2, Int}}([(3, 2), (5, 3), (2, 6), (DT.𝒢, 5), (6, DT.𝒢)]), + 5 => Set{NTuple{2, Int}}([(3, 4), (DT.𝒢, 3), (4, DT.𝒢)]), + 6 => Set{NTuple{2, Int}}([(4, 2), (DT.𝒢, 4), (2, DT.𝒢)]), + ), ) true_DG = DT.Graph{Int}() DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 5, 4, 6, 2]...) @@ -297,14 +311,18 @@ end @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex @test get_graph(tri) == true_DG - DT.delete_triangle!(tri, 4, 2, 6; update_ghost_edges=true) - DT.delete_triangle!(tri, 3, 4, 5; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([(1, 2, 3), - (2, 1, DT.𝒢), - (1, 3, DT.𝒢), - (3, 4, DT.𝒢), - (4, 2, DT.𝒢), - (3, 2, 4)]) + DT.delete_triangle!(tri, 4, 2, 6; update_ghost_edges = true) + DT.delete_triangle!(tri, 3, 4, 5; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), + (2, 1, DT.𝒢), + (1, 3, DT.𝒢), + (3, 4, DT.𝒢), + (4, 2, DT.𝒢), + (3, 2, 4), + ], + ) true_adj = DT.Adjacent( Dict( (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, @@ -312,16 +330,17 @@ end (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, (3, 4) => DT.𝒢, (4, DT.𝒢) => 3, (DT.𝒢, 3) => 4, (4, 2) => DT.𝒢, (2, DT.𝒢) => 4, (DT.𝒢, 4) => 2, - (3, 2) => 4, (2, 4) => 3, (4, 3) => 2 - )) + (3, 2) => 4, (2, 4) => 3, (4, 3) => 2, + ), + ) true_adj2v = DT.Adjacent2Vertex( Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(2, 1), (1, 3), (3, 4), (4, 2)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 4), (4, 3)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (DT.𝒢, 1), (4, DT.𝒢), (2, 4)]), - 4 => Set{NTuple{2,Int}}([(DT.𝒢, 3), (2, DT.𝒢), (3, 2)]) - ) + DT.𝒢 => Set{NTuple{2, Int}}([(2, 1), (1, 3), (3, 4), (4, 2)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 4), (4, 3)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (DT.𝒢, 1), (4, DT.𝒢), (2, 4)]), + 4 => Set{NTuple{2, Int}}([(DT.𝒢, 3), (2, DT.𝒢), (3, 2)]), + ), ) true_DG = DT.Graph{Int}() DT.add_neighbour!(true_DG, DT.𝒢, [1, 3, 4, 2]...) @@ -334,25 +353,30 @@ end @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex @test get_graph(tri) == true_DG - DT.delete_triangle!(tri, 3, 2, 4; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}([(1, 2, 3), - (2, 1, DT.𝒢), - (1, 3, DT.𝒢), - (3, 2, DT.𝒢)]) + DT.delete_triangle!(tri, 3, 2, 4; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}( + [ + (1, 2, 3), + (2, 1, DT.𝒢), + (1, 3, DT.𝒢), + (3, 2, DT.𝒢), + ], + ) true_adj = DT.Adjacent( Dict( (1, 2) => 3, (2, 3) => 1, (3, 1) => 2, (2, 1) => DT.𝒢, (1, DT.𝒢) => 2, (DT.𝒢, 2) => 1, (1, 3) => DT.𝒢, (3, DT.𝒢) => 1, (DT.𝒢, 1) => 3, - (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2 - )) + (3, 2) => DT.𝒢, (2, DT.𝒢) => 3, (DT.𝒢, 3) => 2, + ), + ) true_adj2v = DT.Adjacent2Vertex( Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(2, 1), (1, 3), (3, 2)]), - 1 => Set{NTuple{2,Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), - 2 => Set{NTuple{2,Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 3)]), - 3 => Set{NTuple{2,Int}}([(1, 2), (DT.𝒢, 1), (2, DT.𝒢)]) - ) + DT.𝒢 => Set{NTuple{2, Int}}([(2, 1), (1, 3), (3, 2)]), + 1 => Set{NTuple{2, Int}}([(2, 3), (DT.𝒢, 2), (3, DT.𝒢)]), + 2 => Set{NTuple{2, Int}}([(3, 1), (1, DT.𝒢), (DT.𝒢, 3)]), + 3 => Set{NTuple{2, Int}}([(1, 2), (DT.𝒢, 1), (2, DT.𝒢)]), + ), ) true_DG = DT.Graph{Int}() DT.add_neighbour!(true_DG, DT.𝒢, [1, 2, 3]...) @@ -364,10 +388,10 @@ end @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex @test get_graph(tri) == true_DG - DT.delete_triangle!(tri, 1, 2, 3; update_ghost_edges=true) - true_T = Set{NTuple{3,Int}}() - true_adj = DT.Adjacent{Int,NTuple{2,Int}}() - true_adj2v = DT.Adjacent2Vertex{Int,Set{NTuple{2,Int}}}() + DT.delete_triangle!(tri, 1, 2, 3; update_ghost_edges = true) + true_T = Set{NTuple{3, Int}}() + true_adj = DT.Adjacent{Int, NTuple{2, Int}}() + true_adj2v = DT.Adjacent2Vertex{Int, Set{NTuple{2, Int}}}() true_DG = DT.Graph{Int}() DT.clear_empty_features!(tri) @test DT.compare_triangle_collections(get_triangles(tri), true_T) @@ -391,41 +415,43 @@ end pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] tri = Triangulation(pts) for (i, j, k) in ( - (1, 2, 6), - (1, 6, 8), - (9, 1, 8), - (9, 8, 10), - (10, 8, 11), - (8, 7, 11), - (8, 6, 7), - (6, 2, 3), - (6, 3, 4), - (6, 4, 7), - (7, 4, 5), - (11, 7, 5), - (10, 11, 5) - ) - DT.add_triangle!(tri, i, j, k; update_ghost_edges=true) + (1, 2, 6), + (1, 6, 8), + (9, 1, 8), + (9, 8, 10), + (10, 8, 11), + (8, 7, 11), + (8, 6, 7), + (6, 2, 3), + (6, 3, 4), + (6, 4, 7), + (7, 4, 5), + (11, 7, 5), + (10, 11, 5), + ) + DT.add_triangle!(tri, i, j, k; update_ghost_edges = true) end - [DT.delete_triangle!(tri, i, j, k; update_ghost_edges=true) for (i, j, k) in ( - (1, 8, 9), (9, 8, 10), (10, 11, 5), (5, 7, 4), (4, 6, 3), (3, 6, 2), (2, 6, 1) + [DT.delete_triangle!(tri, i, j, k; update_ghost_edges = true) for (i, j, k) in ( + (1, 8, 9), (9, 8, 10), (10, 11, 5), (5, 7, 4), (4, 6, 3), (3, 6, 2), (2, 6, 1), )] - true_T = Set{NTuple{3,Int}}([ - (1, 6, 8), - (6, 7, 8), - (6, 4, 7), - (8, 7, 11), - (11, 7, 5), - (10, 8, 11), - (1, 8, DT.𝒢), - (8, 10, DT.𝒢), - (10, 11, DT.𝒢), - (11, 5, DT.𝒢), - (5, 7, DT.𝒢), - (7, 4, DT.𝒢), - (4, 6, DT.𝒢), - (6, 1, DT.𝒢) - ]) + true_T = Set{NTuple{3, Int}}( + [ + (1, 6, 8), + (6, 7, 8), + (6, 4, 7), + (8, 7, 11), + (11, 7, 5), + (10, 8, 11), + (1, 8, DT.𝒢), + (8, 10, DT.𝒢), + (10, 11, DT.𝒢), + (11, 5, DT.𝒢), + (5, 7, DT.𝒢), + (7, 4, DT.𝒢), + (4, 6, DT.𝒢), + (6, 1, DT.𝒢), + ], + ) true_adj = DT.Adjacent( Dict( (1, 6) => 8, (6, 8) => 1, (8, 1) => 6, @@ -441,10 +467,10 @@ end (5, 7) => DT.𝒢, (7, DT.𝒢) => 5, (DT.𝒢, 5) => 7, (7, 4) => DT.𝒢, (4, DT.𝒢) => 7, (DT.𝒢, 7) => 4, (4, 6) => DT.𝒢, (6, DT.𝒢) => 4, (DT.𝒢, 4) => 6, - (6, 1) => DT.𝒢, (1, DT.𝒢) => 6, (DT.𝒢, 6) => 1 - ) + (6, 1) => DT.𝒢, (1, DT.𝒢) => 6, (DT.𝒢, 6) => 1, + ), ) - true_adj2v = DT.Adjacent2Vertex{Int,Set{NTuple{2,Int}}}() + true_adj2v = DT.Adjacent2Vertex{Int, Set{NTuple{2, Int}}}() for (ij, k) in true_adj.adjacent DT.add_adjacent2vertex!(true_adj2v, k, ij) end @@ -463,4 +489,4 @@ end @test (get_adjacent ∘ get_adjacent)(tri) == true_adj.adjacent @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v.adjacent2vertex @test get_graph(tri) == true_DG -end \ No newline at end of file +end diff --git a/test/operations/flip_edge.jl b/test/operations/flip_edge.jl index 1ec056949..e7ef3df75 100644 --- a/test/operations/flip_edge.jl +++ b/test/operations/flip_edge.jl @@ -10,19 +10,22 @@ using StaticArrays DT.split_triangle!(tri, 4, 6, 1, 8) DT.split_triangle!(tri, 1, 5, 4, 7) @testset "First flip" begin - true_T = Set{NTuple{3,Int}}([ - (5, 6, 3), - (3, 2, 5), - (4, 1, 7), - (5, 4, 7), - (5, 1, 6), - (1, 5, 7), - (6, 2, 3), - (6, 1, 8), - (4, 6, 8), - (1, 4, 8) - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (5, 6, 3), + (3, 2, 5), + (4, 1, 7), + (5, 4, 7), + (5, 1, 6), + (1, 5, 7), + (6, 2, 3), + (6, 1, 8), + (4, 6, 8), + (1, 4, 8), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (5, 6) => 3, (6, 3) => 5, (3, 5) => 6, (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, @@ -38,18 +41,18 @@ using StaticArrays (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - ) + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(6, 5), (5, 7), (7, 4), (4, 8), (8, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(5, 6), (6, 2), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(6, 8), (8, 1), (1, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 1), (1, 6), (6, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 5), (5, 1), (1, 8), (8, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 5), (5, 4), (4, 1)]), - 8 => Set{NTuple{2,Int}}([(1, 4), (4, 6), (6, 1)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(6, 5), (5, 7), (7, 4), (4, 8), (8, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(5, 6), (6, 2), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(6, 8), (8, 1), (1, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 1), (1, 6), (6, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 5), (5, 1), (1, 8), (8, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 5), (5, 4), (4, 1)]), + 8 => Set{NTuple{2, Int}}([(1, 4), (4, 6), (6, 1)]), ) true_DG = _make_graph_from_adjacency( [ @@ -62,7 +65,8 @@ using StaticArrays 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 1 0 0 - ], Dict(1:9 .=> [-1, 1, 2, 3, 4, 5, 6, 7, 8])) + ], Dict(1:9 .=> [-1, 1, 2, 3, 4, 5, 6, 7, 8]), + ) DT.flip_edge!(tri, 1, 3) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @@ -72,19 +76,22 @@ using StaticArrays end @testset "Second flip" begin - true_T = Set{NTuple{3,Int}}([ - (5, 6, 3), - (3, 2, 5), - (5, 4, 7), - (5, 1, 6), - (1, 5, 7), - (6, 2, 3), - (6, 1, 8), - (4, 6, 8), - (8, 1, 7), - (8, 7, 4) - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (5, 6, 3), + (3, 2, 5), + (5, 4, 7), + (5, 1, 6), + (1, 5, 7), + (6, 2, 3), + (6, 1, 8), + (4, 6, 8), + (8, 1, 7), + (8, 7, 4), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (5, 6) => 3, (6, 3) => 5, (3, 5) => 6, (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, @@ -100,18 +107,18 @@ using StaticArrays (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - ) + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(6, 5), (5, 7), (7, 8), (8, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(5, 6), (6, 2), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(6, 8), (8, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 1), (1, 6), (6, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 5), (5, 1), (1, 8), (8, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 5), (5, 4), (4, 8), (8, 1)]), - 8 => Set{NTuple{2,Int}}([(1, 7), (7, 4), (4, 6), (6, 1)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(6, 5), (5, 7), (7, 8), (8, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(5, 6), (6, 2), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(6, 8), (8, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 1), (1, 6), (6, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 5), (5, 1), (1, 8), (8, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 5), (5, 4), (4, 8), (8, 1)]), + 8 => Set{NTuple{2, Int}}([(1, 7), (7, 4), (4, 6), (6, 1)]), ) true_DG = _make_graph_from_adjacency( [ @@ -124,7 +131,8 @@ using StaticArrays 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 0 0 1 0 1 0 0 1 0 1 1 0 - ], Dict(1:9 .=> [-1, 1, 2, 3, 4, 5, 6, 7, 8])) + ], Dict(1:9 .=> [-1, 1, 2, 3, 4, 5, 6, 7, 8]), + ) DT.flip_edge!(tri, 1, 4) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @@ -142,17 +150,20 @@ end r = 7 e = DT.get_adjacent(tri, j, i) DT.flip_edge!(tri, i, j) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 3, 7), - (3, 5, 7), - (6, 3, 1), - (4, 6, 1), - (6, 2, 3), - (7, 5, 4), - (7, 4, 1) - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 3, 7), + (3, 5, 7), + (6, 3, 1), + (4, 6, 1), + (6, 2, 3), + (7, 5, 4), + (7, 4, 1), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, @@ -166,19 +177,20 @@ end (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - ) + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(6, 3), (3, 7), (7, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 7), (7, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(6, 1), (1, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(3, 5), (5, 4), (4, 1), (1, 3)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(6, 3), (3, 7), (7, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 7), (7, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(6, 1), (1, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(3, 5), (5, 4), (4, 1), (1, 3)]), ) - true_DG = _make_graph_from_adjacency([ + true_DG = _make_graph_from_adjacency( + [ 0 0 1 0 1 1 1 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 1 0 @@ -187,11 +199,12 @@ end 1 0 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 0 - ], Dict(1:8 .=> [-1, (1:7)...])) + ], Dict(1:8 .=> [-1, (1:7)...]), + ) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @test (get_adjacent ∘ get_adjacent)(tri) == true_adj @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri) == true_adj2v @test (get_graph)(tri) == true_DG @test all(DT.is_positively_oriented(DT.triangle_orientation(tri, T...)) for T in each_triangle(tri)) -end \ No newline at end of file +end diff --git a/test/operations/legalise_edge.jl b/test/operations/legalise_edge.jl index fd10a320b..77a1ac708 100644 --- a/test/operations/legalise_edge.jl +++ b/test/operations/legalise_edge.jl @@ -13,17 +13,20 @@ using StaticArrays i, j, r = 5, 1, 7 e = DT.get_adjacent(tri, j, i) DT.legalise_edge!(tri, i, j, r) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 3, 7), - (3, 5, 7), - (6, 3, 1), - (4, 6, 1), - (6, 2, 3), - (7, 5, 4), - (7, 4, 1) - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 3, 7), + (3, 5, 7), + (6, 3, 1), + (4, 6, 1), + (6, 2, 3), + (7, 5, 4), + (7, 4, 1), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (1, 3) => 7, (3, 7) => 1, (7, 1) => 3, @@ -37,19 +40,20 @@ using StaticArrays (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - ) + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(6, 3), (3, 7), (7, 4), (4, 6)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 5), (5, 7), (7, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(6, 1), (1, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(3, 5), (5, 4), (4, 1), (1, 3)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(6, 3), (3, 7), (7, 4), (4, 6)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 5), (5, 7), (7, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(6, 1), (1, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(3, 5), (5, 4), (4, 1), (1, 3)]), ) - true_DG = _make_graph_from_adjacency([ + true_DG = _make_graph_from_adjacency( + [ 0 0 1 0 1 1 1 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 1 0 @@ -58,7 +62,8 @@ using StaticArrays 1 0 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 0 - ], Dict(1:8 .=> [-1, (1:7)...])) + ], Dict(1:8 .=> [-1, (1:7)...]), + ) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @test (get_adjacent ∘ get_adjacent)(tri) == true_adj @@ -68,4 +73,4 @@ using StaticArrays for ((i, j), v) in get_adjacent(tri).adjacent @test DT.is_legal(tri, i, j) |> DT.is_legal end -end \ No newline at end of file +end diff --git a/test/operations/lock_convex_hull.jl b/test/operations/lock_convex_hull.jl index 4aa922a43..fb178d61c 100644 --- a/test/operations/lock_convex_hull.jl +++ b/test/operations/lock_convex_hull.jl @@ -29,7 +29,7 @@ using StaticArrays add_segment!(tri, e) end lock_convex_hull!(tri2) - tri3 = triangulate(pts; boundary_nodes=bn) + tri3 = triangulate(pts; boundary_nodes = bn) @test tri2.boundary_nodes == tri3.boundary_nodes == bn @test tri2.ghost_vertex_map == tri3.ghost_vertex_map == bn_map @test tri2.boundary_edge_map == tri3.boundary_edge_map == bnn_map @@ -42,7 +42,7 @@ using StaticArrays p3 = (1.0, 1.0) p4 = (0.0, 1.0) pts = [p1, p2, p3, p4] - tri = triangulate(pts; boundary_nodes=[1, 2, 3, 4, 1]) + tri = triangulate(pts; boundary_nodes = [1, 2, 3, 4, 1]) @test_throws ArgumentError("Cannot lock the convex hull of a triangulation with boundary nodes.") lock_convex_hull!(tri) end @@ -77,7 +77,7 @@ end @testset "Fixing interior segments that happen to be on the convex hull" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.25, 0.5), (0.75, 0.5)] - tri = triangulate(points; segments=Set([(1, 2), (2, 3), (5, 6)])) + tri = triangulate(points; segments = Set([(1, 2), (2, 3), (5, 6)])) lock_convex_hull!(tri) @test DT.compare_unoriented_edge_collections(get_interior_segments(tri), Set([(5, 6)])) @test DT.compare_unoriented_edge_collections(tri.cache.interior_segments_on_hull, Set([(1, 2), (2, 3)])) @@ -88,7 +88,7 @@ end DT.complete_split_edge_and_legalise!(tri, 7, 2, 8) DT.complete_split_edge_and_legalise!(tri, 7, 8, 9) @test validate_triangulation(tri) - unlock_convex_hull!(tri; reconstruct=true) + unlock_convex_hull!(tri; reconstruct = true) @test validate_triangulation(tri) @test DT.compare_unoriented_edge_collections(get_interior_segments(tri), Set([(5, 6), (1, 7), (7, 9), (9, 8), (8, 2), (2, 3)])) @test isempty(tri.cache.interior_segments_on_hull) @@ -97,7 +97,7 @@ end validate_statistics(tri) points = [(0.0, 0.0), (9.0, 0.0), (9.0, 7.0)] - tri = triangulate(points; segments=Set([(1, 2), (1, 3)])) + tri = triangulate(points; segments = Set([(1, 2), (1, 3)])) lock_convex_hull!(tri) orig_tri = deepcopy(tri) orig_points = copy(orig_tri.points) @@ -105,7 +105,7 @@ end DT.complete_split_edge_and_legalise!(tri, 1, 2, 4) @test validate_triangulation(tri) @test collect(get_point(tri, 4)) ≈ [4.5, 0.0] - unlock_convex_hull!(tri; reconstruct=true) - @test tri == triangulate([orig_points; get_point(tri, 4)]; segments=Set([(1, 4), (4, 2), (1, 3)])) + unlock_convex_hull!(tri; reconstruct = true) + @test tri == triangulate([orig_points; get_point(tri, 4)]; segments = Set([(1, 4), (4, 2), (1, 3)])) end -end \ No newline at end of file +end diff --git a/test/operations/split_edge.jl b/test/operations/split_edge.jl index dcab3e40d..9441a3caf 100644 --- a/test/operations/split_edge.jl +++ b/test/operations/split_edge.jl @@ -18,19 +18,22 @@ using StaticArrays i, j, r = 1, 7, 8 DT.split_edge!(tri, i, j, r) DT.split_edge!(tri, j, i, r) - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (1, 8, 4), - (7, 8, 3), - (3, 5, 7), - (6, 3, 1), - (4, 6, 1), - (4, 7, 5), - (6, 2, 3), - (8, 7, 4), - (8, 1, 3), - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (1, 8, 4), + (7, 8, 3), + (3, 5, 7), + (6, 3, 1), + (4, 6, 1), + (4, 7, 5), + (6, 2, 3), + (8, 7, 4), + (8, 1, 3), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (1, 8) => 4, (8, 4) => 1, (4, 1) => 8, @@ -46,17 +49,18 @@ using StaticArrays (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - )) + ), + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(4, 6), (6, 3), (3, 8), (8, 4)]), - 2 => Set{NTuple{2,Int}}([(5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(6, 2), (2, 5), (5, 7), (7, 8), (8, 1), (1, 6)]), - 4 => Set{NTuple{2,Int}}([(6, 1), (1, 8), (8, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 3), (3, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(3, 5), (5, 4), (4, 8), (8, 3)]), - 8 => Set{NTuple{2,Int}}([(1, 3), (3, 7), (7, 4), (4, 1)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(4, 6), (6, 3), (3, 8), (8, 4)]), + 2 => Set{NTuple{2, Int}}([(5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(6, 2), (2, 5), (5, 7), (7, 8), (8, 1), (1, 6)]), + 4 => Set{NTuple{2, Int}}([(6, 1), (1, 8), (8, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 3), (3, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(3, 5), (5, 4), (4, 8), (8, 3)]), + 8 => Set{NTuple{2, Int}}([(1, 3), (3, 7), (7, 4), (4, 1)]), ) true_DG = _make_graph_from_adjacency( [ @@ -69,7 +73,8 @@ using StaticArrays 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 1 0 1 0 1 1 0 0 1 0 - ], Dict(1:9 .=> [-1, (1:8)...])) + ], Dict(1:9 .=> [-1, (1:8)...]), + ) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @test (get_adjacent ∘ get_adjacent)(tri) == true_adj @@ -80,21 +85,24 @@ using StaticArrays i, j, r = 5, 3, 9 DT.split_edge!(tri, i, j, r) DT.split_edge!(tri, j, i, r) - true_T = Set{NTuple{3,Int}}([ - (1, 8, 4), - (7, 8, 3), - (6, 3, 1), - (4, 6, 1), - (4, 7, 5), - (6, 2, 3), - (8, 7, 4), - (8, 1, 3), - (9, 5, 7), - (3, 9, 7), - (9, 3, 2), - (5, 9, 2) - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (1, 8, 4), + (7, 8, 3), + (6, 3, 1), + (4, 6, 1), + (4, 7, 5), + (6, 2, 3), + (8, 7, 4), + (8, 1, 3), + (9, 5, 7), + (3, 9, 7), + (9, 3, 2), + (5, 9, 2), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (1, 8) => 4, (8, 4) => 1, (4, 1) => 8, (7, 8) => 3, (8, 3) => 7, (3, 7) => 8, @@ -112,18 +120,19 @@ using StaticArrays (5, 2) => DT.𝒢, (2, 6) => DT.𝒢, (6, 4) => DT.𝒢, - )) + ), + ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(4, 6), (6, 3), (3, 8), (8, 4)]), - 2 => Set{NTuple{2,Int}}([(5, 9), (9, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(2, 9), (9, 7), (7, 8), (8, 1), (1, 6), (6, 2)]), - 4 => Set{NTuple{2,Int}}([(6, 1), (1, 8), (8, 7), (7, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 7), (7, 9), (9, 2)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(9, 5), (5, 4), (4, 8), (8, 3), (3, 9)]), - 8 => Set{NTuple{2,Int}}([(1, 3), (3, 7), (7, 4), (4, 1)]), - 9 => Set{NTuple{2,Int}}([(2, 5), (5, 7), (7, 3), (3, 2)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(4, 6), (6, 3), (3, 8), (8, 4)]), + 2 => Set{NTuple{2, Int}}([(5, 9), (9, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(2, 9), (9, 7), (7, 8), (8, 1), (1, 6), (6, 2)]), + 4 => Set{NTuple{2, Int}}([(6, 1), (1, 8), (8, 7), (7, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 7), (7, 9), (9, 2)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(9, 5), (5, 4), (4, 8), (8, 3), (3, 9)]), + 8 => Set{NTuple{2, Int}}([(1, 3), (3, 7), (7, 4), (4, 1)]), + 9 => Set{NTuple{2, Int}}([(2, 5), (5, 7), (7, 3), (3, 2)]), ) true_DG = _make_graph_from_adjacency( [ @@ -137,7 +146,8 @@ using StaticArrays 0 0 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 0 0 0 1 1 0 1 0 1 0 0 - ], Dict(1:10 .=> [-1, (1:9)...])) + ], Dict(1:10 .=> [-1, (1:9)...]), + ) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @test (get_adjacent ∘ get_adjacent)(tri) == true_adj @@ -157,7 +167,7 @@ end DT.push_point!(tri, 4.0, 1.3) DT.complete_split_edge_and_legalise!(tri, 12, 9, DT.num_points(tri)) validate_triangulation(tri) - DT.push_point!(tri, 4.0 + 1e-13, 2.2 - 1e-9) + DT.push_point!(tri, 4.0 + 1.0e-13, 2.2 - 1.0e-9) DT.complete_split_edge_and_legalise!(tri, 12, 10, DT.num_points(tri)) validate_triangulation(tri) DT.push_point!(tri, 4.0, 0.0) @@ -187,19 +197,23 @@ end @testset "Boundary segments" begin for i in 1:100 - curve_1 = [[ - (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), - (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), - (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), - (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), - (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), - (-4.0, 0.0), (0.0, 0.0), - ]] - curve_2 = [[ - (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), - (10.0, 22.0), (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ]] + curve_1 = [ + [ + (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), + (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), + (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), + (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), + (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), + (-4.0, 0.0), (0.0, 0.0), + ], + ] + curve_2 = [ + [ + (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), + (10.0, 22.0), (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], + ] curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] curves = [curve_1, curve_2, curve_3, curve_4] @@ -214,10 +228,11 @@ end (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] - boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) + (7.0, 7.8), (7.0, 7.4), + ] + boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) uncons_tri = triangulate(points) - cons_tri = triangulate(points; boundary_nodes=boundary_nodes) + cons_tri = triangulate(points; boundary_nodes = boundary_nodes) tri = cons_tri @test validate_triangulation(tri) validate_statistics(tri) @@ -251,22 +266,30 @@ end @test get_adjacent(tri, 102, 96) == DT.𝒢 - 3 flag = validate_triangulation(tri) @test flag - @test get_adjacent2vertex(tri, DT.𝒢) == Set(( - (70, 69), (69, 68), (68, 67), (67, 66), (66, 65), (65, 64), (64, 63), - (63, 62), (62, 61), (61, 60), (60, 59), (59, 58), (58, 57), - (57, 56), (56, 55), (55, 78), (78, 77), (77, 76), (76, 75), - (75, 74), (74, 73), (73, 72), (72, 71), (71, 70), - )) - @test get_adjacent2vertex(tri, DT.𝒢 - 1) == Set(( - (79, 89), (89, 88), (88, 87), (87, 86), (86, 85), (85, 84), - (84, 83), (83, 82), (82, 81), (81, 80), (80, 79) - )) - @test get_adjacent2vertex(tri, DT.𝒢 - 2) == Set(( - (90, 93), (93, 92), (92, 91), (91, 90) - )) - @test get_adjacent2vertex(tri, DT.𝒢 - 3) == Set(( - (94, 97), (97, 102), (102, 96), (96, 95), (95, 94) - )) + @test get_adjacent2vertex(tri, DT.𝒢) == Set( + ( + (70, 69), (69, 68), (68, 67), (67, 66), (66, 65), (65, 64), (64, 63), + (63, 62), (62, 61), (61, 60), (60, 59), (59, 58), (58, 57), + (57, 56), (56, 55), (55, 78), (78, 77), (77, 76), (76, 75), + (75, 74), (74, 73), (73, 72), (72, 71), (71, 70), + ), + ) + @test get_adjacent2vertex(tri, DT.𝒢 - 1) == Set( + ( + (79, 89), (89, 88), (88, 87), (87, 86), (86, 85), (85, 84), + (84, 83), (83, 82), (82, 81), (81, 80), (80, 79), + ), + ) + @test get_adjacent2vertex(tri, DT.𝒢 - 2) == Set( + ( + (90, 93), (93, 92), (92, 91), (91, 90), + ), + ) + @test get_adjacent2vertex(tri, DT.𝒢 - 3) == Set( + ( + (94, 97), (97, 102), (102, 96), (96, 95), (95, 94), + ), + ) validate_statistics(tri) @test test_fnc(tri, 87, 86) @@ -290,4 +313,4 @@ end @test test_fnc(tri, 78, 77) end end -end \ No newline at end of file +end diff --git a/test/operations/split_triangle.jl b/test/operations/split_triangle.jl index 4794c3b30..2abdca023 100644 --- a/test/operations/split_triangle.jl +++ b/test/operations/split_triangle.jl @@ -13,16 +13,19 @@ using StaticArrays DT.add_triangle!(tri, 6, 2, 3) @testset "Interior splitting" begin - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (5, 2, 8), - (6, 3, 1), - (4, 6, 1), - (1, 3, 7), (3, 5, 7), (5, 1, 7), - (6, 2, 3), - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (5, 2, 8), + (6, 3, 1), + (4, 6, 1), + (1, 3, 7), (3, 5, 7), (5, 1, 7), + (6, 2, 3), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, @@ -37,21 +40,22 @@ using StaticArrays (5, 8) => DT.𝒢, (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (6, 4) => DT.𝒢, + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(5, 4), (4, 6), (6, 3), (3, 7), (7, 5)]), - 2 => Set{NTuple{2,Int}}([(8, 5), (5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(6, 1), (1, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 8)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 1)]), - 8 => Set{NTuple{2,Int}}([(5, 2)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(5, 4), (4, 6), (6, 3), (3, 7), (7, 5)]), + 2 => Set{NTuple{2, Int}}([(8, 5), (5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(6, 1), (1, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 8)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 1)]), + 8 => Set{NTuple{2, Int}}([(5, 2)]), ) - true_DG = _make_graph_from_adjacency([ + true_DG = _make_graph_from_adjacency( + [ 0 0 1 0 1 1 1 0 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1 @@ -61,7 +65,8 @@ using StaticArrays 1 1 1 1 1 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 0 1 0 0 0 - ], Dict(1:9 .=> [-1, (1:8)...])) + ], Dict(1:9 .=> [-1, (1:8)...]), + ) DT.split_triangle!(tri, 1, 3, 5, 7) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @@ -71,16 +76,19 @@ using StaticArrays end @testset "Splitting a triangle with one boundary edge" begin - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (5, 2, 8), - (6, 3, 1), - (4, 6, 9), (6, 1, 9), (1, 4, 9), - (1, 3, 7), (3, 5, 7), (5, 1, 7), - (6, 2, 3), - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (5, 2, 8), + (6, 3, 1), + (4, 6, 9), (6, 1, 9), (1, 4, 9), + (1, 3, 7), (3, 5, 7), (5, 1, 7), + (6, 2, 3), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, @@ -97,22 +105,23 @@ using StaticArrays (5, 8) => DT.𝒢, (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (6, 4) => DT.𝒢, + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(5, 4), (4, 9), (9, 6), (6, 3), (3, 7), (7, 5)]), - 2 => Set{NTuple{2,Int}}([(8, 5), (5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(6, 9), (9, 1), (1, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 8)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 9), (9, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 1)]), - 8 => Set{NTuple{2,Int}}([(5, 2)]), - 9 => Set{NTuple{2,Int}}([(6, 1), (1, 4), (4, 6)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(5, 4), (4, 9), (9, 6), (6, 3), (3, 7), (7, 5)]), + 2 => Set{NTuple{2, Int}}([(8, 5), (5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(6, 9), (9, 1), (1, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 8)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 9), (9, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 1)]), + 8 => Set{NTuple{2, Int}}([(5, 2)]), + 9 => Set{NTuple{2, Int}}([(6, 1), (1, 4), (4, 6)]), ) - true_DG = _make_graph_from_adjacency([ + true_DG = _make_graph_from_adjacency( + [ 0 0 1 0 1 1 1 0 1 0 0 0 0 1 1 1 1 1 0 1 1 0 0 1 0 1 1 0 1 0 @@ -123,7 +132,8 @@ using StaticArrays 0 1 0 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 0 0 - ], Dict(1:10 .=> [-1, (1:9)...])) + ], Dict(1:10 .=> [-1, (1:9)...]), + ) DT.split_triangle!(tri, 4, 6, 1, 9) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @@ -133,16 +143,19 @@ using StaticArrays end @testset "Splitting two boundary edges" begin - true_T = Set{NTuple{3,Int}}([ - (3, 2, 5), - (4, 1, 5), - (5, 2, 10), (2, 8, 10), (8, 5, 10), - (6, 3, 1), - (4, 6, 9), (6, 1, 9), (1, 4, 9), - (1, 3, 7), (3, 5, 7), (5, 1, 7), - (6, 2, 3), - ]) - true_adj = DefaultDict(DT.∅, + true_T = Set{NTuple{3, Int}}( + [ + (3, 2, 5), + (4, 1, 5), + (5, 2, 10), (2, 8, 10), (8, 5, 10), + (6, 3, 1), + (4, 6, 9), (6, 1, 9), (1, 4, 9), + (1, 3, 7), (3, 5, 7), (5, 1, 7), + (6, 2, 3), + ], + ) + true_adj = DefaultDict( + DT.∅, Dict( (3, 2) => 5, (2, 5) => 3, (5, 3) => 2, (4, 1) => 5, (1, 5) => 4, (5, 4) => 1, @@ -161,23 +174,24 @@ using StaticArrays (5, 8) => DT.𝒢, (8, 2) => DT.𝒢, (2, 6) => DT.𝒢, - (6, 4) => DT.𝒢 - ) + (6, 4) => DT.𝒢, + ), ) true_adj2v = Dict( - DT.𝒢 => Set{NTuple{2,Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), - 1 => Set{NTuple{2,Int}}([(5, 4), (4, 9), (9, 6), (6, 3), (3, 7), (7, 5)]), - 2 => Set{NTuple{2,Int}}([(8, 10), (10, 5), (5, 3), (3, 6)]), - 3 => Set{NTuple{2,Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), - 4 => Set{NTuple{2,Int}}([(6, 9), (9, 1), (1, 5)]), - 5 => Set{NTuple{2,Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 10), (10, 8)]), - 6 => Set{NTuple{2,Int}}([(2, 3), (3, 1), (1, 9), (9, 4)]), - 7 => Set{NTuple{2,Int}}([(1, 3), (3, 5), (5, 1)]), - 8 => Set{NTuple{2,Int}}([(5, 10), (10, 2)]), - 9 => Set{NTuple{2,Int}}([(6, 1), (1, 4), (4, 6)]), - 10 => Set{NTuple{2,Int}}([(5, 2), (2, 8), (8, 5)]) + DT.𝒢 => Set{NTuple{2, Int}}([(4, 5), (5, 8), (8, 2), (2, 6), (6, 4)]), + 1 => Set{NTuple{2, Int}}([(5, 4), (4, 9), (9, 6), (6, 3), (3, 7), (7, 5)]), + 2 => Set{NTuple{2, Int}}([(8, 10), (10, 5), (5, 3), (3, 6)]), + 3 => Set{NTuple{2, Int}}([(5, 7), (7, 1), (1, 6), (6, 2), (2, 5)]), + 4 => Set{NTuple{2, Int}}([(6, 9), (9, 1), (1, 5)]), + 5 => Set{NTuple{2, Int}}([(4, 1), (1, 7), (7, 3), (3, 2), (2, 10), (10, 8)]), + 6 => Set{NTuple{2, Int}}([(2, 3), (3, 1), (1, 9), (9, 4)]), + 7 => Set{NTuple{2, Int}}([(1, 3), (3, 5), (5, 1)]), + 8 => Set{NTuple{2, Int}}([(5, 10), (10, 2)]), + 9 => Set{NTuple{2, Int}}([(6, 1), (1, 4), (4, 6)]), + 10 => Set{NTuple{2, Int}}([(5, 2), (2, 8), (8, 5)]), ) - true_DG = _make_graph_from_adjacency([ + true_DG = _make_graph_from_adjacency( + [ 0 0 1 0 1 1 1 0 1 0 0 0 0 0 1 1 1 1 1 0 1 0 1 0 0 1 0 1 1 0 1 0 1 @@ -189,7 +203,8 @@ using StaticArrays 1 0 1 0 0 1 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 - ], Dict(1:11 .=> [-1, (1:10)...])) + ], Dict(1:11 .=> [-1, (1:10)...]), + ) DT.split_triangle!(tri, 5, 2, 8, 10) DT.clear_empty_features!(tri) @test get_triangles(tri) == true_T @@ -245,4 +260,4 @@ end @test DT.contains_segment(tri, 1, 11) @test DT.edge_exists(tri, 1, 11) && DT.edge_exists(tri, 11, 1) end -end \ No newline at end of file +end diff --git a/test/point_location/brute_force.jl b/test/point_location/brute_force.jl index dba5502aa..f31bfa480 100644 --- a/test/point_location/brute_force.jl +++ b/test/point_location/brute_force.jl @@ -3,7 +3,6 @@ const DT = DelaunayTriangulation using StatsBase - global tri, label_map, index_map = simple_geometry() @testset "Finding points in ghost triangles" begin @@ -73,4 +72,4 @@ end end end end -end \ No newline at end of file +end diff --git a/test/point_location/find_polygon.jl b/test/point_location/find_polygon.jl index 0699b3c65..2d0591b86 100644 --- a/test/point_location/find_polygon.jl +++ b/test/point_location/find_polygon.jl @@ -4,40 +4,40 @@ const DT = DelaunayTriangulation curve = [ [ - [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])] + [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] -tri = triangulate(points; boundary_nodes=curve) -refine!(tri; max_area=1e-2) +tri = triangulate(points; boundary_nodes = curve) +refine!(tri; max_area = 1.0e-2) q = (-1.0, -4.0) idx = find_polygon(tri, q) -@test idx == 3 +@test idx == 3 q = (-1.0, 0.2) idx = find_polygon(tri, q) -@test idx == 1 -q = (-1/2, -3.0) +@test idx == 1 +q = (-1 / 2, -3.0) idx = find_polygon(tri, q) -@test idx == 4 +@test idx == 4 q = (0.0, -4.05) idx = find_polygon(tri, q) -@test idx == 6 +@test idx == 6 q = (0.0, -5.0) idx = find_polygon(tri, q) -@test idx == 0 \ No newline at end of file +@test idx == 0 diff --git a/test/point_location/ghost_search.jl b/test/point_location/ghost_search.jl index 0f205fab1..d14eca3a1 100644 --- a/test/point_location/ghost_search.jl +++ b/test/point_location/ghost_search.jl @@ -5,7 +5,6 @@ using Random using StatsBase - tri, label_map, index_map = simple_geometry() add_ghost_triangles!(tri) DT.compute_representative_points!(tri) @@ -122,8 +121,8 @@ end if DT.is_exterior_boundary_node(tri, k) i, j = DT.exterior_find_triangle(tri, k, get_point(tri, k)) @test k ∈ (i, j) && - DT.is_exterior_ghost_triangle(tri, i, j, get_adjacent(tri, i, j)) + DT.is_exterior_ghost_triangle(tri, i, j, get_adjacent(tri, i, j)) @test DT.is_on(DT.point_position_relative_to_triangle(tri, i, j, k, k)) end end -end \ No newline at end of file +end diff --git a/test/point_location/interior_edge_intersections.jl b/test/point_location/interior_edge_intersections.jl index 854550ae4..8141d9b87 100644 --- a/test/point_location/interior_edge_intersections.jl +++ b/test/point_location/interior_edge_intersections.jl @@ -6,7 +6,6 @@ using Random using ..DelaunayTriangulation: Certificate - tri, label_map, index_map = simple_geometry() add_ghost_triangles!(tri) pts = get_points(tri) @@ -28,331 +27,331 @@ rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) graph = get_graph(tri) @testset "check_for_intersections_with_adjacent_boundary_edges" begin - @testset "General positions" begin - k = index_map["a"] - q = (6.0, 0.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Right && dir_cert == Certificate.On && id == index_map["b"] - @inferred DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q = (14.0, 0.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Right && dir_cert == Certificate.Right && id == index_map["b"] - q = (0.0, 4.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Left && dir_cert == Certificate.On && id == index_map["h"] - q = (0.0, 14.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Left && dir_cert == Certificate.Left && id == index_map["h"] - q = (-2.0, 0.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k - q = (0.0, -2.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k - q = (2.0, -2.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k - q = (4.0, 4.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k - k = index_map["d"] - q = (20.0, 2.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Left && dir_cert == Certificate.On && id == index_map["c"] - q = (20.0, 17.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Right && dir_cert == Certificate.On && id == index_map["e"] - q = (20.0, -5.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Left && dir_cert == Certificate.Left && id == index_map["c"] - q = (20.0, 30.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Right && dir_cert == Certificate.Right && id == index_map["e"] - q = (10.0, 10.0) - dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @inferred DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k - end + @testset "General positions" begin + k = index_map["a"] + q = (6.0, 0.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Right && dir_cert == Certificate.On && id == index_map["b"] + @inferred DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q = (14.0, 0.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Right && dir_cert == Certificate.Right && id == index_map["b"] + q = (0.0, 4.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Left && dir_cert == Certificate.On && id == index_map["h"] + q = (0.0, 14.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Left && dir_cert == Certificate.Left && id == index_map["h"] + q = (-2.0, 0.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k + q = (0.0, -2.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k + q = (2.0, -2.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k + q = (4.0, 4.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k + k = index_map["d"] + q = (20.0, 2.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Left && dir_cert == Certificate.On && id == index_map["c"] + q = (20.0, 17.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Right && dir_cert == Certificate.On && id == index_map["e"] + q = (20.0, -5.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Left && dir_cert == Certificate.Left && id == index_map["c"] + q = (20.0, 30.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Right && dir_cert == Certificate.Right && id == index_map["e"] + q = (10.0, 10.0) + dir, dir_cert, id = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @inferred DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test dir == Certificate.Outside && dir_cert == Certificate.Outside && id == k + end - @testset "Stepping down edges" begin - k = index_map["a"] - q = (6.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) - q = (10.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test DT.is_degenerate(q_pos) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) - q = (12.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @inferred DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["b"], index_map["c"], index_map["p"]) - q = (20.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["b"], index_map["c"], index_map["p"]) - q = (22.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_outside(q_cert) && - (u, v, w) == (index_map["d"], index_map["c"], DT.𝒢) - q = (0.0, 2.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["h"], index_map["a"], index_map["s"]) - q = (0.0, 10.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["h"], index_map["a"], index_map["s"]) - q = (0.0, 12.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["g"], index_map["h"], index_map["b1"]) - q = (0.0, 20.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["g"], index_map["h"], index_map["b1"]) - q = (0.0, 22.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_outside(q_cert) && - (u, v, w) == (index_map["g"], index_map["f"], DT.𝒢) - @inferred DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - q = (0.0, 0.0) - direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) - @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) - end + @testset "Stepping down edges" begin + k = index_map["a"] + q = (6.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) + q = (10.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test DT.is_degenerate(q_pos) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) + q = (12.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @inferred DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["b"], index_map["c"], index_map["p"]) + q = (20.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["b"], index_map["c"], index_map["p"]) + q = (22.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_outside(q_cert) && + (u, v, w) == (index_map["d"], index_map["c"], DT.𝒢) + q = (0.0, 2.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["h"], index_map["a"], index_map["s"]) + q = (0.0, 10.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["h"], index_map["a"], index_map["s"]) + q = (0.0, 12.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["g"], index_map["h"], index_map["b1"]) + q = (0.0, 20.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["g"], index_map["h"], index_map["b1"]) + q = (0.0, 22.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_outside(q_cert) && + (u, v, w) == (index_map["g"], index_map["f"], DT.𝒢) + @inferred DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + q = (0.0, 0.0) + direction, q_pos, next_vertex = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + q_cert, u, v, w = DT.search_down_adjacent_boundary_edges(tri, k, q, direction, q_pos, next_vertex) + @test DT.is_on(q_cert) && (u, v, w) == (index_map["a"], index_map["b"], index_map["t"]) + end - @testset "Outside" begin - k = index_map["b"] - q = [2.0, 4.0] - direction, q_pos, next_vertex, right_cert, left_cert = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test DT.is_outside(direction) - i, j, edge_cert, triangle_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test i == index_map["a"] && - j == index_map["t"] && - DT.has_one_intersection(edge_cert) && - DT.is_outside(triangle_cert) - end + @testset "Outside" begin + k = index_map["b"] + q = [2.0, 4.0] + direction, q_pos, next_vertex, right_cert, left_cert = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test DT.is_outside(direction) + i, j, edge_cert, triangle_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test i == index_map["a"] && + j == index_map["t"] && + DT.has_one_intersection(edge_cert) && + DT.is_outside(triangle_cert) + end - @testset "Testing for points already on the boundary" begin - for k in DT.each_point_index(pts) - local dir, rc, ℓc - if DT.is_exterior_boundary_node(tri, k) - dir, qp, _k, rc, ℓc = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, get_point(tri, k)) - @test DT.is_degenerate(qp) - end + @testset "Testing for points already on the boundary" begin + for k in DT.each_point_index(pts) + local dir, rc, ℓc + if DT.is_exterior_boundary_node(tri, k) + dir, qp, _k, rc, ℓc = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, get_point(tri, k)) + @test DT.is_degenerate(qp) end - end + end + end end @testset "check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex" begin - @testset "General" begin - k = index_map["g"] - right = index_map["h"] - left = index_map["f"] - q = (3.8544234210286, 19.2195032844691) - p = pts[k] - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - dir, dir_cert, id, rc, ℓc = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - @test rc == right_cert && ℓc == left_cert - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) && k == k - q = (6.0, 18.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["f"], index_map["a1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) && k == k - q = (4.2913632954055, 16.864882850327) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a1"], index_map["i"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) && k == k - q = (3.368934671721, 17.3989204745654) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) && k == k - q = (4.0, 17.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) && k == k - q = (5.0, 15.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (j, i, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_right(edge_cert) && DT.is_outside(tri_cert) - @test DT.is_positively_oriented(DT.triangle_orientation(tri, i, j, q)) - q = (5.0, 12.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (3.0, 12.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (3.0, 14.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (2.0, 14.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - q = (0.5, 14.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["h"], index_map["b1"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - q = (1.0, 16.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["h"], index_map["b1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (1.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (2.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (3.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - q = (18.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["f"], index_map["a1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (4.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - q = (4.0, 12.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (-1.0, 19.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (-1.0, 20.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) &&DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (0.0, 21.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (-1.0, 21.0) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) &&DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (3.0, 21.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (-2.0, -2.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - k = index_map["b"] - right = index_map["c"] - left = index_map["a"] - q = (10.0, 1.0) - p = pts[k] - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["p"], index_map["t"], index_map["b"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (16.27931, 0.4487) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["c"], index_map["p"], index_map["b"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - q = (17.0, 1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["c"], index_map["p"], index_map["b"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) - q = (15.0, -1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (23.0, -1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (10.0, -1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (8.0, -1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) - q = (18.0, 3.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["p"], index_map["c"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (11.4965, 2.53) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["t"], index_map["p"], index_map["b"]) &&DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (5.0, 2.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a"], index_map["t"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (4.0, 1.0) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["a"], index_map["t"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) - q = (5.2, 0.6) - right_cert = DT.point_position_relative_to_line(p, pts[right], q) - left_cert = DT.point_position_relative_to_line(p, pts[left], q) - i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test (i, j, k) == (index_map["t"], index_map["a"], index_map["b"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) - @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - end + @testset "General" begin + k = index_map["g"] + right = index_map["h"] + left = index_map["f"] + q = (3.8544234210286, 19.2195032844691) + p = pts[k] + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + dir, dir_cert, id, rc, ℓc = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + @test rc == right_cert && ℓc == left_cert + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) && k == k + q = (6.0, 18.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["f"], index_map["a1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) && k == k + q = (4.2913632954055, 16.864882850327) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a1"], index_map["i"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) && k == k + q = (3.368934671721, 17.3989204745654) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) && k == k + q = (4.0, 17.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) && k == k + q = (5.0, 15.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (j, i, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_right(edge_cert) && DT.is_outside(tri_cert) + @test DT.is_positively_oriented(DT.triangle_orientation(tri, i, j, q)) + q = (5.0, 12.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (3.0, 12.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (3.0, 14.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (2.0, 14.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + q = (0.5, 14.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["h"], index_map["b1"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + q = (1.0, 16.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["h"], index_map["b1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (1.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["b1"], index_map["i"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (2.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["a1"], index_map["g"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (3.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + q = (18.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["f"], index_map["a1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (4.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a1"], index_map["f"], index_map["g"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + q = (4.0, 12.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["i"], index_map["b1"], index_map["g"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (-1.0, 19.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (-1.0, 20.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) &&DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (0.0, 21.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (-1.0, 21.0) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) &&DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (3.0, 21.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (-2.0, -2.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["g"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + k = index_map["b"] + right = index_map["c"] + left = index_map["a"] + q = (10.0, 1.0) + p = pts[k] + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["p"], index_map["t"], index_map["b"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (16.27931, 0.4487) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["c"], index_map["p"], index_map["b"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + q = (17.0, 1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["c"], index_map["p"], index_map["b"]) && DT.is_on(edge_cert) && DT.is_inside(tri_cert) + q = (15.0, -1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (23.0, -1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (10.0, -1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (8.0, -1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (0, 0, index_map["b"]) && DT.is_none(edge_cert) && DT.is_outside(tri_cert) + q = (18.0, 3.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["p"], index_map["c"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (11.4965, 2.53) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["t"], index_map["p"], index_map["b"]) &&DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (5.0, 2.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a"], index_map["t"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (4.0, 1.0) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["a"], index_map["t"], index_map["b"]) && DT.is_single(edge_cert) && DT.is_outside(tri_cert) + q = (5.2, 0.6) + right_cert = DT.point_position_relative_to_line(p, pts[right], q) + left_cert = DT.point_position_relative_to_line(p, pts[left], q) + i, j, edge_cert, tri_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test (i, j, k) == (index_map["t"], index_map["a"], index_map["b"]) && DT.is_none(edge_cert) && DT.is_inside(tri_cert) + @inferred DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + end - @testset "Specific example" begin - k = 6 - q = get_point(pts, 9) - direction, q_pos, next_vertex, right_cert, left_cert = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) - i, j, edge_cert, triangle_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) - @test i == 25 && j == 9 && DT.is_on(edge_cert) && DT.is_inside(triangle_cert) - end -end \ No newline at end of file + @testset "Specific example" begin + k = 6 + q = get_point(pts, 9) + direction, q_pos, next_vertex, right_cert, left_cert = DT.check_for_intersections_with_adjacent_boundary_edges(tri, k, q) + i, j, edge_cert, triangle_cert = DT.check_for_intersections_with_interior_edges_adjacent_to_boundary_vertex(tri, k, q, right_cert, left_cert) + @test i == 25 && j == 9 && DT.is_on(edge_cert) && DT.is_inside(triangle_cert) + end +end diff --git a/test/point_location/jump_and_march.jl b/test/point_location/jump_and_march.jl index ecd32bbd2..8d5e67549 100644 --- a/test/point_location/jump_and_march.jl +++ b/test/point_location/jump_and_march.jl @@ -28,36 +28,50 @@ boundary_nodes = get_boundary_nodes(tri) q3 = (14.2726546767168, 18.7727571005127) V3 = [(index_map["f"], index_map["v"], index_map["e"])] q4 = (12.0, 2.0) - V4 = [(index_map["t"], index_map["p"], index_map["o"]), - (index_map["t"], index_map["b"], index_map["p"])] + V4 = [ + (index_map["t"], index_map["p"], index_map["o"]), + (index_map["t"], index_map["b"], index_map["p"]), + ] q5 = (13.0, 0.0) - V5 = [(index_map["b"], index_map["c"], index_map["p"]), - (index_map["c"], index_map["b"], DT.𝒢)] + V5 = [ + (index_map["b"], index_map["c"], index_map["p"]), + (index_map["c"], index_map["b"], DT.𝒢), + ] q6 = (6.0819947177817, 8.90410894457) V6 = [(index_map["j"], index_map["k"], DT.𝒢 - 1)] q7 = (15.8, 9.2) - V7 = [(index_map["m"], DT.𝒢 - 2, index_map["r"]), - (index_map["m"], DT.𝒢 - 3, index_map["r"])] + V7 = [ + (index_map["m"], DT.𝒢 - 2, index_map["r"]), + (index_map["m"], DT.𝒢 - 3, index_map["r"]), + ] q8 = (14.5391680629781, 8.5135910023477) - V8 = [(index_map["m"], index_map["n"], DT.𝒢 - 2), - (index_map["m"], index_map["n"], DT.𝒢 - 3)] + V8 = [ + (index_map["m"], index_map["n"], DT.𝒢 - 2), + (index_map["m"], index_map["n"], DT.𝒢 - 3), + ] q9 = (22.0, 8.0) V9 = [(index_map["d"], index_map["c"], DT.𝒢)] q10 = (6.0, 11.0) - V10 = [(index_map["j"], index_map["k"], DT.𝒢 - 1), + V10 = [ + (index_map["j"], index_map["k"], DT.𝒢 - 1), (index_map["k"], index_map["ℓ"], DT.𝒢 - 1), (index_map["ℓ"], index_map["i"], DT.𝒢 - 1), - (index_map["i"], index_map["j"], DT.𝒢 - 1)] + (index_map["i"], index_map["j"], DT.𝒢 - 1), + ] q11 = (6.0819947177817, 8.90410894457) V11 = [(index_map["j"], index_map["k"], DT.𝒢 - 1)] q12 = (-6.6465702688004, 19.4798146355492) V12 = [(index_map["h"], index_map["g"], DT.𝒢)] q13 = (-20.0, 10.0) - V13 = [(index_map["h"], index_map["g"], DT.𝒢), - (index_map["a"], index_map["h"], DT.𝒢)] + V13 = [ + (index_map["h"], index_map["g"], DT.𝒢), + (index_map["a"], index_map["h"], DT.𝒢), + ] q14 = (20.0, 6.0) - V14 = [(index_map["c"], index_map["d"], index_map["q"]), - (index_map["c"], index_map["d"], DT.𝒢)] + V14 = [ + (index_map["c"], index_map["d"], index_map["q"]), + (index_map["c"], index_map["d"], DT.𝒢), + ] allq = [q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14] allV = [V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14] for _ in 1:36 @@ -98,14 +112,14 @@ rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) x, y = complicated_geometry() rng = StableRNG(919191919) boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri2 = triangulate(points; rng, boundary_nodes, delete_ghosts=false) + tri2 = triangulate(points; rng, boundary_nodes, delete_ghosts = false) A = get_area(tri2) - refine!(tri2; max_area=1e-2A, use_circumcenter=true) + refine!(tri2; max_area = 1.0e-2A, use_circumcenter = true) a, b, c, d = 2.0, 10.0, -5.0, 7.5 nx = 20 ny = 10 - tri3 = DT.triangulate_rectangle(a, b, c, d, nx, ny, delete_ghosts=false) + tri3 = DT.triangulate_rectangle(a, b, c, d, nx, ny, delete_ghosts = false) for (tri_idx, tri) in enumerate((tri, tri2, tri3)) DT.compute_representative_points!(tri) @@ -133,13 +147,17 @@ rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) local c c = (p .+ q .+ r) ./ 3 for k in DT.each_solid_vertex(tri) - _V = find_triangle(tri, c; k, concavity_protection=true) + _V = find_triangle(tri, c; k, concavity_protection = true) @test DT.is_positively_oriented(DT.triangle_orientation(tri, _V)) if !DT.is_ghost_triangle(_V...) @test DT.compare_triangles(_V, V) && - DT.is_inside(DT.point_position_relative_to_triangle(tri, - _V, - c)) + DT.is_inside( + DT.point_position_relative_to_triangle( + tri, + _V, + c, + ), + ) else local V1, V2 V1 = DT.sort_triangle(V) @@ -154,9 +172,13 @@ rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) end _V = DT.construct_triangle(typeof(V), i1, DT.getj(V1), DT.getk(V1)) @test DT.compare_triangles(_V, V) && - DT.is_inside(DT.point_position_relative_to_triangle(tri, - _V, - c)) + DT.is_inside( + DT.point_position_relative_to_triangle( + tri, + _V, + c, + ), + ) end end end @@ -171,7 +193,7 @@ rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) for k in DT.each_solid_vertex(tri) rand() < 1 / 2 && continue for j in DT.each_solid_vertex(tri) - _V = find_triangle(tri, get_point(tri, k); k=j) + _V = find_triangle(tri, get_point(tri, k); k = j) @test k ∈ triangle_vertices(_V) @test DT.is_positively_oriented(DT.triangle_orientation(tri, _V)) end @@ -209,7 +231,7 @@ end k = [8.0, 4.0] pts = [a, b, c, d, e, f, g, h, i, j, k] rng = StableRNG(213) - tri = triangulate(pts; rng, delete_ghosts=false, randomise=false) + tri = triangulate(pts; rng, delete_ghosts = false, randomise = false) for qi in each_solid_vertex(tri) for k in each_solid_vertex(tri) q = get_point(tri, qi) @@ -221,9 +243,9 @@ end end @testset "History structure" begin - history = DT.PointLocationHistory{NTuple{3,Int},NTuple{2,Int},Int}() - @test history.triangles == NTuple{3,Int}[] - @test history.collinear_segments == NTuple{2,Int}[] + history = DT.PointLocationHistory{NTuple{3, Int}, NTuple{2, Int}, Int}() + @test history.triangles == NTuple{3, Int}[] + @test history.collinear_segments == NTuple{2, Int}[] @test history.left_vertices == Int[] @test history.right_vertices == Int[] @test history.collinear_point_indices == Int[] @@ -284,13 +306,13 @@ end f1 = (5.0, 4.3) pts = [[[d, e, f, a, b, f1, e1, c1, d1, c, d]], [[g, h, i, ℓ, k, j, g]]] existing_points = [m, n, o, p, q, r, s, t, u, v, w, z, a1, b1] - nodes, points = convert_boundary_points_to_indices(pts; existing_points=existing_points) - tri = triangulate(points; boundary_nodes=nodes, delete_ghosts=false) + nodes, points = convert_boundary_points_to_indices(pts; existing_points = existing_points) + tri = triangulate(points; boundary_nodes = nodes, delete_ghosts = false) i, j, k = 2, 25, 8 T = (i, j, k) r = 5 for i in 1:10000 - V = find_triangle(tri, get_point(tri, k); point_indices=nothing, m=nothing, try_points=nothing, k=r, concavity_protection=true) + V = find_triangle(tri, get_point(tri, k); point_indices = nothing, m = nothing, try_points = nothing, k = r, concavity_protection = true) @test !DT.is_outside(DT.point_position_relative_to_triangle(tri, V, get_point(tri, k))) end end @@ -308,17 +330,17 @@ end inner = [[r, z, v, u, w, t, s, r]] boundary_nodes, points = convert_boundary_points_to_indices([outer, inner]) rng = StableRNG(123) - tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) - refine!(tri; max_area=0.01get_area(tri), rng, use_circumcenter=true) + tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) + refine!(tri; max_area = 0.01get_area(tri), rng, use_circumcenter = true) qs = [ (4.0, 5.0), (1.0, 5.6), (0.2, 5.0), (0.0, -1.0), (0.5, 3.5), (2.5, 1.5), (1.0, 2.0), (4.5, 1.0), (6.0, 1.5), - (0.5, 8.5), (1.0, 7.5), (1.2, 1.6) + (0.5, 8.5), (1.0, 7.5), (1.2, 1.6), ] δs = [DelaunayTriangulation.distance_to_polygon(q, get_points(tri), get_boundary_nodes(tri)) for q in qs] for i in 1:1000 - Vs = [find_triangle(tri, q, concavity_protection=true, rng=StableRNG(i + j)) for (j, q) in enumerate(qs)] + Vs = [find_triangle(tri, q, concavity_protection = true, rng = StableRNG(i + j)) for (j, q) in enumerate(qs)] for (q, δ, V) in zip(qs, δs, Vs) cert = DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) if δ ≥ 0.0 @@ -335,7 +357,7 @@ end rng = StableRNG(i) qs = [((b - a) * rand(rng) + a, (d - c) * rand(rng) + c) for _ in 1:1000] δs = [DelaunayTriangulation.distance_to_polygon(q, get_points(tri), get_boundary_nodes(tri)) for q in qs] - Vs = [find_triangle(tri, q, concavity_protection=true, rng=StableRNG(i + j)) for (j, q) in enumerate(qs)] + Vs = [find_triangle(tri, q, concavity_protection = true, rng = StableRNG(i + j)) for (j, q) in enumerate(qs)] for (q, δ, V) in zip(qs, δs, Vs) cert = DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) if δ ≥ 0.0 @@ -368,21 +390,21 @@ end new_domain₂ = [[t₁, w₁, v₁, u₁, t₁]] boundary_nodes, points = convert_boundary_points_to_indices([outer, inner, new_domain₁, new_domain₂]) rng = StableRNG(125123) - tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) + tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) @test DT.is_disjoint(tri) - refine!(tri; max_area=0.001get_area(tri), rng, use_circumcenter=true) + refine!(tri; max_area = 0.001get_area(tri), rng, use_circumcenter = true) qs = [ (0.6, 6.4), (1.4, 0.8), (3.1, 2.9), (6.3, 4.9), (4.6, 3.5), (7.0, 7.0), (8.9, 5.1), (5.8, 0.8), (1.0, 1.5), - (1.5, 2.0), (8.15, 6.0) + (1.5, 2.0), (8.15, 6.0), ] q = (7.0, 7.0) # When you have a point that is exactly the same as a representative point, you need to be careful of (1) the point being exactly collinear with a ghost edge, and (2) the algorithm mistakenly regarding q as if it were equal to a triangle's vertices (since this is where the ghost vertices map). This is now fixed, but we need this isolated to avoid regressions. - V = find_triangle(tri, q, rng=StableRNG(268), k=31, concavity_protection=true) + V = find_triangle(tri, q, rng = StableRNG(268), k = 31, concavity_protection = true) @test !DT.is_outside(DT.point_position_relative_to_triangle(tri, V, q)) δs = [DelaunayTriangulation.distance_to_polygon(q, get_points(tri), get_boundary_nodes(tri)) for q in qs] for i in 1:1000 - Vs = [find_triangle(tri, q; concavity_protection=true, rng=StableRNG(i)) for q in qs] + Vs = [find_triangle(tri, q; concavity_protection = true, rng = StableRNG(i)) for q in qs] for (q, δ, V) in zip(qs, δs, Vs) cert = DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) if δ > 0.0 @@ -401,7 +423,7 @@ end rng = StableRNG(i) qs = [((b - a) * rand(rng) + a, (d - c) * rand(rng) + c) for _ in 1:100] δs = [DelaunayTriangulation.distance_to_polygon(q, get_points(tri), get_boundary_nodes(tri)) for q in qs] - Vs = [find_triangle(tri, q, concavity_protection=true, rng=StableRNG(i + j)) for (j, q) in enumerate(qs)] + Vs = [find_triangle(tri, q, concavity_protection = true, rng = StableRNG(i + j)) for (j, q) in enumerate(qs)] for (q, δ, V) in zip(qs, δs, Vs) cert = DelaunayTriangulation.point_position_relative_to_triangle(tri, V, q) if δ ≥ 0.0 @@ -419,20 +441,20 @@ end @testset "A simple boundary" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], randomise=false) - V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers=Val(true), k=4) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], randomise = false) + V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers = Val(true), k = 4) @test invisible_flag && DT.is_invisible(DT.test_visibility(tri, (1 / 2, -1.0), 4)) - @inferred find_triangle(tri, (1 / 2, -1.0), use_barriers=Val(true), k=4) + @inferred find_triangle(tri, (1 / 2, -1.0), use_barriers = Val(true), k = 4) @test V == (1, 2, 3) @test DT.is_positively_oriented(DT.triangle_orientation(tri, V)) - V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers=Val(true), k=3) + V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers = Val(true), k = 3) @test invisible_flag && DT.is_invisible(DT.test_visibility(tri, (1 / 2, -1.0), 3)) @test V == (1, 2, 3) @test DT.is_positively_oriented(DT.triangle_orientation(tri, V)) - V, invisible_flag = jump_and_march(tri, (1 / 2, -1.0), use_barriers=Val(true), k=1) + V, invisible_flag = jump_and_march(tri, (1 / 2, -1.0), use_barriers = Val(true), k = 1) @test invisible_flag && DT.is_invisible(DT.test_visibility(tri, (1 / 2, -1.0), 1)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V, (1 / 2, -1, 0))) # starting at a boundary edge right next to the query point - V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers=Val(true), k=2) + V, invisible_flag = find_triangle(tri, (1 / 2, -1.0), use_barriers = Val(true), k = 2) @test invisible_flag && DT.is_invisible(DT.test_visibility(tri, (1 / 2, -1.0), 2)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V, (1 / 2, -1.0))) end @@ -440,17 +462,19 @@ end @testset "An unconstrained triangulation with a segment inside it" begin for _ in 1:1000 - points = [(-8.0, 6.0), (-10.0, 1.0), (-2.0, -2.0), (1.38, 2.05), - (2.0, 1.0), (4.78, 3.23), (0.0, 6.0), (-3.0, 4.0), (-3.0, 2.0)] + points = [ + (-8.0, 6.0), (-10.0, 1.0), (-2.0, -2.0), (1.38, 2.05), + (2.0, 1.0), (4.78, 3.23), (0.0, 6.0), (-3.0, 4.0), (-3.0, 2.0), + ] segments = Set([(8, 9)]) - tri = triangulate(points; segments, randomise=false) + tri = triangulate(points; segments, randomise = false) q1 = (-1.0, 1.0) q2 = (-4.0, 1.0) q3 = (-8.0, 2.0) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=1) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=1) - @inferred find_triangle(tri, q1, use_barriers=Val(true), k=1) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=1) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 1) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 1) + @inferred find_triangle(tri, q1, use_barriers = Val(true), k = 1) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 1) @test DT.compare_triangles(V1, (9, 8, 1)) @test DT.is_positively_oriented(DT.triangle_orientation(tri, V1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -460,9 +484,9 @@ end @test invisible_flag1 && DT.is_invisible(DT.test_visibility(tri, q1, 1)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 1)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 1)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=2) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=2) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=2) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 2) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 2) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 2) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -472,9 +496,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 2)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 2)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 2)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=3) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=3) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=3) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 3) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 3) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 3) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -484,9 +508,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 3)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 3)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 3)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=4) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=4) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=4) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 4) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 4) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 4) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -496,9 +520,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 4)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 4)) @test invisible_flag3 && DT.is_invisible(DT.test_visibility(tri, q3, 4)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=5) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=5) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=5) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 5) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 5) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 5) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -508,9 +532,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 5)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 5)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 5)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=6) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=6) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=6) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 6) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 6) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 6) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -520,9 +544,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 6)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 6)) @test invisible_flag3 && DT.is_invisible(DT.test_visibility(tri, q3, 6)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=7) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=7) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=7) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 7) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 7) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 7) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (8, 9, 4)) @@ -532,9 +556,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 7)) @test invisible_flag2 && DT.is_invisible(DT.test_visibility(tri, q2, 7)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 7)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=8) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=8) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=8) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 8) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 8) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 8) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -544,9 +568,9 @@ end @test !invisible_flag1 && DT.is_visible(DT.test_visibility(tri, q1, 8)) @test !invisible_flag2 && DT.is_visible(DT.test_visibility(tri, q2, 8)) @test !invisible_flag3 && DT.is_visible(DT.test_visibility(tri, q3, 8)) - V1, invisible_flag1 = find_triangle(tri, q1, use_barriers=Val(true), k=9) - V2, invisible_flag2 = find_triangle(tri, q2, use_barriers=Val(true), k=9) - V3, invisible_flag3 = find_triangle(tri, q3, use_barriers=Val(true), k=9) + V1, invisible_flag1 = find_triangle(tri, q1, use_barriers = Val(true), k = 9) + V2, invisible_flag2 = find_triangle(tri, q2, use_barriers = Val(true), k = 9) + V3, invisible_flag3 = find_triangle(tri, q3, use_barriers = Val(true), k = 9) @test DT.compare_triangles(V1, (9, 3, 4)) @test DT.is_inside(DT.point_position_relative_to_triangle(tri, V1, q1)) @test DT.compare_triangles(V2, (2, 3, 9)) @@ -581,7 +605,7 @@ end boundary_nodes, points = convert_boundary_points_to_indices(boundary) q1, r1 = (5.0, 6.0), (3.0, 1.0) push!(points, q1, r1) - tri = triangulate(points; boundary_nodes, rng=StableRNG(123)) + tri = triangulate(points; boundary_nodes, rng = StableRNG(123)) K1, L1, M1, N1, O1, P1, S1 = (2.0, 6.0), (6.0, 1.0), (5.2, 2.4), (9.0, 4.0), (5.0, -2.0), (3.0, 13.0), (0.5, 4.0) all_q = [K1, L1, M1, N1, O1, P1, S1] blocked_test(Vfound, Vtrue) = begin @@ -593,14 +617,14 @@ end visible_test(Vfound, Vtrue, q) = begin _p, _q, _r = Vtrue _i, _j, __k = !(_p isa Integer) ? findfirst(==(_p), points) : _p, # check for ghost vertices - !(_q isa Integer) ? findfirst(==(_q), points) : _q, - !(_r isa Integer) ? findfirst(==(_r), points) : _r + !(_q isa Integer) ? findfirst(==(_q), points) : _q, + !(_r isa Integer) ? findfirst(==(_r), points) : _r _Vtrue = (_i, _j, __k) return DT.compare_triangles(Vfound, _Vtrue) && !DT.is_outside(DT.point_position_relative_to_triangle(tri, Vfound, q)) end _k = findfirst(==(a), points) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) #@test blocked_test(VK, (u, f, v)) #@test visible_test(VL, (f1, g1, k), L1) || visible_test(VL, (f1, k, ℓ), L1) # on (f1, k) #@test blocked_test(VM, (d1, r1, g1)) @@ -616,7 +640,7 @@ end @test flagVP && DT.is_invisible(DT.test_visibility(tri, P1, _k)) @test !flagVS && DT.is_visible(DT.test_visibility(tri, S1, _k)) _k = findfirst(==(q), points) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) #@test blocked_test(VK, (q, u, z)) #@test blocked_test(VL, (h1, z, a1)) #@test blocked_test(VM, (z, a1, h1)) @@ -632,7 +656,7 @@ end @test flagVP && DT.is_invisible(DT.test_visibility(tri, P1, _k)) @test flagVS && DT.is_invisible(DT.test_visibility(tri, S1, _k)) _k = findfirst(==(q1), points) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) #@test blocked_test(VK, (a1, w, d1)) #@test blocked_test(VL, (e1, d1, f1)) #@test blocked_test(VM, (e1, d1, f1)) @@ -648,7 +672,7 @@ end @test flagVP && DT.is_invisible(DT.test_visibility(tri, P1, _k)) @test flagVS && DT.is_invisible(DT.test_visibility(tri, S1, _k)) _k = findfirst(==(p), points) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) #@test blocked_test(VK, (a1, w, d1)) #@test visible_test(VL, (f1, g1, k), L1) || visible_test(VL, (f1, k, ℓ), L1) # on (f1, k) #@test blocked_test(VM, (c1, b1, o)) @@ -664,7 +688,7 @@ end @test flagVP && DT.is_invisible(DT.test_visibility(tri, P1, _k)) @test flagVS && DT.is_invisible(DT.test_visibility(tri, S1, _k)) _k = findfirst(==(b), points) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) @test blocked_test(VK, (b1, e1, f1)) || blocked_test(VK, (a1, w, d1)) @test visible_test(VL, (f1, g1, k), L1) || visible_test(VL, (f1, k, ℓ), L1) # on (f1, k) @test blocked_test(VM, (f1, g1, k)) @@ -681,7 +705,7 @@ end @test flagVS && DT.is_invisible(DT.test_visibility(tri, S1, _k)) add_segment!(tri, findfirst(==(m), points), findfirst(==(ℓ), points)) push!(all_q, (9.0, 1.0), (9.5, 0.5), (8.9, 1.1)) - (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS), (VH4, flagVH4), (VK9, flagVK9), (VH5, flagVH5) = find_triangle.(Ref(tri), all_q; k=_k, use_barriers=Val(true)) + (VK, flagVK), (VL, flagVL), (VM, flagVM), (VN, flagVN), (VO, flagVO), (VP, flagVP), (VS, flagVS), (VH4, flagVH4), (VK9, flagVK9), (VH5, flagVH5) = find_triangle.(Ref(tri), all_q; k = _k, use_barriers = Val(true)) @test blocked_test(VK, (m, ℓ, b)) @test blocked_test(VL, (m, ℓ, b)) @test blocked_test(VM, (m, ℓ, b)) @@ -712,7 +736,7 @@ end tri = triangulate(points) for _ in 1:20000 q = rand(2) - V, flag = find_triangle(tri, q; use_barriers=Val(true)) + V, flag = find_triangle(tri, q; use_barriers = Val(true)) @test !DT.is_outside(DT.point_position_relative_to_triangle(tri, V, q)) @test !flag end @@ -725,15 +749,15 @@ end q = (0.19 + 0.19) * rand(2) .- 0.19 push!(points, Tuple(q)) end - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1]) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1]) for _ in 1:20000 q = 2randn(2) k = rand(each_solid_vertex(tri)) while DT.is_boundary_node(tri, k)[1] k = rand(each_solid_vertex(tri)) end - V, flag = find_triangle(tri, q; k, use_barriers=Val(true)) + V, flag = find_triangle(tri, q; k, use_barriers = Val(true)) @test !DT.is_ghost_triangle(V) end end -end \ No newline at end of file +end diff --git a/test/point_location/select_initial_point.jl b/test/point_location/select_initial_point.jl index bc740bca0..ffb73ff4a 100644 --- a/test/point_location/select_initial_point.jl +++ b/test/point_location/select_initial_point.jl @@ -5,7 +5,6 @@ using Random using StableRNGs - global tri, label_map, index_map = simple_geometry() add_ghost_triangles!(tri) DT.compute_representative_points!(tri) @@ -35,12 +34,18 @@ end current_idx = 1 for i in DT.each_point_index(pts) if i ≠ 5 - current_dist, current_idx = DT.compare_distance(current_dist, current_idx, tri, i, - qx, qy) - @inferred DT.compare_distance(current_dist, current_idx, tri, i, - qx, qy) - @inferred DT.compare_distance(current_dist, current_idx, pts, i, - qx, qy) + current_dist, current_idx = DT.compare_distance( + current_dist, current_idx, tri, i, + qx, qy, + ) + @inferred DT.compare_distance( + current_dist, current_idx, tri, i, + qx, qy, + ) + @inferred DT.compare_distance( + current_dist, current_idx, pts, i, + qx, qy, + ) end end cd, ci = findmin([[norm(p .- (qx, qy))^2 + (p == pts[5]) * Inf] for p in pts]) @@ -83,14 +88,14 @@ end q = (20rand(rng), 20rand(rng)) ci = tried_idx[argmin([norm(pts[i] .- q) for i in tried_idx])] rng = StableRNG(s) - ci2 = DT.select_initial_point(tri, q; m, rng, point_indices=(1, 5, 8, 19, 20)) - @inferred DT.select_initial_point(tri, q; m, rng, point_indices=(1, 5, 8, 19, 20)) + ci2 = DT.select_initial_point(tri, q; m, rng, point_indices = (1, 5, 8, 19, 20)) + @inferred DT.select_initial_point(tri, q; m, rng, point_indices = (1, 5, 8, 19, 20)) @test ci == ci2 @test ci2 ∈ (1, 5, 8, 19, 20) end for k in DT.each_point_index(pts) - @test DT.select_initial_point(tri, k; try_points=k) == k + @test DT.select_initial_point(tri, k; try_points = k) == k end end end diff --git a/test/point_location/select_initial_triangle_interior_node.jl b/test/point_location/select_initial_triangle_interior_node.jl index bfc981b3c..5c3e56fd0 100644 --- a/test/point_location/select_initial_triangle_interior_node.jl +++ b/test/point_location/select_initial_triangle_interior_node.jl @@ -6,7 +6,6 @@ using StableRNGs using StatsBase - tri, label_map, index_map = simple_geometry() add_ghost_triangles!(tri) pts = get_points(tri) @@ -28,176 +27,192 @@ rep[3].x = mean([18.0, 18.0, 14.0, 12.0, 14.0, 14.0]) rep[3].y = mean([12.0, 6.0, 2.0, 4.0, 6.0, 10.0]) @testset "Selecting a random edge" begin - k = 7 - edges = DT.get_adjacent2vertex(tri, k) - Random.seed!(2992881) - rng = StableRNG(2992881) - i, j = rand(rng, edges) - pᵢ, pⱼ = pts[i], pts[j] - rng = StableRNG(2992881) - u, v, qᵢ, qⱼ = DT.select_random_edge(tri, edges, rng) - @test u == i && v == j && qᵢ == pᵢ && pⱼ == qⱼ - @inferred DT.select_random_edge(tri, edges, rng) + k = 7 + edges = DT.get_adjacent2vertex(tri, k) + Random.seed!(2992881) + rng = StableRNG(2992881) + i, j = rand(rng, edges) + pᵢ, pⱼ = pts[i], pts[j] + rng = StableRNG(2992881) + u, v, qᵢ, qⱼ = DT.select_random_edge(tri, edges, rng) + @test u == i && v == j && qᵢ == pᵢ && pⱼ == qⱼ + @inferred DT.select_random_edge(tri, edges, rng) end @testset "Testing for a non-exterior-boundary node" begin - for _ in 1:350 - local i, j, pᵢ, pⱼ, line_cert_i, line_cert_j, k - k = index_map["m"] # This point is on the boundary of an interior hole - # Close - q = (16.4445425, 19.8427) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["v"] && - _j == index_map["z"] && - _pᵢ == get_point(pts, index_map["v"]) && - _pⱼ == get_point(pts, index_map["z"]) + for _ in 1:350 + local i, j, pᵢ, pⱼ, line_cert_i, line_cert_j, k + k = index_map["m"] # This point is on the boundary of an interior hole + # Close + q = (16.4445425, 19.8427) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["v"] && + _j == index_map["z"] && + _pᵢ == get_point(pts, index_map["v"]) && + _pⱼ == get_point(pts, index_map["z"]) - # Further away - q = (4.008184, 1.077) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _j == index_map["w"] && - _i == index_map["u"] && - _pⱼ == get_point(pts, index_map["w"]) && - _pᵢ == get_point(pts, index_map["u"]) + # Further away + q = (4.008184, 1.077) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _j == index_map["w"] && + _i == index_map["u"] && + _pⱼ == get_point(pts, index_map["w"]) && + _pᵢ == get_point(pts, index_map["u"]) - # How are collinearities handled? - q = (14.0, 0.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test (_p == get_point(pts, k) && - (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && - _j == index_map["n"] && - _pᵢ == get_point(tri, DT.𝒢 - 2) && - _pⱼ == get_point(pts, index_map["n"])) || - (_p == get_point(pts, k) && - _i == index_map["n"] && - _j == index_map["u"] && - _pᵢ == get_point(tri, index_map["n"]) && - _pⱼ == get_point(pts, index_map["u"])) + # How are collinearities handled? + q = (14.0, 0.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test ( + _p == get_point(pts, k) && + (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && + _j == index_map["n"] && + _pᵢ == get_point(tri, DT.𝒢 - 2) && + _pⱼ == get_point(pts, index_map["n"]) + ) || + ( + _p == get_point(pts, k) && + _i == index_map["n"] && + _j == index_map["u"] && + _pᵢ == get_point(tri, index_map["n"]) && + _pⱼ == get_point(pts, index_map["u"]) + ) - # Now do the same test, but put the point above p - q = (14.0, 19.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test (_p == get_point(pts, k) && - _i == index_map["w"] && - _j == index_map["v"] && - _pᵢ == get_point(tri, index_map["w"]) && - _pⱼ == get_point(pts, index_map["v"])) || - (_p == get_point(pts, k) && - _i == index_map["v"] && - _j == index_map["z"] && - _pᵢ == get_point(tri, index_map["v"]) && - _pⱼ == get_point(pts, index_map["z"])) + # Now do the same test, but put the point above p + q = (14.0, 19.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test ( + _p == get_point(pts, k) && + _i == index_map["w"] && + _j == index_map["v"] && + _pᵢ == get_point(tri, index_map["w"]) && + _pⱼ == get_point(pts, index_map["v"]) + ) || + ( + _p == get_point(pts, k) && + _i == index_map["v"] && + _j == index_map["z"] && + _pᵢ == get_point(tri, index_map["v"]) && + _pⱼ == get_point(pts, index_map["z"]) + ) - # What happens if the point is on an edge? - q = (14.0, 7.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test (_p == get_point(pts, k) && - (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && - _j == index_map["n"] && - _pᵢ == get_point(tri, DT.𝒢 - 2) && - _pⱼ == get_point(pts, index_map["n"])) || - (_p == get_point(pts, k) && - _i == index_map["n"] && - _j == index_map["u"] && - _pᵢ == get_point(tri, index_map["n"]) && - _pⱼ == get_point(pts, index_map["u"])) + # What happens if the point is on an edge? + q = (14.0, 7.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test ( + _p == get_point(pts, k) && + (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && + _j == index_map["n"] && + _pᵢ == get_point(tri, DT.𝒢 - 2) && + _pⱼ == get_point(pts, index_map["n"]) + ) || + ( + _p == get_point(pts, k) && + _i == index_map["n"] && + _j == index_map["u"] && + _pᵢ == get_point(tri, index_map["n"]) && + _pⱼ == get_point(pts, index_map["u"]) + ) - # Now do the same test, but put the point above p - q = (14.0, 14.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test (_p == get_point(pts, k) && - _i == index_map["w"] && - _j == index_map["v"] && - _pᵢ == get_point(tri, index_map["w"]) && - _pⱼ == get_point(pts, index_map["v"])) || - (_p == get_point(pts, k) && - _i == index_map["v"] && - _j == index_map["z"] && - _pᵢ == get_point(tri, index_map["v"]) && - _pⱼ == get_point(pts, index_map["z"])) + # Now do the same test, but put the point above p + q = (14.0, 14.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test ( + _p == get_point(pts, k) && + _i == index_map["w"] && + _j == index_map["v"] && + _pᵢ == get_point(tri, index_map["w"]) && + _pⱼ == get_point(pts, index_map["v"]) + ) || + ( + _p == get_point(pts, k) && + _i == index_map["v"] && + _j == index_map["z"] && + _pᵢ == get_point(tri, index_map["v"]) && + _pⱼ == get_point(pts, index_map["z"]) + ) - # What if it is an existing triangle? - q = (12.0, 6.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["n"] && - _j == index_map["u"] && - _pᵢ == get_point(tri, index_map["n"]) && - _pⱼ == get_point(pts, index_map["u"]) + # What if it is an existing triangle? + q = (12.0, 6.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["n"] && + _j == index_map["u"] && + _pᵢ == get_point(tri, index_map["n"]) && + _pⱼ == get_point(pts, index_map["u"]) - # Now do the same test, but put the point above p - q = (13.288, 15.01) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["w"] && - _j == index_map["v"] && - _pᵢ == get_point(tri, index_map["w"]) && - _pⱼ == get_point(pts, index_map["v"]) - q = (16.437, 15.42) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["v"] && - _j == index_map["z"] && - _pᵢ == get_point(tri, index_map["v"]) && - _pⱼ == get_point(pts, index_map["z"]) - q = (17.46287, 13.111) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["z"] && - _j == index_map["r"] && - _pᵢ == get_point(tri, index_map["z"]) && - _pⱼ == get_point(pts, index_map["r"]) + # Now do the same test, but put the point above p + q = (13.288, 15.01) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["w"] && + _j == index_map["v"] && + _pᵢ == get_point(tri, index_map["w"]) && + _pⱼ == get_point(pts, index_map["v"]) + q = (16.437, 15.42) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["v"] && + _j == index_map["z"] && + _pᵢ == get_point(tri, index_map["v"]) && + _pⱼ == get_point(pts, index_map["z"]) + q = (17.46287, 13.111) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["z"] && + _j == index_map["r"] && + _pᵢ == get_point(tri, index_map["z"]) && + _pⱼ == get_point(pts, index_map["r"]) - # Check that everything is fine when the point is outside - q = (23.068, 6.92) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @inferred DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["r"] && - (_j == DT.𝒢 - 2 || _j == DT.𝒢 - 3) && - _pᵢ == get_point(tri, index_map["r"]) && - _pⱼ == get_point(tri, DT.𝒢 - 3) + # Check that everything is fine when the point is outside + q = (23.068, 6.92) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @inferred DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["r"] && + (_j == DT.𝒢 - 2 || _j == DT.𝒢 - 3) && + _pᵢ == get_point(tri, index_map["r"]) && + _pⱼ == get_point(tri, DT.𝒢 - 3) - # Can interior ghost edges be handled correctly? - q = (15.5, 9.0) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _i == index_map["r"] && - (_j == DT.𝒢 - 2 || _j == DT.𝒢 - 3) && - _pᵢ == get_point(tri, index_map["r"]) && - _pⱼ == get_point(tri, DT.𝒢 - 3) - q = (14.87, 4.01) - _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) - @test _p == get_point(pts, k) && - _j == index_map["n"] && - (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && - _pⱼ == get_point(tri, index_map["n"]) && - _pᵢ == get_point(tri, DT.𝒢 - 3) - end + # Can interior ghost edges be handled correctly? + q = (15.5, 9.0) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _i == index_map["r"] && + (_j == DT.𝒢 - 2 || _j == DT.𝒢 - 3) && + _pᵢ == get_point(tri, index_map["r"]) && + _pⱼ == get_point(tri, DT.𝒢 - 3) + q = (14.87, 4.01) + _p, _i, _j, _pᵢ, _pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, q) + @test _p == get_point(pts, k) && + _j == index_map["n"] && + (_i == DT.𝒢 - 2 || _i == DT.𝒢 - 3) && + _pⱼ == get_point(tri, index_map["n"]) && + _pᵢ == get_point(tri, DT.𝒢 - 3) + end end @testset "Testing points that are already in the triangulation" begin - for k in DT.each_point_index(pts) - local i, j, pᵢ, pⱼ - if !DT.is_exterior_boundary_node(tri, k) - for (i, j) in get_adjacent2vertex(tri, k) - p1, i1, j1, pᵢ1, pⱼ1 = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, i)) - p2, i2, j2, pᵢ2, pⱼ2 = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, j)) - if DT.is_ghost_vertex(i) - @test i ∈ (i1, j1) || i - 1 ∈ (i1, j1) || i + 1 ∈ (i1, j1) - else - @test i ∈ (i1, j1) - end - if DT.is_ghost_vertex(j) - @test j ∈ (i2, j2) || j - 1 ∈ (i2, j2) || j + 1 ∈ (i2, j2) - else - @test j ∈ (i2, j2) - end - end + for k in DT.each_point_index(pts) + local i, j, pᵢ, pⱼ + if !DT.is_exterior_boundary_node(tri, k) + for (i, j) in get_adjacent2vertex(tri, k) + p1, i1, j1, pᵢ1, pⱼ1 = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, i)) + p2, i2, j2, pᵢ2, pⱼ2 = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, j)) + if DT.is_ghost_vertex(i) + @test i ∈ (i1, j1) || i - 1 ∈ (i1, j1) || i + 1 ∈ (i1, j1) + else + @test i ∈ (i1, j1) + end + if DT.is_ghost_vertex(j) + @test j ∈ (i2, j2) || j - 1 ∈ (i2, j2) || j + 1 ∈ (i2, j2) + else + @test j ∈ (i2, j2) + end end - p, i, j, pᵢ, pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, k)) - @test get_adjacent(tri.adjacent, j, i) == k - end -end \ No newline at end of file + end + p, i, j, pᵢ, pⱼ = DT.select_initial_triangle_interior_vertex(tri, k, get_point(tri, k)) + @test get_adjacent(tri.adjacent, j, i) == k + end +end diff --git a/test/predicates/boundaries_and_ghosts.jl b/test/predicates/boundaries_and_ghosts.jl index 111252b64..b406e8708 100644 --- a/test/predicates/boundaries_and_ghosts.jl +++ b/test/predicates/boundaries_and_ghosts.jl @@ -7,13 +7,12 @@ const GV = DT.𝒢 using ..DelaunayTriangulation: Certificate - x, y = complicated_geometry() rng = StableRNG(99988) boundary_nodes, points = convert_boundary_points_to_indices(x, y) -tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) +tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) A = get_area(tri) -refine!(tri; max_area=1e-2A, rng, use_circumcenter=true) +refine!(tri; max_area = 1.0e-2A, rng, use_circumcenter = true) tri2, label_map, index_map = simple_geometry() add_ghost_triangles!(tri2) @@ -198,7 +197,7 @@ end @testset "has_boundary_nodes and is_constrained" begin @test DT.has_boundary_nodes(tri) @test DT.has_boundary_nodes(tri2) - _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary=true) + _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary = true) @test DT.has_boundary_nodes(_tri) __tri = triangulate(_tri.points) @test !DT.has_boundary_nodes(__tri) @@ -213,7 +212,7 @@ end p2 = @SVector[-5.98, 2.17] p3 = @SVector[-6.36, -1.55] pts = [p1, p2, p3] - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) @test all(DT.is_positively_oriented(DT.triangle_orientation(tri, T)) for T in each_triangle(tri)) DT.add_triangle!(get_triangles(tri), (2, 3, -1)) @test !all(DT.is_positively_oriented(DT.triangle_orientation(tri, T)) for T in each_triangle(tri)) @@ -223,7 +222,7 @@ end x, y = complicated_geometry() rng = StableRNG(99988) boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri = triangulate(points; rng, boundary_nodes, delete_ghosts=false) + tri = triangulate(points; rng, boundary_nodes, delete_ghosts = false) for (ghost_vertex, segment_index) in get_ghost_vertex_map(tri) nodes = get_boundary_nodes(tri, segment_index) for node in nodes @@ -271,4 +270,4 @@ end @test !flag2 && res2 == DT.∅ end end -end \ No newline at end of file +end diff --git a/test/predicates/certificate.jl b/test/predicates/certificate.jl index 034b54250..4801f464a 100644 --- a/test/predicates/certificate.jl +++ b/test/predicates/certificate.jl @@ -2,7 +2,8 @@ using ..DelaunayTriangulation const DT = DelaunayTriangulation using ..DelaunayTriangulation: Certificate -global i = [Certificate.Inside, +global i = [ + Certificate.Inside, Certificate.Degenerate, Certificate.Outside, Certificate.On, @@ -20,7 +21,7 @@ global i = [Certificate.Inside, Certificate.Closer, Certificate.Further, Certificate.Equidistant, - Certificate.Above, + Certificate.Above, Certificate.Below, Certificate.EncroachmentFailure, Certificate.PrecisionFailure, @@ -28,8 +29,10 @@ global i = [Certificate.Inside, Certificate.Acute, Certificate.FailedInsertion, Certificate.Visible, - Certificate.Invisible] -global j = [DT.is_inside, + Certificate.Invisible, +] +global j = [ + DT.is_inside, DT.is_degenerate, DT.is_outside, DT.is_on, @@ -47,7 +50,7 @@ global j = [DT.is_inside, DT.is_closer, DT.is_further, DT.is_equidistant, - DT.is_above, + DT.is_above, DT.is_below, DT.is_encroachment_failure, DT.is_precision_failure, @@ -55,7 +58,8 @@ global j = [DT.is_inside, DT.is_acute, DT.is_failed_insertion, DT.is_visible, - DT.is_invisible] + DT.is_invisible, +] @testset "Classifiers" begin for a in eachindex(i) diff --git a/test/predicates/general.jl b/test/predicates/general.jl index e72a94879..26268fb45 100644 --- a/test/predicates/general.jl +++ b/test/predicates/general.jl @@ -146,17 +146,21 @@ global p3, q3, r3 = (2.8, 1.4), (2.8, 2.4), (4.6, 1.4) # - global p4, q4, r4 = (2.8, 1.4), (3.8, 1.4), (4.6, 1.4) # 0 global p5, q5, r5 = (5.0, 1.4), (3.8, 1.4), (4.6, 1.4) # 0 global p6, q6, r6 = (5.0, 1.4), (3.8, 1.4), (4.4, 0.8) # + -global pqr = ((p1, q1, r1), (p2, q2, r2), (p3, q3, r3), +global pqr = ( + (p1, q1, r1), (p2, q2, r2), (p3, q3, r3), (p4, q4, r4), (p5, q5, r5), (p6, q6, r6), - (p4, q4, r4), (p5, q5, r5), (p6, q6, r6)) + (p4, q4, r4), (p5, q5, r5), (p6, q6, r6), +) @testset "triangle_orientation" begin - results = [Certificate.PositivelyOriented, + results = [ + Certificate.PositivelyOriented, Certificate.NegativelyOriented, Certificate.NegativelyOriented, Certificate.Degenerate, Certificate.Degenerate, - Certificate.PositivelyOriented] + Certificate.PositivelyOriented, + ] for ((p, q, r), result) in zip(pqr, results) @test DT.triangle_orientation(p, q, r) == result @inferred DT.triangle_orientation(p, q, r) @@ -170,11 +174,13 @@ end @testset "point_position_relative_to_circle" begin R = 5 a, b, c = (0.0, 5.0), (-3.0, -4.0), (3.0, 4.0) - p1, p2, p3, p4, p5 = [(0.0, -5.0), + p1, p2, p3, p4, p5 = [ + (0.0, -5.0), (5.0, 0.0), (-5.0, 0.0), (-3.0, 4.0), - (3.0, -4.0)] + (3.0, -4.0), + ] for p in (p1, p2, p3, p4, p5) cert = DT.point_position_relative_to_circle(a, b, c, p) @test DT.is_on(cert) @@ -236,12 +242,14 @@ end end @testset "point_position_relative_to_line" begin - results = [Certificate.Left, + results = [ + Certificate.Left, Certificate.Right, Certificate.Right, Certificate.Collinear, Certificate.Collinear, - Certificate.Left] + Certificate.Left, + ] for ((p, q, r), result) in zip(pqr, results) @test DT.point_position_relative_to_line(p, q, r) == result @inferred DT.point_position_relative_to_line(p, q, r) @@ -298,9 +306,9 @@ end @inferred DT.is_right(DT.point_position_on_line_segment(p, q, c3)) @test DT.is_degenerate(DT.point_position_on_line_segment(p, q, p)) @test DT.is_degenerate(DT.point_position_on_line_segment(p, q, q)) - p, q = (4.0, 5.0), (4.0, 1.50) + p, q = (4.0, 5.0), (4.0, 1.5) c1, c2, c3, c4, c5, c6, c7, c8 = (4.0, 3.0), (4.0, 2.5), (4.0, 4.0), (4.0, 4.5), (4.0, 1.0), - (4.0, 6.0), (4.0, 6.5), (4.0, 0.5) + (4.0, 6.0), (4.0, 6.5), (4.0, 0.5) (4.0, 6.0), (4.0, 6.5), (4.0, 0.5) @test DT.is_on(DT.point_position_on_line_segment(p, q, c1)) @test DT.is_on(DT.point_position_on_line_segment(p, q, c2)) @@ -329,7 +337,8 @@ end p11, q11, a11, b11 = (6.0, 6.5), (8.0, 5.5), (8.0, 5.0), (8.0, 7.5) # on point p12, q12, a12, b12 = (6.0, 6.5), (9.947, 8.137), (8.0, 5.0), (8.0, 7.5) # one point p13, q13, a13, b13 = (6.0, 6.5), (9.947, 8.137), (8.0, 5.0), (6.0, 7.0) # one point - results = [Certificate.Single, + results = [ + Certificate.Single, Certificate.None, Certificate.None, Certificate.Multiple, @@ -341,11 +350,14 @@ end Certificate.Touching, Certificate.Touching, Certificate.Single, - Certificate.Single] - pqab = ((p1, q1, a1, b1), (p2, q2, a2, b2), (p3, q3, a3, b3), (p4, q4, a4, b4), + Certificate.Single, + ] + pqab = ( + (p1, q1, a1, b1), (p2, q2, a2, b2), (p3, q3, a3, b3), (p4, q4, a4, b4), (p5, q5, a5, b5), (p6, q6, a6, b6), (p7, q7, a7, b7), (p8, q8, a8, b8), (p9, q9, a9, b9), (p10, q10, a10, b10), (p11, q11, a11, b11), (p12, q12, a12, b12), - (p13, q13, a13, b13)) + (p13, q13, a13, b13), + ) for ((p, q, a, b), result) in zip(pqab, results) @test DT.line_segment_intersection_type(p, q, a, b) == result @inferred DT.line_segment_intersection_type(p, q, a, b) @@ -356,18 +368,18 @@ end p, q, r = (2.0, 1.0), (5.0, 1.0), (2.0, 5.0) c1, c2, c3, c4 = (2.57, 3.35), (2.45, 2.51), (3.11, 2.43), (3.33, 1.83) # inside d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12 = (1.76, 4.06), (1.24, 4.109), + (2.589, 0.505), (3.19, -0.186), + (3.875, 4.53), (4.8, 2.698), (2.0, 6.5), + (2.0, 0.0), + (0.5, 1.0), (6.0, 1.0), (6.0, 0.0), + (1.0, 6.0) # outside (2.589, 0.505), (3.19, -0.186), - (3.875, 4.53), (4.8, 2.698), (2.0, 6.5), - (2.0, 0.0), - (0.5, 1.0), (6.0, 1.0), (6.0, 0.0), - (1.0, 6.0) # outside - (2.589, 0.505), (3.19, -0.186), - (3.875, 4.53), (4.8, 2.698), (2.0, 6.5), - (2.0, 0.0), - (0.5, 1.0), (6.0, 1.0), (6.0, 0.0), - (1.0, 6.0) # outside + (3.875, 4.53), (4.8, 2.698), (2.0, 6.5), + (2.0, 0.0), + (0.5, 1.0), (6.0, 1.0), (6.0, 0.0), + (1.0, 6.0) # outside e1, e2, e3, e4, e5, e6, e7, e8, e9, e10 = (2.0, 3.0), (2.0, 2.5), (2.0, 4.5), (2.0, 1.5), - (2.5, 1.0), (3.5, 1.0), (4.5, 1.0), p, q, r # on + (2.5, 1.0), (3.5, 1.0), (4.5, 1.0), p, q, r # on (2.5, 1.0), (3.5, 1.0), (4.5, 1.0), p, q, r # on for c in (c1, c2, c3, c4) @test DT.point_position_relative_to_triangle(p, q, r, c) == Certificate.Inside @@ -392,126 +404,126 @@ end p8 = Float64[4, -1] p9 = Float64[-1, 4] pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9] - T1 = DT.construct_triangle(NTuple{3,Int}, 4, 1, 6) - T2 = DT.construct_triangle(NTuple{3,Int}, 4, 2, 1) - T3 = DT.construct_triangle(NTuple{3,Int}, 3, 2, 4) - T4 = DT.construct_triangle(NTuple{3,Int}, 8, 1, 2) - T5 = DT.construct_triangle(NTuple{3,Int}, 8, 2, 3) - T6 = DT.construct_triangle(NTuple{3,Int}, 8, 3, 5) - T7 = DT.construct_triangle(NTuple{3,Int}, 5, 3, 7) - T8 = DT.construct_triangle(NTuple{3,Int}, 3, 4, 7) - T9 = DT.construct_triangle(NTuple{3,Int}, 5, 7, 9) - T10 = DT.construct_triangle(NTuple{3,Int}, 7, 6, 9) - T11 = DT.construct_triangle(NTuple{3,Int}, 7, 4, 6) + T1 = DT.construct_triangle(NTuple{3, Int}, 4, 1, 6) + T2 = DT.construct_triangle(NTuple{3, Int}, 4, 2, 1) + T3 = DT.construct_triangle(NTuple{3, Int}, 3, 2, 4) + T4 = DT.construct_triangle(NTuple{3, Int}, 8, 1, 2) + T5 = DT.construct_triangle(NTuple{3, Int}, 8, 2, 3) + T6 = DT.construct_triangle(NTuple{3, Int}, 8, 3, 5) + T7 = DT.construct_triangle(NTuple{3, Int}, 5, 3, 7) + T8 = DT.construct_triangle(NTuple{3, Int}, 3, 4, 7) + T9 = DT.construct_triangle(NTuple{3, Int}, 5, 7, 9) + T10 = DT.construct_triangle(NTuple{3, Int}, 7, 6, 9) + T11 = DT.construct_triangle(NTuple{3, Int}, 7, 4, 6) T = [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11] pt1 = ( - A=(3.9551298987095, 4.7489988803935), - B=(3.2585303811361, 4.3003415639903), - C=(2.69180534989, 4.4066025073489), - D=(3.2231100666833, 4.6781582514877), - E=(2.0424329182538, 4.8198395092992) + A = (3.9551298987095, 4.7489988803935), + B = (3.2585303811361, 4.3003415639903), + C = (2.69180534989, 4.4066025073489), + D = (3.2231100666833, 4.6781582514877), + E = (2.0424329182538, 4.8198395092992), ) pt2 = ( - A=(3.5, 3.5), - B=(3.8384340736083, 3.2777159548861), - C=(4.173119090818, 3.0606229707501), - D=(4.0736181397556, 3.8475850382431), - E=(4.390212074954, 3.6938108411468), - F=(4.390212074954, 4.2546343834981), - G=(4.7520337151806, 4.2998620885264), - H=(4.7520337151806, 4.661683728753) + A = (3.5, 3.5), + B = (3.8384340736083, 3.2777159548861), + C = (4.173119090818, 3.0606229707501), + D = (4.0736181397556, 3.8475850382431), + E = (4.390212074954, 3.6938108411468), + F = (4.390212074954, 4.2546343834981), + G = (4.7520337151806, 4.2998620885264), + H = (4.7520337151806, 4.661683728753), ) pt3 = ( - A=(3.114790793155, 2.9520764786821), - B=(3.3952025643307, 2.8163933635972), - C=(3.3137926952797, 2.4545717233705), - D=(2.951971055053, 2.3098430672799), - E=(2.9157888910304, 2.4726628053818), - F=(3.0786086291324, 2.6535736254952), - G=(3.901752860648, 2.6626191665008), - H=(3.0, 2.0), - I=(2.7258325299114, 1.8213838529739) + A = (3.114790793155, 2.9520764786821), + B = (3.3952025643307, 2.8163933635972), + C = (3.3137926952797, 2.4545717233705), + D = (2.951971055053, 2.3098430672799), + E = (2.9157888910304, 2.4726628053818), + F = (3.0786086291324, 2.6535736254952), + G = (3.901752860648, 2.6626191665008), + H = (3.0, 2.0), + I = (2.7258325299114, 1.8213838529739), ) pt4 = ( - A=(4.5781396673455, 2.7004728027825), - B=(4.6264236360138, 2.9231155471972), - C=(4.6693427192745, 3.1618529478347), - D=(4.70153203172, 3.3871781349531), - E=(4.5325381413811, 2.437593417811), - F=(4.4708419591939, 2.1988560171735), - G=(4.4520648602673, 2.0352270122422), - H=(4.3501320375233, 1.3082850395147) + A = (4.5781396673455, 2.7004728027825), + B = (4.6264236360138, 2.9231155471972), + C = (4.6693427192745, 3.1618529478347), + D = (4.70153203172, 3.3871781349531), + E = (4.5325381413811, 2.437593417811), + F = (4.4708419591939, 2.1988560171735), + G = (4.4520648602673, 2.0352270122422), + H = (4.3501320375233, 1.3082850395147), ) pt5 = ( - A=(3.433718968984, 1.1294534677817), - B=(3.7382811110409, 1.4137114670348), - C=(3.8499538964617, 0.9162599683419), - D=(3.6875207540314, 0.5304812550699), - E=(3.0377881843101, 1.2614303960064), - F=(3.7484331824428, -0.0481868148381), - G=(4.0, 2.0) + A = (3.433718968984, 1.1294534677817), + B = (3.7382811110409, 1.4137114670348), + C = (3.8499538964617, 0.9162599683419), + D = (3.6875207540314, 0.5304812550699), + E = (3.0377881843101, 1.2614303960064), + F = (3.7484331824428, -0.0481868148381), + G = (4.0, 2.0), ) pt6 = ( - A=(2.8956591846836, 0.4086563982472), - B=(2.4286639001964, 0.90610789694), - C=(2.0936455439339, 1.2309741818007), - D=(1.5149774740259, 1.4035593956329), - E=(0.824636618697, 1.586296680867), - F=(1.3322401887918, 1.2715824674082), - G=(1.6063461166429, 1.0177806823609), - H=(2.0225810441206, 0.713218540304), - I=(2.3169911147756, 0.4391126124529), - J=(2.6317053282343, 0.1954628988074), - K=(3.1697651125348, -0.1395554574552) + A = (2.8956591846836, 0.4086563982472), + B = (2.4286639001964, 0.90610789694), + C = (2.0936455439339, 1.2309741818007), + D = (1.5149774740259, 1.4035593956329), + E = (0.824636618697, 1.586296680867), + F = (1.3322401887918, 1.2715824674082), + G = (1.6063461166429, 1.0177806823609), + H = (2.0225810441206, 0.713218540304), + I = (2.3169911147756, 0.4391126124529), + J = (2.6317053282343, 0.1954628988074), + K = (3.1697651125348, -0.1395554574552), ) pt7 = ( - A=(1.0581342609406, 2.2766375361959), - B=(0.9363094041178, 2.550743464047), - C=(1.2916319031842, 2.3070937504015), - D=(1.7281709734657, 1.9923795369428), - E=(1.0, 2.0), - F=(0.5809869050515, 2.1142043937655) + A = (1.0581342609406, 2.2766375361959), + B = (0.9363094041178, 2.550743464047), + C = (1.2916319031842, 2.3070937504015), + D = (1.7281709734657, 1.9923795369428), + E = (1.0, 2.0), + F = (0.5809869050515, 2.1142043937655), ) pt8 = ( - A=(1.5454336882315, 2.845153534702), - B=(1.9921248299149, 2.5405913926451), - C=(2.1545579723453, 2.936522177319), - D=(2.1951662579528, 2.4187665358224), - E=(2.4185118287945, 2.8756097489077), - F=(2.4185118287945, 2.5101351784394), - G=(2.4489680430002, 2.0431398939523), - H=(2.6317053282343, 2.9162180345153) + A = (1.5454336882315, 2.845153534702), + B = (1.9921248299149, 2.5405913926451), + C = (2.1545579723453, 2.936522177319), + D = (2.1951662579528, 2.4187665358224), + E = (2.4185118287945, 2.8756097489077), + F = (2.4185118287945, 2.5101351784394), + G = (2.4489680430002, 2.0431398939523), + H = (2.6317053282343, 2.9162180345153), ) pt9 = ( - A=(-0.5458930205588, 3.5557985328346), - B=(0.0733833349568, 3.2512363907778), - C=(0.3170330486022, 2.9771304629266), - D=(0.0835354063587, 2.6421121066641), - E=(0.0, 2.4187665358224), - F=(0.3576413342098, 2.4695268928319), - G=(-0.2210267356982, 2.9872825343285), - H=(-0.4849805921475, 3.2410843193759), - I=(0.5099224052383, 2.9162180345153) + A = (-0.5458930205588, 3.5557985328346), + B = (0.0733833349568, 3.2512363907778), + C = (0.3170330486022, 2.9771304629266), + D = (0.0835354063587, 2.6421121066641), + E = (0.0, 2.4187665358224), + F = (0.3576413342098, 2.4695268928319), + G = (-0.2210267356982, 2.9872825343285), + H = (-0.4849805921475, 3.2410843193759), + I = (0.5099224052383, 2.9162180345153), ) pt10 = ( - A=(0.3576413342098, 4.1649228169483), - B=(0.0, 4.0), - C=(0.4794661910326, 3.6573192468536), - D=(0.7028117618743, 3.3527571047967), - E=(0.6520514048648, 4.4796370304071), - F=(-0.3530036639228, 4.1243145313408), - G=(0.0, 3.7689920322744) + A = (0.3576413342098, 4.1649228169483), + B = (0.0, 4.0), + C = (0.4794661910326, 3.6573192468536), + D = (0.7028117618743, 3.3527571047967), + E = (0.6520514048648, 4.4796370304071), + F = (-0.3530036639228, 4.1243145313408), + G = (0.0, 3.7689920322744), ) pt11 = ( - A=(1.3931526172031, 4.0735541743313), - B=(2.0022769013168, 3.718231675265), - C=(1.3931526172031, 3.5354943900309), - D=(2.1444059009434, 3.4339736760119), - E=(1.3017839745861, 4.3172038879768), - F=(1.3017839745861, 4.5507015302204), - G=(1.7992354732789, 3.9923376031161), - H=(1.6875626878581, 3.5151902472271), - I=(1.4337609028107, 3.809600317882) + A = (1.3931526172031, 4.0735541743313), + B = (2.0022769013168, 3.718231675265), + C = (1.3931526172031, 3.5354943900309), + D = (2.1444059009434, 3.4339736760119), + E = (1.3017839745861, 4.3172038879768), + F = (1.3017839745861, 4.5507015302204), + G = (1.7992354732789, 3.9923376031161), + H = (1.6875626878581, 3.5151902472271), + I = (1.4337609028107, 3.809600317882), ) test_pts = [pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, pt9, pt10, pt11] for i in eachindex(T) @@ -538,9 +550,9 @@ end @test DT.is_outside(DT.point_position_relative_to_triangle(get_point(pts, i, j, k, ℓ)...)) p1, p2, p3 = ([2.858866215272096, -2.220975375945989], [0.25559192484080395, -0.37340906332046214], [1.3855904656897817, -2.47947044705479]) pts = [p1, p2, p3] - τ1 = DT.construct_triangle(NTuple{3,Int}, 1, 2, 3) - τ2 = DT.construct_triangle(NTuple{3,Int}, 2, 3, 1) - τ3 = DT.construct_triangle(NTuple{3,Int}, 3, 1, 2) + τ1 = DT.construct_triangle(NTuple{3, Int}, 1, 2, 3) + τ2 = DT.construct_triangle(NTuple{3, Int}, 2, 3, 1) + τ3 = DT.construct_triangle(NTuple{3, Int}, 3, 1, 2) e = Vector{Any}(undef, 9) e[1] = DT.point_position_relative_to_triangle(get_point(pts, τ1..., 1)...) e[2] = DT.point_position_relative_to_triangle(get_point(pts, τ2..., 2)...) @@ -555,17 +567,17 @@ end for _ in 1:5000 local pts, i, j, k n = rand(3:5000) - pts = rand(SVector{2,Float64}, n) + pts = rand(SVector{2, Float64}, n) i, j, k = rand(1:n, 3) while length(unique((i, j, k))) < 3 i, j, k = rand(1:n, 3) end local τ1, τ2, τ3, e - τ = DT.construct_positively_oriented_triangle(NTuple{3,Int}, i, j, k, pts) + τ = DT.construct_positively_oriented_triangle(NTuple{3, Int}, i, j, k, pts) i, j, k = triangle_vertices(τ) - τ1 = DT.construct_triangle(NTuple{3,Int}, i, j, k) - τ2 = DT.construct_triangle(NTuple{3,Int}, j, k, i) - τ3 = DT.construct_triangle(NTuple{3,Int}, k, i, j) + τ1 = DT.construct_triangle(NTuple{3, Int}, i, j, k) + τ2 = DT.construct_triangle(NTuple{3, Int}, j, k, i) + τ3 = DT.construct_triangle(NTuple{3, Int}, k, i, j) e = Vector{Any}(undef, 9) e[1] = DT.point_position_relative_to_triangle(get_point(pts, τ1..., i)...) e[2] = DT.point_position_relative_to_triangle(get_point(pts, τ2..., i)...) @@ -590,11 +602,11 @@ end while length(unique((i, j, k))) < 3 i, j, k = rand(1:n, 3) end - τ = DT.construct_positively_oriented_triangle(NTuple{3,Int}, i, j, k, pts) + τ = DT.construct_positively_oriented_triangle(NTuple{3, Int}, i, j, k, pts) i, j, k = triangle_vertices(τ) - τ1 = DT.construct_triangle(NTuple{3,Int}, i, j, k) - τ2 = DT.construct_triangle(NTuple{3,Int}, j, k, i) - τ3 = DT.construct_triangle(NTuple{3,Int}, k, i, j) + τ1 = DT.construct_triangle(NTuple{3, Int}, i, j, k) + τ2 = DT.construct_triangle(NTuple{3, Int}, j, k, i) + τ3 = DT.construct_triangle(NTuple{3, Int}, k, i, j) e = Vector{Any}(undef, 9) e[1] = DT.point_position_relative_to_triangle(get_point(pts, τ1..., i)...) e[2] = DT.point_position_relative_to_triangle(get_point(pts, τ2..., i)...) @@ -624,10 +636,10 @@ end @testset "point_position_relative_to_oriented_outer_halfplane" begin p, q = (3.0, 4.0), (6.0, 4.0) c, d, e, f, g, h, i, j, k, ℓ = (2.0, 4.0), (7.0, 4.0), (5.0, 5.0), + (4.0, 6.0), (6.0, 7.0), (4.0, 4.0), (5.0, 4.0), + (3.0, 2.0), (5.0, 3.0), (6.0, 1.0) (4.0, 6.0), (6.0, 7.0), (4.0, 4.0), (5.0, 4.0), - (3.0, 2.0), (5.0, 3.0), (6.0, 1.0) - (4.0, 6.0), (6.0, 7.0), (4.0, 4.0), (5.0, 4.0), - (3.0, 2.0), (5.0, 3.0), (6.0, 1.0) + (3.0, 2.0), (5.0, 3.0), (6.0, 1.0) @test DT.is_outside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, c)) @test DT.is_outside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, d)) @test DT.is_inside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, e)) @@ -643,12 +655,12 @@ end @inferred DT.is_outside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, ℓ)) p, q = (3.0, 4.0), (6.0, 7.0) c, d, e, f, g, h, i, j, k, ℓ = (3.0, 5.0), (3.0, 7.0), (4.0, 8.0), + (2.0, 3.0), (5.787, 3.774), (4.128, 1.626), + (6.95784, 7.715), (4.0, 5.0), (5.0, 6.0), + (4.143, 6.57) (2.0, 3.0), (5.787, 3.774), (4.128, 1.626), - (6.95784, 7.715), (4.0, 5.0), (5.0, 6.0), - (4.143, 6.57) - (2.0, 3.0), (5.787, 3.774), (4.128, 1.626), - (6.95784, 7.715), (4.0, 5.0), (5.0, 6.0), - (4.143, 6.57) + (6.95784, 7.715), (4.0, 5.0), (5.0, 6.0), + (4.143, 6.57) @test DT.is_inside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, c)) @test DT.is_inside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, d)) @test DT.is_inside(DT.point_position_relative_to_oriented_outer_halfplane(p, q, e)) @@ -678,8 +690,9 @@ end p9 = [31.7813088302274, -22.9759380718838] pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9] tri = triangulate(pts) - @test all(DT.is_legal(DT.is_legal(tri, i, j)) for (i, j) in - ((1, 3), (3, 2), (2, 1), (1, 4), (4, 3), (3, 1), (3, 4), (4, 5), (5, 3), (3, 5), (5, 2), (2, 3)) + @test all( + DT.is_legal(DT.is_legal(tri, i, j)) for (i, j) in + ((1, 3), (3, 2), (2, 1), (1, 4), (4, 3), (3, 1), (3, 4), (4, 5), (5, 3), (3, 5), (5, 2), (2, 3)) ) end @@ -740,7 +753,7 @@ end (a11, b11), (a12, b12), (a13, b13), - (a14, b14) + (a14, b14), ] flags = [DT.triangle_line_segment_intersection(p, q, r, a, b) for (a, b) in ab] true_flags = [ @@ -757,18 +770,18 @@ end Certificate.Touching, Certificate.Inside, Certificate.Outside, - Certificate.Inside + Certificate.Inside, ] @test isempty(findall(flags .≠ true_flags)) for i in eachindex(flags) a, b = ab[i] @test DT.triangle_line_segment_intersection(p, q, r, a, b) == - DT.triangle_line_segment_intersection(p, q, r, b, a) == - DT.triangle_line_segment_intersection(q, r, p, a, b) == - DT.triangle_line_segment_intersection(q, r, p, b, a) == - DT.triangle_line_segment_intersection(r, p, q, a, b) == - DT.triangle_line_segment_intersection(r, p, q, b, a) == - true_flags[i] + DT.triangle_line_segment_intersection(p, q, r, b, a) == + DT.triangle_line_segment_intersection(q, r, p, a, b) == + DT.triangle_line_segment_intersection(q, r, p, b, a) == + DT.triangle_line_segment_intersection(r, p, q, a, b) == + DT.triangle_line_segment_intersection(r, p, q, b, a) == + true_flags[i] end end @@ -878,7 +891,7 @@ end cert = DT.point_position_relative_to_witness_plane(tri, 1, 2, 3, 4) @test DT.is_above(cert) @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, 1, 2, 3, 4)) - tri = Triangulation(points; weights=zeros(4)) + tri = Triangulation(points; weights = zeros(4)) cert = DT.point_position_relative_to_witness_plane(tri, 1, 2, 3, 4) @test DT.is_above(cert) @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, 1, 2, 3, 4)) @@ -889,7 +902,7 @@ end points = [(2.0, 0.0), (1.0, 1.0), (0.0, 0.0), (1.0, 0.0)] weights = [2.0, -1.0, -1.0, -1 / 2] - tri = Triangulation(points; weights=weights) + tri = Triangulation(points; weights = weights) cert = DT.point_position_relative_to_witness_plane(tri, 1, 2, 3, 4) @test DT.is_on(cert) @test DT.is_on(DT.point_position_relative_to_circumcircle(tri, 1, 2, 3, 4)) @@ -972,4 +985,4 @@ end flag2 = DT.is_outside(cert) flag1 && flag2 end -end \ No newline at end of file +end diff --git a/test/predicates/index_and_ghost_handling.jl b/test/predicates/index_and_ghost_handling.jl index 6838f3c23..0cb21e990 100644 --- a/test/predicates/index_and_ghost_handling.jl +++ b/test/predicates/index_and_ghost_handling.jl @@ -8,17 +8,18 @@ using ElasticArrays using ..DelaunayTriangulation: Certificate - global x, y = complicated_geometry() -boundary_nodes, points = convert_boundary_points_to_indices(x, y; existing_points=ElasticMatrix{Float64}(undef, 2, 0)) -_tri = triangulate(points; boundary_nodes, delete_ghosts=false) +boundary_nodes, points = convert_boundary_points_to_indices(x, y; existing_points = ElasticMatrix{Float64}(undef, 2, 0)) +_tri = triangulate(points; boundary_nodes, delete_ghosts = false) A = get_area(_tri) -refine!(_tri; max_area=1e-2A, use_circumcenter=true) +refine!(_tri; max_area = 1.0e-2A, use_circumcenter = true) _pts = ElasticMatrix(get_points(_tri)) -global tri = DT.Triangulation(_pts, _tri.triangles, _tri.boundary_nodes, _tri.interior_segments, +global tri = DT.Triangulation( + _pts, _tri.triangles, _tri.boundary_nodes, _tri.interior_segments, _tri.all_segments, _tri.weights, _tri.adjacent, _tri.adjacent2vertex, _tri.graph, _tri.boundary_curves, _tri.boundary_edge_map, _tri.ghost_vertex_map, _tri.ghost_vertex_ranges, DT.ConvexHull(_pts, _tri.convex_hull.vertices), _tri.representative_point_list, - _tri.polygon_hierarchy, _tri.boundary_enricher, _tri.cache) + _tri.polygon_hierarchy, _tri.boundary_enricher, _tri.cache, +) DT.compute_representative_points!(tri) global rep = DT.get_representative_point_list(tri) global ghost_vertex_map = DT.get_ghost_vertex_map(tri) @@ -61,8 +62,8 @@ global pts = DT.get_points(tri) points = [[0, -3.0], [3.0, 0.0], [0.0, 3.0], [-3.0, 0.0]] temptri = triangulate(points) @test DT.is_positively_oriented(DT.triangle_orientation(temptri, (1, 2, 3))) && - DT.is_positively_oriented(DT.triangle_orientation(temptri, (2, 3, 4))) && - DT.is_positively_oriented(DT.triangle_orientation(temptri, (4, 1, 2))) + DT.is_positively_oriented(DT.triangle_orientation(temptri, (2, 3, 4))) && + DT.is_positively_oriented(DT.triangle_orientation(temptri, (4, 1, 2))) end @testset "point_position_relative_to_circumcircle" begin @@ -72,14 +73,18 @@ end for ℓ in (i, j, k) cert3 = DT.point_position_relative_to_circumcircle(tri, T, ℓ) cert4 = DT.point_position_relative_to_circumcircle(tri, i, j, k, ℓ) - cert5 = DT.point_position_relative_to_circumcircle(tri, pts[:, i], j, k, - pts[:, ℓ]) + cert5 = DT.point_position_relative_to_circumcircle( + tri, pts[:, i], j, k, + pts[:, ℓ], + ) cert6 = DT.point_position_relative_to_circumcircle(tri, i, pts[:, j], k, ℓ) @test all(DT.is_on, (cert3, cert4, cert5, cert6)) @inferred DT.point_position_relative_to_circumcircle(tri, T, ℓ) @inferred DT.point_position_relative_to_circumcircle(tri, i, j, k, ℓ) - @inferred DT.point_position_relative_to_circumcircle(tri, pts[:, i], j, k, - pts[:, ℓ]) + @inferred DT.point_position_relative_to_circumcircle( + tri, pts[:, i], j, k, + pts[:, ℓ], + ) @inferred DT.point_position_relative_to_circumcircle(tri, i, pts[:, j], k, ℓ) end q = (pts[:, i] .+ pts[:, j] .+ pts[:, k]) ./ 3 @@ -105,7 +110,7 @@ end p10 = @SVector[4.74, 2.21] p11 = @SVector[2.32, -0.27] pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) p12 = @SVector[-1.86, 5.99] push!(pts, p12) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 1, 9, DT.𝒢, 12)) @@ -172,7 +177,7 @@ end @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, 4, 3, DT.𝒢, 23)) @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, 3, DT.𝒢, 4, 23)) @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, DT.𝒢, 4, 3, 23)) - p24 = @SVector[-5.04821, -2.54880] + p24 = @SVector[-5.04821, -2.5488] push!(pts, p24) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 4, 3, DT.𝒢, 24)) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 3, DT.𝒢, 4, 24)) @@ -193,7 +198,7 @@ end @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 3, 2, DT.𝒢, 26)) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 2, DT.𝒢, 3, 26)) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, DT.𝒢, 3, 2, 26)) - p27 = @SVector[-5.310, 2.87596] + p27 = @SVector[-5.31, 2.87596] push!(pts, p27) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 2, 1, DT.𝒢, 27)) @test DT.is_inside(DT.point_position_relative_to_circumcircle(tri, 1, DT.𝒢, 2, 27)) @@ -214,7 +219,7 @@ end p13 = (8.0, 2.0) p14 = (0.0, 0.0) pts = [p8, p9, p13, p14] - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) @test DT.is_on(DT.point_position_relative_to_circumcircle(tri, 1, 2, DT.𝒢, 3)) push!(pts, (2.0, 14.0)) @test DT.is_outside(DT.point_position_relative_to_circumcircle(tri, 1, 2, DT.𝒢, 5)) @@ -239,7 +244,7 @@ end p10 = @SVector[4.74, 2.21] p11 = @SVector[2.32, -0.27] pts = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11] - tri = triangulate(pts; delete_ghosts=false, randomise=false) + tri = triangulate(pts; delete_ghosts = false, randomise = false) p12 = @SVector[3.538447, 3.99844] push!(pts, p12) @test DT.is_left(DT.point_position_relative_to_line(tri, 9, 10, 12)) @@ -306,21 +311,57 @@ end orig_length = length(pts) DT.compute_representative_points!(tri) rep = DT.get_representative_point_list(tri) - rep[1] = DT.RepresentativeCoordinates(mean(reinterpret(reshape, + rep[1] = DT.RepresentativeCoordinates( + mean( + reinterpret( + reshape, Float64, - pts[unique(reduce(vcat, - tri.boundary_nodes[1]))]); - dims=2)..., 0) - rep[2] = DT.RepresentativeCoordinates(mean(reinterpret(reshape, + pts[ + unique( + reduce( + vcat, + tri.boundary_nodes[1], + ), + ), + ], + ); + dims = 2, + )..., 0, + ) + rep[2] = DT.RepresentativeCoordinates( + mean( + reinterpret( + reshape, Float64, - pts[unique(reduce(vcat, - tri.boundary_nodes[2]))]); - dims=2)..., 0) - rep[3] = DT.RepresentativeCoordinates(mean(reinterpret(reshape, + pts[ + unique( + reduce( + vcat, + tri.boundary_nodes[2], + ), + ), + ], + ); + dims = 2, + )..., 0, + ) + rep[3] = DT.RepresentativeCoordinates( + mean( + reinterpret( + reshape, Float64, - pts[unique(reduce(vcat, - tri.boundary_nodes[3]))]); - dims=2)..., 0) + pts[ + unique( + reduce( + vcat, + tri.boundary_nodes[3], + ), + ), + ], + ); + dims = 2, + )..., 0, + ) ghost_vertex_map = DT.get_ghost_vertex_map(tri) @testset "point_position_relative_to_circumcircle" begin @@ -343,7 +384,7 @@ end f1_i = length(pts) - 1 g1_i = length(pts) h1 = (21.517785930112, 22.1693108196262) - i1 = (22.0683240766855, 21.526199282940) + i1 = (22.0683240766855, 21.52619928294) push!(pts, h1, i1) h1_i = length(pts) - 1 i1_i = length(pts) @@ -369,7 +410,8 @@ end q1_i = length(pts) - 2 r1_i = length(pts) - 1 s1_i = length(pts) - certs = [("w", "v", "f") => Certificate.Left, + certs = [ + ("w", "v", "f") => Certificate.Left, ("c", "d", "k") => Certificate.Left, ("r", "q", "j") => Certificate.Right, ("r", "q", "d") => Certificate.Left, @@ -403,7 +445,8 @@ end ("m", DT.𝒢 - 2, s1_i) => Certificate.Right, (DT.𝒢 - 2, "m", s1_i) => Certificate.Left, (DT.𝒢 - 2, "p", r1_i) => Certificate.Left, - ("p", DT.𝒢 - 2, r1_i) => Certificate.Right] + ("p", DT.𝒢 - 2, r1_i) => Certificate.Right, + ] for ((i, j, u), cert) in certs i = i isa String ? index_map[i] : i j = j isa String ? index_map[j] : j @@ -549,7 +592,8 @@ end h1_i = length(pts) - 10 g1_i = length(pts) - 11 f1_i = length(pts) - 12 - certs = [("g", "h", "b1", f1_i) => Certificate.Inside, + certs = [ + ("g", "h", "b1", f1_i) => Certificate.Inside, ("b1", "i", "g", f1_i) => Certificate.Outside, ("b1", "h", "j", g1_i) => Certificate.Inside, ("i", "b1", "j", h1_i) => Certificate.Inside, @@ -567,7 +611,8 @@ end ("a1", "f", "g", o1_i) => Certificate.On, ("h", "a", "s", q1_i) => Certificate.On, ("a1", "f", "g", p1_i) => Certificate.On, - ("b1", "j", "i", "v") => Certificate.Outside] + ("b1", "j", "i", "v") => Certificate.Outside, + ] for ((i, j, k, u), cert) in certs local cert1, cert2, cert3, cert4, cert5, cert6 i = i isa String ? index_map[i] : i @@ -617,7 +662,8 @@ end h1_i = length(pts) - 8 g1_i = length(pts) - 9 f1_i = length(pts) - 10 - certs = [("h", "g", DT.𝒢, f1_i) => Certificate.Inside, + certs = [ + ("h", "g", DT.𝒢, f1_i) => Certificate.Inside, ("h", "g", DT.𝒢, g1_i) => Certificate.Inside, ("h", "g", DT.𝒢, h1_i) => Certificate.Inside, (DT.𝒢, "h", "g", i1_i) => Certificate.Inside, @@ -628,7 +674,8 @@ end ("h", "g", DT.𝒢, n1_i) => Certificate.Outside, ("h", "g", DT.𝒢, o1_i) => Certificate.Outside, ("h", "g", DT.𝒢, p1_i) => Certificate.Outside, - ("h", "g", DT.𝒢, "b1") => Certificate.Outside] + ("h", "g", DT.𝒢, "b1") => Certificate.Outside, + ] rep[1].x = 10.0 rep[1].y = 10.0 for ((i, j, k, u), cert) in certs @@ -652,7 +699,7 @@ end g1 = (6.449, 23.343) h1 = (10.0, 24.0) i1 = (12.4666, 22.777) - j1 = (18.555, 22.600) + j1 = (18.555, 22.6) k1 = (24.0, 24.0) push!(pts, f1, g1, h1, i1, j1, k1) f1_i = length(pts) - 5 @@ -661,7 +708,8 @@ end i1_i = length(pts) - 2 j1_i = length(pts) - 1 k1_i = length(pts) - certs = [("g", "f", DT.𝒢, f1_i) => Certificate.Inside, + certs = [ + ("g", "f", DT.𝒢, f1_i) => Certificate.Inside, ("f", "e", DT.𝒢, f1_i) => Certificate.Outside, ("g", "f", DT.𝒢, g1_i) => Certificate.Inside, ("e", DT.𝒢, "f", h1_i) => Certificate.Inside, @@ -671,7 +719,8 @@ end (DT.𝒢, "f", "e", k1_i) => Certificate.Inside, ("e", "d", DT.𝒢, k1_i) => Certificate.Inside, ("b", "a", DT.𝒢, "s") => Certificate.Outside, - (DT.𝒢, "b", "a", "v") => Certificate.Outside] + (DT.𝒢, "b", "a", "v") => Certificate.Outside, + ] for ((i, j, k, u), cert) in certs local cert1, cert2, cert3, cert4, cert5, cert6 i = i isa String ? index_map[i] : i @@ -708,7 +757,8 @@ end h1_i = length(pts) - 8 g1_i = length(pts) - 9 f1_i = length(pts) - 10 - certs = [("ℓ", "i", DT.𝒢 - 1, f1_i) => Certificate.Inside, + certs = [ + ("ℓ", "i", DT.𝒢 - 1, f1_i) => Certificate.Inside, ("i", DT.𝒢 - 1, "ℓ", g1_i) => Certificate.Inside, (DT.𝒢 - 1, "ℓ", "i", k1_i) => Certificate.Outside, ("i", "j", DT.𝒢 - 1, k1_i) => Certificate.Inside, @@ -723,7 +773,8 @@ end ("k", "ℓ", DT.𝒢 - 1, h1_i) => Certificate.Inside, ("ℓ", DT.𝒢 - 1, "k", m1_i) => Certificate.On, ("ℓ", DT.𝒢 - 1, "k", "b1") => Certificate.Outside, - ("j", "k", DT.𝒢 - 1, "s") => Certificate.Outside] + ("j", "k", DT.𝒢 - 1, "s") => Certificate.Outside, + ] for ((i, j, k, u), cert) in certs local cert4, cert5, cert6 i = i isa String ? index_map[i] : i @@ -769,7 +820,8 @@ end h1_i = length(pts) - 12 g1_i = length(pts) - 13 f1_i = length(pts) - 14 - certs = [("o", "p", DT.𝒢 - 2, o1_i) => Certificate.On, + certs = [ + ("o", "p", DT.𝒢 - 2, o1_i) => Certificate.On, ("p", DT.𝒢 - 2, "o", n1_i) => Certificate.On, (DT.𝒢 - 2, "o", "p", q1_i) => Certificate.Inside, (DT.𝒢 - 3, "o", "p", t1_i) => Certificate.Outside, @@ -789,7 +841,8 @@ end ("m", DT.𝒢 - 3, "r", r1_i) => Certificate.Outside, ("m", DT.𝒢 - 3, "r", h1_i) => Certificate.Inside, ("m", "n", DT.𝒢 - 2, p1_i) => Certificate.Inside, - (DT.𝒢 - 2, "m", "n", s1_i) => Certificate.Outside] + (DT.𝒢 - 2, "m", "n", s1_i) => Certificate.Outside, + ] for ((i, j, k, u), cert) in certs local cert4, cert5, cert6 i = i isa String ? index_map[i] : i @@ -804,4 +857,4 @@ end @test all(==(cert), (cert4, cert5, cert6)) end end -end \ No newline at end of file +end diff --git a/test/readme_example.jl b/test/readme_example.jl index 7767892cd..ff8ae7634 100644 --- a/test/readme_example.jl +++ b/test/readme_example.jl @@ -9,58 +9,66 @@ tri1 = triangulate(points; rng) vorn2 = voronoi(tri1; rng) # Clipped Voronoi -vorn3 = voronoi(tri1, clip=true; rng) +vorn3 = voronoi(tri1, clip = true; rng) # Smoothed Voronoi vorn4 = centroidal_smooth(vorn3; rng) # Constrained example with refinement -boundary_points = [(0.0, 0.0), (1.0, 0.0), (1.0, 0.3), (0.5, 0.3), - (0.3, 0.7), (0.1, 1.0), (0.0, 1.0), (0.0, 0.0)] +boundary_points = [ + (0.0, 0.0), (1.0, 0.0), (1.0, 0.3), (0.5, 0.3), + (0.3, 0.7), (0.1, 1.0), (0.0, 1.0), (0.0, 0.0), +] boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) tri5 = triangulate(points; boundary_nodes, rng) -refine!(tri5; max_area=1e-2get_area(tri5), rng) +refine!(tri5; max_area = 1.0e-2get_area(tri5), rng) # Disjoint constrained example with refinement boundary_points = [ [[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)]], [[(0.3, 0.3), (0.3, 0.7), (0.7, 0.7), (0.7, 0.3), (0.3, 0.3)]], - [[(1.2, 0.0), (1.4, 0.0), (1.4, 1.2), (0.0, 1.2), (0.0, 1.1), - (1.1, 1.1), (1.1, 0.0), (1.2, 0.0)]] + [ + [ + (1.2, 0.0), (1.4, 0.0), (1.4, 1.2), (0.0, 1.2), (0.0, 1.1), + (1.1, 1.1), (1.1, 0.0), (1.2, 0.0), + ], + ], ] boundary_nodes, points = convert_boundary_points_to_indices(boundary_points) tri6 = triangulate(points; boundary_nodes, rng) -refine!(tri6; max_area=1e-2get_area(tri6), rng) +refine!(tri6; max_area = 1.0e-2get_area(tri6), rng) # Curve-bounded example using DelaunayTriangulation: EllipticalArc ellipse = EllipticalArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0), 1.0, 2.0, 0.0) -tri7 = triangulate(NTuple{2,Float64}[]; boundary_nodes=[ellipse], rng) -refine!(tri7; max_area=1e-2get_area(tri7), rng) +tri7 = triangulate(NTuple{2, Float64}[]; boundary_nodes = [ellipse], rng) +refine!(tri7; max_area = 1.0e-2get_area(tri7), rng) # Disjoint curve-bounded example ellipse = EllipticalArc((7.0, 3.5), (7.0, 3.5), (0.0, 3.5), 7.0, 10.0, 0.0) -catmull_cp = [(0.0, 0.0), (-2.0, -1.0), (-4.0, 0.0), (-5.0, 2.0), (-1.0, 4.0), (0.0, 3.0), - (1.0, 4.0), (5.0, 2.0), (4.0, 0.0), (2.0, -1.0), (0.0, 0.0)] +catmull_cp = [ + (0.0, 0.0), (-2.0, -1.0), (-4.0, 0.0), (-5.0, 2.0), (-1.0, 4.0), (0.0, 3.0), + (1.0, 4.0), (5.0, 2.0), (4.0, 0.0), (2.0, -1.0), (0.0, 0.0), +] catmull_spl = CatmullRomSpline(catmull_cp) circle = CircularArc((0.5, 1.5), (0.5, 1.5), (0.0, 1.0)) -circle2 = CircularArc((0.1, 1.5), (0.1, 1.5), (0.0, 1.0), positive=false) +circle2 = CircularArc((0.1, 1.5), (0.1, 1.5), (0.0, 1.0), positive = false) points = [(-4.0, -10.0), (4.0, -10.0), (4.0, -7.0), (-4.0, -7.0)] square = [1, 2, 3, 4, 1] boundary_nodes = [[square], [[ellipse]], [[catmull_spl]], [[circle]], [[circle2]]] tri8 = triangulate(points; boundary_nodes, rng) -refine!(tri8; max_area=1e-2get_area(tri8), rng) # could also use find_polygon to help define a custom refinement function for each shape +refine!(tri8; max_area = 1.0e-2get_area(tri8), rng) # could also use find_polygon to help define a custom refinement function for each shape # Plotting fig = Figure(fontsize = 42, size = (2800, 1480)) -ax = Axis(fig[1, 1], title="Unconstrained", width=600,height=600); triplot!(ax, tri1) -ax = Axis(fig[1, 2], title="Voronoi", width=600,height=600); voronoiplot!(ax, vorn2) -ax = Axis(fig[1, 3], title="Clipped Voronoi", width=600,height=600); voronoiplot!(ax, vorn3) -ax = Axis(fig[1, 4], title="Centroidal Voronoi", width=600,height=600); voronoiplot!(ax, vorn4) -ax = Axis(fig[2, 1], title="Constrained", width=600,height=600); triplot!(ax, tri5) -ax = Axis(fig[2, 2], title="Disjoint Constrained", width=600,height=600); triplot!(ax, tri6) -ax = Axis(fig[2, 3], title="Curve-Bounded", width=600,height=600); triplot!(ax, tri7) -ax = Axis(fig[2, 4], title="Disjoint Curve-Bounded", width=600,height=600); triplot!(ax, tri8) +ax = Axis(fig[1, 1], title = "Unconstrained", width = 600, height = 600); triplot!(ax, tri1) +ax = Axis(fig[1, 2], title = "Voronoi", width = 600, height = 600); voronoiplot!(ax, vorn2) +ax = Axis(fig[1, 3], title = "Clipped Voronoi", width = 600, height = 600); voronoiplot!(ax, vorn3) +ax = Axis(fig[1, 4], title = "Centroidal Voronoi", width = 600, height = 600); voronoiplot!(ax, vorn4) +ax = Axis(fig[2, 1], title = "Constrained", width = 600, height = 600); triplot!(ax, tri5) +ax = Axis(fig[2, 2], title = "Disjoint Constrained", width = 600, height = 600); triplot!(ax, tri6) +ax = Axis(fig[2, 3], title = "Curve-Bounded", width = 600, height = 600); triplot!(ax, tri7) +ax = Axis(fig[2, 4], title = "Disjoint Curve-Bounded", width = 600, height = 600); triplot!(ax, tri8) readme_img = joinpath(dirname(dirname(pathof(DelaunayTriangulation))), "readme.png") -@test_reference readme_img fig by=psnr_equality(10) +@test_reference readme_img fig by = psnr_equality(10) diff --git a/test/refinement/curve_bounded.jl b/test/refinement/curve_bounded.jl index 33040aeef..0ef2ee836 100644 --- a/test/refinement/curve_bounded.jl +++ b/test/refinement/curve_bounded.jl @@ -39,7 +39,7 @@ names = ( "multiply_connected_piecewise_linear_interior_circle", "multiply_connected_piecewise_linear_elliptical_bspline_piecewise_linear", "multiply_connected_piecewise_linear_elliptical_bspline_piecewise_linear_catmull_bezier_piecewise_linear_circle", - "multiply_connected_intersecting" + "multiply_connected_intersecting", ) curve_I = [1, 2, 3, 4, 1] @@ -60,7 +60,7 @@ curve_II = [[1, 2, 3, 4, 5], [5, 6, 7, 8, 9], [9, 10, 11, 1]] points_II = [ (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), - (0.75, 0.75), (0.25, 0.25) + (0.75, 0.75), (0.25, 0.25), ] fpoints_II = flatten_boundary_nodes(points_II, curve_II) points_II_extra = copy(points_II) @@ -77,7 +77,7 @@ points_III = [ (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), (0.0, 1.0), (0.0, 0.5), - (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75) + (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75), ] fpoints_III = flatten_boundary_nodes(points_III, curve_III) points_III_extra = copy(points_III) @@ -90,7 +90,7 @@ segments_III = Set([(n + 2, n + 1)]) fpoints_III_extra_segments = flatten_boundary_nodes(points_III_extra_segments, curve_III, segments_III) curve_IV = [CircularArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0))] -points_IV = NTuple{2,Float64}[] +points_IV = NTuple{2, Float64}[] fpoints_IV = flatten_boundary_nodes(points_IV, curve_IV) points_IV_extra = copy(points_IV) push!(points_IV_extra, (0.99, 0.14), (0.0, 0.99), (-0.99, 0.0), (0.99, 0.0), (0.0, -0.99), (0.0, 0.0), (0.5, -0.5)) @@ -110,7 +110,7 @@ push!(points_V_extra, (0.01, 0.01), (0.25, 0.25), (0.5, 0.5), (0.25, 0.55), (0.5 curve_VI = [ [CircularArc((1.0, 0.0), (0.0, 1.0), (0.0, 0.0))], [BSpline([(0.0, 1.0), (-1.0, 2.0), (-2.0, 0.0), (-2.0, -1.0), (0.0, -2.0)])], - [5, 6, 10] + [5, 6, 10], ] points_VI = [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0)] fpoints_VI = flatten_boundary_nodes(points_VI, curve_VI) @@ -119,7 +119,7 @@ push!(points_VI_extra, (0.0, 0.0), (0.999, 0.0), (-1.0, -1.0), (0.5, 0.0), (-1.0 curve_VII = [ [CircularArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0))], - [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])] + [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])], ] points_VII = [(2.0, 0.0), (0.0, 0.5)] fpoints_VII = flatten_boundary_nodes(points_VII, curve_VII) @@ -130,23 +130,25 @@ curve_VIII = [ [1, 2, 3, 4, 5], [DT.EllipticalArc((0.0, 0.0), (2.0, -2.0), (1.0, -1.0), sqrt(2), sqrt(2), 45.0)], [6, 7, 8, 9, 10], - [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)], lookup_steps=5000)] + [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)], lookup_steps = 5000)], +] +points_VIII = [ + (10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), + (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, -0.2), (14.0, -0.05), ] -points_VIII = [(10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), - (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, -0.2), (14.0, -0.05)] fpoints_VIII = flatten_boundary_nodes(points_VIII, curve_VIII) points_VIII_extra = copy(points_VIII) push!(points_VIII_extra, (5.0, -0.01), (10.0, -1.0), (15.0, -1.95), (0.0, -1.0), (2.0, -1.5), (1.0, 0.5), (10.0, -2.0)) curve_IX = [ - [ - [1, 2, 3, 4, 5, 6, 7, 1] - ], - [ - [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive=false)] - ], - ] + [ + [1, 2, 3, 4, 5, 6, 7, 1], + ], + [ + [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive = false)], + ], +] points_IX = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 1.5), (0.0, 1.0), (0.0, 0.5), (0.0, 0.2)] fpoints_IX = flatten_boundary_nodes(points_IX, curve_IX) points_IX_extra = copy(points_IX) @@ -154,14 +156,14 @@ push!(points_IX_extra, (0.5, 0.01), (0.01, 0.01), (0.01, 0.5), (0.01, 1.0), (0.5 curve_X = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]) - ] + [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]), + ], ] points_X = [ - (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2) + (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2), ] fpoints_X = flatten_boundary_nodes(points_X, curve_X) points_X_extra = copy(points_X) @@ -169,23 +171,23 @@ push!(points_X_extra, (0.0, 0.01), (-0.5, 0.27), (1.0, 0.275), (1.5, 0.2), (0.0, curve_XI = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))] + [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points_XI = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] fpoints_XI = flatten_boundary_nodes(points_XI, curve_XI) @@ -196,15 +198,15 @@ ctrl = [ (0.0, 0.0), (2.0, 0.0), (1.6, -0.1), (0.3, -0.2), (-0.31, -0.35), (-0.2, 1.0), (0.0, 0.8), (0.2, 0.6), (0.4, 0.4), - (2.0, 0.4), (0.0, 0.0) + (2.0, 0.4), (0.0, 0.0), ] reverse!(ctrl) points_XII = [ (-0.1, 0.8), (-0.15, -0.15), (0.3, -0.1), (0.0, -0.1), (-0.1, 0.0), - (0.4, 0.2), (0.2, 0.4), (0.0, 0.6) + (0.4, 0.2), (0.2, 0.4), (0.0, 0.6), ] -curve_XII = [[[BSpline(ctrl, lookup_steps=25000)]], [[1, 8, 7, 6, 5, 4, 3, 2, 1]]] +curve_XII = [[[BSpline(ctrl, lookup_steps = 25000)]], [[1, 8, 7, 6, 5, 4, 3, 2, 1]]] fpoints_XII = flatten_boundary_nodes(points_XII, curve_XII) points_XII_extra = copy(points_XII) push!(points_XII_extra, (0.5, -0.15), (1.0, -0.1), (1.0, 0.25), (0.0, 0.75), (-0.01, 0.0)) @@ -287,8 +289,10 @@ end @test curves_X_tuple == (DT.PiecewiseLinear(points_X, curve_X[1][1]), curve_X[1][2][1], curve_X[2][1][1], DT.PiecewiseLinear(points_X, curve_X[2][2])) curves_XI_tuple = DT.to_boundary_curves(points_XI, curve_XI) - @test curves_XI_tuple == (DT.PiecewiseLinear(points_XI, curve_XI[1][1]), curve_XI[1][2][1], curve_XI[2][1][1], DT.PiecewiseLinear(points_XI, curve_XI[3][1]), curve_XI[4][1][1], curve_XI[4][2][1], - DT.PiecewiseLinear(points_XI, curve_XI[5][1]), curve_XI[6][1][1]) + @test curves_XI_tuple == ( + DT.PiecewiseLinear(points_XI, curve_XI[1][1]), curve_XI[1][2][1], curve_XI[2][1][1], DT.PiecewiseLinear(points_XI, curve_XI[3][1]), curve_XI[4][1][1], curve_XI[4][2][1], + DT.PiecewiseLinear(points_XI, curve_XI[5][1]), curve_XI[6][1][1], + ) end @testset "get_skeleton" begin @@ -360,51 +364,53 @@ end boundary_nodes = deepcopy(curve_VI) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[10, 11], [11, 5], [5, 6, 10]] && - points == [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0), (0.0, 1.0)] + new_boundary_nodes == [[10, 11], [11, 5], [5, 6, 10]] && + points == [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0), (0.0, 1.0)] points = deepcopy(points_VII) boundary_nodes = deepcopy(curve_VII) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[1, 3], [3, 1]] && - points == [(2.0, 0.0), (0.0, 0.5), (-2.0, 0.0)] + new_boundary_nodes == [[1, 3], [3, 1]] && + points == [(2.0, 0.0), (0.0, 0.5), (-2.0, 0.0)] points = deepcopy(points_VIII) boundary_nodes = deepcopy(curve_VIII) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[1, 2, 3, 4, 5], [5, 6], [6, 7, 8, 9, 10], [10, 1]] && - points == [(10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), - (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, -0.2), (14.0, -0.05)] + new_boundary_nodes == [[1, 2, 3, 4, 5], [5, 6], [6, 7, 8, 9, 10], [10, 1]] && + points == [ + (10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), + (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, -0.2), (14.0, -0.05), + ] points = deepcopy(points_IX) boundary_nodes = deepcopy(curve_IX) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[[1, 2, 3, 4, 5, 6, 7, 1]], [[8, 8]]] && - points == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 1.5), (0.0, 1.0), (0.0, 0.5), (0.0, 0.2), (0.6, 0.5)] + new_boundary_nodes == [[[1, 2, 3, 4, 5, 6, 7, 1]], [[8, 8]]] && + points == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 1.5), (0.0, 1.0), (0.0, 0.5), (0.0, 0.2), (0.6, 0.5)] points = deepcopy(points_X) boundary_nodes = deepcopy(curve_X) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[[1, 2, 3], [3, 1]], [[4, 8], [8, 7, 6, 5, 4]]] && - points == [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2)] + new_boundary_nodes == [[[1, 2, 3], [3, 1]], [[4, 8], [8, 7, 6, 5, 4]]] && + points == [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2)] points = deepcopy(points_XI) boundary_nodes = deepcopy(curve_XI) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) @test boundary_curves == DT.to_boundary_curves(points, boundary_nodes) && - new_boundary_nodes == [[[1, 2, 3], [3, 1]], [[13, 13]], [[4, 5, 6, 7, 4]], [[14, 8], [8, 14]], [[12, 11, 10, 12]], [[15, 15]]] && - points == [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0), (0.0, 0.4), (0.0, -2.0), (1.1, -3.0)] + new_boundary_nodes == [[[1, 2, 3], [3, 1]], [[13, 13]], [[4, 5, 6, 7, 4]], [[14, 8], [8, 14]], [[12, 11, 10, 12]], [[15, 15]]] && + points == [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0), (0.0, 0.4), (0.0, -2.0), (1.1, -3.0)] end @testset "BoundaryEnricher" begin all_points = deepcopy.((points_I, points_II, points_III, points_IV, points_V, points_VI, points_VII, points_VIII, points_IX, points_X, points_XI)) all_boundary_nodes = deepcopy.((curve_I, curve_II, curve_III, curve_IV, curve_V, curve_VI, curve_VII, curve_VIII, curve_IX, curve_X, curve_XI)) for (points, boundary_nodes) in zip(all_points, all_boundary_nodes) - enricher = DT.BoundaryEnricher(points, boundary_nodes; IntegerType=Int) + enricher = DT.BoundaryEnricher(points, boundary_nodes; IntegerType = Int) @test get_points(enricher) == enricher.points == points @test get_boundary_nodes(enricher) == enricher.boundary_nodes @test DT.get_boundary_curves(enricher) == enricher.boundary_curves @@ -422,7 +428,7 @@ end @test DT.get_queue(enricher) ⊢ DT.Queue{Int}() @test DT.get_boundary_edge_map(enricher) == enricher.boundary_edge_map == DT.construct_boundary_edge_map(DT.get_boundary_nodes(enricher)) @test !DT.has_segments(enricher) - @test DT.get_segments(enricher) == Set{NTuple{2,Int}}() + @test DT.get_segments(enricher) == Set{NTuple{2, Int}}() @test !DT.is_segment(enricher, 1, 2) end points, boundary_nodes, segments = deepcopy(points_I_extra_segments), deepcopy(curve_I), deepcopy(segments_I) @@ -449,7 +455,7 @@ end (8, 9) => 2, (9, 10) => 3, (10, 11) => 3, - (11, 1) => 3 + (11, 1) => 3, ) @test length(DT.get_parent_map(enricher)) == 11 curve_index_map = DT.get_curve_index_map(enricher) @@ -481,7 +487,7 @@ end 5 => 4, 6 => 4, 7 => 5, - 8 => 6 + 8 => 6, ) @test DT.map_curve_index(enricher, 1) == 1 @test DT.map_curve_index(enricher, 7) == 5 @@ -552,14 +558,14 @@ end points = deepcopy(points_V) boundary_nodes = deepcopy(curve_V) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n=5) # 5 gets mapped to 8 + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n = 5) # 5 gets mapped to 8 @test length(points) == 9 all_t = DT.get_inverse.(Ref(curve_V[1]), get_point(points, new_boundary_nodes...)) |> collect all_t[end] = 1.0 @test issorted(all_t) boundary_nodes = new_boundary_nodes @test DT.num_boundary_edges(boundary_nodes) == 8 - for i in 1:(num_boundary_edges(boundary_nodes)-1) + for i in 1:(num_boundary_edges(boundary_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(boundary_nodes, i), get_boundary_nodes(boundary_nodes, j), get_boundary_nodes(boundary_nodes, k) @@ -574,14 +580,14 @@ end end Tθ₁ = slow_total_absolute_curvature(curve_V[1], t₁, t₂) Tθ₂ = slow_total_absolute_curvature(curve_V[1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-2 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-2 end # VI points = deepcopy(points_VI) boundary_nodes = deepcopy(curve_VI) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n=64) + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n = 64) @test length(points) == 137 all_t = DT.get_inverse.(Ref(curve_VI[1][1]), get_point(points, get_boundary_nodes(new_boundary_nodes, 1)...)) |> collect @test issorted(all_t) @@ -593,7 +599,7 @@ end @test DT.num_boundary_edges(boundary_nodes[2]) == 64 for idx in 1:2 section_nodes = get_boundary_nodes(boundary_nodes, idx) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -601,7 +607,7 @@ end t₁, t₂, t₃ = DT.get_inverse(curve_VI[idx][1], p), DT.get_inverse(curve_VI[idx][1], q), DT.get_inverse(curve_VI[idx][1], r) Tθ₁ = DT.total_variation(curve_VI[idx][1], t₁, t₂) Tθ₂ = DT.total_variation(curve_VI[idx][1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-2 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-2 end end @@ -609,7 +615,7 @@ end points = deepcopy(points_VII) boundary_nodes = deepcopy(curve_VII) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n=512) + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n = 512) @test length(points) == 1025 all_t = DT.get_inverse.(Ref(curve_VII[1][1]), get_point(points, get_boundary_nodes(new_boundary_nodes, 1)...)) |> collect @test issorted(all_t) @@ -620,7 +626,7 @@ end @test DT.num_boundary_edges(boundary_nodes[2]) == 512 for idx in 1:2 section_nodes = get_boundary_nodes(boundary_nodes, idx) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -628,7 +634,7 @@ end t₁, t₂, t₃ = DT.get_inverse(curve_VII[idx][1], p), DT.get_inverse(curve_VII[idx][1], q), DT.get_inverse(curve_VII[idx][1], r) Tθ₁ = DT.total_variation(curve_VII[idx][1], t₁, t₂) Tθ₂ = DT.total_variation(curve_VII[idx][1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-1 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-1 end end @@ -651,7 +657,7 @@ end @test boundary_nodes[3] == [6, 7, 8, 9, 10] for idx in [2, 4] section_nodes = get_boundary_nodes(boundary_nodes, idx) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -659,7 +665,7 @@ end t₁, t₂, t₃ = DT.get_inverse(curve_VIII[idx][1], p), DT.get_inverse(curve_VIII[idx][1], q), DT.get_inverse(curve_VIII[idx][1], r) Tθ₁ = DT.total_variation(curve_VIII[idx][1], t₁, t₂) Tθ₂ = DT.total_variation(curve_VIII[idx][1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-2 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-2 end end @@ -667,7 +673,7 @@ end points = deepcopy(points_IX) boundary_nodes = deepcopy(curve_IX) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves, n=1) # check that 1 becomes 4 + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves, n = 1) # check that 1 becomes 4 @test length(points) == 11 # 1 gets ignored because it's a piecewise linear curve all_t = DT.get_inverse.(Ref(curve_IX[2][1][1]), get_point(points, new_boundary_nodes[2][1]...)) |> collect @@ -679,7 +685,7 @@ end for idx in (2,) curve_nodes = get_boundary_nodes(boundary_nodes, idx) section_nodes = get_boundary_nodes(curve_nodes, 1) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -702,7 +708,7 @@ end points = deepcopy(points_X) boundary_nodes = deepcopy(curve_X) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n=32) + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n = 32) @test length(points) == 70 # 1 and 4 are piecewise linear curves all_t = DT.get_inverse.(Ref(curve_X[1][2][1]), get_point(points, new_boundary_nodes[1][2]...)) |> collect @@ -717,7 +723,7 @@ end for (idx, idx2) in zip((1, 2), (2, 1)) curve_nodes = get_boundary_nodes(boundary_nodes, idx) section_nodes = get_boundary_nodes(curve_nodes, idx2) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -725,7 +731,7 @@ end t₁, t₂, t₃ = DT.get_inverse(curve_X[idx][idx2][1], p), DT.get_inverse(curve_X[idx][idx2][1], q), DT.get_inverse(curve_X[idx][idx2][1], r) Tθ₁ = DT.total_variation(curve_X[idx][idx2][1], t₁, t₂) Tθ₂ = DT.total_variation(curve_X[idx][idx2][1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-1 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-1 end end @@ -733,7 +739,7 @@ end points = deepcopy(points_XI) boundary_nodes = deepcopy(curve_XI) boundary_curves, new_boundary_nodes = DT.convert_boundary_curves!(points, boundary_nodes, Int32) - DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n=128) + DT.coarse_discretisation!(points, new_boundary_nodes, boundary_curves; n = 128) @test length(points) == 650 # (1, 1), (3, 1), and (5, 1) are piecewise linear # (2, 1) and (6, 1) are periodic @@ -758,7 +764,7 @@ end for (idx, idx2) in zip((1, 2, 4, 4, 6), (2, 1, 1, 2, 1)) curve_nodes = get_boundary_nodes(boundary_nodes, idx) section_nodes = get_boundary_nodes(curve_nodes, idx2) - for i in 1:(num_boundary_edges(section_nodes)-1) + for i in 1:(num_boundary_edges(section_nodes) - 1) j = i + 1 k = j + 1 u, v, w = get_boundary_nodes(section_nodes, i), get_boundary_nodes(section_nodes, j), get_boundary_nodes(section_nodes, k) @@ -773,7 +779,7 @@ end end Tθ₁ = DT.total_variation(curve_XI[idx][idx2][1], t₁, t₂) Tθ₂ = DT.total_variation(curve_XI[idx][idx2][1], t₂, t₃) - @test Tθ₁ ≈ Tθ₂ rtol = 1e-2 + @test Tθ₁ ≈ Tθ₂ rtol = 1.0e-2 end end end @@ -796,8 +802,8 @@ end @test DT.is_piecewise_linear(enricher_III, 1) @test !DT.is_piecewise_linear(enricher_IV, 1) @test DT.is_piecewise_linear(enricher_XI, 1) && !DT.is_piecewise_linear(enricher_XI, 2) && - !DT.is_piecewise_linear(enricher_XI, 3) && DT.is_piecewise_linear(enricher_XI, 4) && !DT.is_piecewise_linear(enricher_XI, 5) && - !DT.is_piecewise_linear(enricher_XI, 6) && DT.is_piecewise_linear(enricher_XI, 7) && !DT.is_piecewise_linear(enricher_XI, 8) + !DT.is_piecewise_linear(enricher_XI, 3) && DT.is_piecewise_linear(enricher_XI, 4) && !DT.is_piecewise_linear(enricher_XI, 5) && + !DT.is_piecewise_linear(enricher_XI, 6) && DT.is_piecewise_linear(enricher_XI, 7) && !DT.is_piecewise_linear(enricher_XI, 8) @inferred DT.is_piecewise_linear(enricher_I, 1) @inferred DT.is_piecewise_linear(enricher_II, 3) @inferred DT.is_piecewise_linear(enricher_III, 3) @@ -927,7 +933,7 @@ end (3.4, -0.2), (3.4, 0.0) geo1 = [[g, m, h, ℓ, a, ii, b, jj, c, kk, d, p, e, o, f, n, g]] geo2 = [[a1, z, w, v, u, t, s, a1]] - boundary_nodes, points = convert_boundary_points_to_indices([geo1, geo2]; existing_points=[r, c1, b1, d1, e1, f1, g1]) + boundary_nodes, points = convert_boundary_points_to_indices([geo1, geo2]; existing_points = [r, c1, b1, d1, e1, f1, g1]) enricher = DT.BoundaryEnricher(points, boundary_nodes) i, j, k = findfirst(==(ii), points), findfirst(==(b), points), findfirst(==(r), points) @test DT.is_invisible(DT.test_visibility(enricher, i, j, k)) @@ -999,7 +1005,7 @@ end DT.split_edge!(enricher, 1, 2, length(enricher.points)) vis = DT.test_visibility(enricher, length(enricher.points), 2, length(enricher.points) - 1) @test DT.is_invisible(vis) - enricher.points[end-1] = (0.5, 0.49) + enricher.points[end - 1] = (0.5, 0.49) vis = DT.test_visibility(enricher, length(enricher.points), 2, length(enricher.points) - 1) @test DT.is_visible(vis) end @@ -1023,7 +1029,7 @@ end complexes = DT.get_small_angle_complexes(points, boundary_nodes, boundary_curves) _complexes = Dict( 9 => [SAC(9, [SACM(2, 8), SACM(3, 10)])], - 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])] + 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])], ) @test complexes == _complexes @test DT.get_small_angle_complexes(enricher) == complexes @@ -1045,14 +1051,14 @@ end DT.replace_next_edge!(enricher, 9, 1, 2, 17) _complexes = Dict( 9 => [SAC(9, [SACM(2, 8), SACM(3, 17)])], - 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])] + 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])], ) @test DT.get_small_angle_complexes(enricher) == _complexes A, B, C, D, E, F, G, H, I, J, K = (0.0, 0.0), (0.2, 1.4), (0.6, 1.2), - (1.2, 0.2), (1.2, -0.2), (-1.4, -0.2), - (-1.0, -0.6), (0.6, 1.0), (0.8, 0.6), - (0.6, 0.4), (0.6, 0.2) + (1.2, 0.2), (1.2, -0.2), (-1.4, -0.2), + (-1.0, -0.6), (0.6, 1.0), (0.8, 0.6), + (0.6, 0.4), (0.6, 0.2) points = [A, B, C, D, E, F, G, H, I, J, K] boundary_nodes = [[[1, 3, 2, 1]], [[1, 9, 8, 1]], [[1, 11, 10, 1]], [[1, 5, 4, 1]], [[1, 6, 7, 1]]] enricher = DT.BoundaryEnricher(points, boundary_nodes) @@ -1061,8 +1067,8 @@ end _complexes = Dict( 1 => [ SAC(1, [SACM(1, 2), SACM(1, 3), SACM(2, 8), SACM(2, 9), SACM(3, 10), SACM(3, 11), SACM(4, 4), SACM(4, 5)]), - SAC(1, [SACM(5, 7), SACM(5, 6)]) - ] + SAC(1, [SACM(5, 7), SACM(5, 6)]), + ], ) @test complexes == _complexes @test DT.get_small_angle_complexes(enricher) == complexes @@ -1116,8 +1122,8 @@ end _complexes = Dict( 1 => [ SAC(1, [SACM(1, 2), SACM(1, 3), SACM(2, 8), SACM(2, 9), SACM(3, 10), SACM(3, 11), SACM(4, 4), SACM(4, 5)]), - SAC(1, [SACM(5, 7), SACM(5, 20)]) - ] + SAC(1, [SACM(5, 7), SACM(5, 20)]), + ], ) @test DT.get_small_angle_complexes(enricher) == _complexes @@ -1161,7 +1167,7 @@ end 19 => [16], 20 => [16], 21 => [16], - 22 => [16] + 22 => [16], ) end @@ -1172,7 +1178,7 @@ end _complexes = Dict( 9 => [SAC(9, [SACM(2, 8), SACM(3, 10)])], 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])], - 16 => [SAC(16, [SACM(0, 18), SACM(0, 17), SACM(0, 19), SACM(0, 22)]), SAC(16, [SACM(0, 21), SACM(0, 20)])] + 16 => [SAC(16, [SACM(0, 18), SACM(0, 17), SACM(0, 19), SACM(0, 22)]), SAC(16, [SACM(0, 21), SACM(0, 20)])], ) @test complexes == _complexes @@ -1221,9 +1227,9 @@ end ctr = 1 for i in eachindex(enricher_III.boundary_nodes) for j in eachindex(enricher_III.boundary_nodes[i]) - for k in 1:(length(enricher_III.boundary_nodes[i])-1) + for k in 1:(length(enricher_III.boundary_nodes[i]) - 1) u = enricher_III.boundary_nodes[i][j][k] - v = enricher_III.boundary_nodes[i][j][k+1] + v = enricher_III.boundary_nodes[i][j][k + 1] p = enricher_III.parent_map[(u, v)] @test p == ctr end @@ -1233,7 +1239,7 @@ end rects, els = get_dt_rectangles(enricher_III.spatial_tree.tree) all_edges = Set(DT.get_edge(el) for el in els) @test (ii, jj) ∉ all_edges && (jj, ii) ∉ all_edges && - (ii, rr) ∈ all_edges && (jj, rr) ∈ all_edges + (ii, rr) ∈ all_edges && (jj, rr) ∈ all_edges end @testset "split_subcurve! (standard)" begin @@ -1266,7 +1272,7 @@ end enricher_V = DT.BoundaryEnricher(deepcopy(points_V), deepcopy(curve_V)) t, Δθ, ct = DT.compute_split_position(enricher_V, 3, 5) origθ = DT.total_variation(curve_V[1], DT.get_inverse(curve_V[1], get_point(enricher_V.points, 3)), DT.get_inverse(curve_V[1], get_point(enricher_V.points, 5))) - @test Δθ ≈ origθ / 2 rtol = 1e-3 + @test Δθ ≈ origθ / 2 rtol = 1.0e-3 @test 0.4999 ≤ t ≤ 0.708 && t ≈ 0.5994483483424031 && ct ⪧ curve_V[1](t) DT.split_subcurve!(enricher_V, 3, 5) @test enricher_V.points[end] ⪧ ct @@ -1274,7 +1280,7 @@ end enricher_VI = DT.BoundaryEnricher(deepcopy(points_VI), deepcopy(curve_VI)) t, Δθ, ct = DT.compute_split_position(enricher_VI, 12, 14) origθ = DT.total_variation(curve_VI[1][1], DT.get_inverse(curve_VI[1][1], get_point(enricher_VI.points, 12)), DT.get_inverse(curve_VI[1][1], get_point(enricher_VI.points, 14))) - @test Δθ ≈ origθ / 2 rtol = 1e-3 + @test Δθ ≈ origθ / 2 rtol = 1.0e-3 @test 0.5 ≤ t ≤ 0.75 && t ≈ 0.625 && ct ⪧ curve_VI[1][1](t) DT.split_subcurve!(enricher_VI, 12, 14) @test enricher_VI.points[end] ⪧ ct @@ -1282,8 +1288,8 @@ end enricher_VII = DT.BoundaryEnricher(deepcopy(points_VII), deepcopy(curve_VII)) t, Δθ, ct = DT.compute_split_position(enricher_VII, 8, 7) origθ = DT.total_variation(curve_VII[2][1], DT.get_inverse(curve_VII[2][1], get_point(enricher_VII.points, 8)), DT.get_inverse(curve_VII[2][1], get_point(enricher_VII.points, 7))) - @test Δθ ≈ origθ / 2 rtol = 1e-3 - @test 0.10 ≤ t ≤ 0.501 && t ≈ 0.1599962634542922 && ct ⪧ curve_VII[2][1](t) + @test Δθ ≈ origθ / 2 rtol = 1.0e-3 + @test 0.1 ≤ t ≤ 0.501 && t ≈ 0.1599962634542922 && ct ⪧ curve_VII[2][1](t) DT.split_subcurve!(enricher_VII, 8, 7) @test enricher_VII.points[end] ⪧ ct @@ -1303,14 +1309,14 @@ end @test DT.dist(enricher.points[9], enricher.points[13]) ≈ DT.dist(enricher.points[9], enricher.points[12]) ≈ ℓ _complexes = Dict( 9 => [SAC(9, [SACM(2, 12), SACM(3, 13)])], - 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])] + 1 => [SAC(1, [SACM(3, 11), SACM(1, 2)])], ) @test DT.get_small_angle_complexes(enricher) == _complexes A, B, C, D, E, F, G, H, I, J, K = (0.0, 0.0), (0.2, 1.4), (0.6, 1.2), - (1.2, 0.2), (1.2, -0.2), (-1.4, -0.2), - (-1.0, -0.6), (0.6, 1.0), (0.8, 0.6), - (0.6, 0.4), (0.6, 0.2) + (1.2, 0.2), (1.2, -0.2), (-1.4, -0.2), + (-1.0, -0.6), (0.6, 1.0), (0.8, 0.6), + (0.6, 0.4), (0.6, 0.2) points = [A, B, C, D, E, F, G, H, I, J, K] boundary_nodes = [[[1, 3, 2, 1]], [[1, 9, 8, 1]], [[1, 11, 10, 1]], [[1, 5, 4, 1]], [[1, 6, 7, 1]]] enricher = DT.BoundaryEnricher(points, boundary_nodes) @@ -1320,8 +1326,8 @@ end _complexes = Dict( 1 => [ SAC(1, [SACM(1, 12), SACM(1, 13), SACM(2, 14), SACM(2, 15), SACM(3, 16), SACM(3, 17), SACM(4, 18), SACM(4, 19)]), - SAC(1, [SACM(5, 7), SACM(5, 6)]) - ] + SAC(1, [SACM(5, 7), SACM(5, 6)]), + ], ) @test DT.get_small_angle_complexes(enricher) == _complexes DT.split_subcurve!(enricher, 1, 6) @@ -1329,16 +1335,16 @@ end _complexes = Dict( 1 => [ SAC(1, [SACM(1, 12), SACM(1, 13), SACM(2, 14), SACM(2, 15), SACM(3, 16), SACM(3, 17), SACM(4, 18), SACM(4, 19)]), - SAC(1, [SACM(5, 20), SACM(5, 21)]) - ] + SAC(1, [SACM(5, 20), SACM(5, 21)]), + ], ) @test DT.get_small_angle_complexes(enricher) == _complexes end @testset "has_acute_neighbouring_angles and splitting small angles" begin A, B, C, D, E, F, G, H, I, J, K = (0.0, 0.0), (7.0, 0.0), (-0.2, 1.0), (1.0, 0.0), - (2.0, 0.0), (3.0, 0.0), (4.0, 0.0), (4.5, 0.5), (3.0, 0.8), - (1.6, 0.8), (0.4, 0.2) + (2.0, 0.0), (3.0, 0.0), (4.0, 0.0), (4.5, 0.5), (3.0, 0.8), + (1.6, 0.8), (0.4, 0.2) points = [E, F, G, B, H, I, C, A, D, E] boundary_nodes, points = convert_boundary_points_to_indices(points) enricher = DT.BoundaryEnricher(points, boundary_nodes) @@ -1409,8 +1415,8 @@ end end A, B, C, D, E, F, G, H, I, J, K = (0.0, 0.0), (7.0, 0.0), (2.0, 1.0), (1.0, 0.0), - (2.0, 0.0), (3.0, 0.0), (4.0, 0.0), (4.5, 0.5), (3.0, 0.8), - (1.6, 0.8), (0.4, 0.2) + (2.0, 0.0), (3.0, 0.0), (4.0, 0.0), (4.5, 0.5), (3.0, 0.8), + (1.6, 0.8), (0.4, 0.2) points = [E, F, G, B, H, I, C, J, K, A, D, E] boundary_nodes, points = convert_boundary_points_to_indices(points) enricher = DT.BoundaryEnricher(points, boundary_nodes) @@ -1450,11 +1456,11 @@ end point_sets = deepcopy.([points_I, points_II, points_III, points_IV, points_V, points_VI, points_VII, points_VIII, points_IX, points_X, points_XI, points_XII]) curve_sets = deepcopy.([curve_I, curve_II, curve_III, curve_IV, curve_V, curve_VI, curve_VII, curve_VIII, curve_IX, curve_X, curve_XI, curve_XII]) for i in eachindex(point_sets, curve_sets) - if USE_INEXACTPREDICATES && i == 4 - continue + if USE_INEXACTPREDICATES && i == 4 + continue end points, curve = deepcopy(point_sets[i]), deepcopy(curve_sets[i]) - tri = triangulate(points; boundary_nodes=curve, enrich=i ≤ 3) + tri = triangulate(points; boundary_nodes = curve, enrich = i ≤ 3) @test validate_triangulation(tri) @test is_conformal(tri) @test DT.get_boundary_enricher(tri) == DT.enrich_boundary!(DT.BoundaryEnricher(deepcopy(point_sets[i]), deepcopy(curve_sets[i]))) @@ -1468,7 +1474,7 @@ end curve_sets = deepcopy.([curve_I, curve_II, curve_III, curve_IV, curve_V, curve_VI, curve_VII, curve_VIII, curve_IX, curve_X, curve_XI, curve_XII]) for i in eachindex(point_sets, curve_sets) points, curve = deepcopy(point_sets[i]), deepcopy(curve_sets[i]) - tri = triangulate(points; boundary_nodes=curve, enrich=i ≤ 3) + tri = triangulate(points; boundary_nodes = curve, enrich = i ≤ 3) @test validate_triangulation(tri) @test is_conformal(tri) i ∉ (2, 11) && @test DT.get_boundary_enricher(tri) == DT.enrich_boundary!(DT.BoundaryEnricher(deepcopy(point_sets[i]), deepcopy(curve_sets[i]))) # i ≠ 2 since we deliberately included some boundary points in the extra points, which triangulate then sees and mutates @@ -1483,7 +1489,7 @@ end segment_sets = deepcopy.([segments_I, segments_II, segments_III, segments_IV]) for i in eachindex(point_sets, curve_sets, segment_sets) points, curve, segments = deepcopy(point_sets[i]), deepcopy(curve_sets[i]), deepcopy(segment_sets[i]) - tri = triangulate(points; boundary_nodes=curve, segments=segments, enrich=i ≤ 3) + tri = triangulate(points; boundary_nodes = curve, segments = segments, enrich = i ≤ 3) @test validate_triangulation(tri) @test is_conformal(tri) i ≠ 2 && @test DT.get_boundary_enricher(tri) == DT.enrich_boundary!(DT.BoundaryEnricher(deepcopy(point_sets[i]), deepcopy(curve_sets[i]), deepcopy(segment_sets[i]))) @@ -1501,54 +1507,56 @@ end point_sets = (point_sets_no_extra, point_sets_extra_points, point_sets_extra_segments) curve_sets = deepcopy.([curve_I, curve_II, curve_III, curve_IV, curve_V, curve_VI, curve_VII, curve_VIII, curve_IX, curve_X, curve_XI, curve_XII]) point_names = ("default", "extra_points", "extra_segments") - _rng_num(idx1, - idx2, idx3, idx4, idx5, curve_idx, point_idx) = 2^idx1 * 3^idx2 * 5^idx3 * 7^idx4 * 11^idx5 * 13^curve_idx * 17^point_idx + _rng_num( + idx1, + idx2, idx3, idx4, idx5, curve_idx, point_idx, + ) = 2^idx1 * 3^idx2 * 5^idx3 * 7^idx4 * 11^idx5 * 13^curve_idx * 17^point_idx @testset "all_examples" begin max_area_opts = [ - (1e-2, 1e-3), - (1e-2, 1e-3), - (1e-2, 1e-3), - (1e-2, 1e-3), - (1e-2, 1e-3), - (1e-1, 1e-2), - (1e-1, 1e-2), - (1e-1, 1e-2), - (1e-2, 1e-3), - (1e-1, 1e-2), - (1e-1, 1e-2), - (1e-1, 1e-2) + (1.0e-2, 1.0e-3), + (1.0e-2, 1.0e-3), + (1.0e-2, 1.0e-3), + (1.0e-2, 1.0e-3), + (1.0e-2, 1.0e-3), + (1.0e-1, 1.0e-2), + (1.0e-1, 1.0e-2), + (1.0e-1, 1.0e-2), + (1.0e-2, 1.0e-3), + (1.0e-1, 1.0e-2), + (1.0e-1, 1.0e-2), + (1.0e-1, 1.0e-2), ] for curve_idx in 4:lastindex(curve_sets) if curve_idx ∈ (4, 6, 12) && !!USE_INEXACTPREDICATES - continue + continue end for point_idx in 1:3 point_idx == 3 && curve_idx ≥ 5 && continue # no extra segments for curves ≥ 5 for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((20.0, 27.5, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) + for (idx3, min_area) in enumerate((1.0e-12,)) for (idx4, max_area) in enumerate(max_area_opts[curve_idx]) for (idx5, seditious_angle) in enumerate((10.0, 20.0)) @info "Testing curve-bounded refinement with circumcenters. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle; curve: $curve_idx; point set: $point_idx" rng = StableRNG(abs(_rng_num(idx1, idx2, idx3, idx4, idx5, curve_idx, point_idx))) points, curve = deepcopy(point_sets[point_idx][curve_idx]), deepcopy(curve_sets[curve_idx]) if point_idx ≤ 2 - tri = triangulate(points; boundary_nodes=curve, enrich=curve_idx ≤ 3, rng) + tri = triangulate(points; boundary_nodes = curve, enrich = curve_idx ≤ 3, rng) else segments = deepcopy(segment_sets[curve_idx]) - tri = triangulate(points; boundary_nodes=curve, segments=segments, enrich=curve_idx ≤ 3, rng) + tri = triangulate(points; boundary_nodes = curve, segments = segments, enrich = curve_idx ≤ 3, rng) end custom_constraint = (_tri, T) -> curve_idx ≠ 5 ? false : begin - i, j, k = triangle_vertices(T) - p, q, r = get_point(_tri, i, j, k) - c = (p .+ q .+ r) ./ 3 - x, y = getxy(c) - return (x + y^2 < 1 / 4) && DT.triangle_area(p, q, r) > 1e-4 / 2 - end - refine!(tri; min_angle, min_area, max_area, custom_constraint, seditious_angle, use_circumcenter=true, use_lens, rng) - args = DT.RefinementArguments(tri; min_angle, min_area, max_area, seditious_angle, custom_constraint, use_circumcenter=true, use_lens) - @test validate_refinement(tri, args, warn=false) + i, j, k = triangle_vertices(T) + p, q, r = get_point(_tri, i, j, k) + c = (p .+ q .+ r) ./ 3 + x, y = getxy(c) + return (x + y^2 < 1 / 4) && DT.triangle_area(p, q, r) > 1.0e-4 / 2 + end + refine!(tri; min_angle, min_area, max_area, custom_constraint, seditious_angle, use_circumcenter = true, use_lens, rng) + args = DT.RefinementArguments(tri; min_angle, min_area, max_area, seditious_angle, custom_constraint, use_circumcenter = true, use_lens) + @test validate_refinement(tri, args, warn = false) if _rng_num(idx1, idx2, idx3, idx4, idx5, curve_idx, point_idx) == _rng_num(1, 3, 1, 2, 2, curve_idx, point_idx) fig, ax, sc = triplot(tri) @test_reference "refine_curve_bounded_example_$(curve_idx)_$(names[curve_idx])_$(point_names[point_idx])_$(abs(_rng_num(1, 3, 1, 2, 2, curve_idx, point_idx))).png" fig by = psnr_equality(9) @@ -1570,45 +1578,45 @@ end curve_idx = 12 point_idx = 2 points, curve = deepcopy(point_sets[point_idx][curve_idx]), deepcopy(curve_sets[curve_idx]) - tri = triangulate(points; boundary_nodes=curve) - refine!(tri; max_area=1e-3, max_points=500, use_circumcenter=true) + tri = triangulate(points; boundary_nodes = curve) + refine!(tri; max_area = 1.0e-3, max_points = 500, use_circumcenter = true) @test DT.num_solid_vertices(tri) == 500 @test validate_triangulation(tri) - @test !validate_refinement(tri; max_area=1e-3, max_points=500, use_circumcenter=true, warn=false) + @test !validate_refinement(tri; max_area = 1.0e-3, max_points = 500, use_circumcenter = true, warn = false) end end @testset "adding segment to a curve-bounded domain with no existing segments" begin curve = [ [ - [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])] + [BezierCurve([(0.0, -2.0), (0.0, -2.5), (-1.0, -2.5), (-1.0, -3.0)])], [CatmullRomSpline([(-1.0, -3.0), (0.0, -4.0), (1.0, -3.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] rng = StableRNG(123) - tri = triangulate(points; boundary_nodes=curve, rng) - refine!(tri; max_area=1e-2) + tri = triangulate(points; boundary_nodes = curve, rng) + refine!(tri; max_area = 1.0e-2) @test validate_triangulation(tri) r = DT.num_points(tri) - add_point!(tri, -3 / 2, -4.0, concavity_protection=true) - add_point!(tri, -3 / 2, -1.0, concavity_protection=true) + add_point!(tri, -3 / 2, -4.0, concavity_protection = true) + add_point!(tri, -3 / 2, -1.0, concavity_protection = true) @test validate_triangulation(tri) add_segment!(tri, r + 1, r + 2) @test validate_triangulation(tri) @test tri.boundary_enricher.segments ∈ (Set(((r + 1, r + 2),)), Set(((r + 2, r + 1),))) -end \ No newline at end of file +end diff --git a/test/refinement/refine.jl b/test/refinement/refine.jl index c13dc423a..66cbdc439 100644 --- a/test/refinement/refine.jl +++ b/test/refinement/refine.jl @@ -34,10 +34,10 @@ const pT = (1, 2, 3) end @testset "Setting some values" begin - constraints = DT.RefinementConstraints(min_area=1e-9, max_area=13.7, max_points=505, seditious_angle=60.0) + constraints = DT.RefinementConstraints(min_area = 1.0e-9, max_area = 13.7, max_points = 505, seditious_angle = 60.0) @test constraints.min_angle == 0.0 @test constraints.max_angle == 180.0 - @test constraints.min_area == 1e-9 + @test constraints.min_area == 1.0e-9 @test constraints.max_area == 13.7 @test constraints.max_radius_edge_ratio == Inf @test constraints.max_points == 505 @@ -48,8 +48,8 @@ const pT = (1, 2, 3) end @testset "Constraints and setting min_angle" begin - constraints = DT.RefinementConstraints(min_angle=30.0, custom_constraint=(tri, T) -> T == (1, 2, 3)) - @inferred DT.RefinementConstraints(min_angle=30.0, custom_constraint=(tri, T) -> T == (1, 2, 3)) + constraints = DT.RefinementConstraints(min_angle = 30.0, custom_constraint = (tri, T) -> T == (1, 2, 3)) + @inferred DT.RefinementConstraints(min_angle = 30.0, custom_constraint = (tri, T) -> T == (1, 2, 3)) @test constraints.min_angle == 30.0 @test constraints.max_angle == 180.0 @test constraints.min_area == 0.0 @@ -65,10 +65,10 @@ const pT = (1, 2, 3) end @testset "Setting a maximum angle constraint and a non-30 min_angle" begin - constraints = DT.RefinementConstraints(max_angle=179.9, min_angle=27.59, min_area=1e-9) + constraints = DT.RefinementConstraints(max_angle = 179.9, min_angle = 27.59, min_area = 1.0e-9) @test constraints.min_angle == 27.59 @test constraints.max_angle == 179.9 - @test constraints.min_area == 1e-9 + @test constraints.min_area == 1.0e-9 @test constraints.max_area == Inf @test constraints.max_radius_edge_ratio == cscd(27.59) / 2 @test constraints.max_points == typemax(Int) @@ -81,19 +81,19 @@ const pT = (1, 2, 3) end @testset verbose = true "RefinementQueue" begin - T = NTuple{3,Int} - E = NTuple{2,Int} + T = NTuple{3, Int} + E = NTuple{2, Int} F = Float64 @testset "Initialisation" begin - queue1 = DT.RefinementQueue{T,E,F}() + queue1 = DT.RefinementQueue{T, E, F}() queue2 = DT.RefinementQueue(ptri) @inferred DT.RefinementQueue(ptri) for queue in (queue1, queue2) - @test queue.segments == DT.MaxPriorityQueue{E,F}() - @test typeof(queue.segments) == DT.MaxPriorityQueue{E,F} - @test queue.triangles == DT.MaxPriorityQueue{T,F}() - @test typeof(queue.triangles) == DT.MaxPriorityQueue{T,F} + @test queue.segments == DT.MaxPriorityQueue{E, F}() + @test typeof(queue.segments) == DT.MaxPriorityQueue{E, F} + @test queue.triangles == DT.MaxPriorityQueue{T, F}() + @test typeof(queue.triangles) == DT.MaxPriorityQueue{T, F} @test isempty(queue.segments) @test isempty(queue.triangles) @test !DT.has_segments(queue) @@ -119,16 +119,17 @@ end queue[(27, 25)] = 150.0 queue[(17, 13)] = 23.5 queue[(13, 17)] = 109.591 - @test queue.segments == PriorityQueue(Base.Order.Reverse, + @test queue.segments == PriorityQueue( + Base.Order.Reverse, (1, 2) => 1.0, (5, 7) => 5.6, (10, 3) => 1.881, (11, 12) => 0.0, (27, 25) => 150.0, - (17, 13) => 109.591 + (17, 13) => 109.591, ) @test sprint(show, MIME"text/plain"(), queue) == "RefinementQueue\n 6 segments: DelaunayTriangulation.MaxPriorityQueue((27, 25) => 150.0, (17, 13) => 109.591, (5, 7) => 5.6, (10, 3) => 1.881, (1, 2) => 1.0, (11, 12) => 0.0)\n 0 triangles: DelaunayTriangulation.MaxPriorityQueue{Tuple{Int64, Int64, Int64}, Float64}()" - res = Pair{NTuple{2,Int},Float64}[] + res = Pair{NTuple{2, Int}, Float64}[] while DT.has_segments(queue) push!(res, DT.popfirst_segment!(queue)) end @@ -138,7 +139,7 @@ end (5, 7) => 5.6, (10, 3) => 1.881, (1, 2) => 1.0, - (11, 12) => 0.0 + (11, 12) => 0.0, ] @test isempty(queue) @test !DT.has_segments(queue) @@ -158,15 +159,16 @@ end queue[(7, 9, 5)] = 18.375 queue[(10, 15, 20)] = 0.0 queue[(10, 17, 21)] = 13818.5 - @test queue.triangles == PriorityQueue(Base.Order.Reverse, + @test queue.triangles == PriorityQueue( + Base.Order.Reverse, (1, 2, 3) => 1.0, (5, 7, 9) => 18.375, (10, 3, 4) => 1.881, (10, 17, 21) => 13818.5, - (10, 15, 20) => 0.0 + (10, 15, 20) => 0.0, ) @test sprint(show, MIME"text/plain"(), queue) == "RefinementQueue\n 0 segments: DelaunayTriangulation.MaxPriorityQueue{Tuple{Int64, Int64}, Float64}()\n 5 triangles: DelaunayTriangulation.MaxPriorityQueue((10, 17, 21) => 13818.5, (5, 7, 9) => 18.375, (10, 3, 4) => 1.881, (1, 2, 3) => 1.0, (10, 15, 20) => 0.0)" - res = Pair{NTuple{3,Int},Float64}[] + res = Pair{NTuple{3, Int}, Float64}[] while DT.has_triangles(queue) push!(res, DT.popfirst_triangle!(queue)) end @@ -175,7 +177,7 @@ end (5, 7, 9) => 18.375, (10, 3, 4) => 1.881, (1, 2, 3) => 1.0, - (10, 15, 20) => 0.0 + (10, 15, 20) => 0.0, ] @test isempty(queue) @test !DT.has_triangles(queue) @@ -183,8 +185,8 @@ end @testset "Pushing and popping both segments and triangles / haskey" begin queue = DT.RefinementQueue(ptri) - true_triangle_queue = PriorityQueue{NTuple{3,Int},Float64}(Base.Order.Reverse) - true_segment_queue = PriorityQueue{NTuple{2,Int},Float64}(Base.Order.Reverse) + true_triangle_queue = PriorityQueue{NTuple{3, Int}, Float64}(Base.Order.Reverse) + true_segment_queue = PriorityQueue{NTuple{2, Int}, Float64}(Base.Order.Reverse) for T in each_solid_triangle(ptri) _i, _j, _k = triangle_vertices(T) ρ = DT.triangle_radius_edge_ratio(get_point(ptri, T...)...) @@ -225,10 +227,10 @@ end @test !isempty(queue) @test DT.has_segments(queue) @test DT.has_triangles(queue) - triangle_res = Pair{NTuple{3,Int},Float64}[] - segment_res = Pair{NTuple{2,Int},Float64}[] - true_triangle_res = Pair{NTuple{3,Int},Float64}[] - true_segment_res = Pair{NTuple{2,Int},Float64}[] + triangle_res = Pair{NTuple{3, Int}, Float64}[] + segment_res = Pair{NTuple{2, Int}, Float64}[] + true_triangle_res = Pair{NTuple{3, Int}, Float64}[] + true_segment_res = Pair{NTuple{2, Int}, Float64}[] for i in 1:length(true_triangle_queue) T, ρ = DT.popfirst_triangle!(queue) push!(triangle_res, DT.sort_triangle(T) => ρ) @@ -253,8 +255,8 @@ end @testset verbose = true "InsertionEventHistory" begin @testset "Initialisation" begin - T = NTuple{3,Int} - E = NTuple{2,Int} + T = NTuple{3, Int} + E = NTuple{2, Int} F = Float64 history = DT.InsertionEventHistory(ptri) @inferred DT.InsertionEventHistory(ptri) @@ -268,8 +270,8 @@ end end @testset "Mutating" begin - T = NTuple{3,Int} - E = NTuple{2,Int} + T = NTuple{3, Int} + E = NTuple{2, Int} F = Float64 history = DT.InsertionEventHistory(ptri) @test !DT.has_segment_changes(history) @@ -306,11 +308,11 @@ end @testset "Adding some points inside" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; randomise=false) + tri = triangulate(points; randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = 0.9, 0.9 - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test DT.compare_triangle_collections(history.added_triangles, Set([(2, 3, 5), (5, 3, 4), (1, 5, 4), (1, 2, 5)])) @test DT.compare_triangle_collections(history.deleted_triangles, Set([(1, 2, 3), (1, 3, 4)])) @test !DT.has_segment_changes(history) @@ -322,12 +324,12 @@ end validate_insertion_event_history(tri, orig_tri, history) DT.undo_insertion!(tri, history) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) new_points = [(0.5, 0.5), (0.2, 0.2), (0.5, 0.75), (0.236, 0.987)] for (x, y) in new_points empty!(history) - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test tri ≠ orig_tri # make sure == isn't lying for later validate_insertion_event_history(tri, orig_tri, history) @test !DT.has_segment_changes(history) @@ -335,14 +337,14 @@ end validate_statistics(tri) @test validate_triangulation(tri) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) end - @test tri == triangulate(points; randomise=false) + @test tri == triangulate(points; randomise = false) new_points = [Tuple(rand(2)) for _ in 1:100] for (x, y) in new_points empty!(history) - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test tri ≠ orig_tri # make sure == isn't lying for later validate_insertion_event_history(tri, orig_tri, history) @test !DT.has_segment_changes(history) @@ -350,21 +352,21 @@ end validate_statistics(tri) @test validate_triangulation(tri) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) end - @test tri == triangulate(points; randomise=false) + @test tri == triangulate(points; randomise = false) end end @testset "Testing how add_point! handles segments" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.5, 0.0), (0.5, 1.0)] - tri = triangulate(points; segments=Set(((5, 6),)), randomise=false) + tri = triangulate(points; segments = Set(((5, 6),)), randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = 0.5, 0.5 - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test DT.compare_triangle_collections(history.added_triangles, Set([(1, 5, 7), (7, 5, 2), (7, 2, 3), (6, 7, 3), (4, 7, 6), (4, 1, 7)])) @test DT.compare_triangle_collections(history.deleted_triangles, Set([(1, 5, 4), (5, 2, 3), (5, 3, 6), (4, 5, 6)])) @test DT.compare_unoriented_edge_collections(history.added_segments, Set([(5, 7), (7, 6)])) @@ -376,14 +378,14 @@ end validate_insertion_event_history(tri, orig_tri, history) DT.undo_insertion!(tri, history) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) new_points = LinRange(0.0001, 0.9999, 25) |> collect setdiff!(new_points, 0.5) x = 0.5 for y in new_points empty!(history) - add_point!(tri, x, y, store_event_history=Val(true), event_history=history) + add_point!(tri, x, y, store_event_history = Val(true), event_history = history) @test tri ≠ orig_tri # make sure == isn't lying for later validate_insertion_event_history(tri, orig_tri, history) @test DT.has_segment_changes(history) @@ -391,7 +393,7 @@ end @test tri == orig_tri validate_statistics(tri) @test validate_triangulation(tri) - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) end end @@ -400,11 +402,11 @@ end @testset "Testing how add_point! handles points on existing boundary segments" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], randomise=false) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = 0.5, 0.0 - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test validate_triangulation(tri) @test DT.compare_triangle_collections(history.added_triangles, Set([(1, 5, 4), (5, 2, 3), (4, 5, 3), (5, 1, -1), (2, 5, -1)])) @test DT.compare_triangle_collections(history.deleted_triangles, Set([(1, 2, 3), (1, 3, 4), (2, 1, -1)])) @@ -419,7 +421,7 @@ end validate_statistics(tri) @test validate_triangulation(tri) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) new_points = LinRange(0.0001, 0.9999, 10) |> collect setdiff!(new_points, 0.5) @@ -427,7 +429,7 @@ end for r in new_points for p in ((r, 0.0), (1.0, r), (r, 1.0), (0.0, r)) empty!(history) - add_point!(tri, p, store_event_history=Val(true), event_history=history) + add_point!(tri, p, store_event_history = Val(true), event_history = history) @test tri ≠ orig_tri # make sure == isn't lying for later validate_insertion_event_history(tri, orig_tri, history) @test DT.has_segment_changes(history) @@ -439,7 +441,7 @@ end @test validate_triangulation(tri) end @test tri == orig_tri - add_point!(tri, p, store_event_history=Val(true), event_history=history) + add_point!(tri, p, store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) end end @@ -450,11 +452,11 @@ end for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.3, 0.3), (0.7, 0.3), (0.5, 0.7)] boundary_nodes = [[[1, 2], [2, 3], [3, 4], [4, 1]], [[5, 7], [7, 6], [6, 5]]] - tri = triangulate(points; boundary_nodes, randomise=false) + tri = triangulate(points; boundary_nodes, randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = (0.5, 0.3) - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) @test validate_triangulation(tri) @test DT.compare_triangle_collections(history.added_triangles, Set([(1, 8, 5), (1, 2, 8), (8, 2, 6), (8, 6, -7), (5, 8, -7)])) @test DT.compare_triangle_collections(history.deleted_triangles, Set([(1, 6, 5), (1, 2, 6), (5, 6, -7)])) @@ -469,7 +471,7 @@ end validate_statistics(tri) @test validate_triangulation(tri) @test tri == orig_tri - add_point!(tri, (x, y), store_event_history=Val(true), event_history=history) + add_point!(tri, (x, y), store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) new_points = LinRange(0.31, 0.69, 15) |> collect @test validate_triangulation(tri) @@ -477,7 +479,7 @@ end for r in new_points for p in ((r, 0.3), (r, 0.0)) empty!(history) - add_point!(tri, p, store_event_history=Val(true), event_history=history) + add_point!(tri, p, store_event_history = Val(true), event_history = history) @test tri ≠ orig_tri # make sure == isn't lying for later validate_insertion_event_history(tri, orig_tri, history) @test DT.has_segment_changes(history) @@ -487,7 +489,7 @@ end validate_statistics(tri) @test validate_triangulation(tri) @test tri == orig_tri - add_point!(tri, p, store_event_history=Val(true), event_history=history) + add_point!(tri, p, store_event_history = Val(true), event_history = history) orig_tri = deepcopy(tri) end end @@ -497,7 +499,7 @@ end @testset "Testing how split_edge! is handled on non-segments" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.25, 0.25), (0.75, 0.75)] - tri = triangulate(points; randomise=false) + tri = triangulate(points; randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = (0.5, 0.5) @@ -546,7 +548,7 @@ end @testset "Testing how split_edge! is handled on segments" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; randomise=false, segments=Set([(1, 3)])) + tri = triangulate(points; randomise = false, segments = Set([(1, 3)])) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = (0.5, 0.5) @@ -595,7 +597,7 @@ end @testset "Testing how split_edge! is handled on boundary segments" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], randomise=false) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) x, y = (0.5, 0.0) @@ -645,7 +647,7 @@ end @testset "Testing how flip_edge! is handled" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; randomise=false) + tri = triangulate(points; randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) flip_edge!(tri, 1, 3, Val(true), history) @@ -668,7 +670,7 @@ end @testset "Testing how complete_split_edge_and_legalise! is handled for non-segments" begin for _ in 1:100 points = [(0.01, 0.0), (0.99, 0.00027), (1.0, 1.00025), (0.0, 0.994)] - tri = triangulate(points; randomise=false) + tri = triangulate(points; randomise = false) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) push!(points, (0.5, 0.5)) @@ -712,14 +714,14 @@ end DT.complete_split_edge_and_legalise!(tri, DT.num_points(tri) - 1, 3, DT.num_points(tri), Val(true), history) orig_tri = deepcopy(tri) end - @test tri == triangulate(points; randomise=false) + @test tri == triangulate(points; randomise = false) end end @testset "Testing how complete_split_edge_and_legalise! is handled for segments" begin for _ in 1:10 points = [(0.01, 0.0), (0.99, 0.00027), (1.0, 1.00025), (0.0, 0.994), (0.5, 0.1), (0.5, 0.9)] - tri = triangulate(points; randomise=false, segments=Set([(5, 6)])) + tri = triangulate(points; randomise = false, segments = Set([(5, 6)])) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) push!(points, (0.5, 0.5)) @@ -767,7 +769,7 @@ end @testset "Testing how complete_split_edge_and_legalise! is handled for boundary segments" begin for _ in 1:10 points = [(0.01, 0.0), (0.99, 0.00027), (1.0, 1.00025), (0.0, 0.994), (0.5, 0.1), (0.5, 0.9)] - tri = triangulate(points; randomise=false, boundary_nodes=[1, 2, 3, 4, 1]) + tri = triangulate(points; randomise = false, boundary_nodes = [1, 2, 3, 4, 1]) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) push!(points, (0.1, 0.0)) @@ -810,7 +812,7 @@ end orig_tri = deepcopy(tri) end convex_hull!(tri) - @test tri == triangulate(points; randomise=false, boundary_nodes=tri.boundary_nodes) + @test tri == triangulate(points; randomise = false, boundary_nodes = tri.boundary_nodes) end end @@ -820,7 +822,7 @@ end tri = triangulate(points) orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) - delete_point!(tri, 5, store_event_history=Val(true), event_history=history) + delete_point!(tri, 5, store_event_history = Val(true), event_history = history) validate_insertion_event_history(tri, orig_tri, history) DT.undo_insertion!(tri, history, Val(false)) validate_statistics(tri) @@ -840,7 +842,7 @@ end end orig_tri = deepcopy(tri) history = DT.InsertionEventHistory(tri) - delete_point!(tri, i, rng=rng, store_event_history=Val(true), event_history=history) + delete_point!(tri, i, rng = rng, store_event_history = Val(true), event_history = history) @test validate_triangulation(tri) validate_insertion_event_history(tri, orig_tri, history) DT.undo_insertion!(tri, history, Val(false)) @@ -857,7 +859,7 @@ end p4 = (1.0, 1.0) pts = [p1, p2, p3, p4] rng = StableRNG(123) - tri = triangulate(pts; boundary_nodes=[1, 2, 4, 3, 1], rng, delete_ghosts=false) + tri = triangulate(pts; boundary_nodes = [1, 2, 4, 3, 1], rng, delete_ghosts = false) _tri = deepcopy(tri) push!(pts, (0.5, 0.5)) events = DT.InsertionEventHistory(tri) @@ -900,7 +902,7 @@ end @inferred DT.RefinementArguments(tri) @test args.constraints.min_angle == 30.0 @test args.constraints.max_angle == 180.0 - @test args.constraints.min_area == get_area(tri) / 1e9 + @test args.constraints.min_area == get_area(tri) / 1.0e9 @test args.constraints.max_area == Inf @test args.constraints.max_points == 1000^2 @test args.constraints.seditious_angle == 20.0 @@ -916,11 +918,11 @@ end @test DT.has_ghost_triangles(tri) @test DT.has_boundary_nodes(tri) # convex hull @test args.min_steiner_vertex == 51 - segment_list = Set{NTuple{2,Int}}() + segment_list = Set{NTuple{2, Int}}() segment_vertices = Set{Int}() - for i in 1:(length(tri.convex_hull.vertices)-1) + for i in 1:(length(tri.convex_hull.vertices) - 1) u = tri.convex_hull.vertices[i] - v = tri.convex_hull.vertices[i+1] + v = tri.convex_hull.vertices[i + 1] push!(segment_list, (u, v)) push!(segment_vertices, u, v) @test !DT.is_subsegment(args, (u, v)) && !DT.is_subsegment(args, (v, u)) @@ -936,19 +938,20 @@ end @testset "Setting values" begin tri = triangulate(rand(2, 50)) - args = DT.RefinementArguments(tri; - min_angle=30.5, - max_angle=90.5, - min_area=0.2, - max_area=0.9, - max_points=573, - custom_constraint=(tri, T) -> T == (1, 2, 3), - use_circumcenter=true, - use_lens=false, - steiner_scale=0.95, - seditious_angle=25.3, - rng=StableRNG(123), - concavity_protection=true + args = DT.RefinementArguments( + tri; + min_angle = 30.5, + max_angle = 90.5, + min_area = 0.2, + max_area = 0.9, + max_points = 573, + custom_constraint = (tri, T) -> T == (1, 2, 3), + use_circumcenter = true, + use_lens = false, + steiner_scale = 0.95, + seditious_angle = 25.3, + rng = StableRNG(123), + concavity_protection = true, ) @test args.constraints.min_angle == 30.5 @test args.constraints.max_angle == 90.5 @@ -969,11 +972,11 @@ end @test DT.has_ghost_triangles(tri) @test DT.has_boundary_nodes(tri) # convex hull @test args.min_steiner_vertex == 51 - segment_list = Set{NTuple{2,Int}}() + segment_list = Set{NTuple{2, Int}}() segment_vertices = Set{Int}() - for i in 1:(length(tri.convex_hull.vertices)-1) + for i in 1:(length(tri.convex_hull.vertices) - 1) u = tri.convex_hull.vertices[i] - v = tri.convex_hull.vertices[i+1] + v = tri.convex_hull.vertices[i + 1] push!(segment_list, (u, v)) push!(segment_vertices, u, v) @test !DT.is_subsegment(args, (u, v)) && !DT.is_subsegment(args, (v, u)) @@ -984,28 +987,29 @@ end @test args.midpoint_split_list ⊢ Set{Int}() @test args.offcenter_split_list ⊢ Set{Int}() @test args.concavity_protection - @inferred DT.RefinementArguments(tri; - min_angle=30.5, - max_angle=90.5, - min_area=0.2, - max_area=0.9, - max_points=573, - custom_constraint=(tri, T) -> T == (1, 2, 3), - use_circumcenter=true, - use_lens=false, - steiner_scale=0.95, - rng=StableRNG(123), - concavity_protection=true + @inferred DT.RefinementArguments( + tri; + min_angle = 30.5, + max_angle = 90.5, + min_area = 0.2, + max_area = 0.9, + max_points = 573, + custom_constraint = (tri, T) -> T == (1, 2, 3), + use_circumcenter = true, + use_lens = false, + steiner_scale = 0.95, + rng = StableRNG(123), + concavity_protection = true, ) end @testset "Adding ghost triangles" begin points = rand(2, 50) - tri = triangulate(points, delete_ghosts=true) + tri = triangulate(points, delete_ghosts = true) args = DT.RefinementArguments(tri) @test !args.had_ghosts @test DT.has_ghost_triangles(tri) - @test tri == triangulate(points, delete_ghosts=false, boundary_nodes=tri.convex_hull.vertices) + @test tri == triangulate(points, delete_ghosts = false, boundary_nodes = tri.convex_hull.vertices) end @testset "Checking free vertices" begin @@ -1035,7 +1039,7 @@ end @testset "Iteration" begin tri = triangulate([(rand(), rand()) for _ in 1:50]) - args = DT.RefinementArguments(tri; max_points=55) + args = DT.RefinementArguments(tri; max_points = 55) DT.unlock_convex_hull!(tri) # if the random points later are added outside the domain, they don't always get added as a vertex @test !DT.keep_iterating(tri, args) args.queue[(1, 2, 3)] = 1.0 @@ -1069,12 +1073,12 @@ end @testset verbose = true "is_encroached/encroaches_upon" begin @testset "Testing if point is in diametral circle" begin - args1 = DT.RefinementArguments(ptri; use_lens=false) - @inferred DT.RefinementArguments(ptri; use_lens=false) - args2 = DT.RefinementArguments(ptri; use_lens=true, min_angle=45.0) - p = Vector{NTuple{2,Float64}}(undef, 7) - q = Vector{NTuple{2,Float64}}(undef, 7) - r = Vector{NTuple{2,Float64}}(undef, 7) + args1 = DT.RefinementArguments(ptri; use_lens = false) + @inferred DT.RefinementArguments(ptri; use_lens = false) + args2 = DT.RefinementArguments(ptri; use_lens = true, min_angle = 45.0) + p = Vector{NTuple{2, Float64}}(undef, 7) + q = Vector{NTuple{2, Float64}}(undef, 7) + r = Vector{NTuple{2, Float64}}(undef, 7) p[1], q[1], r[1] = (2.6, 1.63), (5.68, 1.37), (4.5, 4.63) p[2], q[2], r[2] = p[1], q[1], (4.18, 1.96) @@ -1109,10 +1113,10 @@ end end @testset "Testing if a point is in a diametral lens" begin - args = DT.RefinementArguments(ptri; use_lens=true, min_angle=30.0) + args = DT.RefinementArguments(ptri; use_lens = true, min_angle = 30.0) p = (-7.0, 4.0) q = (-2.0, 4.0) - points = Vector{Tuple{NTuple{2,Float64},Function}}(undef, 0) + points = Vector{Tuple{NTuple{2, Float64}, Function}}(undef, 0) push!(points, ((-5.5, 5.0), DT.is_inside)) push!(points, ((-4.0, 4.5), DT.is_inside)) push!(points, ((-5.0, 4.5), DT.is_inside)) @@ -1143,25 +1147,25 @@ end p, q = (-7.0, 4.0), (-2.0, 4.0) upper_circle, lower_circle, circle = compute_diametral_circle(p, q) points_in_diametral_circle, points_outside_diametral_circle = get_points_in_diametral_circle(p, q) - fig = Figure(fontsize=43) - ax = Axis(fig[1, 1], width=600, height=600, title="Diametral circle", titlealign=:left) - scatter!(ax, points_in_diametral_circle, markersize=4, color=:blue) - scatter!(ax, points_outside_diametral_circle, markersize=4, color=:red) + fig = Figure(fontsize = 43) + ax = Axis(fig[1, 1], width = 600, height = 600, title = "Diametral circle", titlealign = :left) + scatter!(ax, points_in_diametral_circle, markersize = 4, color = :blue) + scatter!(ax, points_outside_diametral_circle, markersize = 4, color = :red) #band!(ax, lower_circle, upper_circle, color=(:green, 0.4)) - lines!(ax, circle, color=:black, linewidth=7) - lines!(ax, [p, q], color=:black, linewidth=7) + lines!(ax, circle, color = :black, linewidth = 7) + lines!(ax, [p, q], color = :black, linewidth = 7) xlims!(ax, -7.5, -1.5) ylims!(ax, 1, 7) for (i, lens_angle) in enumerate((45.0, 30.0, 20.0, 10.0)) upper_lens, lower_lens, lens = compute_diametral_lens(p, q, lens_angle) points_in_diametral_lens, points_outside_diametral_lens = get_points_in_diametral_lens(p, q, lens_angle) - ax = Axis(fig[1, 1+i], width=600, height=600, title="Diametral lens (angle $(lens_angle)°)", titlealign=:left) - scatter!(ax, points_in_diametral_lens, markersize=4, color=:blue) - scatter!(ax, points_outside_diametral_lens, markersize=4, color=(:red, 0.1)) + ax = Axis(fig[1, 1 + i], width = 600, height = 600, title = "Diametral lens (angle $(lens_angle)°)", titlealign = :left) + scatter!(ax, points_in_diametral_lens, markersize = 4, color = :blue) + scatter!(ax, points_outside_diametral_lens, markersize = 4, color = (:red, 0.1)) #band!(ax, lower_lens, upper_lens, color=(:green, 0.4)) - lines!(ax, lens, color=:black, linewidth=7) - lines!(ax, [p, q], color=:black, linewidth=7) + lines!(ax, lens, color = :black, linewidth = 7) + lines!(ax, [p, q], color = :black, linewidth = 7) xlims!(ax, -7.5, -1.5) ylims!(ax, 1, 7) end @@ -1175,25 +1179,25 @@ end x = _x y = _y boundary_nodes, points = convert_boundary_points_to_indices(x, y) - tri_1 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_1 = triangulate(points; boundary_nodes, delete_ghosts = false) boundary_nodes, points = convert_boundary_points_to_indices(x[1], y[1]) - tri_2 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_2 = triangulate(points; boundary_nodes, delete_ghosts = false) boundary_nodes, points = convert_boundary_points_to_indices([0.0, 2.0, 2.0, 0.0, 0.0], [0.0, 0.0, 2.0, 2.0, 0.0]) - tri_3 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_3 = triangulate(points; boundary_nodes, delete_ghosts = false) boundary_nodes, points = convert_boundary_points_to_indices(reverse(reverse.(x[2])), reverse(reverse.(y[2]))) - tri_4 = triangulate(points; boundary_nodes, delete_ghosts=false) + tri_4 = triangulate(points; boundary_nodes, delete_ghosts = false) a, b = 0.0, 5.0 c, d = 3.0, 7.0 nx = 3 ny = 3 - tri_5 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=false) - tri_6 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri_5 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = false) + tri_6 = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) @static if VERSION ≥ v"1.10" @inferred triangulate(rand(2, 250)) end for (iii, tri) in enumerate((tri_1, tri_2, tri_3, tri_4, tri_5, tri_6)) @info "Testing if encroached edges are detected. Run: $iii." - args = DT.RefinementArguments(tri; use_lens=false) + args = DT.RefinementArguments(tri; use_lens = false) in_dt_encroached_edges, not_in_dt_encroached_edges = slow_encroachment_test(tri) all_bn = DT.get_all_boundary_nodes(tri) for (e, (b, k)) in not_in_dt_encroached_edges @@ -1219,7 +1223,7 @@ end all_bn = DT.get_all_boundary_nodes(tri) for (lens_angle, not_in_dt_encroached_edges) in zip((45.0, 30.0, 20.0, 10.0), (not_in_dt_encroached_edges_lens_45, not_in_dt_encroached_edges_lens_30, not_in_dt_encroached_edges_lens_20, not_in_dt_encroached_edges_lens_10)) @info "Testing encroached edge detection. lens angle: $lens_angle" - args = DT.RefinementArguments(tri; use_lens=true, min_angle=lens_angle) + args = DT.RefinementArguments(tri; use_lens = true, min_angle = lens_angle) for (e, (b, k)) in not_in_dt_encroached_edges if DT.initial(e) ∈ all_bn && DT.terminal(e) ∈ all_bn && !DT.contains_segment(tri, e) # e.g. if an edge crosses an interior continue @@ -1232,7 +1236,7 @@ end end end for (lens_angle, in_dt_encroached_edges) in zip((45.0, 30.0, 20.0, 10.0), (in_dt_encroached_edges_lens_45, in_dt_encroached_edges_lens_30, in_dt_encroached_edges_lens_20, in_dt_encroached_edges_lens_10)) - args = DT.RefinementArguments(tri; use_lens=true, min_angle=lens_angle) + args = DT.RefinementArguments(tri; use_lens = true, min_angle = lens_angle) for (e, (b, k)) in in_dt_encroached_edges if DT.initial(e) ∈ all_bn && DT.terminal(e) ∈ all_bn && !DT.contains_segment(tri, e) continue @@ -1328,7 +1332,7 @@ end @testset "segment_vertices_adjoin_other_segments_at_acute_angle/compute_split_position" begin for _ in 1:10 points = [(-10.0, -10.0), (10.0, -10.0), (10.0, 10.0), (-10.0, 10.0), (0.05717272721, 0.00000001), (0.99988881, -0.000000998881)] # don't use (0, 1), else the split positions are all 1/2 since 1/2 is a power of 2 split - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([(5, 6)])) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([(5, 6)])) args = DT.RefinementArguments(tri) e = (5, 6) # if e = (6, 5) instead, we would need to be sure that t3 below is replaced by 1 - t3, since we always compute relative to the least vertex. See the comment in compute_split_position. adde! = args -> push!(args.segment_list, e) @@ -1448,7 +1452,7 @@ end one_test(tri, args, p, q, e, m2_q) _points = [(0.0, 0.0), (9.0, 0.0), (9.0, 7.0)] - _tri = triangulate(_points; segments=Set([(1, 2), (1, 3)])) + _tri = triangulate(_points; segments = Set([(1, 2), (1, 3)])) @test DT.segment_vertices_adjoin_other_segments_at_acute_angle(_tri, (1, 2)) == (1, 1) @test DT.segment_vertices_adjoin_other_segments_at_acute_angle(_tri, (1, 3)) == (1, 1) @@ -1508,7 +1512,7 @@ end for _ in 1:10 points = [(-2.0, -2.0), (2.0, -2.0), (2.0, 2.0), (-2.0, 2.0), (-1.1, 0.0), (1.1, 0.0)] orig_points = copy(points) - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([(5, 6)])) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([(5, 6)])) orig_tri = deepcopy(tri) args = DT.RefinementArguments(tri) e = (5, 6) @@ -1516,7 +1520,7 @@ end # just a normal split @test DT.is_free(args, 7) DT.split_subsegment!(tri, args, e) - @test tri == triangulate([orig_points; (0.0, 0.0)]; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([(5, 7), (7, 6)])) + @test tri == triangulate([orig_points; (0.0, 0.0)]; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([(5, 7), (7, 6)])) @test DT.is_midpoint_split(args, 7) @test !DT.is_midpoint_split(args, 6) && !DT.is_midpoint_split(args, 5) @test get_point(tri, 7) == (0.0, 0.0) @@ -1532,7 +1536,7 @@ end orig_points = copy(orig_tri.points) DT.split_subsegment!(tri, args, (8, 7)) @test !DT.is_free(args, 9) - @test tri == triangulate([orig_points; (-0.275, 0.0)]; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([(8, 7), (7, 6), (5, 8)])) + @test tri == triangulate([orig_points; (-0.275, 0.0)]; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([(8, 7), (7, 6), (5, 8)])) @test args.midpoint_split_list ⊢ Set([7, 8, 9]) @test get_point(tri, 9) == (-0.275, 0.0) validate_insertion_event_history(tri, orig_tri, args.events) @@ -1552,13 +1556,13 @@ end @test !DT.is_free(args, 12) @test collect(get_point(tri, 11)) ≈ [-0.825, 0.0] @test collect(get_point(tri, 12)) ≈ [-0.4125, 0.0] - @test tri == triangulate([orig_points; get_point(tri, 12)]; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([get_interior_segments(tri)..., (8, 9)])) + @test tri == triangulate([orig_points; get_point(tri, 12)]; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([get_interior_segments(tri)..., (8, 9)])) @test args.midpoint_split_list ⊢ Set([7, 8, 9, 11, 12]) validate_insertion_event_history(tri, orig_tri, args.events) # a small-input angle points = [(0.0, 0.0), (9.0, 0.0), (9.0, 7.0)] - tri = triangulate(points; segments=Set([(1, 2), (1, 3)])) + tri = triangulate(points; segments = Set([(1, 2), (1, 3)])) args = DT.RefinementArguments(tri) orig_tri = deepcopy(tri) orig_points = copy(orig_tri.points) @@ -1598,14 +1602,14 @@ end @test !DT.encroaches_upon(get_point(tri, 1), get_point(tri, 8), get_point(tri, 9), args) # edges aligned on the same concentric circular shell should not encroach upon one another @test !DT.encroaches_upon(get_point(tri, 1), get_point(tri, 9), get_point(tri, 8), args) # edges aligned on the same concentric circular shell should not encroach upon one another @test validate_triangulation(tri) - DT.unlock_convex_hull!(tri; reconstruct=true) + DT.unlock_convex_hull!(tri; reconstruct = true) @test validate_triangulation(tri) # a small-input angle: Same as above, but flipped along vertical axis points = [(0.0, 0.0), (7.0, 0.0), (0.0, 7.0)] - tri = triangulate(points; segments=Set([(1, 2), (2, 3)])) + tri = triangulate(points; segments = Set([(1, 2), (2, 3)])) args = DT.RefinementArguments(tri) - unlock_convex_hull!(tri; reconstruct=true) # so that (1, 3) is not a segment + unlock_convex_hull!(tri; reconstruct = true) # so that (1, 3) is not a segment DT.split_subsegment!(tri, args, (2, 1)) @test collect(get_point(tri, 4)) ≈ [3.5, 0.0] # midpoint DT.split_subsegment!(tri, args, (1, 4)) @@ -1644,7 +1648,7 @@ end segments = Set([(1, 2), (1, 3), (1, 4), (1, 5)]) # (1, 5) doesn't adjoin any at an acute angle tri = triangulate(points; segments) args = DT.RefinementArguments(tri) - unlock_convex_hull!(tri; reconstruct=true) + unlock_convex_hull!(tri; reconstruct = true) DT.split_subsegment!(tri, args, (1, 2)) # -> 6 DT.split_subsegment!(tri, args, (1, 3)) # -> 7 DT.split_subsegment!(tri, args, (1, 4)) # -> 8 @@ -1722,7 +1726,7 @@ if !USE_INEXACTPREDICATES p4 = (1.0, 1.0) p5 = (0.5, 0.5) pts = [p1, p2, p3, p4, p5] - C = Set{NTuple{2,Int}}() + C = Set{NTuple{2, Int}}() for i in 1:15 θ = 2π * rand() r = 0.5sqrt(rand()) @@ -1731,11 +1735,11 @@ if !USE_INEXACTPREDICATES push!(pts, (x, y)) push!(C, (5, 5 + i)) end - tri = triangulate(pts; delete_ghosts=false, boundary_nodes=[1, 2, 4, 3, 1], segments=C) - args = DT.RefinementArguments(tri, use_lens=use_lens, min_angle=25.0, seditious_angle=15.0, max_area=0.1) + tri = triangulate(pts; delete_ghosts = false, boundary_nodes = [1, 2, 4, 3, 1], segments = C) + args = DT.RefinementArguments(tri, use_lens = use_lens, min_angle = 25.0, seditious_angle = 15.0, max_area = 0.1) DT.enqueue_all_encroached_segments!(args, tri) @inferred DT.enqueue_all_encroached_segments!(args, tri) - manual_enqueue = PriorityQueue{NTuple{2,Int},Float64}(Base.Order.Reverse) + manual_enqueue = PriorityQueue{NTuple{2, Int}, Float64}(Base.Order.Reverse) for e in each_edge(tri) if DT.contains_segment(tri, e...) flag = DT.is_encroached(tri, args, e) @@ -1770,10 +1774,10 @@ if !USE_INEXACTPREDICATES for _ in 1:10 push!(points, (rand(), rand())) end - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1]) - args = DT.RefinementArguments(tri, use_lens=use_lens, min_angle=29.0, seditious_angle=19.0, max_area=0.05) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1]) + args = DT.RefinementArguments(tri, use_lens = use_lens, min_angle = 29.0, seditious_angle = 19.0, max_area = 0.05) DT.enqueue_all_encroached_segments!(args, tri) - manual_enqueue = PriorityQueue{NTuple{2,Int},Float64}(Base.Order.Reverse) + manual_enqueue = PriorityQueue{NTuple{2, Int}, Float64}(Base.Order.Reverse) for e in each_edge(tri) if DT.contains_segment(tri, e...) flag = DT.is_encroached(tri, args, e) @@ -1806,7 +1810,7 @@ end @testset "triangle assessment" begin @testset "is_triangle_nestled" begin - tri = triangulate_rectangle(0, 10, 0, 10, 6, 6, single_boundary=false) + tri = triangulate_rectangle(0, 10, 0, 10, 6, 6, single_boundary = false) segments = get_all_segments(tri) @inferred get_all_segments(tri) for T in each_solid_triangle(tri) @@ -1875,7 +1879,7 @@ end points = [(0.0, 0.0), (2.0, 0.0), (10.0, 0.0), (1.0, 1.0), (8.0, 2.0), (0.0, 6.0), (10.0, 6.0)] segments = Set([(1, 2), (1, 5), (1, 4)]) tri = triangulate(points; segments) - args = DT.RefinementArguments(tri; min_angle=15.0, min_area=3.01, max_area=10.0) + args = DT.RefinementArguments(tri; min_angle = 15.0, min_area = 3.01, max_area = 10.0) good_T, bad_T = slow_triangle_assess(tri, args) @test DT.contains_triangle((1, 4, 6), good_T)[2] # small angle, but area = 3 < min_area @test DT.contains_triangle((6, 4, 5), bad_T)[2] # large area @@ -1888,7 +1892,7 @@ end points = [(0.0, 0.0), (6.0, 0.0), (12.0, 0.0), (11.0, 3.0), (5.788590116313, 1.5787063953581)] segments = Set([(1, 2), (2, 3), (1, 5), (5, 4)]) tri = triangulate(points; segments) - args = DT.RefinementArguments(tri, min_angle=31.0) + args = DT.RefinementArguments(tri, min_angle = 31.0) @test !DT.assess_triangle_quality(tri, args, (1, 2, 5))[2] # seditious @test !DT.assess_triangle_quality(tri, args, (5, 2, 4))[2] # seditious @test DT.assess_triangle_quality(tri, args, (4, 2, 3))[2] # small angle @@ -1900,7 +1904,7 @@ end points = [Tuple(rand(2)) for _ in 1:250] push!(points, (-1, -1), (2, -1), (2, 2), (-1, 2)) tri = triangulate(points) - args = DT.RefinementArguments(tri; min_area=1e-8, max_area=1e-2, min_angle=28.5) + args = DT.RefinementArguments(tri; min_area = 1.0e-8, max_area = 1.0e-2, min_angle = 28.5) @test isempty(args.queue.triangles) DT.enqueue_all_bad_triangles!(args, tri) @test !isempty(args.queue.triangles) @@ -1911,11 +1915,13 @@ end points = [(0.0, 0.0), (2.0, 0.0), (10.0, 0.0), (1.0, 1.0), (8.0, 2.0), (0.0, 6.0), (10.0, 6.0)] segments = Set([(1, 2), (1, 5), (1, 4)]) tri = triangulate(points; segments) - args = DT.RefinementArguments(tri; min_angle=15.0, min_area=3.01, max_area=10.0) + args = DT.RefinementArguments(tri; min_angle = 15.0, min_area = 3.01, max_area = 10.0) DT.enqueue_all_bad_triangles!(args, tri) - queue = PriorityQueue(Base.Order.Reverse, + queue = PriorityQueue( + Base.Order.Reverse, (6, 4, 5) => DT.triangle_radius_edge_ratio(get_point(tri, (6, 4, 5)...)...), - (6, 5, 7) => DT.triangle_radius_edge_ratio(get_point(tri, (6, 5, 7)...)...)) + (6, 5, 7) => DT.triangle_radius_edge_ratio(get_point(tri, (6, 5, 7)...)...), + ) compare_triangle_queues(args, queue) end end @@ -1924,9 +1930,9 @@ end @testset "get_steiner_point" begin for _ in 1:10 tri = triangulate(rand(2, 5000)) - args = DT.RefinementArguments(tri, use_circumcenter=true) - good_results = Dict{NTuple{3,Int},NTuple{2,Float64}}() - bad_results = Dict{NTuple{3,Int},NTuple{2,Float64}}() + args = DT.RefinementArguments(tri, use_circumcenter = true) + good_results = Dict{NTuple{3, Int}, NTuple{2, Float64}}() + bad_results = Dict{NTuple{3, Int}, NTuple{2, Float64}}() for T in each_solid_triangle(tri) flag, c = DT.get_steiner_point(tri, args, T) DT.is_none(flag) && @test c == DT.triangle_circumcenter(get_point(tri, T...)...) @@ -1945,7 +1951,7 @@ end # random tests for _ in 1:10 tri = triangulate(randn(2, 5000)) - args = DT.RefinementArguments(tri, use_circumcenter=true) + args = DT.RefinementArguments(tri, use_circumcenter = true) for T in each_solid_triangle(tri) flag, c = DT.get_steiner_point(tri, args, T) V, loc_flag = DT.locate_steiner_point(tri, args, T, c) @@ -1961,7 +1967,7 @@ end # circumcenter on hypotenuse tri = triangulate([(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)]) - args = DT.RefinementArguments(tri, use_circumcenter=true) + args = DT.RefinementArguments(tri, use_circumcenter = true) c = (0.5, 0.5) for _ in 1:100 for T in ((1, 2, 3), (2, 3, 1), (3, 1, 2)) @@ -1976,13 +1982,13 @@ end @testset "many triangles" begin for _ in 1:10 a, b, c, d, e, f, g, h, i, j, k, ℓ = (0.0, 0.0), (8.0, 0.0), (4.0, 0.0), - (8.0, 4.0), (8.0, 8.0), (4.0, 8.0), (0.0, 8.0), - (0.0, 4.0), (4.0, 6.0), (2.0, 4.0), (4.0, 2.0), (6.0, 4.0) + (8.0, 4.0), (8.0, 8.0), (4.0, 8.0), (0.0, 8.0), + (0.0, 4.0), (4.0, 6.0), (2.0, 4.0), (4.0, 2.0), (6.0, 4.0) boundary_nodes, points = convert_boundary_points_to_indices([[[a, c, b, d, e, f, g, h, a]], [[i, ℓ, k, j, i]]]) m, n, o, p, q, r = (1.0, 7.0), (6.0, 7.0), (6.0, 3.0), (2.0, 3.0), (2.5, 2.5), (1.0, 1.0) push!(points, m, n, o, p, q, r) - tri = triangulate(points; boundary_nodes=boundary_nodes) - args = DT.RefinementArguments(tri, use_circumcenter=true) + tri = triangulate(points; boundary_nodes = boundary_nodes) + args = DT.RefinementArguments(tri, use_circumcenter = true) _to_T = ((p, q, r),) -> (findfirst(==(p), points), findfirst(==(q), points), findfirst(==(r), points)) _ls = T -> DT.locate_steiner_point(tri, args, _to_T(T), DT.triangle_circumcenter(get_point(tri, _to_T(T)...)...)) _check = (T, V, flag) -> DT.check_for_invisible_steiner_point(tri, V, _to_T(T), flag, DT.triangle_circumcenter(get_point(tri, _to_T(T)...)...)) @@ -2052,8 +2058,8 @@ end @testset "triangle on boundary edge" begin for _ in 1:10 points = [(0.0, 0.0), (2.0, 0.0), (0.0, 2.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 1]) - args = DT.RefinementArguments(tri, use_circumcenter=true) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 1]) + args = DT.RefinementArguments(tri, use_circumcenter = true) flag, c = DT.get_steiner_point(tri, args, (1, 2, 3)) @inferred DT.get_steiner_point(tri, args, (1, 2, 3)) @test DT.is_none(flag) && c == DT.triangle_circumcenter(get_point(tri, 1, 2, 3)...) @@ -2071,8 +2077,8 @@ end @testset "triangle on segment edge" begin for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (0.7, 0.7), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], segments=Set([(2, 4)])) - args = DT.RefinementArguments(tri, use_circumcenter=true) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], segments = Set([(2, 4)])) + args = DT.RefinementArguments(tri, use_circumcenter = true) T = (1, 2, 4) flag, c = DT.get_steiner_point(tri, args, T) @test DT.is_none(flag) && c == DT.triangle_circumcenter(get_point(tri, T...)...) @@ -2099,7 +2105,7 @@ end for _ in 1:10 points = [(0.0, 0.0), (0.0, 8.0), (10.0, 8.0), (8.0, 0.0), (4.0, 6.0), (4.5, 5.0), (5.0, 8.0)] tri = triangulate(points) - args = DT.RefinementArguments(tri, use_circumcenter=true) + args = DT.RefinementArguments(tri, use_circumcenter = true) orig_tri = deepcopy(tri) orig_points = deepcopy(points) @@ -2128,7 +2134,7 @@ end points = [(0.0, 0.0), (0.0, 8.0), (10.0, 8.0), (8.0, 0.0), (4.0, 6.0), (4.0, 1.0), (5.0, 8.0)] tri = triangulate(points) - args = DT.RefinementArguments(tri, use_circumcenter=true) + args = DT.RefinementArguments(tri, use_circumcenter = true) orig_tri = deepcopy(tri) orig_points = deepcopy(points) flag = DT.split_triangle!(tri, args, (6, 1, 4)) @@ -2140,7 +2146,7 @@ end tri = triangulate(points) orig_tri = deepcopy(tri) orig_points = deepcopy(points) - args = DT.RefinementArguments(tri, use_circumcenter=true) + args = DT.RefinementArguments(tri, use_circumcenter = true) unlock_convex_hull!(tri) # don't want to deal with EncroachmentFailure proper, only if it's outside of the domain flag = DT.split_triangle!(tri, args, (6, 1, 4)) @test DT.is_successful_insertion(flag) @@ -2152,7 +2158,7 @@ end @testset "check_for_steiner_point_on_segment" begin points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; randomise=false) + tri = triangulate(points; randomise = false) push!(points, (1 / 2, 1 / 2)) V = (1, 2, 3) V′ = (1, 2, 3) @@ -2182,7 +2188,7 @@ end @test !DT.has_boundary_nodes(tri) @test DT.has_ghost_triangles(tri) - tri = triangulate_rectangle(0, 1, 0, 1, 5, 5, delete_ghosts=true) + tri = triangulate_rectangle(0, 1, 0, 1, 5, 5, delete_ghosts = true) args = DT.RefinementArguments(tri) @test DT.has_boundary_nodes(tri) @test DT.has_ghost_triangles(tri) @@ -2198,7 +2204,7 @@ end @test DT.has_boundary_nodes(tri) @test DT.has_ghost_triangles(tri) - tri = triangulate(rand(2, 50), delete_ghosts=true) + tri = triangulate(rand(2, 50), delete_ghosts = true) args = DT.RefinementArguments(tri) @test DT.has_boundary_nodes(tri) @test DT.has_ghost_triangles(tri) @@ -2216,15 +2222,15 @@ end for p in [(4.0, 2.0), (5.0, 2.5), (3.0, 3.5), (5.0, 4.5), (6.5, 3.5), (7.0, 4.0), (6.5, 1.5), (4.0, 3.5)] add_point!(tri, p) end - fig = Figure(fontsize=33) - ax = Axis(fig[1, 1], width=600, height=400) + fig = Figure(fontsize = 33) + ax = Axis(fig[1, 1], width = 600, height = 400) _, _, C = compute_diametral_circle(get_point(tri, 5, 6)...) triplot!(ax, tri) - lines!(ax, C, color=:red) + lines!(ax, C, color = :red) DT.split_subsegment!(tri, args, (5, 6)) - ax = Axis(fig[1, 2], width=600, height=400) + ax = Axis(fig[1, 2], width = 600, height = 400) triplot!(ax, tri) - lines!(ax, C, color=:red) + lines!(ax, C, color = :red) resize_to_layout!(fig) fig @test_reference "delete_free_vertices_around_subsegment.png" fig @@ -2238,15 +2244,15 @@ end for p in [(4.0, 2.0), (5.0, 2.5), (3.0, 3.5), (5.0, 4.5), (6.5, 3.5), (7.0, 4.0), (6.5, 1.5), (4.0, 3.5)] add_point!(tri, p) end - fig = Figure(fontsize=33) - ax = Axis(fig[1, 1], width=600, height=400) + fig = Figure(fontsize = 33) + ax = Axis(fig[1, 1], width = 600, height = 400) _, _, C = compute_diametral_circle(get_point(tri, 5, 6)...) triplot!(ax, tri) - lines!(ax, C, color=:red) + lines!(ax, C, color = :red) DT.split_subsegment!(tri, args, (5, 6)) - ax = Axis(fig[1, 2], width=600, height=400) + ax = Axis(fig[1, 2], width = 600, height = 400) triplot!(ax, tri) - lines!(ax, C, color=:red) + lines!(ax, C, color = :red) resize_to_layout!(fig) fig @test_reference "delete_free_vertices_around_subsegment2.png" fig @@ -2258,22 +2264,22 @@ end @testset "A simple convex example" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((20.0, 27.5, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-1, 1e-2)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-1, 1.0e-2)) for (idx5, seditious_angle) in enumerate((10.0, 20.0)) @info "Testing refinement of a simple convex example. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1], rng) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1], rng) custom_constraint = (_tri, T) -> begin i, j, k = triangle_vertices(T) p, q, r = get_point(_tri, i, j, k) c = (p .+ q .+ r) ./ 3 y = gety(c) - return y < 1 / 2 && DT.triangle_area(p, q, r) > 1e-3 + return y < 1 / 2 && DT.triangle_area(p, q, r) > 1.0e-3 end - refine!(tri; min_angle, min_area, max_area, custom_constraint, seditious_angle, use_circumcenter=true, use_lens, rng) - args = DT.RefinementArguments(tri; min_angle, min_area, max_area, seditious_angle, custom_constraint, use_circumcenter=true, use_lens) + refine!(tri; min_angle, min_area, max_area, custom_constraint, seditious_angle, use_circumcenter = true, use_lens, rng) + args = DT.RefinementArguments(tri; min_angle, min_area, max_area, seditious_angle, custom_constraint, use_circumcenter = true, use_lens) @test validate_refinement(tri, args) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 3, 1, 2, 2) fig, ax, sc = triplot(tri) @@ -2292,17 +2298,19 @@ end @testset "Triangulation with a hole" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((12.9, 27.5, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-2, 1e-3, 1e-4)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-2, 1.0e-3, 1.0e-4)) for (idx5, seditious_angle) in enumerate((20.0, 40.0)) @info "Testing refinement of a triangulation with a hole. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) - points = [(0.0, 0.0), (0.5, 0.1), (1.0, 0.0), (0.9, 0.5), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), - (0.3, 0.3), (0.7, 0.3), (0.7, 0.7), (0.3, 0.7)] + points = [ + (0.0, 0.0), (0.5, 0.1), (1.0, 0.0), (0.9, 0.5), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), + (0.3, 0.3), (0.7, 0.3), (0.7, 0.7), (0.3, 0.7), + ] boundary_nodes = [[[1, 2, 3, 4, 5, 6, 7, 1]], [[11, 10, 9, 8, 11]]] tri = triangulate(points; boundary_nodes, rng) - refine!(tri; min_angle, min_area, max_area, use_circumcenter=true, use_lens, rng, seditious_angle) - @test validate_refinement(tri, DT.RefinementArguments(tri; min_angle, min_area, seditious_angle, max_area, use_circumcenter=true, use_lens)) + refine!(tri; min_angle, min_area, max_area, use_circumcenter = true, use_lens, rng, seditious_angle) + @test validate_refinement(tri, DT.RefinementArguments(tri; min_angle, min_area, seditious_angle, max_area, use_circumcenter = true, use_lens)) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 3, 1, 3, 1) fig, ax, sc = triplot(tri) @test_reference "triangulation_with_a_hole_circle.png" fig by = psnr_equality(15) @@ -2320,12 +2328,13 @@ end @testset "A very non-convex example" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((12.9, 15.8, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-1, 1e-3, 1e-4)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-1, 1.0e-3, 1.0e-4)) for (idx5, seditious_angle) in enumerate((10.0, 20.0, 60.0)) @info "Testing refinement of a very non-convex example. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) - points = [(0.0, 0.0), (0.0, 1.0), (0.1, 1.0), + points = [ + (0.0, 0.0), (0.0, 1.0), (0.1, 1.0), (0.1, 0.1), (0.2, 0.1), (0.2, 1.0), (0.3, 1.0), (0.3, 0.0), (0.4, 0.0), (0.4, 0.9), (0.5, 0.9), (0.5, 0.1), @@ -2333,11 +2342,12 @@ end (0.7, 0.1), (0.8, 0.1), (0.8, 0.9), (0.9, 0.9), (0.9, 0.1), (0.9, 0.0), (1.0, 0.0), (1.0, -0.1), (0.0, -0.1), - (0.0, 0.0)] |> reverse! + (0.0, 0.0), + ] |> reverse! boundary_nodes, points = convert_boundary_points_to_indices(points) tri = triangulate(points; boundary_nodes, rng) - refine!(tri; min_angle, min_area, max_area, use_circumcenter=true, use_lens, seditious_angle, rng) - @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter=true, use_lens, check_conformal=false) + refine!(tri; min_angle, min_area, max_area, use_circumcenter = true, use_lens, seditious_angle, rng) + @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter = true, use_lens, check_conformal = false) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 3, 1, 3, 2) fig, ax, sc = triplot(tri) @test_reference "a_very_non_convex_example_circle.png" fig @@ -2355,24 +2365,28 @@ end @testset "A constrained triangulation with multiple holes" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((12.9, 15.8, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-2, 1e-3, 1e-4)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-2, 1.0e-3, 1.0e-4)) for (idx5, seditious_angle) in enumerate((20.0, 40.0)) @info "Testing refinement of a triangulation with multiple holes. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) - curve_1 = [[ - (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), - (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), - (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), - (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), - (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), - (-4.0, 0.0), (0.0, 0.0), - ]] - curve_2 = [[ - (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), - (10.0, 22.0), (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), - (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0) - ]] + curve_1 = [ + [ + (0.0, 0.0), (4.0, 0.0), (8.0, 0.0), (12.0, 0.0), (12.0, 4.0), + (12.0, 8.0), (14.0, 10.0), (16.0, 12.0), (16.0, 16.0), + (14.0, 18.0), (12.0, 20.0), (12.0, 24.0), (12.0, 28.0), + (8.0, 28.0), (4.0, 28.0), (0.0, 28.0), (-2.0, 26.0), (0.0, 22.0), + (0.0, 18.0), (0.0, 10.0), (0.0, 8.0), (0.0, 4.0), (-4.0, 4.0), + (-4.0, 0.0), (0.0, 0.0), + ], + ] + curve_2 = [ + [ + (4.0, 26.0), (8.0, 26.0), (10.0, 26.0), (10.0, 24.0), + (10.0, 22.0), (10.0, 20.0), (8.0, 20.0), (6.0, 20.0), + (4.0, 20.0), (4.0, 22.0), (4.0, 24.0), (4.0, 26.0), + ], + ] curve_3 = [[(4.0, 16.0), (12.0, 16.0), (12.0, 14.0), (4.0, 14.0), (4.0, 16.0)]] curve_4 = [[(4.0, 8.0), (10.0, 8.0), (8.0, 6.0), (6.0, 6.0), (4.0, 8.0)]] curves = [curve_1, curve_2, curve_3, curve_4] @@ -2387,12 +2401,13 @@ end (-4.0, 22.0), (-4.0, 26.0), (-2.0, 28.0), (6.0, 15.0), (7.0, 15.0), (8.0, 15.0), (9.0, 15.0), (10.0, 15.0), (6.2, 7.8), (5.6, 7.8), (5.6, 7.6), (5.6, 7.4), (6.2, 7.4), (6.0, 7.6), - (7.0, 7.8), (7.0, 7.4)] - boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points=points) + (7.0, 7.8), (7.0, 7.4), + ] + boundary_nodes, points = convert_boundary_points_to_indices(curves; existing_points = points) tri = triangulate(points; boundary_nodes, rng) max_area = max_area * get_area(tri) - refine!(tri; min_angle, min_area, max_area, use_circumcenter=true, seditious_angle, use_lens, rng) - @test validate_refinement(tri; min_angle, min_area, max_area, use_circumcenter=true, seditious_angle, use_lens, check_conformal=false) + refine!(tri; min_angle, min_area, max_area, use_circumcenter = true, seditious_angle, use_lens, rng) + @test validate_refinement(tri; min_angle, min_area, max_area, use_circumcenter = true, seditious_angle, use_lens, check_conformal = false) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 3, 1, 3, 1) fig, ax, sc = triplot(tri) @test_reference "a_constrained_triangulation_with_multiple_holes_circle.png" fig by = psnr_equality(15) @@ -2410,8 +2425,8 @@ end @testset "another square example, directly testing stats" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((12.9, 15.8, 27.5, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-1, 1e-2, 1e-4)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-1, 1.0e-2, 1.0e-4)) for (idx5, seditious_angle) in enumerate((10.0, 20.0)) @info "Testing refinement of a square. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) @@ -2421,7 +2436,7 @@ end p4 = (1.0, 1.0) pts = [p1, p2, p3, p4] tri = triangulate(pts; rng) - refine!(tri; min_angle, min_area, max_area, use_circumcenter=true, seditious_angle, use_lens, rng) + refine!(tri; min_angle, min_area, max_area, use_circumcenter = true, seditious_angle, use_lens, rng) stats = statistics(tri) @test DT.get_smallest_angle(stats) ≥ deg2rad(min_angle) @test DT.get_largest_area(stats) ≤ max_area @@ -2430,7 +2445,7 @@ end @test DT.convex_hull(tri).vertices == DT.convex_hull(tri.points).vertices @test validate_triangulation(tri) validate_statistics(tri) - @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter=true, use_lens) + @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter = true, use_lens) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 4, 1, 3, 2) fig, ax, sc = triplot(tri) @test_reference "another_square_example_circle.png" fig by = psnr_equality(15) @@ -2453,18 +2468,18 @@ end p4 = (1.0, 1.0) pts = [p1, p2, p3, p4] tri = triangulate(pts) - refine!(tri; max_area=1e-6, max_points=5_000, use_circumcenter=true) + refine!(tri; max_area = 1.0e-6, max_points = 5_000, use_circumcenter = true) @test DT.num_solid_vertices(tri) == 5000 @test validate_triangulation(tri) - @test !validate_refinement(tri; max_area=1e-6, max_points=5_000, use_circumcenter=true, warn=false) + @test !validate_refinement(tri; max_area = 1.0e-6, max_points = 5_000, use_circumcenter = true, warn = false) end end @testset "avoiding infinite bouncing with concentric circular shells" begin for (idx1, use_lens) in enumerate((false, true)) for (idx2, min_angle) in enumerate((23.0, 27.5, 30.0)) - for (idx3, min_area) in enumerate((1e-12,)) - for (idx4, max_area) in enumerate((1e-1, 1e-2)) + for (idx3, min_area) in enumerate((1.0e-12,)) + for (idx4, max_area) in enumerate((1.0e-1, 1.0e-2)) for (idx5, seditious_angle) in enumerate((10.0, 20.0)) @info "Testing that infinite bouncing is avoided during refinement. use_lens: $use_lens; min_angle: $min_angle; min_area: $min_area; max_area: $max_area; seditious_angle: $seditious_angle." p1 = (0.0, 0.0) @@ -2475,8 +2490,8 @@ end rng = StableRNG(_rng_num(idx1, idx2, idx3, idx4, idx5)) tri = triangulate(pts; rng) add_segment!(tri, 1, 4; rng) - refine!(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter=true, use_lens, rng) - @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter=true, use_lens) + refine!(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter = true, use_lens, rng) + @test validate_refinement(tri; min_angle, min_area, max_area, seditious_angle, use_circumcenter = true, use_lens) validate_statistics(tri) if _rng_num(idx1, idx2, idx3, idx4, idx5) == _rng_num(1, 3, 1, 2, 2) fig, ax, sc = triplot(tri) @@ -2496,21 +2511,21 @@ end for _ in 1:10 points = [(0.0, 0.0), (1.0, 0.0), (0.8, 0.2)] tri = triangulate(points) - refine!(tri, use_circumcenter=true) + refine!(tri, use_circumcenter = true) @test_reference "seditious_edge_testing_1.png" triplot(tri) by = psnr_equality(15) - @test validate_refinement(tri, use_circumcenter=true) + @test validate_refinement(tri, use_circumcenter = true) validate_statistics(tri) points = [(0.0, 0.0), (1.0, 0.0), (0.8, 0.2)] tri = triangulate(points) - refine!(tri, use_circumcenter=true, use_lens=false) + refine!(tri, use_circumcenter = true, use_lens = false) @test_reference "seditious_edge_testing_2.png" triplot(tri) by = psnr_equality(15) - @test validate_refinement(tri, use_circumcenter=true, use_lens=false) + @test validate_refinement(tri, use_circumcenter = true, use_lens = false) validate_statistics(tri) points = [(0.0, 0.0), (1.0, 0.0), (0.8, 0.2)] tri = triangulate(points) - args = DT.RefinementArguments(tri, use_circumcenter=true, use_lens=false, max_area=1e-3get_area(tri)) + args = DT.RefinementArguments(tri, use_circumcenter = true, use_lens = false, max_area = 1.0e-3get_area(tri)) refine!(tri, args) @test validate_refinement(tri, args) @test_reference "seditious_edge_testing_3.png" triplot(tri) by = psnr_equality(15) @@ -2530,7 +2545,7 @@ end pts = [p1, p2, p3, p4, p5, p6, p7, p8] boundary_nodes = [[[1, 2, 3, 4, 1]], [[8, 7, 6, 5, 8]]] rng = StableRNG(123) - tri = triangulate(pts; rng, boundary_nodes=boundary_nodes, delete_ghosts=false) + tri = triangulate(pts; rng, boundary_nodes = boundary_nodes, delete_ghosts = false) add_point!(tri, 0.1, 0.8; rng) add_point!(tri, 0.3, 0.2; rng) add_point!(tri, 0.7, 0.2; rng) @@ -2539,7 +2554,7 @@ end add_segment!(tri, 11, 12; rng) add_segment!(tri, 9, 12; rng) add_segment!(tri, 10, 11; rng) - refine!(tri; max_area=0.001, max_points=5000, use_circumcenter=true, use_lens=true, rng) + refine!(tri; max_area = 0.001, max_points = 5000, use_circumcenter = true, use_lens = true, rng) stats = statistics(tri) @test DT.get_smallest_angle(stats) ≥ deg2rad(30) @test DT.get_largest_area(stats) ≤ 0.001 @@ -2547,7 +2562,7 @@ end @test DT.convex_hull(tri).vertices == DT.convex_hull(tri.points).vertices validate_statistics(tri, stats) @test validate_triangulation(tri) - @test validate_refinement(tri; max_area=0.001, max_points=5000, use_circumcenter=true, use_lens=true) + @test validate_refinement(tri; max_area = 0.001, max_points = 5000, use_circumcenter = true, use_lens = true) fig, ax, sc = triplot(tri) @test_reference "triangulating_with_an_interior_hole.png" fig by = psnr_equality(15) end @@ -2555,7 +2570,7 @@ end @testset "Refining disjoint sets" begin θ = LinRange(0, 2π, 30) |> collect θ[end] = 0 - xy = Vector{Vector{Vector{NTuple{2,Float64}}}}() + xy = Vector{Vector{Vector{NTuple{2, Float64}}}}() rng = StableRNG(123) cx = 0.0 for i in 1:2 @@ -2564,14 +2579,14 @@ end cx += 3.0 end boundary_nodes, points = convert_boundary_points_to_indices(xy) - tri = triangulate(points; boundary_nodes=boundary_nodes, rng) + tri = triangulate(points; boundary_nodes = boundary_nodes, rng) A = DT.get_area(tri) max_area = 0.001A - min_area = 1e-9A - refine!(tri; min_area, rng, max_area, use_circumcenter=true) + min_area = 1.0e-9A + refine!(tri; min_area, rng, max_area, use_circumcenter = true) stats = statistics(tri) validate_statistics(tri) - @test validate_refinement(tri; min_area, max_area, use_circumcenter=true) + @test validate_refinement(tri; min_area, max_area, use_circumcenter = true) fig, ax, sc = triplot(tri) @test_reference "refining_disjoint_sets.png" fig by = psnr_equality(15) end @@ -2579,15 +2594,15 @@ end if !USE_INEXACTPREDICATES @testset "Small angles" begin ps = 0 - fig = Figure(fontsize=52) + fig = Figure(fontsize = 52) for i in 1:12 if i > 6 use_lens = true i -= 6 - ax = Axis(fig[2, i], title="Lens; $i", width=600, height=600) + ax = Axis(fig[2, i], title = "Lens; $i", width = 600, height = 600) else use_lens = false - ax = Axis(fig[1, i], title="Circle; $i", width=600, height=600) + ax = Axis(fig[1, i], title = "Circle; $i", width = 600, height = 600) end hidedecorations!(ax) hidespines!(ax) @@ -2598,7 +2613,7 @@ end p4 = (1.0, 1.0) p5 = (0.5, 0.5) pts = [p1, p2, p3, p4, p5] - C = Set{NTuple{2,Int}}() + C = Set{NTuple{2, Int}}() for i in 1:20 θ = 2π * rand(rng) r = 0.5sqrt(rand(rng)) @@ -2607,12 +2622,12 @@ end push!(pts, (x, y)) push!(C, (5, 5 + i)) end - tri = triangulate(pts; rng, boundary_nodes=[1, 2, 4, 3, 1], segments=C) - refine!(tri; min_angle=27.3, min_area=0.0, use_circumcenter=true, rng, use_lens) + tri = triangulate(pts; rng, boundary_nodes = [1, 2, 4, 3, 1], segments = C) + refine!(tri; min_angle = 27.3, min_area = 0.0, use_circumcenter = true, rng, use_lens) stats = statistics(tri) ps += DT.get_largest_angle(stats) ≤ max(π - 2 * deg2rad(17.0), 2asin((sqrt(3) - 1) / 2)) # Corollary 8 of "When and Why Ruppert's Algorithm Works. In Twelfth International Meshing Roundtable, pp. 91–102, Santa Fe, NM, Sept 2003." validate_statistics(tri) - @test validate_refinement(tri; min_angle=27.3, min_area=0.0, use_circumcenter=true, warn=false, use_lens, rng) + @test validate_refinement(tri; min_angle = 27.3, min_area = 0.0, use_circumcenter = true, warn = false, use_lens, rng) triplot!(ax, tri) end resize_to_layout!(fig) @@ -2634,21 +2649,25 @@ end reverse!(inverse_points) curve_points = [[points], [inverse_points]] boundary_nodes, points = convert_boundary_points_to_indices(curve_points) - C = Set([[(50, i) for i in 98:-1:81]..., [(50, i) for i in 69:-1:51]..., - [(10, i) for i in 36:49]...]) + C = Set( + [ + [(50, i) for i in 98:-1:81]..., [(50, i) for i in 69:-1:51]..., + [(10, i) for i in 36:49]..., + ], + ) C′ = empty(C) bem = DT.construct_boundary_edge_map(boundary_nodes) for c in C c′ = DT.reverse_edge(c) c ∉ keys(bem) && c′ ∉ keys(bem) && push!(C′, c) end - tri = triangulate(points; boundary_nodes, rng, segments=C′) + tri = triangulate(points; boundary_nodes, rng, segments = C′) @test DT.is_disjoint(tri) @test validate_triangulation(tri) A = DT.get_area(tri) - refine!(tri, max_area=1e-3A, min_area=1e-12A, rng=rng, use_circumcenter=true, use_lens=true) + refine!(tri, max_area = 1.0e-3A, min_area = 1.0e-12A, rng = rng, use_circumcenter = true, use_lens = true) validate_statistics(tri) - @test validate_refinement(tri, max_area=1e-3A, min_area=0.0, use_circumcenter=true, use_lens=true, warn=false) + @test validate_refinement(tri, max_area = 1.0e-3A, min_area = 0.0, use_circumcenter = true, use_lens = true, warn = false) fig, ax, sc = triplot(tri) @test_reference "refining_disjoint_sets_2.png" fig by = psnr_equality(15) end @@ -2695,12 +2714,12 @@ end boundary_pts = [[pts], [inner_pts]] nodes, points = convert_boundary_points_to_indices(boundary_pts) rng = StableRNG(123) - tri = triangulate(points; boundary_nodes=nodes, rng) + tri = triangulate(points; boundary_nodes = nodes, rng) @test validate_triangulation(tri) A = get_area(tri) - refine!(tri; max_area=1e-3A, use_circumcenter=true, rng) + refine!(tri; max_area = 1.0e-3A, use_circumcenter = true, rng) validate_statistics(tri) - @test validate_refinement(tri; max_area=1e-3A, rng, use_circumcenter=true, warn=true) + @test validate_refinement(tri; max_area = 1.0e-3A, rng, use_circumcenter = true, warn = true) fig, ax, sc = triplot(tri) @test_reference "tight_example_with_a_single_triangle_boundary_interior.png" fig by = psnr_equality(15) end @@ -2759,7 +2778,7 @@ end boundary_pts = [[pts], [inner_pts]] nodes, points = convert_boundary_points_to_indices(boundary_pts) push!(points, (20.0, 20.0)) - C = Set{NTuple{2,Int}}() + C = Set{NTuple{2, Int}}() for i in 1:50 θ = 2π * rand(rng) r = 4sqrt(rand(rng)) @@ -2768,10 +2787,10 @@ end push!(points, (x, y)) push!(C, (48, 48 + i)) end - tri = triangulate(points; boundary_nodes=nodes, segments=C, rng) + tri = triangulate(points; boundary_nodes = nodes, segments = C, rng) @test validate_triangulation(tri) A = get_area(tri) - refine!(tri; max_area=1.0, rng, use_circumcenter=true) + refine!(tri; max_area = 1.0, rng, use_circumcenter = true) validate_statistics(tri) fig, ax, sc = triplot(tri) @test_reference "complicated_example_with_tight_walls_and_small_angles.png" fig by = psnr_equality(15) @@ -2789,11 +2808,11 @@ end unique!(tassy) push!(tassy, tassy[begin]) boundary_nodes, points = convert_boundary_points_to_indices(tassy) - tri = triangulate(points; rng, boundary_nodes=boundary_nodes) + tri = triangulate(points; rng, boundary_nodes = boundary_nodes) A = get_area(tri) - refine!(tri; max_area=1e-2A, use_circumcenter=true, rng) + refine!(tri; max_area = 1.0e-2A, use_circumcenter = true, rng) validate_statistics(tri) - @test validate_refinement(tri; max_area=1e-2A, rng, use_circumcenter=true, warn=false) + @test validate_refinement(tri; max_area = 1.0e-2A, rng, use_circumcenter = true, warn = false) fig, ax, sc = triplot(tri) @test_reference "tasmania.png" fig by = psnr_equality(15) end @@ -2807,9 +2826,9 @@ end p3 = (0.0f0, 1.0f0) p4 = (1.0f0, 1.0f0) pts = [p1, p2, p3, p4] - tri = triangulate(pts; delete_ghosts=false) + tri = triangulate(pts; delete_ghosts = false) validate_statistics(tri) - refine!(tri; max_area=0.001, max_points=25_000, use_circumcenter=true) + refine!(tri; max_area = 0.001, max_points = 25_000, use_circumcenter = true) stats = statistics(tri) @inferred statistics(tri) @test DT.get_smallest_angle(stats) ≥ deg2rad(30.0) @@ -2817,7 +2836,7 @@ end @test !DT.is_constrained(tri) @test DT.convex_hull(tri).vertices == DT.convex_hull(tri.points).vertices @test validate_triangulation(tri) - @test validate_refinement(tri; max_area=0.001, max_points=25_000, use_circumcenter=true) + @test validate_refinement(tri; max_area = 0.001, max_points = 25_000, use_circumcenter = true) end for _ in 1:5 @@ -2832,7 +2851,7 @@ end p8 = (0.4f0, 0.6f0) pts = [p1, p2, p3, p4, p5, p6, p7, p8] boundary_nodes = [[[1, 2, 3, 4, 1]], [[8, 7, 6, 5, 8]]] - tri = triangulate(pts; rng, boundary_nodes=boundary_nodes, delete_ghosts=false) + tri = triangulate(pts; rng, boundary_nodes = boundary_nodes, delete_ghosts = false) add_point!(tri, 0.1f0, 0.8f0) add_point!(tri, 0.3f0, 0.2f0) add_point!(tri, 0.7f0, 0.2f0) @@ -2841,13 +2860,13 @@ end add_segment!(tri, 11, 12) add_segment!(tri, 9, 12) add_segment!(tri, 10, 11) - refine!(tri; rng, max_area=0.001f0, max_points=25000, min_angle=24.0f0, min_area=0.0, use_circumcenter=true) + refine!(tri; rng, max_area = 0.001f0, max_points = 25000, min_angle = 24.0f0, min_area = 0.0, use_circumcenter = true) stats = statistics(tri) @test DT.get_smallest_angle(stats) ≥ deg2rad(24.0f0) @test DT.get_largest_area(stats) ≤ 0.001f0 @test DT.is_constrained(tri) @test DT.convex_hull(tri).vertices == DT.convex_hull(tri.points).vertices - @test validate_refinement(tri; max_area=0.001, max_points=25000, min_angle=24.0f0, min_area=0.0, use_circumcenter=true) + @test validate_refinement(tri; max_area = 0.001, max_points = 25000, min_angle = 24.0f0, min_area = 0.0, use_circumcenter = true) end end @@ -2886,14 +2905,14 @@ end return A ≥ 0.008 || θ ≤ 30.0 end end - refine!(tri; custom_constraint=custom_refine_ex, rng, use_circumcenter=true) + refine!(tri; custom_constraint = custom_refine_ex, rng, use_circumcenter = true) stat = Bool[] delete_ghost_triangles!(tri) for T in each_triangle(tri) push!(stat, custom_refine_ex(tri, T)) end @test !any(stat) - @test validate_refinement(tri; custom_constraint=custom_refine_ex, use_circumcenter=true) + @test validate_refinement(tri; custom_constraint = custom_refine_ex, use_circumcenter = true) validate_statistics(tri) end @@ -3043,10 +3062,13 @@ end U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] - A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] + A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], + ] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -3054,12 +3076,12 @@ end dot_4 = [[K3, L3, M3, N3, O3, P3, Q3, R3, S3, T3, U3, V3, K3]] curves = [J_curve, U_curve, L_curve, I_curve, A_curve_outline, A_curve_hole, dot_1, dot_2, dot_3, dot_4] nodes, points = convert_boundary_points_to_indices(curves) - tri = triangulate(points; boundary_nodes=nodes, rng) + tri = triangulate(points; boundary_nodes = nodes, rng) A = get_area(tri) - refine!(tri; min_angle=26.45, max_area=0.005A / 9, rng, use_circumcenter=true) + refine!(tri; min_angle = 26.45, max_area = 0.005A / 9, rng, use_circumcenter = true) validate_statistics(tri) - @test validate_refinement(tri; min_angle=26.45, max_area=0.005A / 9, rng, use_circumcenter=true) + @test validate_refinement(tri; min_angle = 26.45, max_area = 0.005A / 9, rng, use_circumcenter = true) fig, ax, sc = triplot(tri) @test_reference "julia_logo.png" fig by = psnr_equality(15) end -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 5da79f241..4391e3fd0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,9 +1,9 @@ # setup LocalPreferences.toml -using Preferences +using Preferences PREDICATES = get(ENV, "PREDICATES", "EXACT") if PREDICATES == "EXACT" set_preferences!("DelaunayTriangulation", "PREDICATES" => "EXACT") -elseif PREDICATES == "INEXACT" +elseif PREDICATES == "INEXACT" set_preferences!("DelaunayTriangulation", "PREDICATES" => "INEXACT") elseif PREDICATES != "DEFAULT" throw("Invalid PREDICATES setting, $PREDICATES.") @@ -50,7 +50,7 @@ include("helper_functions.jl") using .HelperFunctions ct() = Dates.format(now(), "HH:MM:SS") -function safe_include(filename; name=filename, push=true, verbose = true) # Workaround for not being able to interpolate into SafeTestset test names +function safe_include(filename; name = filename, push = true, verbose = true) # Workaround for not being able to interpolate into SafeTestset test names push && push!(ALL_TEST_SCRIPTS, normpath(filename)) mod = @eval module $(gensym()) end @info "[$(ct())] Testing $name" @@ -63,9 +63,9 @@ end @testset verbose = true "DelaunayTriangulation.jl" begin @testset verbose = true "Aqua" begin - Aqua.test_all(DelaunayTriangulation; ambiguities=false, project_extras=false, stale_deps = !USE_INEXACTPREDICATES) # don't care about julia < 1.2 + Aqua.test_all(DelaunayTriangulation; ambiguities = false, project_extras = false, stale_deps = !USE_INEXACTPREDICATES) # don't care about julia < 1.2 Aqua.test_ambiguities(DelaunayTriangulation) # don't pick up Base and Core... - end + end @testset verbose = true "Triangulation" begin safe_include("triangulation/rectangle.jl") @@ -162,24 +162,24 @@ end app_dir = joinpath(dirname(dirname(pathof(DelaunayTriangulation))), "docs", "src", "literate_applications") app_files = readdir(app_dir) for file in app_files - safe_include(joinpath(app_dir, file); push=false) + safe_include(joinpath(app_dir, file); push = false) end mp4_path = joinpath(dirname(dirname(pathof(DelaunayTriangulation))), "cell_simulation.mp4") isfile(mp4_path) && rm(mp4_path) end - + @testset verbose = true "Test the tutorials" begin tut_dir = joinpath(dirname(dirname(pathof(DelaunayTriangulation))), "docs", "src", "literate_tutorials") tut_files = readdir(tut_dir) for file in tut_files - safe_include(joinpath(tut_dir, file); push=false) + safe_include(joinpath(tut_dir, file); push = false) end end - + @testset verbose = true "Test the readme example" begin safe_include("readme_example.jl") end - + @testset "All script files are included somewhere" begin missing_set = String[] test_dir = joinpath(dirname(dirname(pathof(DelaunayTriangulation))), "test", "") @@ -200,4 +200,4 @@ end @test isempty(missing_set) end end -end \ No newline at end of file +end diff --git a/test/triangulation/bowyer_watson.jl b/test/triangulation/bowyer_watson.jl index 525656cd7..93851024d 100644 --- a/test/triangulation/bowyer_watson.jl +++ b/test/triangulation/bowyer_watson.jl @@ -39,14 +39,15 @@ end end @testset "Initialising the Bowyer-Watson algorithm" begin - tri = triangulate_rectangle(0.0, 10.0, 0.0, 20.0, 11, 21, delete_ghosts=false) + tri = triangulate_rectangle(0.0, 10.0, 0.0, 20.0, 11, 21, delete_ghosts = false) _tri = DT.Triangulation(tri.points) DT.initialise_bowyer_watson!(_tri, DT.each_point_index(_tri) |> collect) S = filter(!DT.is_ghost_triangle, _tri.triangles) u, v, w = first(S) BI = DT.𝒢 @test get_triangles(_tri) == Set(((u, v, w), (w, v, BI), (v, u, BI), (u, w, BI))) - @test get_adjacent(get_adjacent(_tri)) == Dict((u, v) => w, + @test get_adjacent(get_adjacent(_tri)) == Dict( + (u, v) => w, (v, w) => u, (w, u) => v, (w, v) => BI, @@ -57,49 +58,56 @@ end (BI, v) => u, (u, w) => BI, (w, BI) => u, - (BI, u) => w) + (BI, u) => w, + ) @test get_adjacent2vertex(get_adjacent2vertex(_tri)) == - Dict(BI => Set{NTuple{2,Int}}([(w, v), (v, u), (u, w)]), - u => Set{NTuple{2,Int}}([(v, w), (BI, v), (w, BI)]), - v => Set{NTuple{2,Int}}([(w, u), (BI, w), (u, BI)]), - w => Set{NTuple{2,Int}}([(u, v), (v, BI), (BI, u)])) + Dict( + BI => Set{NTuple{2, Int}}([(w, v), (v, u), (u, w)]), + u => Set{NTuple{2, Int}}([(v, w), (BI, v), (w, BI)]), + v => Set{NTuple{2, Int}}([(w, u), (BI, w), (u, BI)]), + w => Set{NTuple{2, Int}}([(u, v), (v, BI), (BI, u)]), + ) @test DT.get_graph(_tri).vertices == Set([u, v, w, BI]) end @testset "A basic triangulation" begin a, b, c, d, e, f, g = [-1.78, 5.77], [-4.96, 0.31], [0.08, -3.73], [7.74, -3.03], - [8.0, 3.0], [-0.6, 1.57], [3.58, 6.15] + [8.0, 3.0], [-0.6, 1.57], [3.58, 6.15] points = [a, b, c, d, e, f, g] rng = StableRNG(8881) - tri = DT.triangulate(points; rng, delete_ghosts=false) + tri = DT.triangulate(points; rng, delete_ghosts = false) @static if VERSION ≥ v"1.9" - @inferred DT.triangulate(points; rng, delete_ghosts=false) + @inferred DT.triangulate(points; rng, delete_ghosts = false) end BI = DT.𝒢 - @test get_triangles(tri) == Set{NTuple{3,Int}}(((3, 2, BI), - (4, BI, 5), - (5, 7, 6), - (3, 6, 2), - (5, BI, 7), - (4, 6, 3), - (4, 3, BI), - (4, 5, 6), - (1, 2, 6), - (1, 6, 7), - (1, 7, BI), - (1, BI, 2))) + @test get_triangles(tri) == Set{NTuple{3, Int}}( + ( + (3, 2, BI), + (4, BI, 5), + (5, 7, 6), + (3, 6, 2), + (5, BI, 7), + (4, 6, 3), + (4, 3, BI), + (4, 5, 6), + (1, 2, 6), + (1, 6, 7), + (1, 7, BI), + (1, BI, 2), + ), + ) @test validate_triangulation(tri) end @testset "A random triangulation" begin pts = randn(2, 500) - tri = DT.triangulate(pts; delete_ghosts=false) + tri = DT.triangulate(pts; delete_ghosts = false) @test validate_triangulation(tri) end if !USE_INEXACTPREDICATES @testset "Lots of collinearity" begin - _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary=true) + _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary = true) @test validate_triangulation(_tri) for _ in 1:100 tri = DT.triangulate(_tri.points) @@ -110,38 +118,47 @@ end @testset "A detailed example" begin @time for _ in 1:500 - T = Set{NTuple{3,Int}}(((2, 9, 8), - (2, 8, 6), - (2, 6, 1), - (1, 6, 10), - (6, 8, 10), - (10, 8, 3), - (10, 3, 4), - (10, 4, 5), - (1, 10, 5), - (8, 9, 3), - (9, 7, 3), - (3, 7, 4), - (1, 5, DT.𝒢), - (5, 4, DT.𝒢), - (4, 7, DT.𝒢), - (7, 9, DT.𝒢), - (9, 2, DT.𝒢), - (2, 1, DT.𝒢))) - T2 = Set{NTuple{3,Int}}(((2, 9, 8), - (2, 8, 6), - (2, 6, 1), - (1, 6, 10), - (6, 8, 10), - (10, 8, 3), - (10, 3, 4), - (10, 4, 5), - (1, 10, 5), - (8, 9, 3), - (9, 7, 3), - (3, 7, 4))) + T = Set{NTuple{3, Int}}( + ( + (2, 9, 8), + (2, 8, 6), + (2, 6, 1), + (1, 6, 10), + (6, 8, 10), + (10, 8, 3), + (10, 3, 4), + (10, 4, 5), + (1, 10, 5), + (8, 9, 3), + (9, 7, 3), + (3, 7, 4), + (1, 5, DT.𝒢), + (5, 4, DT.𝒢), + (4, 7, DT.𝒢), + (7, 9, DT.𝒢), + (9, 2, DT.𝒢), + (2, 1, DT.𝒢), + ), + ) + T2 = Set{NTuple{3, Int}}( + ( + (2, 9, 8), + (2, 8, 6), + (2, 6, 1), + (1, 6, 10), + (6, 8, 10), + (10, 8, 3), + (10, 3, 4), + (10, 4, 5), + (1, 10, 5), + (8, 9, 3), + (9, 7, 3), + (3, 7, 4), + ), + ) adj = DT.Adjacent( - Dict(@_adj(2, 9, 8)..., + Dict( + @_adj(2, 9, 8)..., @_adj(2, 8, 6)..., @_adj(2, 6, 1)..., @_adj(1, 6, 10)..., @@ -158,9 +175,12 @@ end @_adj(4, 7, DT.𝒢)..., @_adj(7, 9, DT.𝒢)..., @_adj(9, 2, DT.𝒢)..., - @_adj(2, 1, DT.𝒢)...)) + @_adj(2, 1, DT.𝒢)..., + ), + ) adj2 = DT.Adjacent( - Dict(@_adj(2, 9, 8)..., + Dict( + @_adj(2, 9, 8)..., @_adj(2, 8, 6)..., @_adj(2, 6, 1)..., @_adj(1, 6, 10)..., @@ -177,69 +197,159 @@ end (4, 7) => DT.𝒢, (7, 9) => DT.𝒢, (9, 2) => DT.𝒢, - (2, 1) => DT.𝒢)) - adj2v = DT.Adjacent2Vertex(Dict(DT.𝒢 => Set{NTuple{2,Int}}(((1, 5), - (5, 4), - (4, 7), - (7, 9), - (9, 2), - (2, 1))), - 1 => Set{NTuple{2,Int}}(((2, 6), (6, 10), - (10, 5), - (5, DT.𝒢), - (DT.𝒢, 2))), - 2 => Set{NTuple{2,Int}}(((9, 8), (8, 6), (6, 1), - (1, DT.𝒢), - (DT.𝒢, 9))), - 3 => Set{NTuple{2,Int}}(((9, 7), (7, 4), (4, 10), - (10, 8), (8, 9))), - 4 => Set{NTuple{2,Int}}(((5, 10), (10, 3), - (3, 7), - (7, DT.𝒢), - (DT.𝒢, 5))), - 5 => Set{NTuple{2,Int}}(((1, 10), (10, 4), - (4, DT.𝒢), - (DT.𝒢, 1))), - 6 => Set{NTuple{2,Int}}(((2, 8), (8, 10), - (10, 1), (1, 2))), - 7 => Set{NTuple{2,Int}}(((4, 3), (3, 9), - (9, DT.𝒢), - (DT.𝒢, 4))), - 8 => Set{NTuple{2,Int}}(((3, 10), (10, 6), - (6, 2), (2, 9), (9, 3))), - 9 => Set{NTuple{2,Int}}(((7, 3), (3, 8), (8, 2), - (2, DT.𝒢), - (DT.𝒢, 7))), - 10 => Set{NTuple{2,Int}}(((8, 3), (3, 4), (4, 5), - (5, 1), (1, 6), - (6, 8))))) - adj2v2 = DT.Adjacent2Vertex(Dict(DT.𝒢 => Set{NTuple{2,Int}}(((1, 5), - (5, 4), - (4, 7), - (7, 9), - (9, 2), - (2, 1))), - 1 => Set{NTuple{2,Int}}(((2, 6), (6, 10), - (10, 5))), - 2 => Set{NTuple{2,Int}}(((9, 8), (8, 6), - (6, 1))), - 3 => Set{NTuple{2,Int}}(((9, 7), (7, 4), - (4, 10), (10, 8), - (8, 9))), - 4 => Set{NTuple{2,Int}}(((5, 10), (10, 3), - (3, 7))), - 5 => Set{NTuple{2,Int}}(((1, 10), (10, 4))), - 6 => Set{NTuple{2,Int}}(((2, 8), (8, 10), - (10, 1), (1, 2))), - 7 => Set{NTuple{2,Int}}(((4, 3), (3, 9))), - 8 => Set{NTuple{2,Int}}(((3, 10), (10, 6), - (6, 2), (2, 9), - (9, 3))), - 9 => Set{NTuple{2,Int}}(((7, 3), (3, 8), - (8, 2))), - 10 => Set{NTuple{2,Int}}(((8, 3), (3, 4), - (4, 5), (5, 1), - (1, 6), (6, 8))))) + (2, 1) => DT.𝒢, + ), + ) + adj2v = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}( + ( + (1, 5), + (5, 4), + (4, 7), + (7, 9), + (9, 2), + (2, 1), + ), + ), + 1 => Set{NTuple{2, Int}}( + ( + (2, 6), (6, 10), + (10, 5), + (5, DT.𝒢), + (DT.𝒢, 2), + ), + ), + 2 => Set{NTuple{2, Int}}( + ( + (9, 8), (8, 6), (6, 1), + (1, DT.𝒢), + (DT.𝒢, 9), + ), + ), + 3 => Set{NTuple{2, Int}}( + ( + (9, 7), (7, 4), (4, 10), + (10, 8), (8, 9), + ), + ), + 4 => Set{NTuple{2, Int}}( + ( + (5, 10), (10, 3), + (3, 7), + (7, DT.𝒢), + (DT.𝒢, 5), + ), + ), + 5 => Set{NTuple{2, Int}}( + ( + (1, 10), (10, 4), + (4, DT.𝒢), + (DT.𝒢, 1), + ), + ), + 6 => Set{NTuple{2, Int}}( + ( + (2, 8), (8, 10), + (10, 1), (1, 2), + ), + ), + 7 => Set{NTuple{2, Int}}( + ( + (4, 3), (3, 9), + (9, DT.𝒢), + (DT.𝒢, 4), + ), + ), + 8 => Set{NTuple{2, Int}}( + ( + (3, 10), (10, 6), + (6, 2), (2, 9), (9, 3), + ), + ), + 9 => Set{NTuple{2, Int}}( + ( + (7, 3), (3, 8), (8, 2), + (2, DT.𝒢), + (DT.𝒢, 7), + ), + ), + 10 => Set{NTuple{2, Int}}( + ( + (8, 3), (3, 4), (4, 5), + (5, 1), (1, 6), + (6, 8), + ), + ), + ), + ) + adj2v2 = DT.Adjacent2Vertex( + Dict( + DT.𝒢 => Set{NTuple{2, Int}}( + ( + (1, 5), + (5, 4), + (4, 7), + (7, 9), + (9, 2), + (2, 1), + ), + ), + 1 => Set{NTuple{2, Int}}( + ( + (2, 6), (6, 10), + (10, 5), + ), + ), + 2 => Set{NTuple{2, Int}}( + ( + (9, 8), (8, 6), + (6, 1), + ), + ), + 3 => Set{NTuple{2, Int}}( + ( + (9, 7), (7, 4), + (4, 10), (10, 8), + (8, 9), + ), + ), + 4 => Set{NTuple{2, Int}}( + ( + (5, 10), (10, 3), + (3, 7), + ), + ), + 5 => Set{NTuple{2, Int}}(((1, 10), (10, 4))), + 6 => Set{NTuple{2, Int}}( + ( + (2, 8), (8, 10), + (10, 1), (1, 2), + ), + ), + 7 => Set{NTuple{2, Int}}(((4, 3), (3, 9))), + 8 => Set{NTuple{2, Int}}( + ( + (3, 10), (10, 6), + (6, 2), (2, 9), + (9, 3), + ), + ), + 9 => Set{NTuple{2, Int}}( + ( + (7, 3), (3, 8), + (8, 2), + ), + ), + 10 => Set{NTuple{2, Int}}( + ( + (8, 3), (3, 4), + (4, 5), (5, 1), + (1, 6), (6, 8), + ), + ), + ), + ) A = zeros(Int, 10, 10) A[1, [2, 6, 10, 5]] .= 1 A[2, [1, 6, 8, 9]] .= 1 @@ -253,8 +363,8 @@ end A[10, [1, 6, 8, 3, 4, 5]] .= 1 B = zeros(Int, 11, 11) B[2:end, 2:end] .= A - B[1, [1, 5, 4, 7, 9, 2].+1] .= 1 - B[[1, 5, 4, 7, 9, 2].+1, 1] .= 1 + B[1, [1, 5, 4, 7, 9, 2] .+ 1] .= 1 + B[[1, 5, 4, 7, 9, 2] .+ 1, 1] .= 1 graph = _make_graph_from_adjacency(B, Dict(1 => DT.𝒢, (2:11 .=> 1:10)...)) a = [1.5, 4.0] b = [0.0, 3.5] @@ -268,19 +378,19 @@ end j = [1.5, 3.0] pts = [a, b, c, d, e, f, g, h, i, j] ch = DT.ConvexHull(pts, [1, 2, 9, 7, 4, 5, 1]) - tri = DT.triangulate(pts; delete_ghosts=false) + tri = DT.triangulate(pts; delete_ghosts = false) @test DT.compare_triangle_collections(T, get_triangles(tri)) && - get_adjacent(tri) == adj && - get_adjacent2vertex(tri) == adj2v && - DT.get_graph(tri) == graph && - get_convex_hull(tri) == ch + get_adjacent(tri) == adj && + get_adjacent2vertex(tri) == adj2v && + DT.get_graph(tri) == graph && + get_convex_hull(tri) == ch @test validate_triangulation(tri) delete_ghost_triangles!(tri) @test DT.compare_triangle_collections(T2, get_triangles(tri)) && - get_adjacent(tri) == adj2 && - get_adjacent2vertex(tri) == adj2v2 && - get_graph(tri) == graph && - get_convex_hull(tri) == ch + get_adjacent(tri) == adj2 && + get_adjacent2vertex(tri) == adj2v2 && + get_graph(tri) == graph && + get_convex_hull(tri) == ch @test validate_triangulation(tri) end a = [1.5, 4.0] @@ -294,7 +404,7 @@ end i = [0.0, 0.5] j = [1.5, 3.0] pts = [a, b, c, d, e, f, g, h, i, j] - tri = DT.triangulate(pts; delete_ghosts=false) + tri = DT.triangulate(pts; delete_ghosts = false) @test validate_triangulation(tri) end @@ -304,4 +414,4 @@ end points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.5, 0.5), (0.2, 0.8), (0.1, 0.785)] tri = triangulate(points; rng) @test validate_triangulation(tri) -end \ No newline at end of file +end diff --git a/test/triangulation/check_args.jl b/test/triangulation/check_args.jl index cd5c5da99..2676b9811 100644 --- a/test/triangulation/check_args.jl +++ b/test/triangulation/check_args.jl @@ -2,7 +2,7 @@ using ..DelaunayTriangulation const DT = DelaunayTriangulation using CairoMakie -_test_throws(e1, e2=e1) = @static VERSION ≥ v"1.9" ? e1 : e2 +_test_throws(e1, e2 = e1) = @static VERSION ≥ v"1.9" ? e1 : e2 @testset "A simple case" begin @@ -126,8 +126,10 @@ end end @testset "Orientation and connectivity of a multiply-connected boundary" begin - points = [(0.0, 0.0), (0.5, 0.1), (1.0, 0.0), (0.9, 0.5), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), - (0.3, 0.3), (0.7, 0.3), (0.7, 0.7), (0.3, 0.7)] + points = [ + (0.0, 0.0), (0.5, 0.1), (1.0, 0.0), (0.9, 0.5), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), + (0.3, 0.3), (0.7, 0.3), (0.7, 0.7), (0.3, 0.7), + ] boundary_nodes = [[[1, 2, 3, 4, 5, 6, 7, 1]], [[11, 10, 9, 8, 11]]] hierarchy = DT.construct_polygon_hierarchy(points, boundary_nodes) @test DT.check_args(points, boundary_nodes, hierarchy) @@ -303,10 +305,13 @@ end U_curve = [[T, U, V, W, Z, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, T]] L_curve = [[P1, Q1, R1, S1, P1]] I_curve = [[T1, U1, V1, W1, T1]] - A_curve_outline = [[ - K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, - O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, - H5, I5, J5, K5]] + A_curve_outline = [ + [ + K5, W3, Z3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, M4, N4, + O4, P4, Q4, R4, S4, T4, U4, V4, W4, Z4, A5, B5, C5, D5, E5, F5, G5, + H5, I5, J5, K5, + ], + ] A_curve_hole = [[L5, M5, N5, O5, P5, Q5, R5, S5, T5, U5, L5]] dot_1 = [[Z1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, Z1]] dot_2 = [[Z2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, Z2]] @@ -339,7 +344,7 @@ end points_II = [ (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), - (0.75, 0.75), (0.25, 0.25) + (0.75, 0.75), (0.25, 0.25), ] enricher_II = DT.BoundaryEnricher(points_II, curve_II) points, boundary_nodes = get_points(enricher_II), get_boundary_nodes(enricher_II) @@ -352,7 +357,7 @@ end (0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.25), (1.0, 0.5), (1.0, 0.75), (1.0, 1.0), (0.0, 1.0), (0.0, 0.5), - (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75), (0.5, 0.5) + (0.25, 0.25), (0.75, 0.25), (0.75, 0.75), (0.25, 0.75), (0.5, 0.5), ] enricher_III = DT.BoundaryEnricher(points_III, curve_III) points, boundary_nodes = get_points(enricher_III), get_boundary_nodes(enricher_III) @@ -361,14 +366,14 @@ end @test DT.check_args(enricher_III) curve_IV = [CircularArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0))] - points_IV = NTuple{2,Float64}[] + points_IV = NTuple{2, Float64}[] enricher_IV = DT.BoundaryEnricher(points_IV, curve_IV) points, boundary_nodes = get_points(enricher_IV), get_boundary_nodes(enricher_IV) hierarchy = DT.get_polygon_hierarchy(enricher_IV) @test DT.check_args(points, boundary_nodes, hierarchy) @test DT.check_args(enricher_IV) - curve_IV = [CircularArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0), positive=false)] - points_IV = NTuple{2,Float64}[] + curve_IV = [CircularArc((1.0, 0.0), (1.0, 0.0), (0.0, 0.0), positive = false)] + points_IV = NTuple{2, Float64}[] enricher_IV = DT.BoundaryEnricher(points_IV, curve_IV) points, boundary_nodes = get_points(enricher_IV), get_boundary_nodes(enricher_IV) hierarchy = DT.get_polygon_hierarchy(enricher_IV) @@ -387,7 +392,7 @@ end curve_VI = [ [CircularArc((1.0, 0.0), (0.0, 1.0), (0.0, 0.0))], [BSpline([(0.0, 1.0), (-1.0, 2.0), (-2.0, 0.0), (-2.0, -1.0), (0.0, -2.0)])], - [5, 6, 10] + [5, 6, 10], ] points_VI = [(0.1, 0.1), (0.15, 0.15), (0.23, 0.23), (0.009, 0.11), (0.0, -2.0), (0.2, -1.7), (0.000591, 0.00019), (0.111, -0.005), (-0.0001, -0.00991), (1.0, 0.0)] enricher_VI = DT.BoundaryEnricher(points_VI, curve_VI) @@ -398,7 +403,7 @@ end curve_VII = [ [CircularArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0))], - [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])] + [BSpline([(-2.0, 0.0), (-2.0, -1.0), (0.0, -1.0), (1.0, -1.0), (2.0, -1.0), (2.0, 0.0)])], ] points_VII = [(2.0, 0.0), (0.0, 0.5)] enricher_VII = DT.BoundaryEnricher(points_VII, curve_VII) @@ -411,10 +416,12 @@ end [1, 2, 3, 4, 5], [DT.EllipticalArc((0.0, 0.0), (2.0, -2.0), (1.0, -1.0), sqrt(2), sqrt(2), 45.0)], [6, 7, 8, 9, 10], - [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)])] + [CatmullRomSpline([(10.0, -3.0), (20.0, 0.0), (18.0, 0.0), (10.0, 0.0)])], + ] + points_VIII = [ + (10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), + (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, 12.0), (14.0, 0.0), ] - points_VIII = [(10.0, 0.0), (8.0, 0.0), (4.0, 0.0), (2.0, 2.0), (0.0, 0.0), (2.0, -2.0), - (2.5, -2.0), (3.5, -2.0), (4.5, -3.0), (10.0, -3.0), (10.0, 12.0), (14.0, 0.0)] enricher_VIII = DT.BoundaryEnricher(points_VIII, curve_VIII) points, boundary_nodes = get_points(enricher_VIII), get_boundary_nodes(enricher_VIII) hierarchy = DT.get_polygon_hierarchy(enricher_VIII) @@ -423,13 +430,13 @@ end curve_IX = [ - [ - [1, 2, 3, 4, 5, 6, 7, 1] - ], - [ - [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive=false)] - ], - ] + [ + [1, 2, 3, 4, 5, 6, 7, 1], + ], + [ + [CircularArc((0.6, 0.5), (0.6, 0.5), (0.5, 0.5), positive = false)], + ], + ] points_IX = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 1.5), (0.0, 1.0), (0.0, 0.5), (0.0, 0.2)] enricher_IX = DT.BoundaryEnricher(points_IX, curve_IX) points, boundary_nodes = get_points(enricher_IX), get_boundary_nodes(enricher_IX) @@ -439,14 +446,14 @@ end curve_X = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]) - ] + [BSpline(reverse([(1.0, 0.2), (0.0, 0.4), (0.0, 0.3), (-1.0, 0.2)]))], reverse([4, 5, 6, 7, 8]), + ], ] points_X = [ - (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2) + (-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-1.0, 0.2), (-1.0, 0.1), (0.0, 0.1), (1.0, 0.1), (1.0, 0.2), ] enricher_X = DT.BoundaryEnricher(points_X, curve_X) points, boundary_nodes = get_points(enricher_X), get_boundary_nodes(enricher_X) @@ -456,23 +463,23 @@ end curve_XI = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))] + [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline(reverse([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)]))], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points_XI = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] enricher_XI = DT.BoundaryEnricher(points_XI, curve_XI) @@ -482,23 +489,23 @@ end @test DT.check_args(enricher_XI) curve_XI = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)])] + [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline([(0.0, -2.0), (1.0, -3.0), (0.0, -4.0), (-1.0, -3.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points_XI = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] enricher_XI = DT.BoundaryEnricher(points_XI, curve_XI) @@ -508,23 +515,23 @@ end @test_throws _test_throws(DT.InconsistentConnectionError) DT.check_args(enricher_XI) curve_XI = [ [ - [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)] + [1, 2, 3], [DT.EllipticalArc((2.0, 0.0), (-2.0, 0.0), (0.0, 0.0), 2, 1 / 2, 0.0)], ], [ - [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])] + [BSpline([(0.0, 0.4), (1.0, 0.2), (0.0, 0.1), (-1.0, 0.2), (0.0, 0.4)])], ], [ - [4, 5, 6, 7, 4] + [4, 5, 6, 7, 4], ], [ - [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline([(-1.0, -3.0), (1.0, -3.0), (0.0, -4.0), (0.0, -2.0)])] + [BezierCurve(reverse([(-1.0, -3.0), (-1.0, -2.5), (0.0, -2.5), (0.0, -2.0)]))], [CatmullRomSpline([(-1.0, -3.0), (1.0, -3.0), (0.0, -4.0), (0.0, -2.0)])], ], [ - [12, 11, 10, 12] + [12, 11, 10, 12], ], [ - [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive=false)] - ] + [CircularArc((1.1, -3.0), (1.1, -3.0), (0.0, -3.0), positive = false)], + ], ] points_XI = [(-2.0, 0.0), (0.0, 0.0), (2.0, 0.0), (-2.0, -5.0), (2.0, -5.0), (2.0, -1 / 10), (-2.0, -1 / 10), (-1.0, -3.0), (0.0, -4.0), (0.0, -2.3), (-0.5, -3.5), (0.9, -3.0)] enricher_XI = DT.BoundaryEnricher(points_XI, curve_XI) @@ -538,13 +545,13 @@ end (0.0, 0.0), (2.0, 0.0), (1.6, -0.1), (0.3, -0.2), (-0.31, -0.35), (-0.2, 1.0), (0.0, 0.8), (0.2, 0.6), (0.4, 0.4), - (2.0, 0.4), (0.0, 0.0) + (2.0, 0.4), (0.0, 0.0), ] reverse!(ctrl) points_XII = [ (-0.1, 0.8), (-0.15, -0.15), (0.3, -0.1), (0.0, -0.1), (-0.1, 0.0), - (0.4, 0.2), (0.2, 0.4), (0.0, 0.6) + (0.4, 0.2), (0.2, 0.4), (0.0, 0.6), ] curve_XII = [[[BSpline(ctrl)]], [[1, 8, 7, 6, 5, 4, 3, 2, 1]]] enricher_XII = DT.BoundaryEnricher(points_XII, curve_XII) @@ -552,4 +559,4 @@ end hierarchy = DT.get_polygon_hierarchy(enricher_XII) @test DT.check_args(points, boundary_nodes, hierarchy) @test DT.check_args(enricher_XII) -end \ No newline at end of file +end diff --git a/test/triangulation/constrained.jl b/test/triangulation/constrained.jl index b2b2e2d19..8a77d2667 100644 --- a/test/triangulation/constrained.jl +++ b/test/triangulation/constrained.jl @@ -11,24 +11,24 @@ using Preferences rng = StableRNG(i) points, edges, mat_edges = get_random_vertices_and_constrained_edges(40, 100, 20, rng) # Need to deepcopy edges below, else it gets changed and updated on the first call to tri, which changes the insertion order of the segments and thus comparing tri to _tri might not work - tri = triangulate(points; segments=deepcopy(edges), rng=StableRNG(i)) + tri = triangulate(points; segments = deepcopy(edges), rng = StableRNG(i)) if i % 5 == 0 - _tri = retriangulate(tri; segments=deepcopy(edges), rng=StableRNG(i)) + _tri = retriangulate(tri; segments = deepcopy(edges), rng = StableRNG(i)) @inferred retriangulate(tri) @test tri == _tri end @test validate_triangulation(tri) empty!(get_all_segments(tri)) - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) end for i in 1:10 @info "Testing random constrained Delaunay triangulations. Run: $i; Block: 2." rng = StableRNG(i^5) points, edges, mat_edges = get_random_vertices_and_constrained_edges(200, 500, 100, rng) - tri = triangulate(points; segments=edges, rng) + tri = triangulate(points; segments = edges, rng) @test validate_triangulation(tri) empty!(get_all_segments(tri)) - @test !validate_triangulation(tri; print_result=false) + @test !validate_triangulation(tri; print_result = false) end end @@ -36,7 +36,7 @@ end pts, C = second_shewchuk_example_constrained() for i in 1:500 rng = StableRNG(i^6) - tri = triangulate(pts; segments=C, rng) + tri = triangulate(pts; segments = C, rng) @test validate_triangulation(tri) end end @@ -49,13 +49,13 @@ end pts = [(2rand(rng) - 1, rand(rng)) for _ in 1:100] x = LinRange(-1, 1, 26) a = 10.0 .^ (LinRange(0, log10(2), 20)) .- 1 - C = Set{NTuple{2,Int}}() + C = Set{NTuple{2, Int}}() for i in eachindex(a) y = a[i] * x .^ 2 append!(pts, zip(x, y)) - push!(C, [(j, j + 1) for j in (np+nx*(i-1)+1):(np+nx*(i-1)+(nx-1))]...) + push!(C, [(j, j + 1) for j in (np + nx * (i - 1) + 1):(np + nx * (i - 1) + (nx - 1))]...) end - tri = triangulate(pts; segments=C, rng) + tri = triangulate(pts; segments = C, rng) @test validate_triangulation(tri) end end @@ -64,8 +64,8 @@ end for i in 1:10 @info "Testing random collection of straight lines. Run: $i" rng = StableRNG(i) - pts = NTuple{2,Float64}[] - C = Set{NTuple{2,Int}}() + pts = NTuple{2, Float64}[] + C = Set{NTuple{2, Int}}() j = 1 for i in 1:10 push!(pts, (2i / 11 - 1, 2rand(rng) - 1)) @@ -73,20 +73,20 @@ end push!(C, (j, j + 1)) j += 2 end - x1 = LinRange(-1, 1 - 1e-12, 10) + x1 = LinRange(-1, 1 - 1.0e-12, 10) y1 = LinRange(-1, -1, 10) x2 = LinRange(1, 1, 10) - y2 = LinRange(-1, 1 - 1e-12, 10) - x3 = LinRange(1, -1 + 1e-12, 10) + y2 = LinRange(-1, 1 - 1.0e-12, 10) + x3 = LinRange(1, -1 + 1.0e-12, 10) y3 = LinRange(1, 1, 10) x4 = LinRange(-1, -1, 10) - y4 = LinRange(1, -1 + 1e-12, 10) + y4 = LinRange(1, -1 + 1.0e-12, 10) append!(pts, zip(x1, y1), zip(x2, y2), zip(x3, y3), zip(x4, y4)) push!(C, [(j, j + 1) for j in 21:29]...) push!(C, [(j, j + 1) for j in 31:39]...) push!(C, [(j, j + 1) for j in 41:49]...) push!(C, [(j, j + 1) for j in 51:59]...) - tri = triangulate(pts; segments=C, rng) + tri = triangulate(pts; segments = C, rng) @test validate_triangulation(tri) end end @@ -102,7 +102,7 @@ if !USE_INEXACTPREDICATES d = 7.0 nx = 13 ny = 20 - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) add_segment!(tri, 56, 162; rng) for e in [(1, 249), (1, 250), (1, 251), (1, 26), (1, 39), (1, 52)] add_segment!(tri, e; rng) @@ -119,13 +119,13 @@ if !USE_INEXACTPREDICATES d = 0.01 nx = 25 ny = 25 - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) tri = triangulate(get_points(tri)) for i in 2:24 add_segment!(tri, i, 600 + i; rng) end @test validate_triangulation(tri) - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) tri = triangulate(get_points(tri); rng) for e in [(1, 28), (28, 103), (103, 180), (180, 625), (625, 523)] add_segment!(tri, e; rng) @@ -144,7 +144,7 @@ if !USE_INEXACTPREDICATES d = 1.0 nx = 2 ny = 2 - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) add_segment!(tri, 1, 4; rng) @test validate_triangulation(tri) @@ -154,9 +154,9 @@ if !USE_INEXACTPREDICATES d = 5 nx = 25 ny = 3 - tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(a, b, c, d, nx, ny; delete_ghosts = false, single_boundary = true) tri = triangulate(get_points(tri); rng) - for i in 1:(nx-1) + for i in 1:(nx - 1) u = i v = 2nx add_segment!(tri, u, v) @@ -179,7 +179,7 @@ end bnd_pts = [(0.3cos(θ), 0.3sin(θ)) .+ 0.5 for θ in LinRange(0, 2π - 1 / 250, 25)] bnd_id = [(51:75)..., 51] append!(pts, bnd_pts) - tri = triangulate(pts; boundary_nodes=bnd_id, rng) + tri = triangulate(pts; boundary_nodes = bnd_id, rng) @test validate_triangulation(tri) _tri = retriangulate(tri) @inferred retriangulate(tri) @@ -213,8 +213,8 @@ if !USE_INEXACTPREDICATES inner_circle_y = [last.(circ_pts)] x = [outer_square_x, inner_circle_x] y = [outer_square_y, inner_circle_y] - nodes, pts = convert_boundary_points_to_indices(x, y; existing_points=pts) - tri = triangulate(pts; boundary_nodes=nodes, rng) + nodes, pts = convert_boundary_points_to_indices(x, y; existing_points = pts) + tri = triangulate(pts; boundary_nodes = nodes, rng) @test validate_triangulation(tri) end end @@ -224,7 +224,7 @@ end for L in 1:10 @info "Testing the addition of points into a constrained triangulation. Run: $L" pts, C = example_for_testing_add_point_on_constrained_triangulation() - tri = triangulate(pts; segments=C, delete_ghosts=false) + tri = triangulate(pts; segments = C, delete_ghosts = false) @test validate_triangulation(tri) DT.push_point!(tri, 2, 1.8) add_point!(tri, 15) @@ -319,19 +319,19 @@ end @info "Testing the addition of points into a constrained triangulation with interior segment collinearities. Run: $m" pts, C = example_for_testing_add_point_on_constrained_triangulation() push!(C, (1, 12)) - tri = triangulate(pts; segments=C, delete_ghosts=false) + tri = triangulate(pts; segments = C, delete_ghosts = false) new_points = [ (1.0, 3.0), (2.0, 3.0), (3.0, 3.0), - (4.0, 3.0) + (4.0, 3.0), ] DT.push_point!(tri, new_points[1]) add_point!(tri, DT.num_points(tri)) @test sort_edge_vector(collect(get_interior_segments(tri))) == - sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 12)]))) == - sort_edge_vector(collect(get_interior_segments(tri))) + sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 12)]))) == + sort_edge_vector(collect(get_interior_segments(tri))) T = [ (1, 15, 5) (10, 6, 11) @@ -368,8 +368,8 @@ end DT.push_point!(tri, new_points[2]) add_point!(tri, DT.num_points(tri)) @test sort_edge_vector(collect(get_interior_segments(tri))) == - sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 12)]))) == - sort_edge_vector(collect(get_interior_segments(tri))) + sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 12)]))) == + sort_edge_vector(collect(get_interior_segments(tri))) T = [ (16, 9, 15) (1, 10, 11) @@ -408,8 +408,8 @@ end DT.push_point!(tri, new_points[3]) add_point!(tri, DT.num_points(tri)) @test sort_edge_vector(collect(get_interior_segments(tri))) == - sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 17), (17, 12)]))) == - sort_edge_vector(collect(get_interior_segments(tri))) + sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 17), (17, 12)]))) == + sort_edge_vector(collect(get_interior_segments(tri))) T = [ (13, 16, 14) (15, 1, 14) @@ -450,8 +450,8 @@ end DT.push_point!(tri, new_points[4]) add_point!(tri, DT.num_points(tri)) @test sort_edge_vector(collect(get_interior_segments(tri))) == - sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 17), (17, 18), (18, 12)]))) == - sort_edge_vector(collect(get_interior_segments(tri))) + sort_edge_vector(collect(Set([(1, 2), (1, 15), (15, 16), (16, 17), (17, 18), (18, 12)]))) == + sort_edge_vector(collect(get_interior_segments(tri))) T = [ (13, 16, 14) (15, 1, 14) @@ -517,8 +517,8 @@ end @testset "Adding a point onto a single boundary edge" begin for i in 1:20 - tri = triangulate_rectangle(0, 10, 0, 20, 11, 21; delete_ghosts=false) - add_point!(tri, 1.5, 0.0; initial_search_point=i) + tri = triangulate_rectangle(0, 10, 0, 20, 11, 21; delete_ghosts = false) + add_point!(tri, 1.5, 0.0; initial_search_point = i) @test validate_triangulation(tri) @test tri.boundary_nodes[1] == [1, 2, 232, 3, 4, 5, 6, 7, 8, 9, 10, 11] @test isempty(tri.interior_segments) @@ -533,7 +533,7 @@ end @testset "Adding a point onto multiple boundary edges with multiple ghost indices" begin for _ in 1:20 - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false) + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false) add_point!(tri, 1.5, 0.0) add_segment!(tri, 1, 45) add_point!(tri, 4.0, 2.5) @@ -551,7 +551,7 @@ end [1, 2, 46, 3, 4, 5], [5, 10, 15, 47, 48, 20, 25, 30, 35, 40, 49, 45], [45, 44, 50, 43, 51, 42, 41], - [41, 36, 52, 31, 26, 21, 16, 53, 11, 6, 1] + [41, 36, 52, 31, 26, 21, 16, 53, 11, 6, 1], ] @test validate_triangulation(tri) end @@ -559,7 +559,7 @@ end @testset "Handling only a single boundary index" begin for _ in 1:20 - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false, single_boundary=true) + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false, single_boundary = true) for x in [0.2, 0.3, 1.5, 2.3, 2.8, 3.5] add_point!(tri, x, 0.0) end @@ -572,9 +572,11 @@ end for y in [7.5, 5.9, 3.4, 1.9, 0.1] add_point!(tri, 0.0, y) end - @test DT.get_boundary_nodes(tri) == [1, 46, 47, 2, 48, 3, 49, 50, 4, 51, 5, 52, 53, + @test DT.get_boundary_nodes(tri) == [ + 1, 46, 47, 2, 48, 3, 49, 50, 4, 51, 5, 52, 53, 10, 54, 15, 20, 25, 55, 30, 35, 56, 40, 57, 45, 63, 44, 62, 61, 43, 60, 59, 42, 58, - 41, 64, 36, 31, 65, 26, 21, 66, 16, 11, 67, 6, 68, 1] + 41, 64, 36, 31, 65, 26, 21, 66, 16, 11, 67, 6, 68, 1, + ] @test validate_triangulation(tri) end end @@ -582,38 +584,40 @@ end @testset "Starting with a thin set of boundary nodes, and filling them in with automatic collinearity detection" begin @testset "Contiguous boundary" begin for _ in 1:20 - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false) + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false) pts = get_points(tri) boundary_nodes = [1, 5, 45, 41, 1] - tri = triangulate(pts; boundary_nodes, randomise=false, delete_ghosts=false) + tri = triangulate(pts; boundary_nodes, randomise = false, delete_ghosts = false) flip_edge!(tri, 1, 7) flip_edge!(tri, 2, 8) - @test sort_edge_vector(collect(get_all_segments(tri))) == sort_edge_vector([ - (1, 2) - (2, 3) - (3, 4) - (4, 5) - (5, 10) - (6, 1) - (10, 15) - (11, 6) - (15, 20) - (16, 11) - (20, 25) - (21, 16) - (25, 30) - (26, 21) - (30, 35) - (31, 26) - (35, 40) - (36, 31) - (40, 45) - (41, 36) - (42, 41) - (43, 42) - (44, 43) - (45, 44) - ]) + @test sort_edge_vector(collect(get_all_segments(tri))) == sort_edge_vector( + [ + (1, 2) + (2, 3) + (3, 4) + (4, 5) + (5, 10) + (6, 1) + (10, 15) + (11, 6) + (15, 20) + (16, 11) + (20, 25) + (21, 16) + (25, 30) + (26, 21) + (30, 35) + (31, 26) + (35, 40) + (36, 31) + (40, 45) + (41, 36) + (42, 41) + (43, 42) + (44, 43) + (45, 44) + ], + ) T = [ (11, 7, 12) (22, 27, 26) @@ -705,10 +709,12 @@ end (2, 1, DT.𝒢) ] @test DT.compare_triangle_collections(get_triangles(tri), T) - @test get_boundary_nodes(tri) == [1, 2, 3, 4, 5, + @test get_boundary_nodes(tri) == [ + 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45, 44, 43, 42, 41, 36, 31, 26, - 21, 16, 11, 6, 1] + 21, 16, 11, 6, 1, + ] @test validate_triangulation(tri) add_segment!(tri, 1, 45) add_segment!(tri, 6, 44) @@ -719,38 +725,40 @@ end @testset "Multiple segments" begin for _ in 1:20 - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false) + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false) pts = get_points(tri) boundary_nodes = [[1, 5], [5, 45], [45, 41], [41, 1]] - tri = triangulate(pts; boundary_nodes, randomise=false, delete_ghosts=false) + tri = triangulate(pts; boundary_nodes, randomise = false, delete_ghosts = false) flip_edge!(tri, 1, 7) flip_edge!(tri, 2, 8) - @test sort_edge_vector(collect(get_all_segments(tri))) == sort_edge_vector([ - (1, 2) - (2, 3) - (3, 4) - (4, 5) - (5, 10) - (6, 1) - (10, 15) - (11, 6) - (15, 20) - (16, 11) - (20, 25) - (21, 16) - (25, 30) - (26, 21) - (30, 35) - (31, 26) - (35, 40) - (36, 31) - (40, 45) - (41, 36) - (42, 41) - (43, 42) - (44, 43) - (45, 44) - ]) + @test sort_edge_vector(collect(get_all_segments(tri))) == sort_edge_vector( + [ + (1, 2) + (2, 3) + (3, 4) + (4, 5) + (5, 10) + (6, 1) + (10, 15) + (11, 6) + (15, 20) + (16, 11) + (20, 25) + (21, 16) + (25, 30) + (26, 21) + (30, 35) + (31, 26) + (35, 40) + (36, 31) + (40, 45) + (41, 36) + (42, 41) + (43, 42) + (44, 43) + (45, 44) + ], + ) T = [ (11, 7, 12) (22, 27, 26) @@ -842,10 +850,12 @@ end (2, 1, DT.𝒢) ] @test DT.compare_triangle_collections(get_triangles(tri), T) - @test get_boundary_nodes(tri) == [[1, 2, 3, 4, 5], + @test get_boundary_nodes(tri) == [ + [1, 2, 3, 4, 5], [5, 10, 15, 20, 25, 30, 35, 40, 45], [45, 44, 43, 42, 41], - [41, 36, 31, 26, 21, 16, 11, 6, 1]] + [41, 36, 31, 26, 21, 16, 11, 6, 1], + ] @test validate_triangulation(tri) add_segment!(tri, 1, 45) add_segment!(tri, 6, 44) @@ -856,15 +866,16 @@ end end @testset "Adding points and segments into a multiply-connected domain" begin - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false) - boundary_nodes = [[ - [1, 5, 45], [45, 41], [41, 1] + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false) + boundary_nodes = [ + [ + [1, 5, 45], [45, 41], [41, 1], ], - [[12, 32, 34], [34, 14, 12]] + [[12, 32, 34], [34, 14, 12]], ] points = get_points(tri) rng = StableRNG(19119) - tri = triangulate(points; boundary_nodes, delete_ghosts=false, randomise=false, rng) + tri = triangulate(points; boundary_nodes, delete_ghosts = false, randomise = false, rng) flip_edge!(tri, 1, 7) flip_edge!(tri, 2, 8) T = [ @@ -994,10 +1005,11 @@ end @test sort_edge_vector(collect(get_all_segments(tri))) == sort_edge_vector(C) @test DT.compare_triangle_collections(get_triangles(tri), T) @test validate_triangulation(tri) - @test get_boundary_nodes(tri) == [[ - [1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45], [45, 44, 43, 42, 41], [41, 36, 31, 26, 21, 16, 11, 6, 1] + @test get_boundary_nodes(tri) == [ + [ + [1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45], [45, 44, 43, 42, 41], [41, 36, 31, 26, 21, 16, 11, 6, 1], ], - [[12, 17, 22, 27, 32, 33, 34], [34, 29, 24, 19, 14, 13, 12]] + [[12, 17, 22, 27, 32, 33, 34], [34, 29, 24, 19, 14, 13, 12]], ] add_point!(tri, 1.5, 0.0; rng) @test validate_triangulation(tri) @@ -1023,15 +1035,16 @@ end add_segment!(tri, 2, 52) add_segment!(tri, 53, 21) @test validate_triangulation(tri) - @test get_boundary_nodes(tri) == [[ + @test get_boundary_nodes(tri) == [ + [ [1, 2, 46, 3, 47, 4, 5, 10, 15, 48, 20, 25, 30, 35, 40, 49, 45], [45, 44, 50, 43, 42, 41], - [41, 36, 31, 51, 26, 21, 16, 11, 6, 1] + [41, 36, 31, 51, 26, 21, 16, 11, 6, 1], ], [ [12, 53, 17, 22, 27, 54, 32, 33, 57, 34], - [34, 56, 29, 24, 19, 14, 55, 13, 12] - ] + [34, 56, 29, 24, 19, 14, 55, 13, 12], + ], ] @test validate_triangulation(tri) add_point!(tri, 0.5, 4.4) @@ -1040,19 +1053,21 @@ end @test validate_triangulation(tri) for L in 1:3 - tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts=false) - boundary_nodes = [[ - [1, 5, 45], [45, 41], [41, 1] + tri = triangulate_rectangle(0, 4, 0, 8, 5, 9; delete_ghosts = false) + boundary_nodes = [ + [ + [1, 5, 45], [45, 41], [41, 1], ], - [[12, 32, 34], [34, 14, 12]] + [[12, 32, 34], [34, 14, 12]], ] points = get_points(tri) - tri = triangulate(points; boundary_nodes, delete_ghosts=false) + tri = triangulate(points; boundary_nodes, delete_ghosts = false) @test validate_triangulation(tri) - @test get_boundary_nodes(tri) == [[ - [1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45], [45, 44, 43, 42, 41], [41, 36, 31, 26, 21, 16, 11, 6, 1] + @test get_boundary_nodes(tri) == [ + [ + [1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45], [45, 44, 43, 42, 41], [41, 36, 31, 26, 21, 16, 11, 6, 1], ], - [[12, 17, 22, 27, 32, 33, 34], [34, 29, 24, 19, 14, 13, 12]] + [[12, 17, 22, 27, 32, 33, 34], [34, 29, 24, 19, 14, 13, 12]], ] add_point!(tri, 1.5, 0.0) add_point!(tri, 2.5, 0.0) @@ -1078,15 +1093,16 @@ end add_segment!(tri, 2, 52) add_segment!(tri, 53, 21) @test validate_triangulation(tri) - @test get_boundary_nodes(tri) == [[ + @test get_boundary_nodes(tri) == [ + [ [1, 2, 46, 3, 47, 4, 5, 10, 15, 48, 20, 25, 30, 35, 40, 49, 45], [45, 44, 50, 43, 42, 41], - [41, 36, 31, 51, 26, 21, 16, 11, 6, 1] + [41, 36, 31, 51, 26, 21, 16, 11, 6, 1], ], [ [12, 53, 17, 22, 27, 54, 32, 33, 57, 34], - [34, 56, 29, 24, 19, 14, 55, 13, 12] - ] + [34, 56, 29, 24, 19, 14, 55, 13, 12], + ], ] @test validate_triangulation(tri) add_point!(tri, 0.5, 4.4) @@ -1094,4 +1110,4 @@ end add_point!(tri, 0.5, 4.5) @test validate_triangulation(tri) end -end \ No newline at end of file +end diff --git a/test/triangulation/convex_triangulation.jl b/test/triangulation/convex_triangulation.jl index f0ebcc659..abc6ef5a1 100644 --- a/test/triangulation/convex_triangulation.jl +++ b/test/triangulation/convex_triangulation.jl @@ -8,7 +8,6 @@ using ReferenceTests using StatsBase - @testset "Triangulating random convex polygons" begin for n in Iterators.flatten([3:20, 25:50:1000]) points = rand(2, n) @@ -78,7 +77,7 @@ end @test_throws AssertionError("S must not be circular.") triangulate_convex(pts, S) pop!(S) tri_chew = triangulate_convex(pts, S) - tri_bowyer = triangulate(pts; skip_points=setdiff(1:50, [11, 27, 5]), delete_ghosts=false) + tri_bowyer = triangulate(pts; skip_points = setdiff(1:50, [11, 27, 5]), delete_ghosts = false) @test get_convex_hull(tri_chew) == get_convex_hull(tri_bowyer) @test DT.compare_triangle_collections(get_triangles(tri_chew), get_triangles(tri_bowyer)) @test (get_adjacent ∘ get_adjacent)(tri_chew) == (get_adjacent ∘ get_adjacent)(tri_bowyer) @@ -88,11 +87,11 @@ end pts[:, 28] .= [1.01, 1.01] S = [11, 27, 28, 5] tri_chew = triangulate_convex(pts, S) - tri_bowyer = triangulate(pts; skip_points=setdiff(1:50, [11, 27, 5, 28]), delete_ghosts=false) + tri_bowyer = triangulate(pts; skip_points = setdiff(1:50, [11, 27, 5, 28]), delete_ghosts = false) @test get_convex_hull(tri_chew) == get_convex_hull(tri_bowyer) @test DT.compare_triangle_collections(get_triangles(tri_chew), get_triangles(tri_bowyer)) @test (get_adjacent ∘ get_adjacent)(tri_chew) == (get_adjacent ∘ get_adjacent)(tri_bowyer) @test (get_adjacent2vertex ∘ get_adjacent2vertex)(tri_chew) == (get_adjacent2vertex ∘ get_adjacent2vertex)(tri_bowyer) @test get_graph(tri_chew) == get_graph(tri_bowyer) end -end \ No newline at end of file +end diff --git a/test/triangulation/rectangle.jl b/test/triangulation/rectangle.jl index 17e2d177b..4e2f2b9a3 100644 --- a/test/triangulation/rectangle.jl +++ b/test/triangulation/rectangle.jl @@ -17,7 +17,7 @@ end a, b, c, d = 2.0, 10.0, -5.0, 7.5 nx = 20 ny = 10 - tri = DT.triangulate_rectangle(a, b, c, d, nx, ny; single_boundary=true) + tri = DT.triangulate_rectangle(a, b, c, d, nx, ny; single_boundary = true) @test validate_triangulation(tri) bn = reduce(vcat, [1:20, 20:20:200, 200:-1:181, 181:-20:1]) unique!(bn) diff --git a/test/triangulation/triangulate.jl b/test/triangulation/triangulate.jl index 60ffd176f..d67b8279f 100644 --- a/test/triangulation/triangulate.jl +++ b/test/triangulation/triangulate.jl @@ -6,7 +6,6 @@ using DataStructures using CairoMakie - @testset "Random tests" begin for _ in 1:100 pts = rand(2, 38) @@ -14,10 +13,10 @@ using CairoMakie @test validate_triangulation(tri) _tri = DT.triangulate(pts) @test DT.compare_triangle_collections(get_triangles(_tri), get_triangles(tri)) && - get_adjacent(tri) == get_adjacent(_tri) && - get_adjacent2vertex(tri) == get_adjacent2vertex(_tri) && - get_graph(tri) == get_graph(_tri) && - get_convex_hull(tri) == get_convex_hull(_tri) + get_adjacent(tri) == get_adjacent(_tri) && + get_adjacent2vertex(tri) == get_adjacent2vertex(_tri) && + get_graph(tri) == get_graph(_tri) && + get_convex_hull(tri) == get_convex_hull(_tri) __tri = retriangulate(_tri) @inferred retriangulate(_tri) DT.compare_triangle_collections(get_triangles(_tri), get_triangles(tri)) && @@ -28,7 +27,7 @@ using CairoMakie end end -@testset "Retriangulate should ignore deleted points" begin +@testset "Retriangulate should ignore deleted points" begin points = [(0.0, 0.0), (0.87, 0.0), (1.0006, 0.7766), (0.0, 1.0), (0.5, 0.5)] tri = triangulate(points; skip_points = 5) _tri = retriangulate(tri) @@ -36,10 +35,10 @@ end end @testset "Lots of collinearity" begin - _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary=true) + _tri = triangulate_rectangle(-3.0, 2.0, 5.0, 17.3, 23, 57; single_boundary = true) @test validate_triangulation(_tri) for _ in 1:10 tri = triangulate(_tri.points) @test validate_triangulation(tri) end -end \ No newline at end of file +end diff --git a/test/triangulation/weighted.jl b/test/triangulation/weighted.jl index e47392991..dc78b4b4f 100644 --- a/test/triangulation/weighted.jl +++ b/test/triangulation/weighted.jl @@ -36,11 +36,11 @@ end @testset "is_weighted" begin tri = Triangulation(rand(10)) @test !DT.is_weighted(tri) - tri = Triangulation(rand(10); weights=rand(10)) + tri = Triangulation(rand(10); weights = rand(10)) @test DT.is_weighted(tri) - tri = Triangulation(rand(10); weights=DT.ZeroWeight()) + tri = Triangulation(rand(10); weights = DT.ZeroWeight()) @test !DT.is_weighted(tri) - tri = Triangulation(rand(10); weights=zeros(10)) + tri = Triangulation(rand(10); weights = zeros(10)) @test DT.is_weighted(tri) end @@ -117,15 +117,15 @@ end _weights[58] = weights[2] _weights[498] = weights[3] _weights[5] = weights[4] - tri = Triangulation(_points; weights=_weights) + tri = Triangulation(_points; weights = _weights) d = DT.get_distance_to_witness_plane(tri, 5, (137, 58, 498)) @test d ≈ -2.129523129725314 @test DT.get_distance_to_witness_plane(tri, 5, (137, 58, 498)) ≈ - DT.get_distance_to_witness_plane(tri, 5, (58, 137, 498)) ≈ - DT.get_distance_to_witness_plane(tri, 5, (498, 58, 137)) ≈ - DT.get_distance_to_witness_plane(tri, 5, (137, 498, 58)) ≈ - DT.get_distance_to_witness_plane(tri, 5, (58, 498, 137)) ≈ - DT.get_distance_to_witness_plane(tri, 5, (498, 137, 58)) + DT.get_distance_to_witness_plane(tri, 5, (58, 137, 498)) ≈ + DT.get_distance_to_witness_plane(tri, 5, (498, 58, 137)) ≈ + DT.get_distance_to_witness_plane(tri, 5, (137, 498, 58)) ≈ + DT.get_distance_to_witness_plane(tri, 5, (58, 498, 137)) ≈ + DT.get_distance_to_witness_plane(tri, 5, (498, 137, 58)) _points[5] = (-3.9, 2.01) _weights[5] = -15.0 d = DT.get_distance_to_witness_plane(tri, 5, (137, 58, 498)) @@ -211,7 +211,7 @@ end for j in 3:10 tri = triangulate_rectangle(0, 10, 0, 10, i, j) @test validate_triangulation(tri) - tri = triangulate(get_points(tri); weights=zeros(i * j)) + tri = triangulate(get_points(tri); weights = zeros(i * j)) @test validate_triangulation(tri) end end @@ -230,7 +230,7 @@ end for j in 3:10 tri = triangulate_rectangle(0, 10, 0, 10, i, j) @test validate_triangulation(tri) - tri = triangulate(get_points(tri); weights=10randn() * ones(i * j)) + tri = triangulate(get_points(tri); weights = 10randn() * ones(i * j)) @test validate_triangulation(tri) end end @@ -269,4 +269,4 @@ end # While we have tested the convex polygons and everything else properly, # normal triangulations still need to be correctly updated. To test this, # we will need to test the ones provided in helper_functions.jl properly. -# See the get_weighted_example function in that file and the comments surrounding it. \ No newline at end of file +# See the get_weighted_example function in that file and the comments surrounding it. diff --git a/test/utils.jl b/test/utils.jl index 461fdc825..b1e7599b8 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -5,564 +5,565 @@ using BenchmarkTools using StableRNGs @testset "is_true" begin - @test DT.is_true(true) - @test DT.is_true(Val(true)) - @test !DT.is_true(false) - @test !DT.is_true(Val(false)) + @test DT.is_true(true) + @test DT.is_true(Val(true)) + @test !DT.is_true(false) + @test !DT.is_true(Val(false)) end @testset "number_type" begin - @test DT.number_type([1, 2, 3]) == Int - @test DT.number_type([1.0, 2.0, 3.0]) == Float64 - @test DT.number_type([1.0 2.0; 3.0 3.5; 10.0 17.3]) == Float64 - @test DT.number_type((1.0, 5.0)) == Float64 - @test DT.number_type([(1.0f0, 2.0f0), (1.7f0, 2.5f0)]) == Float32 - @test DT.number_type(2.4) == Float64 + @test DT.number_type([1, 2, 3]) == Int + @test DT.number_type([1.0, 2.0, 3.0]) == Float64 + @test DT.number_type([1.0 2.0; 3.0 3.5; 10.0 17.3]) == Float64 + @test DT.number_type((1.0, 5.0)) == Float64 + @test DT.number_type([(1.0f0, 2.0f0), (1.7f0, 2.5f0)]) == Float32 + @test DT.number_type(2.4) == Float64 end @testset "get_ghost_vertex" begin - @test DT.get_ghost_vertex(1, 2, -3) == -3 - @test DT.get_ghost_vertex(1, 2, -1) == -1 - @test DT.get_ghost_vertex(1, -5, 2) == -5 - @test DT.get_ghost_vertex(-1, 2, 3) == -1 - @test DT.get_ghost_vertex(2, 5, 7) == 7 - @test DT.get_ghost_vertex(1, -2) == -2 - @test DT.get_ghost_vertex(-5, 1) == -5 - @test DT.get_ghost_vertex(2, 5) == 5 + @test DT.get_ghost_vertex(1, 2, -3) == -3 + @test DT.get_ghost_vertex(1, 2, -1) == -1 + @test DT.get_ghost_vertex(1, -5, 2) == -5 + @test DT.get_ghost_vertex(-1, 2, 3) == -1 + @test DT.get_ghost_vertex(2, 5, 7) == 7 + @test DT.get_ghost_vertex(1, -2) == -2 + @test DT.get_ghost_vertex(-5, 1) == -5 + @test DT.get_ghost_vertex(2, 5) == 5 end @testset "sort_triangle" begin - @test DT.sort_triangle(1, 2, DT.𝒢) == (1, 2, DT.𝒢) - @test DT.sort_triangle(DT.𝒢 - 2, 2, 3) == (2, 3, DT.𝒢 - 2) - @test DT.sort_triangle(5, DT.𝒢 - 1, 3) == (3, 5, DT.𝒢 - 1) - @test DT.sort_triangle((1, 5, DT.𝒢)) == (1, 5, DT.𝒢) - @test DT.sort_triangle([1, DT.𝒢 - 2, 7]) == [7, 1, DT.𝒢 - 2] - @test DT.sort_triangle((DT.𝒢 - 10, 5, 3)) == (5, 3, DT.𝒢 - 10) + @test DT.sort_triangle(1, 2, DT.𝒢) == (1, 2, DT.𝒢) + @test DT.sort_triangle(DT.𝒢 - 2, 2, 3) == (2, 3, DT.𝒢 - 2) + @test DT.sort_triangle(5, DT.𝒢 - 1, 3) == (3, 5, DT.𝒢 - 1) + @test DT.sort_triangle((1, 5, DT.𝒢)) == (1, 5, DT.𝒢) + @test DT.sort_triangle([1, DT.𝒢 - 2, 7]) == [7, 1, DT.𝒢 - 2] + @test DT.sort_triangle((DT.𝒢 - 10, 5, 3)) == (5, 3, DT.𝒢 - 10) end -const _POINTS = [ # Don't know why the points on 1.10 get slightly changed, e.g. with 357 replacing 363 and 363 replacing 357, so this is needed to make the next set of tests more robust. This is NOT some hack to force the test to pass when it shouldn't, it just makes sure the point order matches the hard-coded node numbers below. - 0.0 0.0 - 0.6666666666666666 0.0 - 1.3333333333333333 0.0 - 2.0 0.0 - 2.0 2.0 - 2.0 4.0 - 2.0 6.0 - 1.3333333333333335 6.0 - 0.6666666666666667 6.0 - 0.0 6.0 - 0.0 4.0 - 0.0 2.0 - 1.1 0.5999999999999999 - 1.095895006911623 0.5360614191577466 - 1.0836474315195146 0.47317270804524625 - 1.063458378673011 0.41236649756031307 - 1.0356593520616948 0.35464122399803105 - 1.0007068109339783 0.3009447347543919 - 0.9591746750488634 0.2521587246982565 - 0.9117449009293667 0.20908425876598502 - 0.8591962841552626 0.172428618497327 - 0.8023916715611968 0.14279368849209373 - 0.742263793315516 0.12066607348166958 - 0.6797999475166896 0.10640910829277489 - 0.6160257887858274 0.10025689189965603 - 0.5519884870461588 0.10231044352540092 - 0.4887395330218427 0.11253604390908817 - 0.4273174727893459 0.13076578897511987 - 0.36873085487958235 0.15670034681349998 - 0.31394166993891537 0.18991387270152188 - 0.26384955486934164 0.22986100146234217 - 0.21927702081543265 0.2758858023461059 - 0.18095594755407962 0.32723254939472574 - 0.1495155660487904 0.38305813044122095 - 0.12547212649466555 0.44244589098818987 - 0.10922042150446726 0.5044206856493141 - 0.10102730362483181 0.5679648900096435 - 0.10102730362483181 0.6320351099903566 - 0.10922042150446731 0.6955793143506862 - 0.1254721264946656 0.7575541090118102 - 0.14951556604879046 0.8169418695587791 - 0.18095594755407968 0.8727674506052743 - 0.21927702081543277 0.9241141976538942 - 0.2638495548693417 0.9701389985376578 - 0.3139416699389151 1.0100861272984778 - 0.36873085487958224 1.0432996531865 - 0.42731747278934623 1.0692342110248803 - 0.4887395330218428 1.0874639560909118 - 0.5519884870461592 1.0976895564745992 - 0.6160257887858274 1.099743108100344 - 0.6797999475166895 1.093590891707225 - 0.7422637933155162 1.0793339265183302 - 0.802391671561197 1.0572063115079062 - 0.8591962841552626 1.027571381502673 - 0.9117449009293666 0.990915741234015 - 0.9591746750488637 0.9478412753017432 - 1.0007068109339783 0.899055265245608 - 1.0356593520616948 0.8453587760019688 - 1.063458378673011 0.7876335024396869 - 1.0836474315195146 0.7268272919547538 - 1.095895006911623 0.6639385808422531 - 1.7 0.49999999999999994 - 1.6983580027646492 0.47442456766309865 - 1.693458972607806 0.4492690832180985 - 1.6853833514692045 0.42494659902412524 - 1.6742637408246779 0.40185648959921244 - 1.6602827243735914 0.38037789390175675 - 1.6436698700195453 0.3608634898793026 - 1.6246979603717466 0.343633703506394 - 1.603678513662105 0.3289714473989308 - 1.5809566686244787 0.3171174753968375 - 1.5569055173262063 0.3082664293926678 - 1.5319199790066758 0.30256364331710994 - 1.506410315514331 0.3001027567598624 - 1.4807953948184636 0.30092417741016037 - 1.455495813208737 0.30501441756363523 - 1.4309269891157383 0.31230631559004796 - 1.407492341951833 0.3226801387254 - 1.3855766679755661 0.3359655490806087 - 1.3655398219477366 0.35194440058493687 - 1.347710808326173 0.37035432093844234 - 1.3323823790216318 0.3908930197578903 - 1.3198062264195163 0.41322325217648836 - 1.3101888505978663 0.43697835639527594 - 1.303688168601787 0.4617682742597256 - 1.3004109214499326 0.4871859560038574 - 1.3004109214499326 0.5128140439961426 - 1.303688168601787 0.5382317257402746 - 1.3101888505978663 0.5630216436047241 - 1.3198062264195163 0.5867767478235116 - 1.3323823790216318 0.6091069802421097 - 1.347710808326173 0.6296456790615577 - 1.3655398219477366 0.6480555994150632 - 1.3855766679755661 0.6640344509193912 - 1.4074923419518328 0.6773198612746 - 1.4309269891157386 0.6876936844099522 - 1.4554958132087372 0.6949855824363648 - 1.4807953948184638 0.6990758225898397 - 1.506410315514331 0.6998972432401376 - 1.5319199790066758 0.6974363566828901 - 1.5569055173262065 0.6917335706073321 - 1.5809566686244787 0.6828825246031625 - 1.603678513662105 0.6710285526010692 - 1.6246979603717466 0.656366296493606 - 1.6436698700195456 0.6391365101206973 - 1.6602827243735914 0.6196221060982432 - 1.6742637408246779 0.5981435104007875 - 1.6853833514692043 0.5750534009758748 - 1.693458972607806 0.5507309167819016 - 1.6983580027646492 0.5255754323369012 - 1.0 2.0 - 1.0 3.0 - 1.0 4.000000000000001 - 1.0 5.0 - 1.1666666666666665 5.0 - 1.3333333333333333 5.0 - 1.5 5.0 - 1.5 4.0 - 1.5 3.0 - 1.5 2.0 - 1.3333333333333335 2.0 - 1.1666666666666667 2.0 - 0.2 2.0 - 0.2 5.0 - 0.75 4.0 - 0.75 3.0 - 0.5 2.0 - 0.2 3.5 - 2.0 5.0 - 0.0 3.0 - 2.0 3.0 - 2.0 1.0 - 0.0 5.0 - 0.0 1.0 - 0.2 4.5 - 0.2 3.0 - 0.2 4.0 - 0.0 4.5 - 0.0 0.5 - 2.0 0.5 - 0.0 3.5 - 1.6666666666666665 0.0 - 1.0 0.0 - 0.3333333333333333 0.0 - 0.0 0.25 - 0.0 0.75 - 0.7916666666666666 0.0 - 0.5416666666666666 0.0 - 0.0 0.625 - 1.4740544522373191 1.309077721762752 - 1.3499698939387508 1.0055012112239021 - 1.6795817213270934 0.9879815502040521 - 2.0 0.75 - 2.0 0.25 - 1.7828347010132077 0.1885675610394171 - 1.19953813886343 0.20901891414515464 - 1.7742377105455027 0.8019661970196654 - 0.0 1.5 - 0.9388315428915 1.5207147605911762 - 1.2572693115310343 0.8043746560736462 - 1.5416666666666665 0.0 - 1.4877125131091204 0.8831690890011553 - 1.8624474074396582 0.6203408303941387 - 1.862447407439658 0.37965916960586316 - 0.4487051545335375 1.535812115275885 - 1.441199151969013 0.13629596364476348 - 1.624263604487171 0.16233564360848637 - 1.6185917257370095 0.8222520295432142 - 1.1917579283891429 0.37520661583202014 - 1.3293751090374275 0.21853639574589828 - 1.2191572487719817 0.6581676907984143 - 1.0529166570030704 1.2492900864648844 - 0.0 1.25 - 1.3724252107559454 0.7881936711216704 - 1.7396173332189573 0.2960107901378373 - 1.8110061512826319 0.5199672573998425 - 1.761187193038501 0.6700140220581073 - 0.6745044586363241 1.372316652669158 - 0.28592779118073197 1.3094945905319997 - 1.1953751211197607 0.5 - 1.5289331661582095 0.2000774658667932 - 1.6681251875542065 0.7410200991200366 - 1.528217827526302 0.7925073008997648 - 1.775506905040127 0.40852540520001573 - 1.26831267650853 0.3270872565921958 - 1.418160934512214 0.22425703203449873 - 1.295455646032882 0.6980901602542381 - 1.6315588938199306 0.24782623088951797 - 1.137591811617686 1.057658581735622 - 1.0833333333333333 5.527777777777778 - 1.7661043175005355 0.5883527206490259 - 0.48832789133187804 1.290731478047606 - 0.8416520629881481 1.2566467201424116 - 0.16692117116205538 1.1430636744441975 - 1.2314189884870388 0.5704302352100531 - 1.4563071262047091 0.7702558737066645 - 1.2378485908218748 0.4312558050732817 - 1.5935642184148526 0.7542442070846888 - 1.3320629484886526 0.2894135981807518 - 0.125 0.0 - 0.0 2.5 - 0.2 2.5 - 0.0 5.5 - 1.363898107854514 0.7245143067518455 - 1.6763532155896466 0.3058155104275537 - 1.7198413454244592 0.35689914227621217 - 1.7603049822572803 0.48328786565231235 - 1.6986162550807449 0.6690844831441323 - 1.2732086411580512 0.6277265137313147 - 0.1357338269089258 0.15038328438526705 - 0.9681905883861459 1.127828895829673 - 1.5569357954505727 0.2505479812612332 - 1.4917990544438116 0.2442643181947033 - 1.4166666666666665 5.362573099415204 - 0.6610307417000465 1.2326474818074256 - 0.3427260032157782 1.181186440179403 - 1.4166666666666667 1.6571810441100427 - 1.0238883307733782 0.13325183852345296 - 1.2486746582268176 0.5 - 1.0 3.5000000000000004 - 0.75 3.5 - 0.47500000000000003 4.5 - 1.0 4.5 - 0.625 2.5 - 1.0 2.5 - 1.2821205078623963 0.3772925560903774 - 1.3990607282139222 0.271976426778746 - 1.1173493764498315 0.9367571253255303 - 0.0 0.375 - 1.741444624549862 0.5470213364192468 - 1.7216209675111749 0.6067270329489496 - 1.640658487617645 0.7016445193064772 - 1.523607866265877 0.7447202299680109 - 0.0 0.875 - 0.16036607072667938 1.0257617177590372 - 1.731605030618596 0.4231018317802659 - 1.4308793419171846 0.7328904331187506 - 1.1070433482398665 0.2699513556188709 - 0.875 0.0 - 1.326733072952154 0.6677996614425488 - 1.611490638036034 0.2862933200657552 - 1.3269281024201038 0.33238921406445593 - 1.0833333333333333 5.257309941520468 - 0.5647973445143255 5.392543859649123 - 0.5047539390232997 1.1891305650202075 - 0.8061070342543368 1.1600593943533914 - 1.0833333333333335 1.7458187278913946 - 0.4583333333333333 0.0 - 1.6810772213147687 0.34584671399258676 - 0.0820730652316044 0.30830898459576883 - 0.29187380922086326 0.09171361966873727 - 1.2701959364187478 0.5602617219999282 - 1.1611993909112273 0.7863310354349395 - 0.9961530910081264 1.036208580108681 - 1.462487223491946 0.2679702132241154 - 1.5225695030046766 0.2660434914632048 - 0.2962726981257435 1.1010299529782763 - 1.2735053984345062 0.44060612113937503 - 1.5808501167410969 0.7196958855831329 - 0.09063815833613441 0.886867244835494 - 0.9340092492886052 0.1211726241519101 - 1.3795327553781789 0.3012766796536391 - 0.0 3.75 - 0.2 3.75 - 0.2 2.25 - 0.0 2.25 - 0.0 4.25 - 0.2 4.25 - 0.2 4.75 - 0.0 4.75 - 0.0 2.75 - 0.2 2.75 - 0.0 5.25 - 0.0 3.25 - 0.2 3.25 - 0.0 1.75 - 1.7305994280094303 0.5148049744879046 - 1.6936605339465862 0.6260590379916767 - 1.7193022924897394 0.5728133777310767 - 1.4925952162260299 0.7309084256300289 - 1.6553197408864884 0.6710242963459636 - 2.0 1.5 - 1.7261014731069777 0.45596674205660387 - 1.7075375557401247 0.4000551807062032 - 1.406921135389704 0.7102667764910945 - 1.0370994517765144 0.22789181149262006 - 1.125 0.0 - 1.3570113367409984 0.6793021124621966 - 1.316206997826056 0.6371682824339902 - 1.6311751370246665 0.31195057690225014 - 1.5791854380321182 0.284827584238829 - 1.316282242285531 0.36288787396558325 - 1.1154407188558464 0.3517768322991175 - 0.5816906605550696 1.1709526266542052 - 0.864223205343458 1.1064664170034129 - 0.4374647190632682 1.1476352949226916 - 0.7271142209552935 1.1569237906798149 - 0.1428028406433256 0.25878489202052457 - 0.3690795881569608 0.07834676725460561 - 0.2443121381562888 0.15398152865993447 - 0.25 0.0 - 1.2737384055431993 0.5291732020831812 - 1.2885382384146338 0.5856113791101021 - 1.113130134633655 0.847110448984858 - 1.1590288414186054 0.7088708571143922 - 1.033197322819307 0.9687862576934944 - 1.4353052654987943 0.28202197206461327 - 0.24588090864430434 1.044051295369198 - 0.2688387528122659 5.375 - 0.33333333333333337 6.0 - 1.2894711087692583 0.4147662982391812 - 1.2747365658359935 0.47095549643502305 - 1.6050489090123727 0.701359091410823 - 1.550537613507314 0.7214197520535767 - 0.07387658485528542 0.8130037639664341 - 0.14511290432603197 0.939491062646291 - 0.7291666666666666 0.0 - 0.8624443884933936 0.09694324186960815 - 0.07431874516150205 0.3871752469020991 - 1.3586733685981895 0.32278200956665326 - 0.7743125163556892 1.7852573023241183 - 1.3951319674273832 0.7467489457540966 - 1.6723555903905802 0.6467284533501322 - 1.4638740821559169 0.7234515755624243 - 1.4927477124566209 0.2738469683956681 - 1.6895818983651612 0.3765958595614554 - 1.725742831711937 0.4855068293396377 - 1.3828391994677471 0.6932689949811435 - 1.5502891882510008 0.2796686701104153 - 1.6519383611714682 0.33269897851362074 - 1.4166666666666665 5.171709936804376 - 2.0 5.5 - 1.7470040926571286 5.26714151810979 - 1.762711901635018 0.44520425603505154 - 1.8366469302468644 0.45042453510946423 - 1.9060886700063842 0.5155263895621286 - 1.7432094576086072 0.3868933176340165 - 1.7985506191032619 0.3391937098408574 - 1.8878694231956714 0.26883597168004963 - 1.7916666666666665 0.0 - 2.0 0.125 - 0.9230460198845826 1.0631107620790716 - 1.1358084873427654 0.4220993253764972 - 0.19447305594557093 0.20726905545353125 - 1.3032549844320298 0.6108047284553858 - 2.0 0.625 - 1.2500000000000002 1.8319281123363502 - 0.6541111351264756 1.160918521091478 - 0.371895480593367 1.115292082681653 - 1.494273560202694 0.7688633005731953 - 1.4773323581048208 0.8252320844062707 - 1.4030882061420913 0.8684322443508078 - 0.7944598296275528 0.07158982321352167 - 1.0 3.25 - 0.75 3.25 - 0.595479687443039 4.280946022830838 - 1.0 4.25 - 2.0 4.5 - 1.5 4.5 - 2.0 2.5 - 1.5 2.5 - 2.0 3.5 - 1.5 3.5 - 0.6893660937409167 2.757464374963667 - 1.0 2.75 - 1.0 3.750000000000001 - 0.75 3.75 - 0.20607015431451464 0.07547310822581126 - 1.1137966762594949 0.1795335656241746 - 1.2083333333333333 0.0 - 1.1666666666666665 0.09271643952630988 - 0.3994151065612831 5.677353293275649 - 1.6783486674776207 0.70087084995281 - 1.7392543857928202 0.7377559547642759 - 1.8302710234553803 0.7298028546873176 - 2.0 0.875 - 1.8888519575683367 0.8331257280027056 - 1.800336932191529 0.9323381323744324 - 2.0 1.25 - 1.8227502338782238 1.1398294920180019 - 1.7994421968210412 1.375 - 1.7395586704615544 1.6944745976100235 - 1.7267593429098054 0.6440448038896638 - 1.7678827403626947 0.5201876828851476 - 1.2035918506774017 0.8877754751066075 - 1.16093306626047 0.5639869022785741 - 0.0 0.4375 - 1.291551342829673 0.6627651416324978 - 1.2538080175158937 0.6848149997324289 - 1.2577128301399019 0.7445318850453346 - 1.2090408575917337 0.7071751969044885 - 1.3306373761553634 0.7031246800642893 - 1.3160528628068418 0.7623584294631466 - 1.6462859848898292 0.27997768754971447 - 1.7020584160349093 0.234982296630739 - 1.5967635469661356 0.2541418634055588 - 1.6061662460929913 0.20693653438447443 - 1.570825246339907 0.16662443239081526 - 1.5905483961970126 0.07730943253130455 - 1.51018175705595 0.13363920248553696 - 1.4583333333333333 0.0 - 1.6590520810618847 0.20242355254666858 - 1.7125852936455277 0.12082842146382869 - 1.431068012499545 0.9581022021491937 - 1.477452094723081 1.130541403025688 - 1.5531080005501499 0.9914800857679006 - 1.2813569642026876 1.216110095730245 - 1.2018317226108364 1.4715704518745842 - 1.6198909607221894 1.1179240078762014 - 1.7983548141425743 0.46657478567124433 - 0.9770513066521348 0.18482460736504314 - 0.7938123559004582 5.2089259691333805 - 0.6407123629255758 4.851627018928146 - 1.319484941905665 0.8292893422114065 - 1.2761296818296555 0.5 - 1.8099178972915033 0.26187472706351006 - 1.7111729419512756 0.17826049305063374 - 1.759634673818009 0.34999662375758167 - 1.718142438071527 0.703889427730984 - 1.473230604388981 0.071097758315114 - 1.3863435254451124 0.06887822829586042 - 1.2782854698688741 0.09720405683617961 - 0.7375 4.501716097368583 - 0.44121509031025474 0.06500095027943562 - 1.305524838337339 0.3904736294480411 - 1.6684438208715549 0.25037958358667844 - 1.6996902177676332 0.2742036674155371 - 1.3624484903113168 0.2687327852709218 - 0.06974484917671708 0.9630027278134988 - 0.0 1.125 - 0.07352010305180143 1.054357451563032 - 1.1563399977503028 0.6357182129391813 - 0.5597884117036155 1.2501563862805738 - 0.5715382250636158 1.354065450073582 - 0.5980032696789671 1.504333348664305 - 0.5656039401938803 1.7204555756412738 - 0.3037866871454204 1.7568871511798612 - 0.46161571048938355 1.4121561268225087 - 0.3161306261019238 1.459468430239305 - 0.149758655496108 1.4149454869965006 - 0.16391023227107437 1.6142327799518283 - 0.7683057766893729 1.5148465969437765 - 0.7637530559523047 1.230480162353276 - 0.7720830332001749 1.3347191336230664 - 0.9050972636859582 1.3832137934898427 - 1.0559347141051296 1.4190962037054105 - 0.43329341865156223 1.2297056567872398 - 0.3893995908276335 1.3246186881965123 - 0.8840060412901801 1.1862259521425271 - 0.9479694782050885 1.272643328918064 - 1.4361522732329282 0.25034394087790574 - 1.4603794219490087 0.21438773060391503 - 1.4301726911242494 0.18040552911767954 - 1.3664948543862412 0.14105443922716654 - 1.3800869372880815 0.19025696838292824 - 1.4771932167810962 0.16902551127432658 - 1.40980282641639 0.2962430137342318 - 0.0 0.6875 - 2.0 0.375 - 1.9132736730754663 0.4382760179317226 - 0.055964514785385895 0.46875 - 1.6666208006494743 5.608342938440153 - 1.2445796724660527 0.5415967162439137 - 1.2035138373071206 0.5402730217783609 - 1.257035252439734 0.5890952409660676 - 1.2196380370307442 0.6135093363907388 - 1.383611268856942 0.23811038285103012 - 1.6226023422523703 0.7328606305005508 - 1.6335516540160544 0.7781375493960542 - 1.698042873799217 0.824601373114044 - 1.6559767278839401 0.902581204581636 - 1.5575918148450751 0.7567851055371636 - 1.5786042901358082 0.7983586872318487 - 1.561956830704648 0.8716273239716548 - 1.25 5.146519289061359 - 1.4166666666666667 1.853986608235224 - 1.6106377773288556 1.84006951687984 - 1.75 2.0547125573551916 - 1.5 2.25 - 1.75 2.375 - 1.75 2.6875 - 1.7351882330544273 0.25666486669089317 - 1.740696001877012 0.21209770142048218 - 1.7716317714671403 0.27248473247545524 - 1.780747250326824 0.23099526710030466 - 1.8315421621777004 0.21222918129712579 - 1.8571475226715097 0.09755754869299872 - 1.9212830619181216 0.17925938128868346 - 1.8307671503240839 0.15186156285696936 - 1.782563159254053 0.09488484980088335 - 1.7291666666666665 0.0 - 1.6979166666666665 0.05726348727905952 - 0.0635245517925628 0.7406804293007325 +const _POINTS = [ + # Don't know why the points on 1.10 get slightly changed, e.g. with 357 replacing 363 and 363 replacing 357, so this is needed to make the next set of tests more robust. This is NOT some hack to force the test to pass when it shouldn't, it just makes sure the point order matches the hard-coded node numbers below. + 0.0 0.0 + 0.6666666666666666 0.0 + 1.3333333333333333 0.0 + 2.0 0.0 + 2.0 2.0 + 2.0 4.0 + 2.0 6.0 + 1.3333333333333335 6.0 + 0.6666666666666667 6.0 + 0.0 6.0 + 0.0 4.0 + 0.0 2.0 + 1.1 0.5999999999999999 + 1.095895006911623 0.5360614191577466 + 1.0836474315195146 0.47317270804524625 + 1.063458378673011 0.41236649756031307 + 1.0356593520616948 0.35464122399803105 + 1.0007068109339783 0.3009447347543919 + 0.9591746750488634 0.2521587246982565 + 0.9117449009293667 0.20908425876598502 + 0.8591962841552626 0.172428618497327 + 0.8023916715611968 0.14279368849209373 + 0.742263793315516 0.12066607348166958 + 0.6797999475166896 0.10640910829277489 + 0.6160257887858274 0.10025689189965603 + 0.5519884870461588 0.10231044352540092 + 0.4887395330218427 0.11253604390908817 + 0.4273174727893459 0.13076578897511987 + 0.36873085487958235 0.15670034681349998 + 0.31394166993891537 0.18991387270152188 + 0.26384955486934164 0.22986100146234217 + 0.21927702081543265 0.2758858023461059 + 0.18095594755407962 0.32723254939472574 + 0.1495155660487904 0.38305813044122095 + 0.12547212649466555 0.44244589098818987 + 0.10922042150446726 0.5044206856493141 + 0.10102730362483181 0.5679648900096435 + 0.10102730362483181 0.6320351099903566 + 0.10922042150446731 0.6955793143506862 + 0.1254721264946656 0.7575541090118102 + 0.14951556604879046 0.8169418695587791 + 0.18095594755407968 0.8727674506052743 + 0.21927702081543277 0.9241141976538942 + 0.2638495548693417 0.9701389985376578 + 0.3139416699389151 1.0100861272984778 + 0.36873085487958224 1.0432996531865 + 0.42731747278934623 1.0692342110248803 + 0.4887395330218428 1.0874639560909118 + 0.5519884870461592 1.0976895564745992 + 0.6160257887858274 1.099743108100344 + 0.6797999475166895 1.093590891707225 + 0.7422637933155162 1.0793339265183302 + 0.802391671561197 1.0572063115079062 + 0.8591962841552626 1.027571381502673 + 0.9117449009293666 0.990915741234015 + 0.9591746750488637 0.9478412753017432 + 1.0007068109339783 0.899055265245608 + 1.0356593520616948 0.8453587760019688 + 1.063458378673011 0.7876335024396869 + 1.0836474315195146 0.7268272919547538 + 1.095895006911623 0.6639385808422531 + 1.7 0.49999999999999994 + 1.6983580027646492 0.47442456766309865 + 1.693458972607806 0.4492690832180985 + 1.6853833514692045 0.42494659902412524 + 1.6742637408246779 0.40185648959921244 + 1.6602827243735914 0.38037789390175675 + 1.6436698700195453 0.3608634898793026 + 1.6246979603717466 0.343633703506394 + 1.603678513662105 0.3289714473989308 + 1.5809566686244787 0.3171174753968375 + 1.5569055173262063 0.3082664293926678 + 1.5319199790066758 0.30256364331710994 + 1.506410315514331 0.3001027567598624 + 1.4807953948184636 0.30092417741016037 + 1.455495813208737 0.30501441756363523 + 1.4309269891157383 0.31230631559004796 + 1.407492341951833 0.3226801387254 + 1.3855766679755661 0.3359655490806087 + 1.3655398219477366 0.35194440058493687 + 1.347710808326173 0.37035432093844234 + 1.3323823790216318 0.3908930197578903 + 1.3198062264195163 0.41322325217648836 + 1.3101888505978663 0.43697835639527594 + 1.303688168601787 0.4617682742597256 + 1.3004109214499326 0.4871859560038574 + 1.3004109214499326 0.5128140439961426 + 1.303688168601787 0.5382317257402746 + 1.3101888505978663 0.5630216436047241 + 1.3198062264195163 0.5867767478235116 + 1.3323823790216318 0.6091069802421097 + 1.347710808326173 0.6296456790615577 + 1.3655398219477366 0.6480555994150632 + 1.3855766679755661 0.6640344509193912 + 1.4074923419518328 0.6773198612746 + 1.4309269891157386 0.6876936844099522 + 1.4554958132087372 0.6949855824363648 + 1.4807953948184638 0.6990758225898397 + 1.506410315514331 0.6998972432401376 + 1.5319199790066758 0.6974363566828901 + 1.5569055173262065 0.6917335706073321 + 1.5809566686244787 0.6828825246031625 + 1.603678513662105 0.6710285526010692 + 1.6246979603717466 0.656366296493606 + 1.6436698700195456 0.6391365101206973 + 1.6602827243735914 0.6196221060982432 + 1.6742637408246779 0.5981435104007875 + 1.6853833514692043 0.5750534009758748 + 1.693458972607806 0.5507309167819016 + 1.6983580027646492 0.5255754323369012 + 1.0 2.0 + 1.0 3.0 + 1.0 4.000000000000001 + 1.0 5.0 + 1.1666666666666665 5.0 + 1.3333333333333333 5.0 + 1.5 5.0 + 1.5 4.0 + 1.5 3.0 + 1.5 2.0 + 1.3333333333333335 2.0 + 1.1666666666666667 2.0 + 0.2 2.0 + 0.2 5.0 + 0.75 4.0 + 0.75 3.0 + 0.5 2.0 + 0.2 3.5 + 2.0 5.0 + 0.0 3.0 + 2.0 3.0 + 2.0 1.0 + 0.0 5.0 + 0.0 1.0 + 0.2 4.5 + 0.2 3.0 + 0.2 4.0 + 0.0 4.5 + 0.0 0.5 + 2.0 0.5 + 0.0 3.5 + 1.6666666666666665 0.0 + 1.0 0.0 + 0.3333333333333333 0.0 + 0.0 0.25 + 0.0 0.75 + 0.7916666666666666 0.0 + 0.5416666666666666 0.0 + 0.0 0.625 + 1.4740544522373191 1.309077721762752 + 1.3499698939387508 1.0055012112239021 + 1.6795817213270934 0.9879815502040521 + 2.0 0.75 + 2.0 0.25 + 1.7828347010132077 0.1885675610394171 + 1.19953813886343 0.20901891414515464 + 1.7742377105455027 0.8019661970196654 + 0.0 1.5 + 0.9388315428915 1.5207147605911762 + 1.2572693115310343 0.8043746560736462 + 1.5416666666666665 0.0 + 1.4877125131091204 0.8831690890011553 + 1.8624474074396582 0.6203408303941387 + 1.862447407439658 0.37965916960586316 + 0.4487051545335375 1.535812115275885 + 1.441199151969013 0.13629596364476348 + 1.624263604487171 0.16233564360848637 + 1.6185917257370095 0.8222520295432142 + 1.1917579283891429 0.37520661583202014 + 1.3293751090374275 0.21853639574589828 + 1.2191572487719817 0.6581676907984143 + 1.0529166570030704 1.2492900864648844 + 0.0 1.25 + 1.3724252107559454 0.7881936711216704 + 1.7396173332189573 0.2960107901378373 + 1.8110061512826319 0.5199672573998425 + 1.761187193038501 0.6700140220581073 + 0.6745044586363241 1.372316652669158 + 0.28592779118073197 1.3094945905319997 + 1.1953751211197607 0.5 + 1.5289331661582095 0.2000774658667932 + 1.6681251875542065 0.7410200991200366 + 1.528217827526302 0.7925073008997648 + 1.775506905040127 0.40852540520001573 + 1.26831267650853 0.3270872565921958 + 1.418160934512214 0.22425703203449873 + 1.295455646032882 0.6980901602542381 + 1.6315588938199306 0.24782623088951797 + 1.137591811617686 1.057658581735622 + 1.0833333333333333 5.527777777777778 + 1.7661043175005355 0.5883527206490259 + 0.48832789133187804 1.290731478047606 + 0.8416520629881481 1.2566467201424116 + 0.16692117116205538 1.1430636744441975 + 1.2314189884870388 0.5704302352100531 + 1.4563071262047091 0.7702558737066645 + 1.2378485908218748 0.4312558050732817 + 1.5935642184148526 0.7542442070846888 + 1.3320629484886526 0.2894135981807518 + 0.125 0.0 + 0.0 2.5 + 0.2 2.5 + 0.0 5.5 + 1.363898107854514 0.7245143067518455 + 1.6763532155896466 0.3058155104275537 + 1.7198413454244592 0.35689914227621217 + 1.7603049822572803 0.48328786565231235 + 1.6986162550807449 0.6690844831441323 + 1.2732086411580512 0.6277265137313147 + 0.1357338269089258 0.15038328438526705 + 0.9681905883861459 1.127828895829673 + 1.5569357954505727 0.2505479812612332 + 1.4917990544438116 0.2442643181947033 + 1.4166666666666665 5.362573099415204 + 0.6610307417000465 1.2326474818074256 + 0.3427260032157782 1.181186440179403 + 1.4166666666666667 1.6571810441100427 + 1.0238883307733782 0.13325183852345296 + 1.2486746582268176 0.5 + 1.0 3.5000000000000004 + 0.75 3.5 + 0.47500000000000003 4.5 + 1.0 4.5 + 0.625 2.5 + 1.0 2.5 + 1.2821205078623963 0.3772925560903774 + 1.3990607282139222 0.271976426778746 + 1.1173493764498315 0.9367571253255303 + 0.0 0.375 + 1.741444624549862 0.5470213364192468 + 1.7216209675111749 0.6067270329489496 + 1.640658487617645 0.7016445193064772 + 1.523607866265877 0.7447202299680109 + 0.0 0.875 + 0.16036607072667938 1.0257617177590372 + 1.731605030618596 0.4231018317802659 + 1.4308793419171846 0.7328904331187506 + 1.1070433482398665 0.2699513556188709 + 0.875 0.0 + 1.326733072952154 0.6677996614425488 + 1.611490638036034 0.2862933200657552 + 1.3269281024201038 0.33238921406445593 + 1.0833333333333333 5.257309941520468 + 0.5647973445143255 5.392543859649123 + 0.5047539390232997 1.1891305650202075 + 0.8061070342543368 1.1600593943533914 + 1.0833333333333335 1.7458187278913946 + 0.4583333333333333 0.0 + 1.6810772213147687 0.34584671399258676 + 0.0820730652316044 0.30830898459576883 + 0.29187380922086326 0.09171361966873727 + 1.2701959364187478 0.5602617219999282 + 1.1611993909112273 0.7863310354349395 + 0.9961530910081264 1.036208580108681 + 1.462487223491946 0.2679702132241154 + 1.5225695030046766 0.2660434914632048 + 0.2962726981257435 1.1010299529782763 + 1.2735053984345062 0.44060612113937503 + 1.5808501167410969 0.7196958855831329 + 0.09063815833613441 0.886867244835494 + 0.9340092492886052 0.1211726241519101 + 1.3795327553781789 0.3012766796536391 + 0.0 3.75 + 0.2 3.75 + 0.2 2.25 + 0.0 2.25 + 0.0 4.25 + 0.2 4.25 + 0.2 4.75 + 0.0 4.75 + 0.0 2.75 + 0.2 2.75 + 0.0 5.25 + 0.0 3.25 + 0.2 3.25 + 0.0 1.75 + 1.7305994280094303 0.5148049744879046 + 1.6936605339465862 0.6260590379916767 + 1.7193022924897394 0.5728133777310767 + 1.4925952162260299 0.7309084256300289 + 1.6553197408864884 0.6710242963459636 + 2.0 1.5 + 1.7261014731069777 0.45596674205660387 + 1.7075375557401247 0.4000551807062032 + 1.406921135389704 0.7102667764910945 + 1.0370994517765144 0.22789181149262006 + 1.125 0.0 + 1.3570113367409984 0.6793021124621966 + 1.316206997826056 0.6371682824339902 + 1.6311751370246665 0.31195057690225014 + 1.5791854380321182 0.284827584238829 + 1.316282242285531 0.36288787396558325 + 1.1154407188558464 0.3517768322991175 + 0.5816906605550696 1.1709526266542052 + 0.864223205343458 1.1064664170034129 + 0.4374647190632682 1.1476352949226916 + 0.7271142209552935 1.1569237906798149 + 0.1428028406433256 0.25878489202052457 + 0.3690795881569608 0.07834676725460561 + 0.2443121381562888 0.15398152865993447 + 0.25 0.0 + 1.2737384055431993 0.5291732020831812 + 1.2885382384146338 0.5856113791101021 + 1.113130134633655 0.847110448984858 + 1.1590288414186054 0.7088708571143922 + 1.033197322819307 0.9687862576934944 + 1.4353052654987943 0.28202197206461327 + 0.24588090864430434 1.044051295369198 + 0.2688387528122659 5.375 + 0.33333333333333337 6.0 + 1.2894711087692583 0.4147662982391812 + 1.2747365658359935 0.47095549643502305 + 1.6050489090123727 0.701359091410823 + 1.550537613507314 0.7214197520535767 + 0.07387658485528542 0.8130037639664341 + 0.14511290432603197 0.939491062646291 + 0.7291666666666666 0.0 + 0.8624443884933936 0.09694324186960815 + 0.07431874516150205 0.3871752469020991 + 1.3586733685981895 0.32278200956665326 + 0.7743125163556892 1.7852573023241183 + 1.3951319674273832 0.7467489457540966 + 1.6723555903905802 0.6467284533501322 + 1.4638740821559169 0.7234515755624243 + 1.4927477124566209 0.2738469683956681 + 1.6895818983651612 0.3765958595614554 + 1.725742831711937 0.4855068293396377 + 1.3828391994677471 0.6932689949811435 + 1.5502891882510008 0.2796686701104153 + 1.6519383611714682 0.33269897851362074 + 1.4166666666666665 5.171709936804376 + 2.0 5.5 + 1.7470040926571286 5.26714151810979 + 1.762711901635018 0.44520425603505154 + 1.8366469302468644 0.45042453510946423 + 1.9060886700063842 0.5155263895621286 + 1.7432094576086072 0.3868933176340165 + 1.7985506191032619 0.3391937098408574 + 1.8878694231956714 0.26883597168004963 + 1.7916666666666665 0.0 + 2.0 0.125 + 0.9230460198845826 1.0631107620790716 + 1.1358084873427654 0.4220993253764972 + 0.19447305594557093 0.20726905545353125 + 1.3032549844320298 0.6108047284553858 + 2.0 0.625 + 1.2500000000000002 1.8319281123363502 + 0.6541111351264756 1.160918521091478 + 0.371895480593367 1.115292082681653 + 1.494273560202694 0.7688633005731953 + 1.4773323581048208 0.8252320844062707 + 1.4030882061420913 0.8684322443508078 + 0.7944598296275528 0.07158982321352167 + 1.0 3.25 + 0.75 3.25 + 0.595479687443039 4.280946022830838 + 1.0 4.25 + 2.0 4.5 + 1.5 4.5 + 2.0 2.5 + 1.5 2.5 + 2.0 3.5 + 1.5 3.5 + 0.6893660937409167 2.757464374963667 + 1.0 2.75 + 1.0 3.750000000000001 + 0.75 3.75 + 0.20607015431451464 0.07547310822581126 + 1.1137966762594949 0.1795335656241746 + 1.2083333333333333 0.0 + 1.1666666666666665 0.09271643952630988 + 0.3994151065612831 5.677353293275649 + 1.6783486674776207 0.70087084995281 + 1.7392543857928202 0.7377559547642759 + 1.8302710234553803 0.7298028546873176 + 2.0 0.875 + 1.8888519575683367 0.8331257280027056 + 1.800336932191529 0.9323381323744324 + 2.0 1.25 + 1.8227502338782238 1.1398294920180019 + 1.7994421968210412 1.375 + 1.7395586704615544 1.6944745976100235 + 1.7267593429098054 0.6440448038896638 + 1.7678827403626947 0.5201876828851476 + 1.2035918506774017 0.8877754751066075 + 1.16093306626047 0.5639869022785741 + 0.0 0.4375 + 1.291551342829673 0.6627651416324978 + 1.2538080175158937 0.6848149997324289 + 1.2577128301399019 0.7445318850453346 + 1.2090408575917337 0.7071751969044885 + 1.3306373761553634 0.7031246800642893 + 1.3160528628068418 0.7623584294631466 + 1.6462859848898292 0.27997768754971447 + 1.7020584160349093 0.234982296630739 + 1.5967635469661356 0.2541418634055588 + 1.6061662460929913 0.20693653438447443 + 1.570825246339907 0.16662443239081526 + 1.5905483961970126 0.07730943253130455 + 1.51018175705595 0.13363920248553696 + 1.4583333333333333 0.0 + 1.6590520810618847 0.20242355254666858 + 1.7125852936455277 0.12082842146382869 + 1.431068012499545 0.9581022021491937 + 1.477452094723081 1.130541403025688 + 1.5531080005501499 0.9914800857679006 + 1.2813569642026876 1.216110095730245 + 1.2018317226108364 1.4715704518745842 + 1.6198909607221894 1.1179240078762014 + 1.7983548141425743 0.46657478567124433 + 0.9770513066521348 0.18482460736504314 + 0.7938123559004582 5.2089259691333805 + 0.6407123629255758 4.851627018928146 + 1.319484941905665 0.8292893422114065 + 1.2761296818296555 0.5 + 1.8099178972915033 0.26187472706351006 + 1.7111729419512756 0.17826049305063374 + 1.759634673818009 0.34999662375758167 + 1.718142438071527 0.703889427730984 + 1.473230604388981 0.071097758315114 + 1.3863435254451124 0.06887822829586042 + 1.2782854698688741 0.09720405683617961 + 0.7375 4.501716097368583 + 0.44121509031025474 0.06500095027943562 + 1.305524838337339 0.3904736294480411 + 1.6684438208715549 0.25037958358667844 + 1.6996902177676332 0.2742036674155371 + 1.3624484903113168 0.2687327852709218 + 0.06974484917671708 0.9630027278134988 + 0.0 1.125 + 0.07352010305180143 1.054357451563032 + 1.1563399977503028 0.6357182129391813 + 0.5597884117036155 1.2501563862805738 + 0.5715382250636158 1.354065450073582 + 0.5980032696789671 1.504333348664305 + 0.5656039401938803 1.7204555756412738 + 0.3037866871454204 1.7568871511798612 + 0.46161571048938355 1.4121561268225087 + 0.3161306261019238 1.459468430239305 + 0.149758655496108 1.4149454869965006 + 0.16391023227107437 1.6142327799518283 + 0.7683057766893729 1.5148465969437765 + 0.7637530559523047 1.230480162353276 + 0.7720830332001749 1.3347191336230664 + 0.9050972636859582 1.3832137934898427 + 1.0559347141051296 1.4190962037054105 + 0.43329341865156223 1.2297056567872398 + 0.3893995908276335 1.3246186881965123 + 0.8840060412901801 1.1862259521425271 + 0.9479694782050885 1.272643328918064 + 1.4361522732329282 0.25034394087790574 + 1.4603794219490087 0.21438773060391503 + 1.4301726911242494 0.18040552911767954 + 1.3664948543862412 0.14105443922716654 + 1.3800869372880815 0.19025696838292824 + 1.4771932167810962 0.16902551127432658 + 1.40980282641639 0.2962430137342318 + 0.0 0.6875 + 2.0 0.375 + 1.9132736730754663 0.4382760179317226 + 0.055964514785385895 0.46875 + 1.6666208006494743 5.608342938440153 + 1.2445796724660527 0.5415967162439137 + 1.2035138373071206 0.5402730217783609 + 1.257035252439734 0.5890952409660676 + 1.2196380370307442 0.6135093363907388 + 1.383611268856942 0.23811038285103012 + 1.6226023422523703 0.7328606305005508 + 1.6335516540160544 0.7781375493960542 + 1.698042873799217 0.824601373114044 + 1.6559767278839401 0.902581204581636 + 1.5575918148450751 0.7567851055371636 + 1.5786042901358082 0.7983586872318487 + 1.561956830704648 0.8716273239716548 + 1.25 5.146519289061359 + 1.4166666666666667 1.853986608235224 + 1.6106377773288556 1.84006951687984 + 1.75 2.0547125573551916 + 1.5 2.25 + 1.75 2.375 + 1.75 2.6875 + 1.7351882330544273 0.25666486669089317 + 1.740696001877012 0.21209770142048218 + 1.7716317714671403 0.27248473247545524 + 1.780747250326824 0.23099526710030466 + 1.8315421621777004 0.21222918129712579 + 1.8571475226715097 0.09755754869299872 + 1.9212830619181216 0.17925938128868346 + 1.8307671503240839 0.15186156285696936 + 1.782563159254053 0.09488484980088335 + 1.7291666666666665 0.0 + 1.6979166666666665 0.05726348727905952 + 0.0635245517925628 0.7406804293007325 ] _NODES1 = [ - [1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370, 3, 401, 161, 142, 491, 340, 4], - [4, 341, 154, 459, 140, 346, 153, 376, 132, 379, 282, 5, 360, 131, 362, 6, 358, 129, 332, 7], - [7, 8, 9, 310, 10], - [10 203 273 133 270 138 267 11 263 141 274 130 271 201 266 12 276 158 173 430 134 234 146 458 149 139 387 229 145 1][:], + [1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370, 3, 401, 161, 142, 491, 340, 4], + [4, 341, 154, 459, 140, 346, 153, 376, 132, 379, 282, 5, 360, 131, 362, 6, 358, 129, 332, 7], + [7, 8, 9, 310, 10], + [10 203 273 133 270 138 267 11 263 141 274 130 271 201 266 12 276 158 173 430 134 234 146 458 149 139 387 229 145 1][:], ] _NODES2 = [ - [13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 13][:], + [13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 13][:], ] _NODES3 = [ - [62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 62][:], + [62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 62][:], ] _NODES4 = [ - [111, 225, 365, 112, 354, 220, 366, 113, 357, 223, 114][:], - [114, 115, 116, 117][:], - [117, 359, 118, 363, 119, 361, 479, 120][:], - [120, 121, 122, 111][:], + [111, 225, 365, 112, 354, 220, 366, 113, 357, 223, 114][:], + [114, 115, 116, 117][:], + [117, 359, 118, 363, 119, 361, 479, 120][:], + [120, 121, 122, 111][:], ] _NODES5 = [ - [123 265 202 272 136 275 128 264 137 268 135 269 124 222 356 125 367 221 355 126 364 224 127 123][:], + [123 265 202 272 136 275 128 264 137 268 135 269 124 222 356 125 367 221 355 126 364 224 127 123][:], ] const __BOUNDARY_NODES = [ - _NODES1, _NODES2, _NODES3, _NODES4, _NODES5 + _NODES1, _NODES2, _NODES3, _NODES4, _NODES5, ] @testset "get_left/right_boundary_node" begin - rng = StableRNG(1234555) - #= + rng = StableRNG(1234555) + #= _x, _y = complicated_geometry() x = _x y = _y @@ -571,848 +572,892 @@ const __BOUNDARY_NODES = [ A = get_area(tri) refine!(tri; max_area=1e-1A, rng) =# - points = tuple.(_POINTS[:, 1], _POINTS[:, 2]) - tri = triangulate(points; boundary_nodes=__BOUNDARY_NODES, rng, delete_ghosts=false) - nodes = [1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370] - right = [200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370, 3] - left = [145, 1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287] - @inferred DT.get_right_boundary_node(tri, 1, DT.𝒢) - @inferred DT.get_left_boundary_node(tri, 1, DT.𝒢) + points = tuple.(_POINTS[:, 1], _POINTS[:, 2]) + tri = triangulate(points; boundary_nodes = __BOUNDARY_NODES, rng, delete_ghosts = false) + nodes = [1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370] + right = [200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287, 370, 3] + left = [145, 1, 200, 301, 144, 248, 148, 2, 317, 147, 239, 143, 287] + @inferred DT.get_right_boundary_node(tri, 1, DT.𝒢) + @inferred DT.get_left_boundary_node(tri, 1, DT.𝒢) - for (i, r, ℓ) in zip(nodes, right, left) - DT.get_right_boundary_node(tri, i, DT.𝒢) == r - DT.get_left_boundary_node(tri, i, DT.𝒢) == ℓ - @inferred DT.get_left_boundary_node(tri, i, DT.𝒢) - end - nodes = [13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61] - right = [nodes[2:end]..., nodes[1]] - left = [nodes[end]..., nodes[1:(end-1)]...] - for (i, r, ℓ) in zip(nodes, right, left) - @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 4) == r - @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 4) == ℓ - end - nodes = [62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110] - right = [nodes[2:end]..., nodes[1]] - left = [nodes[end]..., nodes[1:(end-1)]...] - for (i, r, ℓ) in zip(nodes, right, left) - @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 5) == r - @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 5) == ℓ - end - nodes = [111 225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121 122] - right = [225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121 122 111] - left = [122 111 225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121] - for (i, r, ℓ) in zip(nodes, right, left) - @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 7) == r - @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 8) == ℓ - end - nodes = [123, 265, 202, 272, 136, 275, 128, 264] - right = [265, 202, 272, 136, 275, 128, 264, 137] - left = [127, 123, 265, 202, 272, 136, 275, 128] - for (i, r, ℓ) in zip(nodes, right, left) - @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 10) == r - @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 10) == ℓ - end + for (i, r, ℓ) in zip(nodes, right, left) + DT.get_right_boundary_node(tri, i, DT.𝒢) == r + DT.get_left_boundary_node(tri, i, DT.𝒢) == ℓ + @inferred DT.get_left_boundary_node(tri, i, DT.𝒢) + end + nodes = [13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61] + right = [nodes[2:end]..., nodes[1]] + left = [nodes[end]..., nodes[1:(end - 1)]...] + for (i, r, ℓ) in zip(nodes, right, left) + @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 4) == r + @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 4) == ℓ + end + nodes = [62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110] + right = [nodes[2:end]..., nodes[1]] + left = [nodes[end]..., nodes[1:(end - 1)]...] + for (i, r, ℓ) in zip(nodes, right, left) + @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 5) == r + @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 5) == ℓ + end + nodes = [111 225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121 122] + right = [225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121 122 111] + left = [122 111 225 365 112 354 220 366 113 357 223 114 115 116 117 359 118 363 119 361 479 120 121] + for (i, r, ℓ) in zip(nodes, right, left) + @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 7) == r + @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 8) == ℓ + end + nodes = [123, 265, 202, 272, 136, 275, 128, 264] + right = [265, 202, 272, 136, 275, 128, 264, 137] + left = [127, 123, 265, 202, 272, 136, 275, 128] + for (i, r, ℓ) in zip(nodes, right, left) + @test DT.get_right_boundary_node(tri, i, DT.𝒢 - 10) == r + @test DT.get_left_boundary_node(tri, i, DT.𝒢 - 10) == ℓ + end end @testset "find_edge" begin - points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.5, 0.0), (0.5, 0.5), (0.0, 0.5)] - tri = triangulate(points, randomise=false) - T = (1, 2, 3) - ℓ = 4 - @test DT.find_edge(tri, T, ℓ) == (1, 2) - T = (2, 3, 1) - @test DT.find_edge(tri, T, ℓ) == (1, 2) - T = (1, 2, 3) - ℓ = 5 - @test DT.find_edge(tri, T, ℓ) == (2, 3) - T = (2, 3, 1) - @test DT.find_edge(tri, T, ℓ) == (2, 3) - T = (1, 2, 3) - ℓ = 6 - @test DT.find_edge(tri, T, ℓ) == (3, 1) - T = (2, 3, 1) - @test DT.find_edge(tri, T, ℓ) == (3, 1) - p1 = [2.0, 3.5] - p2 = [0.0, 0.0] - p3 = [3.0, 0.0] - p4 = [17.2, -2.5] - p5 = [0.0, 3.0] - points = [p1, p2, p3, p4, p5] - tri = triangulate(points, randomise=false) - T = (2, 3, 5) - push!(points, [1.0, 0.0]) - @test DT.find_edge(tri, T, length(points)) == (2, 3) - push!(points, [2.0, 0.0]) - @test DT.find_edge(tri, T, length(points)) == (2, 3) - push!(points, [1.5, 0.0]) - @test DT.find_edge(tri, T, length(points)) == (2, 3) - push!(points, [1.0, 0.0]) - @test DT.find_edge(tri, T, length(points)) == (2, 3) - push!(points, [0.5, 0.0]) - @test DT.find_edge(tri, T, length(points)) == (2, 3) - push!(points, [2.5, 0.5]) - @test DT.find_edge(tri, T, length(points)) == (3, 5) - push!(points, [2.0, 1.0]) - @test DT.find_edge(tri, T, length(points)) == (3, 5) - push!(points, [1.5, 1.5]) - @test DT.find_edge(tri, T, length(points)) == (3, 5) - push!(points, [1.0, 2.0]) - @test DT.find_edge(tri, T, length(points)) == (3, 5) - push!(points, [0.5, 2.5]) - @test DT.find_edge(tri, T, length(points)) == (3, 5) - push!(points, [0.0, 2.5]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) - push!(points, [0.0, 2.2]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) - push!(points, [0.0, 2.0]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) - push!(points, [0.0, 1.5]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) - push!(points, [0.0, 0.8]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) - push!(points, [0.0, 0.2]) - @test DT.find_edge(tri, T, length(points)) == (5, 2) + points = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.5, 0.0), (0.5, 0.5), (0.0, 0.5)] + tri = triangulate(points, randomise = false) + T = (1, 2, 3) + ℓ = 4 + @test DT.find_edge(tri, T, ℓ) == (1, 2) + T = (2, 3, 1) + @test DT.find_edge(tri, T, ℓ) == (1, 2) + T = (1, 2, 3) + ℓ = 5 + @test DT.find_edge(tri, T, ℓ) == (2, 3) + T = (2, 3, 1) + @test DT.find_edge(tri, T, ℓ) == (2, 3) + T = (1, 2, 3) + ℓ = 6 + @test DT.find_edge(tri, T, ℓ) == (3, 1) + T = (2, 3, 1) + @test DT.find_edge(tri, T, ℓ) == (3, 1) + p1 = [2.0, 3.5] + p2 = [0.0, 0.0] + p3 = [3.0, 0.0] + p4 = [17.2, -2.5] + p5 = [0.0, 3.0] + points = [p1, p2, p3, p4, p5] + tri = triangulate(points, randomise = false) + T = (2, 3, 5) + push!(points, [1.0, 0.0]) + @test DT.find_edge(tri, T, length(points)) == (2, 3) + push!(points, [2.0, 0.0]) + @test DT.find_edge(tri, T, length(points)) == (2, 3) + push!(points, [1.5, 0.0]) + @test DT.find_edge(tri, T, length(points)) == (2, 3) + push!(points, [1.0, 0.0]) + @test DT.find_edge(tri, T, length(points)) == (2, 3) + push!(points, [0.5, 0.0]) + @test DT.find_edge(tri, T, length(points)) == (2, 3) + push!(points, [2.5, 0.5]) + @test DT.find_edge(tri, T, length(points)) == (3, 5) + push!(points, [2.0, 1.0]) + @test DT.find_edge(tri, T, length(points)) == (3, 5) + push!(points, [1.5, 1.5]) + @test DT.find_edge(tri, T, length(points)) == (3, 5) + push!(points, [1.0, 2.0]) + @test DT.find_edge(tri, T, length(points)) == (3, 5) + push!(points, [0.5, 2.5]) + @test DT.find_edge(tri, T, length(points)) == (3, 5) + push!(points, [0.0, 2.5]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) + push!(points, [0.0, 2.2]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) + push!(points, [0.0, 2.0]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) + push!(points, [0.0, 1.5]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) + push!(points, [0.0, 0.8]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) + push!(points, [0.0, 0.2]) + @test DT.find_edge(tri, T, length(points)) == (5, 2) end @testset "choose_uvw" begin - i, j, k = rand(Int, 3) - @test DT.choose_uvw(true, false, false, i, j, k) == (i, j, k) - @test DT.choose_uvw(false, true, false, i, j, k) == (j, k, i) - @test DT.choose_uvw(false, false, true, i, j, k) == (k, i, j) + i, j, k = rand(Int, 3) + @test DT.choose_uvw(true, false, false, i, j, k) == (i, j, k) + @test DT.choose_uvw(false, true, false, i, j, k) == (j, k, i) + @test DT.choose_uvw(false, false, true, i, j, k) == (k, i, j) end @testset "is_circular" begin - x = rand(10) - @test !DT.is_circular(x) - push!(x, x[begin]) - @test DT.is_circular(x) - @test DT.is_circular(Float64[]) + x = rand(10) + @test !DT.is_circular(x) + push!(x, x[begin]) + @test DT.is_circular(x) + @test DT.is_circular(Float64[]) end @testset "circular_equality" begin - @test !DT.circular_equality([1, 2, 3, 4, 1], [3, 2, 4, 1, 3]) - @test !DT.circular_equality([1, 2, 3, 1], [3, 4, 5, 3]) - @test_throws AssertionError DT.circular_equality([1, 2, 3, 1], [3, 4, 5]) - @test_throws AssertionError DT.circular_equality([1, 2, 3], [5, 4, 3]) - @test !DT.circular_equality([1, 2, 3, 4, 1], [1, 2, 1]) - x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] - for i in 1:10 - local y - y = @views circshift(x[begin:(end-1)], i) - push!(y, y[begin]) - @test DT.circular_equality(x, y) && DT.circular_equality(y, x) - end - @test DT.circular_equality([3, 2, 1, 13, 12, 11, 5, 4, 3], [1, 13, 12, 11, 5, 4, 3, 2, 1]) - @test DT.circular_equality(Float64[], Float64[]) + @test !DT.circular_equality([1, 2, 3, 4, 1], [3, 2, 4, 1, 3]) + @test !DT.circular_equality([1, 2, 3, 1], [3, 4, 5, 3]) + @test_throws AssertionError DT.circular_equality([1, 2, 3, 1], [3, 4, 5]) + @test_throws AssertionError DT.circular_equality([1, 2, 3], [5, 4, 3]) + @test !DT.circular_equality([1, 2, 3, 4, 1], [1, 2, 1]) + x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] + for i in 1:10 + local y + y = @views circshift(x[begin:(end - 1)], i) + push!(y, y[begin]) + @test DT.circular_equality(x, y) && DT.circular_equality(y, x) + end + @test DT.circular_equality([3, 2, 1, 13, 12, 11, 5, 4, 3], [1, 13, 12, 11, 5, 4, 3, 2, 1]) + @test DT.circular_equality(Float64[], Float64[]) end @testset "get_surrounding_polygon" begin - tri = example_triangulation() - rng = StableRNG(999987897899) - tri = triangulate(get_points(tri); delete_ghosts=false, rng) - polys = Dict( - 1 => [6, 3, 7, 4, 6], - 2 => [8, 3, 6, DT.𝒢, 8], - 3 => [8, 7, 1, 6, 2, 8], - 4 => [6, 1, 7, 5, DT.𝒢, 6], - 5 => [4, 7, 8, DT.𝒢, 4], - 6 => [2, 3, 1, 4, DT.𝒢, 2], - 7 => [8, 5, 4, 1, 3, 8], - 8 => [5, 7, 3, 2, DT.𝒢, 5], - DT.𝒢 => [5, 8, 2, 6, 4, 5] - ) - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) - fnc_polys[i] = DT.get_surrounding_polygon(tri, i) - push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) - @test DT.circular_equality(poly_true, poly_f) - end - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) - fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices=true) - push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) - @test DT.circular_equality(filter(!DT.is_ghost_vertex, poly_true), poly_f) - end - tri, label_map, index_map = simple_geometry() - DT.compute_representative_points!(tri) - add_ghost_triangles!(tri) - polys = Dict( - 1 => [[2, 20, 19, 8, DT.𝒢, 2]], - 2 => [[3, 16, 20, 1, DT.𝒢, 3]], - 3 => [[4, 17, 16, 2, DT.𝒢, 4]], - 4 => [[5, 18, 17, 3, DT.𝒢, 5]], - 5 => [[6, 22, 24, 18, 4, DT.𝒢, 6]], - 6 => [[7, 25, 9, 12, 23, 22, 5, DT.𝒢, 7]], - 7 => [[8, 26, 9, 25, 6, DT.𝒢, 8]], - 8 => [[1, 19, 10, 26, 7, DT.𝒢, 1]], - 9 => [[6, 25, 7, 26, 10, DT.𝒢 - 1, 12, 6]], - 10 => [[11, DT.𝒢 - 1, 9, 26, 8, 19, 20, 21, 11]], - 11 => [[12, DT.𝒢 - 1, 10, 21, 23, 12]], - 12 => [[23, 6, 9, DT.𝒢 - 1, 11, 23]], - 13 => [[18, 24, 22, 23, 21, 14, DT.𝒢 - 2, 18], - [18, 24, 22, 23, 21, 14, DT.𝒢 - 3, 18]], - 14 => [[13, 21, 15, DT.𝒢 - 2, 13], - [13, 21, 15, DT.𝒢 - 3, 13]], - 15 => [[14, 21, 20, 16, DT.𝒢 - 2, 14], - [14, 21, 20, 16, DT.𝒢 - 3, 14]], - 16 => [[15, 20, 2, 3, 17, DT.𝒢 - 2, 15], - [15, 20, 2, 3, 17, DT.𝒢 - 3, 15]], - 17 => [[16, 3, 4, 18, DT.𝒢 - 2, 16], - [16, 3, 4, 18, DT.𝒢 - 3, 16]], - 18 => [[17, 4, 5, 24, 13, DT.𝒢 - 2, 17], - [17, 4, 5, 24, 13, DT.𝒢 - 3, 17]], - 19 => [[1, 20, 10, 8, 1]], - 20 => [[16, 15, 21, 10, 19, 1, 2, 16]], - 21 => [[15, 14, 13, 23, 11, 10, 20, 15]], - 22 => [[24, 5, 6, 23, 13, 24]], - 23 => [[13, 22, 6, 12, 11, 21, 13]], - 24 => [[18, 5, 22, 13, 18]], - 25 => [[9, 6, 7, 9]], - 26 => [[10, 9, 7, 8, 10]], - DT.𝒢 => [[5, 4, 3, 2, 1, 8, 7, 6, 5]], - DT.𝒢 - 1 => [[9, 10, 11, 12, 9]], - DT.𝒢 - 2 => [[14, 15, 16, 17, 18, 13, 14]], - DT.𝒢 - 3 => [[14, 15, 16, 17, 18, 13, 14]] - ) - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) + tri = example_triangulation() + rng = StableRNG(999987897899) + tri = triangulate(get_points(tri); delete_ghosts = false, rng) + polys = Dict( + 1 => [6, 3, 7, 4, 6], + 2 => [8, 3, 6, DT.𝒢, 8], + 3 => [8, 7, 1, 6, 2, 8], + 4 => [6, 1, 7, 5, DT.𝒢, 6], + 5 => [4, 7, 8, DT.𝒢, 4], + 6 => [2, 3, 1, 4, DT.𝒢, 2], + 7 => [8, 5, 4, 1, 3, 8], + 8 => [5, 7, 3, 2, DT.𝒢, 5], + DT.𝒢 => [5, 8, 2, 6, 4, 5], + ) + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) + fnc_polys[i] = DT.get_surrounding_polygon(tri, i) + push!(fnc_polys[i], fnc_polys[i][begin]) + end + for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) + @test DT.circular_equality(poly_true, poly_f) + end + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) + fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices = true) + push!(fnc_polys[i], fnc_polys[i][begin]) + end + for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) + @test DT.circular_equality(filter(!DT.is_ghost_vertex, poly_true), poly_f) + end + tri, label_map, index_map = simple_geometry() + DT.compute_representative_points!(tri) + add_ghost_triangles!(tri) + polys = Dict( + 1 => [[2, 20, 19, 8, DT.𝒢, 2]], + 2 => [[3, 16, 20, 1, DT.𝒢, 3]], + 3 => [[4, 17, 16, 2, DT.𝒢, 4]], + 4 => [[5, 18, 17, 3, DT.𝒢, 5]], + 5 => [[6, 22, 24, 18, 4, DT.𝒢, 6]], + 6 => [[7, 25, 9, 12, 23, 22, 5, DT.𝒢, 7]], + 7 => [[8, 26, 9, 25, 6, DT.𝒢, 8]], + 8 => [[1, 19, 10, 26, 7, DT.𝒢, 1]], + 9 => [[6, 25, 7, 26, 10, DT.𝒢 - 1, 12, 6]], + 10 => [[11, DT.𝒢 - 1, 9, 26, 8, 19, 20, 21, 11]], + 11 => [[12, DT.𝒢 - 1, 10, 21, 23, 12]], + 12 => [[23, 6, 9, DT.𝒢 - 1, 11, 23]], + 13 => [ + [18, 24, 22, 23, 21, 14, DT.𝒢 - 2, 18], + [18, 24, 22, 23, 21, 14, DT.𝒢 - 3, 18], + ], + 14 => [ + [13, 21, 15, DT.𝒢 - 2, 13], + [13, 21, 15, DT.𝒢 - 3, 13], + ], + 15 => [ + [14, 21, 20, 16, DT.𝒢 - 2, 14], + [14, 21, 20, 16, DT.𝒢 - 3, 14], + ], + 16 => [ + [15, 20, 2, 3, 17, DT.𝒢 - 2, 15], + [15, 20, 2, 3, 17, DT.𝒢 - 3, 15], + ], + 17 => [ + [16, 3, 4, 18, DT.𝒢 - 2, 16], + [16, 3, 4, 18, DT.𝒢 - 3, 16], + ], + 18 => [ + [17, 4, 5, 24, 13, DT.𝒢 - 2, 17], + [17, 4, 5, 24, 13, DT.𝒢 - 3, 17], + ], + 19 => [[1, 20, 10, 8, 1]], + 20 => [[16, 15, 21, 10, 19, 1, 2, 16]], + 21 => [[15, 14, 13, 23, 11, 10, 20, 15]], + 22 => [[24, 5, 6, 23, 13, 24]], + 23 => [[13, 22, 6, 12, 11, 21, 13]], + 24 => [[18, 5, 22, 13, 18]], + 25 => [[9, 6, 7, 9]], + 26 => [[10, 9, 7, 8, 10]], + DT.𝒢 => [[5, 4, 3, 2, 1, 8, 7, 6, 5]], + DT.𝒢 - 1 => [[9, 10, 11, 12, 9]], + DT.𝒢 - 2 => [[14, 15, 16, 17, 18, 13, 14]], + DT.𝒢 - 3 => [[14, 15, 16, 17, 18, 13, 14]], + ) + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) + fnc_polys[i] = DT.get_surrounding_polygon(tri, i) + push!(fnc_polys[i], fnc_polys[i][begin]) + end + for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) + @test any(DT.circular_equality(S, poly_f) for S in poly_true) + end + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) + fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices = true) + push!(fnc_polys[i], fnc_polys[i][begin]) + end + for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) + @test any(DT.circular_equality(filter(!DT.is_ghost_vertex, S), poly_f) for S in poly_true) + end + + tri2 = example_with_special_corners() + polys = Dict( + 1 => [DT.𝒢, 5, 4, 16, 3, 2, DT.𝒢], + 2 => [DT.𝒢, 1, 3, DT.𝒢], + 3 => [2, 1, 16, 6, 7, DT.𝒢, 2], + 4 => [5, 16, 1, 5], + 5 => [13, 18, 16, 4, 1, DT.𝒢, 13], + 6 => [3, 16, 17, 7, 3], + 7 => [3, 6, 17, 15, 8, DT.𝒢, 3], + 8 => [7, 15, 9, DT.𝒢, 7], + 9 => [8, 15, 11, 10, DT.𝒢, 8], + 10 => [9, 11, 12, 13, DT.𝒢, 9], + 11 => [9, 15, 12, 10, 9], + 12 => [18, 13, 10, 11, 15, 14, 18], + 13 => [10, 12, 18, 5, DT.𝒢, 10], + 14 => [15, 17, 18, 12, 15], + 15 => [8, 7, 17, 14, 12, 11, 9, 8], + 16 => [4, 5, 18, 17, 6, 3, 1, 4], + 17 => [7, 6, 16, 18, 14, 15, 7], + 18 => [5, 13, 12, 14, 17, 16, 5], + ) + for mmm in 1:1000 + local tri, fnc_polys + tri = triangulate(get_points(tri2); delete_ghosts = false) + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) fnc_polys[i] = DT.get_surrounding_polygon(tri, i) push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) - @test any(DT.circular_equality(S, poly_f) for S in poly_true) - end - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) - fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices=true) + end + for (k, S) in polys + @test DT.circular_equality(S, fnc_polys[k]) + end + fnc_polys = Dict{Int, Vector{Int}}() + for i in keys(polys) + fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices = true) push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (poly_true, poly_f) in zip(values(polys), values(fnc_polys)) - @test any(DT.circular_equality(filter(!DT.is_ghost_vertex, S), poly_f) for S in poly_true) - end - - tri2 = example_with_special_corners() - polys = Dict( - 1 => [DT.𝒢, 5, 4, 16, 3, 2, DT.𝒢], - 2 => [DT.𝒢, 1, 3, DT.𝒢], - 3 => [2, 1, 16, 6, 7, DT.𝒢, 2], - 4 => [5, 16, 1, 5], - 5 => [13, 18, 16, 4, 1, DT.𝒢, 13], - 6 => [3, 16, 17, 7, 3], - 7 => [3, 6, 17, 15, 8, DT.𝒢, 3], - 8 => [7, 15, 9, DT.𝒢, 7], - 9 => [8, 15, 11, 10, DT.𝒢, 8], - 10 => [9, 11, 12, 13, DT.𝒢, 9], - 11 => [9, 15, 12, 10, 9], - 12 => [18, 13, 10, 11, 15, 14, 18], - 13 => [10, 12, 18, 5, DT.𝒢, 10], - 14 => [15, 17, 18, 12, 15], - 15 => [8, 7, 17, 14, 12, 11, 9, 8], - 16 => [4, 5, 18, 17, 6, 3, 1, 4], - 17 => [7, 6, 16, 18, 14, 15, 7], - 18 => [5, 13, 12, 14, 17, 16, 5] - ) - for mmm in 1:1000 - local tri, fnc_polys - tri = triangulate(get_points(tri2); delete_ghosts=false) - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) - fnc_polys[i] = DT.get_surrounding_polygon(tri, i) - push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (k, S) in polys - @test DT.circular_equality(S, fnc_polys[k]) - end - fnc_polys = Dict{Int,Vector{Int}}() - for i in keys(polys) - fnc_polys[i] = DT.get_surrounding_polygon(tri, i; skip_ghost_vertices=true) - push!(fnc_polys[i], fnc_polys[i][begin]) - end - for (k, S) in polys - _S = filter(!DT.is_ghost_vertex, S) - DT.is_ghost_vertex(S[begin]) && push!(_S, _S[begin]) # might have removed a boundary index in the first entry, so we'd no longer have a circular array - @test DT.circular_equality(_S, fnc_polys[k]) - end - end + end + for (k, S) in polys + _S = filter(!DT.is_ghost_vertex, S) + DT.is_ghost_vertex(S[begin]) && push!(_S, _S[begin]) # might have removed a boundary index in the first entry, so we'd no longer have a circular array + @test DT.circular_equality(_S, fnc_polys[k]) + end + end end @testset "sort_edge_by_degree" begin - tri = triangulate(rand(2, 500); delete_ghosts=false) - graph = get_graph(tri) - for e in DT.get_edges(graph) - new_e = DT.sort_edge_by_degree(tri, e) - d1 = DT.num_neighbours(graph, e[1]) - d2 = DT.num_neighbours(graph, e[2]) - if d1 ≤ d2 - @test new_e == e - else - @test new_e == (e[2], e[1]) - end - end + tri = triangulate(rand(2, 500); delete_ghosts = false) + graph = get_graph(tri) + for e in DT.get_edges(graph) + new_e = DT.sort_edge_by_degree(tri, e) + d1 = DT.num_neighbours(graph, e[1]) + d2 = DT.num_neighbours(graph, e[2]) + if d1 ≤ d2 + @test new_e == e + else + @test new_e == (e[2], e[1]) + end + end end @testset "split_segment!" begin - constrained_edges = Set{NTuple{2,Int}}(((2, 7),)) - DT.split_segment!(constrained_edges, (2, 7), []) - @test constrained_edges == Set{NTuple{2,Int}}(((2, 7),)) - DT.split_segment!(constrained_edges, (2, 7), [(2, 3), (3, 5), (10, 12)]) - @test constrained_edges == Set{NTuple{2,Int}}(((2, 3), (3, 5), (10, 12))) - DT.split_segment!(constrained_edges, (2, 7), []) - @test constrained_edges == Set{NTuple{2,Int}}(((2, 3), (3, 5), (10, 12))) - DT.split_segment!(constrained_edges, (3, 5), [(2, 10), (11, 15), (2, 3)]) - @test constrained_edges == Set{NTuple{2,Int}}(((2, 3), (2, 10), (11, 15), (10, 12))) - DT.split_segment!(constrained_edges, (3, 2), []) - @test constrained_edges == Set{NTuple{2,Int}}(((2, 3), (2, 10), (11, 15), (10, 12))) - DT.split_segment!(constrained_edges, (3, 2), [(10, 2), (23, 10)]) - @test constrained_edges == Set{NTuple{2,Int}}(((11, 15), (10, 12), (23, 10), (2, 10))) + constrained_edges = Set{NTuple{2, Int}}(((2, 7),)) + DT.split_segment!(constrained_edges, (2, 7), []) + @test constrained_edges == Set{NTuple{2, Int}}(((2, 7),)) + DT.split_segment!(constrained_edges, (2, 7), [(2, 3), (3, 5), (10, 12)]) + @test constrained_edges == Set{NTuple{2, Int}}(((2, 3), (3, 5), (10, 12))) + DT.split_segment!(constrained_edges, (2, 7), []) + @test constrained_edges == Set{NTuple{2, Int}}(((2, 3), (3, 5), (10, 12))) + DT.split_segment!(constrained_edges, (3, 5), [(2, 10), (11, 15), (2, 3)]) + @test constrained_edges == Set{NTuple{2, Int}}(((2, 3), (2, 10), (11, 15), (10, 12))) + DT.split_segment!(constrained_edges, (3, 2), []) + @test constrained_edges == Set{NTuple{2, Int}}(((2, 3), (2, 10), (11, 15), (10, 12))) + DT.split_segment!(constrained_edges, (3, 2), [(10, 2), (23, 10)]) + @test constrained_edges == Set{NTuple{2, Int}}(((11, 15), (10, 12), (23, 10), (2, 10))) end @testset "connect_segments!" begin - C = [(7, 12), (12, 17), (17, 22), (32, 37), (37, 42), (42, 47)] - DT.connect_segments!(C) - @test C == [(7, 12), (12, 17), (17, 22), (22, 32), (32, 37), (37, 42), (42, 47)] - C = [(4, 9), (19, 24), (24, 29), (34, 39), (39, 44), (44, 49)] - DT.connect_segments!(C) - @test C == [(4, 9), (9, 19), (19, 24), (24, 29), (29, 34), (34, 39), (39, 44), (44, 49)] - C = [(4, 9), (9, 5)] - DT.connect_segments!(C) - @test C == [(4, 9), (9, 5)] - C = [(49, 44), (44, 39), (39, 34), (29, 24), (24, 19), (9, 4)] - DT.connect_segments!(C) - @test C == [(49, 44), (44, 39), (39, 34), (34, 29), (29, 24), (24, 19), (19, 9), (9, 4)] + C = [(7, 12), (12, 17), (17, 22), (32, 37), (37, 42), (42, 47)] + DT.connect_segments!(C) + @test C == [(7, 12), (12, 17), (17, 22), (22, 32), (32, 37), (37, 42), (42, 47)] + C = [(4, 9), (19, 24), (24, 29), (34, 39), (39, 44), (44, 49)] + DT.connect_segments!(C) + @test C == [(4, 9), (9, 19), (19, 24), (24, 29), (29, 34), (34, 39), (39, 44), (44, 49)] + C = [(4, 9), (9, 5)] + DT.connect_segments!(C) + @test C == [(4, 9), (9, 5)] + C = [(49, 44), (44, 39), (39, 34), (29, 24), (24, 19), (9, 4)] + DT.connect_segments!(C) + @test C == [(49, 44), (44, 39), (39, 34), (34, 29), (29, 24), (24, 19), (19, 9), (9, 4)] end @testset "extend_segments!" begin - segments = [(7, 12), (12, 17), (17, 22), (22, 27)] - constrained_edge = (7, 27) - DT.extend_segments!(segments, constrained_edge) - @test segments == [(7, 12), (12, 17), (17, 22), (22, 27)] - constrained_edge = (2, 32) - DT.extend_segments!(segments, constrained_edge) - @test segments == [(2, 7), (7, 12), (12, 17), (17, 22), (22, 27), (27, 32)] - segments = [(33, 29)] - constrained_edge = (37, 29) - DT.extend_segments!(segments, constrained_edge) - @test segments == [(37, 33), (33, 29)] - segments = [(29, 33)] - constrained_edge = (29, 37) - DT.extend_segments!(segments, constrained_edge) - @test segments == [(29, 33), (33, 37)] - segments = [(3, 25), (25, 1)] - DT.extend_segments!(segments, (3, 1)) - @test segments == [(3, 25), (25, 1)] + segments = [(7, 12), (12, 17), (17, 22), (22, 27)] + constrained_edge = (7, 27) + DT.extend_segments!(segments, constrained_edge) + @test segments == [(7, 12), (12, 17), (17, 22), (22, 27)] + constrained_edge = (2, 32) + DT.extend_segments!(segments, constrained_edge) + @test segments == [(2, 7), (7, 12), (12, 17), (17, 22), (22, 27), (27, 32)] + segments = [(33, 29)] + constrained_edge = (37, 29) + DT.extend_segments!(segments, constrained_edge) + @test segments == [(37, 33), (33, 29)] + segments = [(29, 33)] + constrained_edge = (29, 37) + DT.extend_segments!(segments, constrained_edge) + @test segments == [(29, 33), (33, 37)] + segments = [(3, 25), (25, 1)] + DT.extend_segments!(segments, (3, 1)) + @test segments == [(3, 25), (25, 1)] end @testset "convert_boundary_points_to_indices" begin - x = [[1.0, 2.0, 3.0, 4.0, 5.0], [5.0, 6.0, 7.0, 8.0], [8.0, 13.0, 15.0, 1.0]] - y = [[0.0, 2.5, 3.0, 9.0, 7.0], [7.0, 9.0, 2.0, 1.0], [1.0, 23.0, 25.0, 0.0]] - nodes, _pts = convert_boundary_points_to_indices(x, y) - @test nodes == [[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 1]] - @test _pts == [(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), - (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0)] - existing_points = [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)] - nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) - @test nodes == [[1, 2, 3, 4, 5] .+ 5, [5, 6, 7, 8] .+ 5, [8, 9, 10, 1] .+ 5] - @test _pts == existing_points == append!( - [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)], - [(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), - (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0)] - ) - nodes, _pts = convert_boundary_points_to_indices([[(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0)], - [(5.0, 7.0), (6.0, 9.0), (7.0, 2.0), (8.0, 1.0)], [(8.0, 1.0), (13.0, 23.0), (15.0, 25.0), (1.0, 0.0)]]) - @test nodes == [[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 1]] - @test _pts == [(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), - (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0)] - existing_points = [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)] - nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) - @test nodes == [[1, 2, 3, 4, 5] .+ 5, [5, 6, 7, 8] .+ 5, [8, 9, 10, 1] .+ 5] - @test _pts == existing_points == append!( - [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)], - [(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), - (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0)] - ) + x = [[1.0, 2.0, 3.0, 4.0, 5.0], [5.0, 6.0, 7.0, 8.0], [8.0, 13.0, 15.0, 1.0]] + y = [[0.0, 2.5, 3.0, 9.0, 7.0], [7.0, 9.0, 2.0, 1.0], [1.0, 23.0, 25.0, 0.0]] + nodes, _pts = convert_boundary_points_to_indices(x, y) + @test nodes == [[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 1]] + @test _pts == [ + (1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), + (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0), + ] + existing_points = [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)] + nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) + @test nodes == [[1, 2, 3, 4, 5] .+ 5, [5, 6, 7, 8] .+ 5, [8, 9, 10, 1] .+ 5] + @test _pts == existing_points == append!( + [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)], + [ + (1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), + (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0), + ], + ) + nodes, _pts = convert_boundary_points_to_indices( + [ + [(1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0)], + [(5.0, 7.0), (6.0, 9.0), (7.0, 2.0), (8.0, 1.0)], [(8.0, 1.0), (13.0, 23.0), (15.0, 25.0), (1.0, 0.0)], + ], + ) + @test nodes == [[1, 2, 3, 4, 5], [5, 6, 7, 8], [8, 9, 10, 1]] + @test _pts == [ + (1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), + (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0), + ] + existing_points = [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)] + nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) + @test nodes == [[1, 2, 3, 4, 5] .+ 5, [5, 6, 7, 8] .+ 5, [8, 9, 10, 1] .+ 5] + @test _pts == existing_points == append!( + [(1.0, 3.0), (15.0, 17.3), (9.3, 2.5), (11.0, 29.0), (35.0, -5.0)], + [ + (1.0, 0.0), (2.0, 2.5), (3.0, 3.0), (4.0, 9.0), (5.0, 7.0), (6.0, 9.0), + (7.0, 2.0), (8.0, 1.0), (13.0, 23.0), (15.0, 25.0), + ], + ) - x1 = [[1.0, 2.0, 3.0], [3.0, 4.0, 5.5, 6.7], [6.7, 2.0, 1.0]] - y1 = [[2.0, 2.5, 3.5], [3.5, 4.5, 7.7, 9.9], [9.9, 1.1, 2.0]] - x2 = [[1.0, 1.2, 1.3, 1.4, 1.5, 1.0]] - y2 = [[2.5, 2.7, 9.9, 2.0, 3.5, 2.5]] - x3 = [[9.5, 13.7, 3.3], [3.3, 5.5, 9.5]] - y3 = [[2.5, 11.7, 3.9], [3.9, 1.0, 2.5]] - x = [x1, x2, x3] - y = [y1, y2, y3] - nodes, _pts = convert_boundary_points_to_indices(x, y) - node1 = [[1, 2, 3], [3, 4, 5, 6], [6, 7, 1]] - node2 = [[8, 9, 10, 11, 12, 8]] - node3 = [[13, 14, 15], [15, 16, 13]] - @test nodes == [node1, node2, node3] - @test _pts == [(1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), + x1 = [[1.0, 2.0, 3.0], [3.0, 4.0, 5.5, 6.7], [6.7, 2.0, 1.0]] + y1 = [[2.0, 2.5, 3.5], [3.5, 4.5, 7.7, 9.9], [9.9, 1.1, 2.0]] + x2 = [[1.0, 1.2, 1.3, 1.4, 1.5, 1.0]] + y2 = [[2.5, 2.7, 9.9, 2.0, 3.5, 2.5]] + x3 = [[9.5, 13.7, 3.3], [3.3, 5.5, 9.5]] + y3 = [[2.5, 11.7, 3.9], [3.9, 1.0, 2.5]] + x = [x1, x2, x3] + y = [y1, y2, y3] + nodes, _pts = convert_boundary_points_to_indices(x, y) + node1 = [[1, 2, 3], [3, 4, 5, 6], [6, 7, 1]] + node2 = [[8, 9, 10, 11, 12, 8]] + node3 = [[13, 14, 15], [15, 16, 13]] + @test nodes == [node1, node2, node3] + @test _pts == [ + (1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), + (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), + (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0), + ] + existing_points = [(1.0, 3.0), (3.5, 5.5), (13.7, 25.0), (19.0, 37.3), (100.0, 100.0), (10.3, 5.5)] + nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) + node1 = [[1, 2, 3] .+ 6, [3, 4, 5, 6] .+ 6, [6, 7, 1] .+ 6] + node2 = [[8, 9, 10, 11, 12, 8] .+ 6] + node3 = [[13, 14, 15] .+ 6, [15, 16, 13] .+ 6] + @test nodes == [node1, node2, node3] + @test _pts == append!( + existing_points, + [ + (1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), - (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0)] - existing_points = [(1.0, 3.0), (3.5, 5.5), (13.7, 25.0), (19.0, 37.3), (100.0, 100.0), (10.3, 5.5)] - nodes, _pts = convert_boundary_points_to_indices(x, y; existing_points) - node1 = [[1, 2, 3] .+ 6, [3, 4, 5, 6] .+ 6, [6, 7, 1] .+ 6] - node2 = [[8, 9, 10, 11, 12, 8] .+ 6] - node3 = [[13, 14, 15] .+ 6, [15, 16, 13] .+ 6] - @test nodes == [node1, node2, node3] - @test _pts == append!( - existing_points, - [(1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), - (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), - (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0)] - ) - xy1 = [[(1.0, 2.0), (2.0, 2.5), (3.0, 3.5)], [(3.0, 3.5), (4.0, 4.5), (5.5, 7.7), (6.7, 9.9)], [(6.7, 9.9), (2.0, 1.1), (1.0, 2.0)]] - xy2 = [[(1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), (1.0, 2.5)]] - xy3 = [[(9.5, 2.5), (13.7, 11.7), (3.3, 3.9)], [(3.3, 3.9), (5.5, 1.0), (9.5, 2.5)]] - xy = [xy1, xy2, xy3] - nodes, _pts = convert_boundary_points_to_indices(xy) - node1 = [[1, 2, 3], [3, 4, 5, 6], [6, 7, 1]] - node2 = [[8, 9, 10, 11, 12, 8]] - node3 = [[13, 14, 15], [15, 16, 13]] - @test nodes == [node1, node2, node3] - @test _pts == [(1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), + (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0), + ], + ) + xy1 = [[(1.0, 2.0), (2.0, 2.5), (3.0, 3.5)], [(3.0, 3.5), (4.0, 4.5), (5.5, 7.7), (6.7, 9.9)], [(6.7, 9.9), (2.0, 1.1), (1.0, 2.0)]] + xy2 = [[(1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), (1.0, 2.5)]] + xy3 = [[(9.5, 2.5), (13.7, 11.7), (3.3, 3.9)], [(3.3, 3.9), (5.5, 1.0), (9.5, 2.5)]] + xy = [xy1, xy2, xy3] + nodes, _pts = convert_boundary_points_to_indices(xy) + node1 = [[1, 2, 3], [3, 4, 5, 6], [6, 7, 1]] + node2 = [[8, 9, 10, 11, 12, 8]] + node3 = [[13, 14, 15], [15, 16, 13]] + @test nodes == [node1, node2, node3] + @test _pts == [ + (1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), + (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), + (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0), + ] + existing_points = [(1.0, 3.0), (3.5, 5.5), (13.7, 25.0), (19.0, 37.3), (100.0, 100.0), (10.3, 5.5)] + nodes, _pts = convert_boundary_points_to_indices(xy; existing_points) + node1 = [[1, 2, 3] .+ 6, [3, 4, 5, 6] .+ 6, [6, 7, 1] .+ 6] + node2 = [[8, 9, 10, 11, 12, 8] .+ 6] + node3 = [[13, 14, 15] .+ 6, [15, 16, 13] .+ 6] + @test nodes == [node1, node2, node3] + @test _pts == append!( + existing_points, + [ + (1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), - (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0)] - existing_points = [(1.0, 3.0), (3.5, 5.5), (13.7, 25.0), (19.0, 37.3), (100.0, 100.0), (10.3, 5.5)] - nodes, _pts = convert_boundary_points_to_indices(xy; existing_points) - node1 = [[1, 2, 3] .+ 6, [3, 4, 5, 6] .+ 6, [6, 7, 1] .+ 6] - node2 = [[8, 9, 10, 11, 12, 8] .+ 6] - node3 = [[13, 14, 15] .+ 6, [15, 16, 13] .+ 6] - @test nodes == [node1, node2, node3] - @test _pts == append!( - existing_points, - [(1.0, 2.0), (2.0, 2.5), (3.0, 3.5), (4.0, 4.5), (5.5, 7.7), - (6.7, 9.9), (2.0, 1.1), (1.0, 2.5), (1.2, 2.7), (1.3, 9.9), (1.4, 2.0), (1.5, 3.5), - (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0)] - ) + (9.5, 2.5), (13.7, 11.7), (3.3, 3.9), (5.5, 1.0), + ], + ) end @testset "get_ordinal_suffix" begin - @test DT.get_ordinal_suffix.(0:115) == [ - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "st" - "nd" - "rd" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - "th" - ] + @test DT.get_ordinal_suffix.(0:115) == [ + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "st" + "nd" + "rd" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + "th" + ] end @testset "fix_segment!" begin - c = [(2, 15), (2, 28), (2, 41), (2, 54)] - bad_indices = [1, 2, 3, 4] - DT.fix_segments!(c, bad_indices) - @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] - c = [(2, 15), (15, 28), (28, 41), (2, 54)] - bad_indices = [1, 4] - DT.fix_segments!(c, bad_indices) - @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] - c = [(2, 15), (15, 28), (2, 41), (41, 54)] - bad_indices = [1, 3] - DT.fix_segments!(c, bad_indices) - @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] - c = [(2, 15), (15, 28), (2, 41), (41, 54)] - bad_indices = [3] - DT.fix_segments!(c, bad_indices) - @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] - c = [(2, 7), (2, 12), (12, 17), (2, 22), (2, 27), (2, 32), (32, 37), (2, 42), (42, 47)] - bad_indices = [2, 4, 5, 6, 8] - DT.fix_segments!(c, bad_indices) - @test c == [(2, 7), (7, 12), (12, 17), (17, 22), (22, 27), (27, 32), (32, 37), (37, 42), (42, 47)] + c = [(2, 15), (2, 28), (2, 41), (2, 54)] + bad_indices = [1, 2, 3, 4] + DT.fix_segments!(c, bad_indices) + @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] + c = [(2, 15), (15, 28), (28, 41), (2, 54)] + bad_indices = [1, 4] + DT.fix_segments!(c, bad_indices) + @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] + c = [(2, 15), (15, 28), (2, 41), (41, 54)] + bad_indices = [1, 3] + DT.fix_segments!(c, bad_indices) + @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] + c = [(2, 15), (15, 28), (2, 41), (41, 54)] + bad_indices = [3] + DT.fix_segments!(c, bad_indices) + @test c == [(2, 15), (15, 28), (28, 41), (41, 54)] + c = [(2, 7), (2, 12), (12, 17), (2, 22), (2, 27), (2, 32), (32, 37), (2, 42), (42, 47)] + bad_indices = [2, 4, 5, 6, 8] + DT.fix_segments!(c, bad_indices) + @test c == [(2, 7), (7, 12), (12, 17), (17, 22), (22, 27), (27, 32), (32, 37), (37, 42), (42, 47)] end @testset "next/previndex_circular" begin - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 1) == 2 - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 2) == 3 - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 3) == 4 - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 4) == 5 - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 5) == 6 - @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 6) == 1 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 1) == 2 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 2) == 3 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 3) == 4 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 4) == 5 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 5) == 6 + @test DT.nextindex_circular([1, 2, 3, 4, 5, 6], 6) == 1 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 1) == 5 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 2) == 1 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 3) == 2 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 4) == 3 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 5) == 4 - @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 6) == 5 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 1) == 5 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 2) == 1 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 3) == 2 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 4) == 3 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 5) == 4 + @test DT.previndex_circular([1, 2, 3, 4, 5, 6], 6) == 5 end @testset "first/last_ghost_vertex" begin - @test DT.is_first_ghost_vertex([1, 2, 3, -1, -5], 4) - @test !DT.is_first_ghost_vertex([1, 2, 3, -1, -5], 5) - @test DT.is_first_ghost_vertex([-1, -2, 5, 4], 1) - @test DT.is_last_ghost_vertex([-1, 5, 4, 6, -2, -1], 1) - @test DT.is_first_ghost_vertex([-1, 2, 3, 4, 5, -6, -1], 6) + @test DT.is_first_ghost_vertex([1, 2, 3, -1, -5], 4) + @test !DT.is_first_ghost_vertex([1, 2, 3, -1, -5], 5) + @test DT.is_first_ghost_vertex([-1, -2, 5, 4], 1) + @test DT.is_last_ghost_vertex([-1, 5, 4, 6, -2, -1], 1) + @test DT.is_first_ghost_vertex([-1, 2, 3, 4, 5, -6, -1], 6) end @testset "get_neighbouring_boundary_edges" begin - tri = fixed_shewchuk_example_constrained() - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (10, 11)) - @test left_e == (11, 7) && right_e == (3, 10) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (11, 7)) - @test left_e == (7, 6) && right_e == (10, 11) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (7, 6)) - @test left_e == (6, 5) && right_e == (11, 7) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (6, 5)) - @test left_e == (5, 4) && right_e == (7, 6) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (5, 4)) - @test left_e == (4, 1) && right_e == (6, 5) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (4, 1)) - @test left_e == (1, 2) && right_e == (5, 4) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (1, 2)) - @test left_e == (2, 3) && right_e == (4, 1) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (2, 3)) - @test left_e == (3, 10) && right_e == (1, 2) - @test DT.get_neighbouring_boundary_edges(tri, (10, 11)) == DT.get_neighbouring_boundary_edges(tri, (11, 10)) - @test DT.get_neighbouring_boundary_edges(tri, (11, 7)) == DT.get_neighbouring_boundary_edges(tri, (7, 11)) - @test DT.get_neighbouring_boundary_edges(tri, (7, 6)) == DT.get_neighbouring_boundary_edges(tri, (6, 7)) - @test DT.get_neighbouring_boundary_edges(tri, (6, 5)) == DT.get_neighbouring_boundary_edges(tri, (5, 6)) - @test DT.get_neighbouring_boundary_edges(tri, (5, 4)) == DT.get_neighbouring_boundary_edges(tri, (4, 5)) - @test DT.get_neighbouring_boundary_edges(tri, (4, 1)) == DT.get_neighbouring_boundary_edges(tri, (1, 4)) - @test DT.get_neighbouring_boundary_edges(tri, (1, 2)) == DT.get_neighbouring_boundary_edges(tri, (2, 1)) - @test DT.get_neighbouring_boundary_edges(tri, (2, 3)) == DT.get_neighbouring_boundary_edges(tri, (3, 2)) + tri = fixed_shewchuk_example_constrained() + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (10, 11)) + @test left_e == (11, 7) && right_e == (3, 10) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (11, 7)) + @test left_e == (7, 6) && right_e == (10, 11) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (7, 6)) + @test left_e == (6, 5) && right_e == (11, 7) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (6, 5)) + @test left_e == (5, 4) && right_e == (7, 6) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (5, 4)) + @test left_e == (4, 1) && right_e == (6, 5) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (4, 1)) + @test left_e == (1, 2) && right_e == (5, 4) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (1, 2)) + @test left_e == (2, 3) && right_e == (4, 1) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (2, 3)) + @test left_e == (3, 10) && right_e == (1, 2) + @test DT.get_neighbouring_boundary_edges(tri, (10, 11)) == DT.get_neighbouring_boundary_edges(tri, (11, 10)) + @test DT.get_neighbouring_boundary_edges(tri, (11, 7)) == DT.get_neighbouring_boundary_edges(tri, (7, 11)) + @test DT.get_neighbouring_boundary_edges(tri, (7, 6)) == DT.get_neighbouring_boundary_edges(tri, (6, 7)) + @test DT.get_neighbouring_boundary_edges(tri, (6, 5)) == DT.get_neighbouring_boundary_edges(tri, (5, 6)) + @test DT.get_neighbouring_boundary_edges(tri, (5, 4)) == DT.get_neighbouring_boundary_edges(tri, (4, 5)) + @test DT.get_neighbouring_boundary_edges(tri, (4, 1)) == DT.get_neighbouring_boundary_edges(tri, (1, 4)) + @test DT.get_neighbouring_boundary_edges(tri, (1, 2)) == DT.get_neighbouring_boundary_edges(tri, (2, 1)) + @test DT.get_neighbouring_boundary_edges(tri, (2, 3)) == DT.get_neighbouring_boundary_edges(tri, (3, 2)) - tri, _, _ = simple_geometry() - add_ghost_triangles!(tri) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (18, 13)) - @test left_e == (13, 14) && right_e == (17, 18) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (13, 14)) - @test left_e == (14, 15) && right_e == (18, 13) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (12, 9)) - @test left_e == (9, 10) && right_e == (11, 12) - left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (5, 4)) - @test left_e == (4, 3) && right_e == (6, 5) + tri, _, _ = simple_geometry() + add_ghost_triangles!(tri) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (18, 13)) + @test left_e == (13, 14) && right_e == (17, 18) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (13, 14)) + @test left_e == (14, 15) && right_e == (18, 13) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (12, 9)) + @test left_e == (9, 10) && right_e == (11, 12) + left_e, right_e = DT.get_neighbouring_boundary_edges(tri, (5, 4)) + @test left_e == (4, 3) && right_e == (6, 5) end @testset "convert_to_edge_adjoining_ghost_vertex" begin - a = (3.0, 3.0) - b = (0.0, 3.0) - c = (0.0, 0.0) - d = (4.0, 0.0) - e = (1.0, 1.5) - pts = [a, b, c, d, e] - tri = triangulate(pts, delete_ghosts=false, randomise=false) - @test DT.convert_to_edge_adjoining_ghost_vertex(tri, (1, 2)) == (2, 1) - @test DT.convert_to_edge_adjoining_ghost_vertex(tri, (2, 1)) == (2, 1) + a = (3.0, 3.0) + b = (0.0, 3.0) + c = (0.0, 0.0) + d = (4.0, 0.0) + e = (1.0, 1.5) + pts = [a, b, c, d, e] + tri = triangulate(pts, delete_ghosts = false, randomise = false) + @test DT.convert_to_edge_adjoining_ghost_vertex(tri, (1, 2)) == (2, 1) + @test DT.convert_to_edge_adjoining_ghost_vertex(tri, (2, 1)) == (2, 1) end @testset "get_shared_vertex" begin - e = (1, 3) - f = (7, 5) - @test DT.get_shared_vertex(e, f) == DT.∅ - @test DT.get_shared_vertex(f, e) == DT.∅ - e = (7, 3) - f = (3, 8) - @test DT.get_shared_vertex(e, f) == 3 - @test DT.get_shared_vertex(f, e) == 3 - f = (9, 7) - @test DT.get_shared_vertex(e, f) == 7 - @test DT.get_shared_vertex(f, e) == 7 + e = (1, 3) + f = (7, 5) + @test DT.get_shared_vertex(e, f) == DT.∅ + @test DT.get_shared_vertex(f, e) == DT.∅ + e = (7, 3) + f = (3, 8) + @test DT.get_shared_vertex(e, f) == 3 + @test DT.get_shared_vertex(f, e) == 3 + f = (9, 7) + @test DT.get_shared_vertex(e, f) == 7 + @test DT.get_shared_vertex(f, e) == 7 end @testset "replace_(boundary/ghost)_triangle_with_(ghost/boundary)_triangle" begin - for _ in 1:10 - tri = triangulate(rand(2, 5000), delete_ghosts=false) - _tri = triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 25, 25, delete_ghosts=false) - for tri in (tri, _tri) - for T in each_ghost_triangle(tri) - T = DT.sort_triangle(T) - i, j, k = triangle_vertices(T) - w = get_adjacent(tri, j, i) - V = (j, i, w) - kr = count(e -> DT.is_boundary_edge(tri, e...), DT.triangle_edges(V)) - kr == 2 && continue # two associated ghosts, test is not clear - @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T - @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == V - V = (i, w, j) - @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T - @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == (j, i, w) - V = (w, j, i) - @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T - @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == (j, i, w) - end + for _ in 1:10 + tri = triangulate(rand(2, 5000), delete_ghosts = false) + _tri = triangulate_rectangle(0.0, 1.0, 0.0, 1.0, 25, 25, delete_ghosts = false) + for tri in (tri, _tri) + for T in each_ghost_triangle(tri) + T = DT.sort_triangle(T) + i, j, k = triangle_vertices(T) + w = get_adjacent(tri, j, i) + V = (j, i, w) + kr = count(e -> DT.is_boundary_edge(tri, e...), DT.triangle_edges(V)) + kr == 2 && continue # two associated ghosts, test is not clear + @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T + @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == V + V = (i, w, j) + @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T + @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == (j, i, w) + V = (w, j, i) + @test DT.replace_boundary_triangle_with_ghost_triangle(tri, V) == T + @test DT.replace_ghost_triangle_with_boundary_triangle(tri, T) == (j, i, w) end - end + end + end end @testset "iterated_neighbourhood" begin - points = NTuple{2,Float64}[] - for i in 1:5 - t = [0.0, π / 2, π, 3π / 2] - push!(points, [(i^2 * cos(t), i^2 * sin(t)) for t in t]...) - end - push!(points, (0.0, 0.0)) - n = DT.num_points(points) - tri = triangulate(points, delete_ghosts=false) + points = NTuple{2, Float64}[] + for i in 1:5 + t = [0.0, π / 2, π, 3π / 2] + push!(points, [(i^2 * cos(t), i^2 * sin(t)) for t in t]...) + end + push!(points, (0.0, 0.0)) + n = DT.num_points(points) + tri = triangulate(points, delete_ghosts = false) - neighbours = DT.iterated_neighbourhood(tri, n, 1) - @test neighbours == filter(!DT.is_ghost_vertex, get_neighbours(tri, n)) - neighbours = DT.iterated_neighbourhood(tri, n, 2) - S1 = get_neighbours(tri, n) - S2 = [get_neighbours(tri, i) for i in S1] - [union!(S1, S) for S in S2] - filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) - @test S1 == neighbours - neighbours = DT.iterated_neighbourhood(tri, n, 3) - S1 = get_neighbours(tri, n) - S2 = [get_neighbours(tri, i) for i in S1] - S3 = [get_neighbours(tri, i) for i in reduce(union, S2)] - [union!(S1, S) for S in S2] - [union!(S1, S) for S in S3] - filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) - @test S1 == neighbours - neighbours = DT.iterated_neighbourhood(tri, n, 4) - S1 = get_neighbours(tri, n) - S2 = [get_neighbours(tri, i) for i in S1] - S3 = [get_neighbours(tri, i) for i in reduce(union, S2)] - S4 = [get_neighbours(tri, i) for i in reduce(union, S3)] - [union!(S1, S) for S in S2] - [union!(S1, S) for S in S3] - [union!(S1, S) for S in S4] - filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) - @test S1 == neighbours + neighbours = DT.iterated_neighbourhood(tri, n, 1) + @test neighbours == filter(!DT.is_ghost_vertex, get_neighbours(tri, n)) + neighbours = DT.iterated_neighbourhood(tri, n, 2) + S1 = get_neighbours(tri, n) + S2 = [get_neighbours(tri, i) for i in S1] + [union!(S1, S) for S in S2] + filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) + @test S1 == neighbours + neighbours = DT.iterated_neighbourhood(tri, n, 3) + S1 = get_neighbours(tri, n) + S2 = [get_neighbours(tri, i) for i in S1] + S3 = [get_neighbours(tri, i) for i in reduce(union, S2)] + [union!(S1, S) for S in S2] + [union!(S1, S) for S in S3] + filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) + @test S1 == neighbours + neighbours = DT.iterated_neighbourhood(tri, n, 4) + S1 = get_neighbours(tri, n) + S2 = [get_neighbours(tri, i) for i in S1] + S3 = [get_neighbours(tri, i) for i in reduce(union, S2)] + S4 = [get_neighbours(tri, i) for i in reduce(union, S3)] + [union!(S1, S) for S in S2] + [union!(S1, S) for S in S3] + [union!(S1, S) for S in S4] + filter!(s -> !(s == n || DT.is_ghost_vertex(s)), S1) + @test S1 == neighbours - tri = triangulate_rectangle(0, 1, 0, 1, 10, 10) - neighbours = DT.iterated_neighbourhood(tri, 1, 3) - @test neighbours == Set(( + tri = triangulate_rectangle(0, 1, 0, 1, 10, 10) + neighbours = DT.iterated_neighbourhood(tri, 1, 3) + @test neighbours == Set( + ( 2, 11, 21, 12, 3, - 31, 22, 13, 4 - )) - neighbours = DT.iterated_neighbourhood!(neighbours, tri, 1, 2) - @test neighbours == Set(( + 31, 22, 13, 4, + ), + ) + neighbours = DT.iterated_neighbourhood!(neighbours, tri, 1, 2) + @test neighbours == Set( + ( 2, 11, - 21, 12, 3 - )) - neighbours = DT.iterated_neighbourhood!(neighbours, tri, 1, 6) - @test neighbours == Set(( + 21, 12, 3, + ), + ) + neighbours = DT.iterated_neighbourhood!(neighbours, tri, 1, 6) + @test neighbours == Set( + ( 2, 11, 21, 12, 3, 31, 22, 13, 4, 41, 32, 23, 14, 5, 51, 42, 33, 24, 15, 6, - 61, 52, 43, 34, 25, 16, 7 - )) - add_ghost_triangles!(tri) - neighbours = DT.iterated_neighbourhood(tri, 1, 3) - @test neighbours == Set(( + 61, 52, 43, 34, 25, 16, 7, + ), + ) + add_ghost_triangles!(tri) + neighbours = DT.iterated_neighbourhood(tri, 1, 3) + @test neighbours == Set( + ( 2, 11, 21, 12, 3, - 31, 22, 13, 4 - )) - neighbours = DT.iterated_neighbourhood(tri, 1, 2) - @test neighbours == Set(( + 31, 22, 13, 4, + ), + ) + neighbours = DT.iterated_neighbourhood(tri, 1, 2) + @test neighbours == Set( + ( 2, 11, - 21, 12, 3 - )) - neighbours = DT.iterated_neighbourhood(tri, 1, 6) - @test neighbours == Set(( + 21, 12, 3, + ), + ) + neighbours = DT.iterated_neighbourhood(tri, 1, 6) + @test neighbours == Set( + ( 2, 11, 21, 12, 3, 31, 22, 13, 4, 41, 32, 23, 14, 5, 51, 42, 33, 24, 15, 6, - 61, 52, 43, 34, 25, 16, 7 - )) + 61, 52, 43, 34, 25, 16, 7, + ), + ) end @testset "getxy" begin - @test DT.getxy((0.3, 0.5)) == (0.3, 0.5) - @test DT.getxy((0.3f0, 0.7f0)) == (Float64(0.3f0), Float64(0.7f0)) + @test DT.getxy((0.3, 0.5)) == (0.3, 0.5) + @test DT.getxy((0.3f0, 0.7f0)) == (Float64(0.3f0), Float64(0.7f0)) end @testset "norm" begin - # test that we avoid underflow - @test DT.norm((1e-300, 1e-300)) ≈ norm([1e-300, 1e-300]) ≈ 1.414213562373095e-300 - @test DT.norm((1e-300, 0.0)) ≈ norm([1e-300, 0.0]) ≈ 1e-300 - @test DT.norm((0.0, 1e-300)) ≈ norm([0.0, 1e-300]) ≈ 1e-300 + # test that we avoid underflow + @test DT.norm((1.0e-300, 1.0e-300)) ≈ norm([1.0e-300, 1.0e-300]) ≈ 1.414213562373095e-300 + @test DT.norm((1.0e-300, 0.0)) ≈ norm([1.0e-300, 0.0]) ≈ 1.0e-300 + @test DT.norm((0.0, 1.0e-300)) ≈ norm([0.0, 1.0e-300]) ≈ 1.0e-300 - # that we avoid overflow - @test DT.norm((1e300, 1e300)) ≈ norm([1e300, 1e300]) ≈ 1.414213562373095e300 - @test DT.norm((1e300, 0.0)) ≈ norm([1e300, 0.0]) ≈ 1e300 - @test DT.norm((0.0, 1e300)) ≈ norm([0.0, 1e300]) ≈ 1e300 + # that we avoid overflow + @test DT.norm((1.0e300, 1.0e300)) ≈ norm([1.0e300, 1.0e300]) ≈ 1.414213562373095e300 + @test DT.norm((1.0e300, 0.0)) ≈ norm([1.0e300, 0.0]) ≈ 1.0e300 + @test DT.norm((0.0, 1.0e300)) ≈ norm([0.0, 1.0e300]) ≈ 1.0e300 - # some other random tests - for _ in 1:10000 - x, y = rand(2) - @test DT.norm((x, y)) ≈ norm((x, y)) ≈ DT.norm((y, x)) - @test DT.norm((x, y))^2 ≈ DT.norm_sqr((x, y)) - end - @inferred DT.norm((1.0, 1.0)) - @inferred DT.norm((1.0f0, 1.0f0)) + # some other random tests + for _ in 1:10000 + x, y = rand(2) + @test DT.norm((x, y)) ≈ norm((x, y)) ≈ DT.norm((y, x)) + @test DT.norm((x, y))^2 ≈ DT.norm_sqr((x, y)) + end + @inferred DT.norm((1.0, 1.0)) + @inferred DT.norm((1.0f0, 1.0f0)) - # specific case - @test DT.dist_sqr((3.0, -1.0), (2.0, 0.0)) == 2.0 + # specific case + @test DT.dist_sqr((3.0, -1.0), (2.0, 0.0)) == 2.0 end @testset "edge_length" begin - tri = triangulate(rand(2, 50)) - for e in each_solid_edge(tri) - @test DT.edge_length(tri, e) ≈ - DT.edge_length(tri, DT.reverse_edge(e)) ≈ - DT.edge_length(tri, e...) ≈ - norm(get_point(tri, e[1]) .- get_point(tri, e[2])) - @test DT.edge_length_sqr(tri, e) ≈ - DT.edge_length_sqr(tri, DT.reverse_edge(e)) ≈ - DT.edge_length_sqr(tri, e...) ≈ - LinearAlgebra.norm_sqr(get_point(tri, e[1]) .- get_point(tri, e[2])) - end + tri = triangulate(rand(2, 50)) + for e in each_solid_edge(tri) + @test DT.edge_length(tri, e) ≈ + DT.edge_length(tri, DT.reverse_edge(e)) ≈ + DT.edge_length(tri, e...) ≈ + norm(get_point(tri, e[1]) .- get_point(tri, e[2])) + @test DT.edge_length_sqr(tri, e) ≈ + DT.edge_length_sqr(tri, DT.reverse_edge(e)) ≈ + DT.edge_length_sqr(tri, e...) ≈ + LinearAlgebra.norm_sqr(get_point(tri, e[1]) .- get_point(tri, e[2])) + end end @testset "midpoint" begin - tri = triangulate(rand(2, 50)) - for e in each_solid_edge(tri) - @test collect(DT.midpoint(tri, e)) ≈ - collect(DT.midpoint(tri, DT.reverse_edge(e))) ≈ - collect(DT.midpoint(tri, e...)) ≈ - 0.5 .* collect((get_point(tri, e[1]) .+ get_point(tri, e[2]))) - end + tri = triangulate(rand(2, 50)) + for e in each_solid_edge(tri) + @test collect(DT.midpoint(tri, e)) ≈ + collect(DT.midpoint(tri, DT.reverse_edge(e))) ≈ + collect(DT.midpoint(tri, e...)) ≈ + 0.5 .* collect((get_point(tri, e[1]) .+ get_point(tri, e[2]))) + end end @testset "check_precision" begin - @test DT.check_precision(sqrt(eps(Float64)) - 1e-32) - @test !DT.check_precision(1.0) - @test DT.check_precision(sqrt(eps(Float64))) + @test DT.check_precision(sqrt(eps(Float64)) - 1.0e-32) + @test !DT.check_precision(1.0) + @test DT.check_precision(sqrt(eps(Float64))) - @test DT.check_absolute_precision(1e-32, 0.0) - @test DT.check_absolute_precision(sqrt(eps(Float64)), 0) - @test !DT.check_absolute_precision(0.5, 2.0) + @test DT.check_absolute_precision(1.0e-32, 0.0) + @test DT.check_absolute_precision(sqrt(eps(Float64)), 0) + @test !DT.check_absolute_precision(0.5, 2.0) - @test !DT.check_relative_precision(1e-32, 0.0) - @test !DT.check_relative_precision(sqrt(eps(Float64)), 0) - @test !DT.check_relative_precision(0, 1e-32) - @test !DT.check_relative_precision(0, sqrt(eps(Float64))) + @test !DT.check_relative_precision(1.0e-32, 0.0) + @test !DT.check_relative_precision(sqrt(eps(Float64)), 0) + @test !DT.check_relative_precision(0, 1.0e-32) + @test !DT.check_relative_precision(0, sqrt(eps(Float64))) - @test DT.check_ratio_precision(1.0, 1.0) - @test !DT.check_ratio_precision(5, 2) - @test !DT.check_ratio_precision(0.0, 1.0) - @test !DT.check_ratio_precision(1.0, 0.0) + @test DT.check_ratio_precision(1.0, 1.0) + @test !DT.check_ratio_precision(5, 2) + @test !DT.check_ratio_precision(0.0, 1.0) + @test !DT.check_ratio_precision(1.0, 0.0) end @testset "get_boundary_chain" begin - rng = StableRNG(123) - points = randn(rng, 2, 250) - tri = triangulate(points; rng) - hull = get_convex_hull_vertices(tri) - chain = DT.get_boundary_chain(tri, 65, 147, -1) - @test DT.circular_equality([chain..., chain[1]], hull) - chain = DT.get_boundary_chain(tri, 199, 96, -1) - @test chain == [199, 151, 96] - chain = DT.get_boundary_chain(tri, 151, 96, -1) - @test chain == [151, 96] + rng = StableRNG(123) + points = randn(rng, 2, 250) + tri = triangulate(points; rng) + hull = get_convex_hull_vertices(tri) + chain = DT.get_boundary_chain(tri, 65, 147, -1) + @test DT.circular_equality([chain..., chain[1]], hull) + chain = DT.get_boundary_chain(tri, 199, 96, -1) + @test chain == [199, 151, 96] + chain = DT.get_boundary_chain(tri, 151, 96, -1) + @test chain == [151, 96] end #= @@ -1421,168 +1466,168 @@ Tuple{Bool, Bool, Tuple{Int64, Int64, Int64}, Vector{Float64}, Int64, In =# @testset "dist" begin - for i in 1:10 - tri = triangulate(rand(StableRNG(i), 2, 500); rng=StableRNG(i + 1)) - for j in 1:10 - p = randn(StableRNG(i * j), 2) - δ = DT.distance_to_polygon(p, get_points(tri), get_convex_hull_vertices(tri)) - V = find_triangle(tri, p) - if DT.is_ghost_triangle(V) - @test δ < 0 - else - @test δ ≥ 0.0 - end - @test δ ≈ DT.dist(tri, p) - end - end - points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), (0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8)] - tri = triangulate(points; boundary_nodes=[[[1, 2, 3, 4, 5, 1]], [[6, 9, 8, 7, 6]]]) - for i in 1:100 - p = randn(StableRNG(i^2), 2) - δ = DT.distance_to_polygon(p, get_points(tri), get_boundary_nodes(tri)) - V = find_triangle(tri, p; rng=StableRNG(i^3), concavity_protection=true) + for i in 1:10 + tri = triangulate(rand(StableRNG(i), 2, 500); rng = StableRNG(i + 1)) + for j in 1:10 + p = randn(StableRNG(i * j), 2) + δ = DT.distance_to_polygon(p, get_points(tri), get_convex_hull_vertices(tri)) + V = find_triangle(tri, p) if DT.is_ghost_triangle(V) - @test δ < 0 + @test δ < 0 else - @test δ ≥ 0.0 + @test δ ≥ 0.0 end @test δ ≈ DT.dist(tri, p) - end + end + end + points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.5, 0.9), (0.0, 1.0), (0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8)] + tri = triangulate(points; boundary_nodes = [[[1, 2, 3, 4, 5, 1]], [[6, 9, 8, 7, 6]]]) + for i in 1:100 + p = randn(StableRNG(i^2), 2) + δ = DT.distance_to_polygon(p, get_points(tri), get_boundary_nodes(tri)) + V = find_triangle(tri, p; rng = StableRNG(i^3), concavity_protection = true) + if DT.is_ghost_triangle(V) + @test δ < 0 + else + @test δ ≥ 0.0 + end + @test δ ≈ DT.dist(tri, p) + end end @testset "adjust_θ" begin - θ₁ = deg2rad(77.4711922908485) - θ₂ = deg2rad(175.2363583092738) - θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, true) - @test (θ₁, θ₂) == (θ₁′, θ₂′) - θ₁′, θ₂′ = DT.adjust_θ(θ₂, θ₁, true) - @test (θ₁′, θ₂′) ⪧ (θ₂, θ₁ + 2π) && θ₂′ - θ₁′ ≈ deg2rad(262.2348339815747) - θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, false) - @test (θ₁′, θ₂′) ⪧ (θ₁, θ₂ - 2π) && θ₂′ - θ₁′ ≈ -deg2rad(360 - 97.7651660184254) - θ₁′, θ₂′ = DT.adjust_θ(θ₂, θ₁, false) - @test (θ₁′, θ₂′) ⪧ (θ₂, θ₁) && θ₂′ - θ₁′ ≈ -deg2rad(97.7651660184254) - for _ in 1:100000 - θ₁, θ₂ = 2π .* rand(2) - θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, rand() < 1 / 2) - @test abs(θ₂′ - θ₁′) ≤ 2π - end + θ₁ = deg2rad(77.4711922908485) + θ₂ = deg2rad(175.2363583092738) + θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, true) + @test (θ₁, θ₂) == (θ₁′, θ₂′) + θ₁′, θ₂′ = DT.adjust_θ(θ₂, θ₁, true) + @test (θ₁′, θ₂′) ⪧ (θ₂, θ₁ + 2π) && θ₂′ - θ₁′ ≈ deg2rad(262.2348339815747) + θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, false) + @test (θ₁′, θ₂′) ⪧ (θ₁, θ₂ - 2π) && θ₂′ - θ₁′ ≈ -deg2rad(360 - 97.7651660184254) + θ₁′, θ₂′ = DT.adjust_θ(θ₂, θ₁, false) + @test (θ₁′, θ₂′) ⪧ (θ₂, θ₁) && θ₂′ - θ₁′ ≈ -deg2rad(97.7651660184254) + for _ in 1:100000 + θ₁, θ₂ = 2π .* rand(2) + θ₁′, θ₂′ = DT.adjust_θ(θ₁, θ₂, rand() < 1 / 2) + @test abs(θ₂′ - θ₁′) ≤ 2π + end end @testset "uniquetol" begin - A = [0.0, 0.1, 0.2, 0.3, 0.4, 0.4 + 1e-16] - B = DT.uniquetol(A) - @test B == [0.0, 0.1, 0.2, 0.3, 0.4] - A = [-5, -4, -3, -3 - 1e-16, 0, 5 - 1e-16, 5 - 1e-14, 5 + 1e-16, 5 + 1e-14, 10, 15 + 1e-16] - sort!(A) - B = DT.uniquetol(A) - @test B == [-5, -4, -3, 0, 5 - 1e-14, 10.0, 15.0] + A = [0.0, 0.1, 0.2, 0.3, 0.4, 0.4 + 1.0e-16] + B = DT.uniquetol(A) + @test B == [0.0, 0.1, 0.2, 0.3, 0.4] + A = [-5, -4, -3, -3 - 1.0e-16, 0, 5 - 1.0e-16, 5 - 1.0e-14, 5 + 1.0e-16, 5 + 1.0e-14, 10, 15 + 1.0e-16] + sort!(A) + B = DT.uniquetol(A) + @test B == [-5, -4, -3, 0, 5 - 1.0e-14, 10.0, 15.0] end @testset "eval_fnc_at_het_tuple_element" begin - global basic_def - f = x -> x isa Number - tup = (1, 2.0, "string", [1 2 3], [5, 7, 9], 0x00, 'A') - basic_def(f, tup, idx) = f(tup[idx]) - DT.eval_fnc_at_het_tuple_element(f, tup, 1) - DT.eval_fnc_at_het_tuple_element(f, tup, 4) - DT.eval_fnc_at_het_tuple_element(f, tup, 7) - basic_def(f, tup, 1) - basic_def(f, tup, 4) - basic_def(f, tup, 7) - a1 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $1) - a2 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $2) - a3 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $3) - a4 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $4) - a5 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $5) - a6 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $6) - a7 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $7) - b1 = @ballocated basic_def($f, $tup, $1) - b2 = @ballocated basic_def($f, $tup, $2) - b3 = @ballocated basic_def($f, $tup, $3) - b4 = @ballocated basic_def($f, $tup, $4) - b5 = @ballocated basic_def($f, $tup, $5) - b6 = @ballocated basic_def($f, $tup, $6) - b7 = @ballocated basic_def($f, $tup, $7) - @test all(iszero, (a1, a2, a3, a4, a5, a6, a7)) - @test all(!iszero, (b1, b2, b3, b4, b5, b6, b7)) - for i in 1:7 - global basic_def - @test DT.eval_fnc_at_het_tuple_element(f, tup, i) == basic_def(f, tup, i) - @inferred DT.eval_fnc_at_het_tuple_element(f, tup, i) - end + global basic_def + f = x -> x isa Number + tup = (1, 2.0, "string", [1 2 3], [5, 7, 9], 0x00, 'A') + basic_def(f, tup, idx) = f(tup[idx]) + DT.eval_fnc_at_het_tuple_element(f, tup, 1) + DT.eval_fnc_at_het_tuple_element(f, tup, 4) + DT.eval_fnc_at_het_tuple_element(f, tup, 7) + basic_def(f, tup, 1) + basic_def(f, tup, 4) + basic_def(f, tup, 7) + a1 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $1) + a2 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $2) + a3 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $3) + a4 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $4) + a5 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $5) + a6 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $6) + a7 = @ballocated DT.eval_fnc_at_het_tuple_element($f, $tup, $7) + b1 = @ballocated basic_def($f, $tup, $1) + b2 = @ballocated basic_def($f, $tup, $2) + b3 = @ballocated basic_def($f, $tup, $3) + b4 = @ballocated basic_def($f, $tup, $4) + b5 = @ballocated basic_def($f, $tup, $5) + b6 = @ballocated basic_def($f, $tup, $6) + b7 = @ballocated basic_def($f, $tup, $7) + @test all(iszero, (a1, a2, a3, a4, a5, a6, a7)) + @test all(!iszero, (b1, b2, b3, b4, b5, b6, b7)) + for i in 1:7 + global basic_def + @test DT.eval_fnc_at_het_tuple_element(f, tup, i) == basic_def(f, tup, i) + @inferred DT.eval_fnc_at_het_tuple_element(f, tup, i) + end end @testset "eval_fnc_in_het_tuple" begin - global basic_def2 - gg1(x) = x - gg2(x) = x^2 - gg3(x) = x^3 - gg4(x) = x^4 - gg5(x) = x^5 - gg6(x) = x^6 - gg7(x) = x^7 - tup = (gg1, gg2, gg3, gg4, gg5, gg6, gg7) - arg = rand() - basic_def2(tup, arg, idx) = tup[idx](arg) - DT.eval_fnc_in_het_tuple(tup, arg, 1) - DT.eval_fnc_in_het_tuple(tup, arg, 4) - DT.eval_fnc_in_het_tuple(tup, arg, 7) - basic_def2(tup, arg, 1) - basic_def2(tup, arg, 4) - basic_def2(tup, arg, 7) - a1 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $1) - a2 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $2) - a3 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $3) - a4 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $4) - a5 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $5) - a6 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $6) - a7 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $7) - b1 = @ballocated basic_def2($tup, $arg, $1) - b2 = @ballocated basic_def2($tup, $arg, $2) - b3 = @ballocated basic_def2($tup, $arg, $3) - b4 = @ballocated basic_def2($tup, $arg, $4) - b5 = @ballocated basic_def2($tup, $arg, $5) - b6 = @ballocated basic_def2($tup, $arg, $6) - b7 = @ballocated basic_def2($tup, $arg, $7) - @test all(iszero, (a1, a2, a3, a4, a5, a6, a7)) - @test all(!iszero, (b1, b2, b3, b4, b5, b6, b7)) - for i in 1:7 - global basic_def2 - @test DT.eval_fnc_in_het_tuple(tup, arg, i) == basic_def2(tup, arg, i) - @inferred DT.eval_fnc_in_het_tuple(tup, arg, i) - @test_throws Exception @inferred basic_def2(tup, arg, i) - end + global basic_def2 + gg1(x) = x + gg2(x) = x^2 + gg3(x) = x^3 + gg4(x) = x^4 + gg5(x) = x^5 + gg6(x) = x^6 + gg7(x) = x^7 + tup = (gg1, gg2, gg3, gg4, gg5, gg6, gg7) + arg = rand() + basic_def2(tup, arg, idx) = tup[idx](arg) + DT.eval_fnc_in_het_tuple(tup, arg, 1) + DT.eval_fnc_in_het_tuple(tup, arg, 4) + DT.eval_fnc_in_het_tuple(tup, arg, 7) + basic_def2(tup, arg, 1) + basic_def2(tup, arg, 4) + basic_def2(tup, arg, 7) + a1 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $1) + a2 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $2) + a3 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $3) + a4 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $4) + a5 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $5) + a6 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $6) + a7 = @ballocated DT.eval_fnc_in_het_tuple($tup, $arg, $7) + b1 = @ballocated basic_def2($tup, $arg, $1) + b2 = @ballocated basic_def2($tup, $arg, $2) + b3 = @ballocated basic_def2($tup, $arg, $3) + b4 = @ballocated basic_def2($tup, $arg, $4) + b5 = @ballocated basic_def2($tup, $arg, $5) + b6 = @ballocated basic_def2($tup, $arg, $6) + b7 = @ballocated basic_def2($tup, $arg, $7) + @test all(iszero, (a1, a2, a3, a4, a5, a6, a7)) + @test all(!iszero, (b1, b2, b3, b4, b5, b6, b7)) + for i in 1:7 + global basic_def2 + @test DT.eval_fnc_in_het_tuple(tup, arg, i) == basic_def2(tup, arg, i) + @inferred DT.eval_fnc_in_het_tuple(tup, arg, i) + @test_throws Exception @inferred basic_def2(tup, arg, i) + end end @testset "eval_fnc_at_het_tuple_two_elements" begin - global fft - global basic_defft - fft(x, y) = objectid(x) + objectid(y) - tup = (1, 2.0, "string", [1 2 3], [5, 7, 9], 0x00, 'A') - basic_defft(f, tup, idx, idx2) = f(tup[idx], tup[idx2]) - DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 1, 4) - DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 4, 3) - DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 2, 5) - basic_defft(fft, tup, 1, 4) - basic_defft(fft, tup, 4, 3) - basic_defft(fft, tup, 2, 5) - a = zeros(length(tup), length(tup)) - b = similar(a) - for i in eachindex(tup) - for j in eachindex(tup) - global fft - global basic_defft - a[i, j] = @allocated DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) - b[i, j] = @allocated basic_defft(fft, tup, i, j) - @test DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) == basic_defft(fft, tup, i, j) - @inferred DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) - end - end - @test all(iszero, a .- 16) || all(iszero, a) - @test all(!iszero, b) + global fft + global basic_defft + fft(x, y) = objectid(x) + objectid(y) + tup = (1, 2.0, "string", [1 2 3], [5, 7, 9], 0x00, 'A') + basic_defft(f, tup, idx, idx2) = f(tup[idx], tup[idx2]) + DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 1, 4) + DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 4, 3) + DT.eval_fnc_at_het_tuple_two_elements(fft, tup, 2, 5) + basic_defft(fft, tup, 1, 4) + basic_defft(fft, tup, 4, 3) + basic_defft(fft, tup, 2, 5) + a = zeros(length(tup), length(tup)) + b = similar(a) + for i in eachindex(tup) + for j in eachindex(tup) + global fft + global basic_defft + a[i, j] = @allocated DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) + b[i, j] = @allocated basic_defft(fft, tup, i, j) + @test DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) == basic_defft(fft, tup, i, j) + @inferred DT.eval_fnc_at_het_tuple_two_elements(fft, tup, i, j) + end + end + @test all(iszero, a .- 16) || all(iszero, a) + @test all(!iszero, b) end @testset "_to_val" begin - @test DT._to_val(2) == Val(2) - @test DT._to_val(Val(2)) == Val(2) -end \ No newline at end of file + @test DT._to_val(2) == Val(2) + @test DT._to_val(Val(2)) == Val(2) +end diff --git a/test/voronoi/voronoi.jl b/test/voronoi/voronoi.jl index b4514d376..a8b5a2f97 100644 --- a/test/voronoi/voronoi.jl +++ b/test/voronoi/voronoi.jl @@ -21,7 +21,7 @@ using Preferences F = (1.0, 4.0) G = (-3.0, 5.0) pts = [A, B, C, D, E, F, G] - tri = triangulate(pts; delete_ghosts=false, randomise=false) + tri = triangulate(pts; delete_ghosts = false, randomise = false) vorn = voronoi(tri) for (i, p) in DT.get_generators(vorn) @@ -51,45 +51,59 @@ using Preferences @test isempty(DT.get_boundary_polygons(vorn)) @test DT.circular_equality( get_polygon(vorn, 1), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (7, 4, 1), (4, 6, 1), (6, 2, 1), (1, 2, -1), (7, 1, -1), (7, 4, 1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (7, 4, 1), (4, 6, 1), (6, 2, 1), (1, 2, -1), (7, 1, -1), (7, 4, 1), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 2), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (2, 5, -1), (1, 2, -1), (6, 2, 1), (6, 5, 2), (2, 5, -1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (2, 5, -1), (1, 2, -1), (6, 2, 1), (6, 5, 2), (2, 5, -1), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 3), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (5, 3, -1), (5, 4, 3), (4, 7, 3), (3, 7, -1), (5, 3, -1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (5, 3, -1), (5, 4, 3), (4, 7, 3), (3, 7, -1), (5, 3, -1), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 4), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (5, 6, 4), (4, 6, 1), (7, 4, 1), (4, 7, 3), (5, 4, 3), (5, 6, 4) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (5, 6, 4), (4, 6, 1), (7, 4, 1), (4, 7, 3), (5, 4, 3), (5, 6, 4), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 5), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (6, 5, 2), (5, 6, 4), (5, 4, 3), (5, 3, -1), (2, 5, -1), (6, 5, 2) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (6, 5, 2), (5, 6, 4), (5, 4, 3), (5, 3, -1), (2, 5, -1), (6, 5, 2), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 6), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (6, 5, 2), (6, 2, 1), (4, 6, 1), (5, 6, 4), (6, 5, 2) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (6, 5, 2), (6, 2, 1), (4, 6, 1), (5, 6, 4), (6, 5, 2), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 7), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (7, 4, 1), (7, 1, -1), (3, 7, -1), (4, 7, 3), (7, 4, 1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (7, 4, 1), (7, 1, -1), (3, 7, -1), (4, 7, 3), (7, 4, 1), + ], + ), ) end end @@ -110,61 +124,89 @@ end c6 = DT.get_polygon_coordinates(vorn, 6, bbox) c7 = DT.get_polygon_coordinates(vorn, 7, bbox) @test all(DT.is_circular, (c1, c2, c3, c4, c5, c6, c7)) - @test DT.circular_equality(collect.(c1), collect.([ - (-1.5, 0.5) - (0.166666666666, -1.1666666666666665) - (1.0, 0.5) - (1.0, 3.0) - (-1.5, 0.5) - ]), ≈) - @test DT.circular_equality(collect.(c2), collect.([ - (0.5, -3.2) - (5.7, -3.2) - (5.7, -1.700000000000001) - (3.5, 0.5) - (0.5, -2.5) - (0.5, -3.2) - ]), ≈) - @test DT.circular_equality(collect.(c3), collect.([ - (3.5, 0.5) - (1.0, 0.5) - (0.16666666666666666, -1.1666666666666665) - (0.5, -2.5) - (3.5, 0.5) - ]), ≈) - @test DT.circular_equality(collect.(c4), collect.([ - (1.5, 5.2) - (-2.7, 5.2) - (-2.7, 0.9000000000000001) - (-1.5, 0.5) - (1.0, 3.0) - (1.5, 4.5) - (1.5, 5.2) - ]), ≈) - @test DT.circular_equality(collect.(c5), collect.([ - (1.5, 4.5) - (3.5, 0.5) - (5.7, 2.6999999999999997) - (5.7, 5.2) - (1.5, 5.2) - (1.5, 4.5) - ]), ≈) - @test DT.circular_equality(collect.(c6), collect.([ - (-2.7, 0.9000000000000001) - (-2.7, -3.2) - (0.5, -3.2) - (0.5, -2.5) - (0.16666666666666666, -1.1666666666666665) - (-1.5, 0.5) - (-2.7, 0.9000000000000001) - ]), ≈) - @test DT.circular_equality(collect.(c7), collect.([ - (1.5, 4.5) - (1.0, 3.0) - (1.0, 0.5) - (3.5, 0.5) - (1.5, 4.5) - ]), ≈) + @test DT.circular_equality( + collect.(c1), collect.( + [ + (-1.5, 0.5) + (0.166666666666, -1.1666666666666665) + (1.0, 0.5) + (1.0, 3.0) + (-1.5, 0.5) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c2), collect.( + [ + (0.5, -3.2) + (5.7, -3.2) + (5.7, -1.700000000000001) + (3.5, 0.5) + (0.5, -2.5) + (0.5, -3.2) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c3), collect.( + [ + (3.5, 0.5) + (1.0, 0.5) + (0.16666666666666666, -1.1666666666666665) + (0.5, -2.5) + (3.5, 0.5) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c4), collect.( + [ + (1.5, 5.2) + (-2.7, 5.2) + (-2.7, 0.9000000000000001) + (-1.5, 0.5) + (1.0, 3.0) + (1.5, 4.5) + (1.5, 5.2) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c5), collect.( + [ + (1.5, 4.5) + (3.5, 0.5) + (5.7, 2.6999999999999997) + (5.7, 5.2) + (1.5, 5.2) + (1.5, 4.5) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c6), collect.( + [ + (-2.7, 0.9000000000000001) + (-2.7, -3.2) + (0.5, -3.2) + (0.5, -2.5) + (0.16666666666666666, -1.1666666666666665) + (-1.5, 0.5) + (-2.7, 0.9000000000000001) + ], + ), ≈, + ) + @test DT.circular_equality( + collect.(c7), collect.( + [ + (1.5, 4.5) + (1.0, 3.0) + (1.0, 0.5) + (3.5, 0.5) + (1.5, 4.5) + ], + ), ≈, + ) end end @@ -178,36 +220,36 @@ end F = (1.0, 4.0) G = (-3.0, 5.0) pts = [A, B, C, D, E, F, G] - tri = triangulate(pts; delete_ghosts=false, randomise=false) + tri = triangulate(pts; delete_ghosts = false, randomise = false) vorn = voronoi(tri) @test get_adjacent(vorn, 1, -2) == get_adjacent(vorn, -2, -1) == - get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == - 5 + get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == + 5 DT.delete_polygon_adjacent!(vorn, 5) @test get_adjacent(vorn, 1, -2) == get_adjacent(vorn, -2, -1) == - get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == - DT.∅ + get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == + DT.∅ DT.add_polygon_adjacent!(vorn, 5) @test get_adjacent(vorn, 1, -2) == get_adjacent(vorn, -2, -1) == - get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == - 5 + get_adjacent(vorn, -1, 7) == get_adjacent(vorn, 7, 3) == get_adjacent(vorn, 3, 1) == + 5 end end @testset "Voronoi point location" begin - A = (-1.0, 7.0) .+ (1e-6rand(), 1e-6rand()) # perturb to allow the tests to work even without ExactPredicates - B = (4.0, 4.0) .+ (1e-6rand(), 1e-6rand()) - C = (-2.0, -1.0) .+ (1e-6rand(), 1e-6rand()) - D = (-1.0, 3.0) .+ (1e-6rand(), 1e-6rand()) - E = (3.0, -1.0) .+ (1e-6rand(), 1e-6rand()) - F = (1.0, 4.0) .+ (1e-6rand(), 1e-6rand()) - G = (-3.0, 5.0) .+ (1e-6rand(), 1e-6rand()) + A = (-1.0, 7.0) .+ (1.0e-6rand(), 1.0e-6rand()) # perturb to allow the tests to work even without ExactPredicates + B = (4.0, 4.0) .+ (1.0e-6rand(), 1.0e-6rand()) + C = (-2.0, -1.0) .+ (1.0e-6rand(), 1.0e-6rand()) + D = (-1.0, 3.0) .+ (1.0e-6rand(), 1.0e-6rand()) + E = (3.0, -1.0) .+ (1.0e-6rand(), 1.0e-6rand()) + F = (1.0, 4.0) .+ (1.0e-6rand(), 1.0e-6rand()) + G = (-3.0, 5.0) .+ (1.0e-6rand(), 1.0e-6rand()) pts = [A, B, C, D, E, F, G] - tri = triangulate(pts; delete_ghosts=false, randomise=false) + tri = triangulate(pts; delete_ghosts = false, randomise = false) vor = voronoi(tri) @test validate_tessellation(vor) xmin, xmax, ymin, ymax = DT.polygon_bounds(get_points(tri), get_convex_hull_vertices(tri)) - p = NTuple{2,Float64}[] + p = NTuple{2, Float64}[] n = 100000 while length(p) ≤ n # only going to test points that are inside the polygon pt = (xmin + rand() * (xmax - xmin), ymin + rand() * (ymax - ymin)) @@ -228,9 +270,9 @@ end (0.1, -1.0), (-0.8, -1.0), (-1.0, -1.0), (-1.0, -0.7), (-1.0, -0.1), (-1.0, 0.6), (-0.1, -0.8), (0.2, -0.8), - (-0.6, -0.4), (0.9, 0.0), (-0.5, 0.5), (-0.4, 0.6), (-0.1, 0.8) + (-0.6, -0.4), (0.9, 0.0), (-0.5, 0.5), (-0.4, 0.6), (-0.1, 0.8), ] - tri = triangulate(points, delete_ghosts=false) + tri = triangulate(points, delete_ghosts = false) vorn = voronoi(tri) @test validate_tessellation(vorn) xg = LinRange(-1, 1, 250) @@ -245,7 +287,7 @@ end k = findmin(all_dists)[2] @test k == u for m in DT.each_point_index(tri) - u = get_nearest_neighbour(vorn, p, try_points=m) + u = get_nearest_neighbour(vorn, p, try_points = m) @test u == k end end @@ -262,9 +304,9 @@ end F = (1.0, 4.0) G = (-3.0, 5.0) pts = [A, B, C, D, E, F, G] - tri = triangulate(pts; delete_ghosts=false, randomise=true) + tri = triangulate(pts; delete_ghosts = false, randomise = true) #lock_convex_hull!(tri) - vorn = voronoi(tri; clip=true) + vorn = voronoi(tri; clip = true) for (i, p) in DT.get_generators(vorn) @test get_point(tri, i) == get_generator(vorn, i) == p end @@ -288,25 +330,29 @@ end @test DT.get_circumcenter_to_triangle(vorn, c) == V @test DT.get_triangle_to_circumcenter(vorn, V) == c end - orig_pt = collect.([(0.5, 0.5) - (2.5, 7.166666666666667) - (1.1666666666666665, 1.1666666666666667) - (-4.3, 1.7000000000000002) - (-1.0, 5.0) - (-0.75, 5.0) - (2.5, 1.7000000000000002) - (0.5, -1.0) - (3.5, 1.5) - (3.0, -1.0) - (-2.7142857142857144, 3.2857142857142856) - (-2.369565217391304, 1.2173913043478262) - (2.5000000000000004, 4.8999999999999995) - (0.7105263157894739, 5.973684210526315) - (-2.0, 6.0) - (-3.0, 5.0) - (4.0, 4.0) - (-2.0, -1.0) - (-1.0, 7.0)]) + orig_pt = collect.( + [ + (0.5, 0.5) + (2.5, 7.166666666666667) + (1.1666666666666665, 1.1666666666666667) + (-4.3, 1.7000000000000002) + (-1.0, 5.0) + (-0.75, 5.0) + (2.5, 1.7000000000000002) + (0.5, -1.0) + (3.5, 1.5) + (3.0, -1.0) + (-2.7142857142857144, 3.2857142857142856) + (-2.369565217391304, 1.2173913043478262) + (2.5000000000000004, 4.8999999999999995) + (0.7105263157894739, 5.973684210526315) + (-2.0, 6.0) + (-3.0, 5.0) + (4.0, 4.0) + (-2.0, -1.0) + (-1.0, 7.0) + ], + ) @test validate_tessellation(vorn) @test isempty(DT.get_unbounded_polygons(vorn)) @test all([0 ≤ get_area(vorn, i) < Inf for i in each_polygon_index(vorn)]) @@ -322,7 +368,7 @@ end C = get_polygon(vorn, i) for (j, v) in pairs(C) δ = DT.distance_to_polygon(get_polygon_point(vorn, v), get_points(tri), get_convex_hull_vertices(tri)) - @test δ ≥ -1e-15 + @test δ ≥ -1.0e-15 end end end @@ -331,7 +377,7 @@ end @testset "Another example" begin for _ in 1:100 tri = fixed_shewchuk_example_constrained() - vorn = voronoi(tri; clip=false) + vorn = voronoi(tri; clip = false) @test validate_tessellation(vorn) for (i, p) in DT.get_generators(vorn) @test get_point(tri, i) == get_generator(vorn, i) == p @@ -359,66 +405,86 @@ end end @test DT.circular_equality( get_polygon(vorn, 1), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (4, 2, 1), (1, 2, -1), (4, 1, -1), (4, 2, 1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (4, 2, 1), (1, 2, -1), (4, 1, -1), (4, 2, 1), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 2), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (4, 2, 1), (4, 3, 2), (2, 3, -1), (1, 2, -1), (4, 2, 1) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (4, 2, 1), (4, 3, 2), (2, 3, -1), (1, 2, -1), (4, 2, 1), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 3), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (4, 3, 2), (4, 10, 3), (3, 10, -1), (2, 3, -1), (4, 3, 2) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (4, 3, 2), (4, 10, 3), (3, 10, -1), (2, 3, -1), (4, 3, 2), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 4), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (5, 9, 4), (9, 10, 4), (4, 10, 3), (4, 3, 2), (4, 2, 1), (4, 1, -1), (5, 4, -1), (5, 9, 4) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (5, 9, 4), (9, 10, 4), (4, 10, 3), (4, 3, 2), (4, 2, 1), (4, 1, -1), (5, 4, -1), (5, 9, 4), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 5), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (6, 8, 5), (8, 10, 5), (10, 9, 5), (5, 9, 4), (5, 4, -1), (6, 5, -1), (6, 8, 5) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (6, 8, 5), (8, 10, 5), (10, 9, 5), (5, 9, 4), (5, 4, -1), (6, 5, -1), (6, 8, 5), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 6), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (7, 8, 6), (6, 8, 5), (6, 5, -1), (7, 6, -1), (7, 8, 6) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (7, 8, 6), (6, 8, 5), (6, 5, -1), (7, 6, -1), (7, 8, 6), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 7), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (11, 8, 7), (7, 8, 6), (7, 6, -1), (11, 7, -1), (11, 8, 7) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (11, 8, 7), (7, 8, 6), (7, 6, -1), (11, 7, -1), (11, 8, 7), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 8), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (7, 8, 6), (11, 8, 7), (11, 10, 8), (8, 10, 5), (6, 8, 5), (7, 8, 6) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (7, 8, 6), (11, 8, 7), (11, 10, 8), (8, 10, 5), (6, 8, 5), (7, 8, 6), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 9), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (10, 9, 5), (9, 10, 4), (5, 9, 4), (10, 9, 5) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (10, 9, 5), (9, 10, 4), (5, 9, 4), (10, 9, 5), + ], + ), ) @test DT.circular_equality( get_polygon(vorn, 10), - DT.get_triangle_to_circumcenter.(Ref(vorn), [ - (9, 10, 4), (10, 9, 5), (8, 10, 5), (11, 10, 8), (10, 11, -1), (3, 10, -1), (4, 10, 3), (9, 10, 4) - ]) + DT.get_triangle_to_circumcenter.( + Ref(vorn), [ + (9, 10, 4), (10, 9, 5), (8, 10, 5), (11, 10, 8), (10, 11, -1), (3, 10, -1), (4, 10, 3), (9, 10, 4), + ], + ), ) - _vorn = voronoi(tri; clip=true) + _vorn = voronoi(tri; clip = true) @test validate_tessellation(_vorn) for (i, p) in DT.get_generators(_vorn) @test get_point(tri, i) == get_generator(_vorn, i) == p @@ -507,30 +573,30 @@ end d = (4.0, 0.0) e = (2.0, 1.5) pts = [a, b, c, d, e] - tri = triangulate(pts, delete_ghosts=false, randomise=false) + tri = triangulate(pts, delete_ghosts = false, randomise = false) vorn = voronoi(tri) lock_convex_hull!(tri) edges_to_process, - polygon_edge_queue, - boundary_sites, - segment_intersections, - processed_pairs, - intersected_edge_cache, - exterior_circumcenters, - left_edge_intersectors, - right_edge_intersectors, - current_edge_intersectors, - equal_circumcenter_mapping = DT.initialise_clipping_arrays(vorn) + polygon_edge_queue, + boundary_sites, + segment_intersections, + processed_pairs, + intersected_edge_cache, + exterior_circumcenters, + left_edge_intersectors, + right_edge_intersectors, + current_edge_intersectors, + equal_circumcenter_mapping = DT.initialise_clipping_arrays(vorn) @test edges_to_process == Set(((1, 2), (4, 1), (3, 4), (2, 3))) - @test polygon_edge_queue == DT.Queue{Tuple{NTuple{2,Int},Int}}() - @test boundary_sites == Dict{Int,Set{Int}}() - @test segment_intersections == NTuple{2,Int}[] - @test processed_pairs == Set{Tuple{NTuple{2,Int},Int}}() - @test intersected_edge_cache == Pair{NTuple{2,Int},NTuple{2,Int}}[] - @test left_edge_intersectors == Set{NTuple{2,Int}}() - @test right_edge_intersectors == Set{NTuple{2,Int}}() - @test current_edge_intersectors == Set{NTuple{2,Int}}() - @test equal_circumcenter_mapping == Dict{Int,Int}() + @test polygon_edge_queue == DT.Queue{Tuple{NTuple{2, Int}, Int}}() + @test boundary_sites == Dict{Int, Set{Int}}() + @test segment_intersections == NTuple{2, Int}[] + @test processed_pairs == Set{Tuple{NTuple{2, Int}, Int}}() + @test intersected_edge_cache == Pair{NTuple{2, Int}, NTuple{2, Int}}[] + @test left_edge_intersectors == Set{NTuple{2, Int}}() + @test right_edge_intersectors == Set{NTuple{2, Int}}() + @test current_edge_intersectors == Set{NTuple{2, Int}}() + @test equal_circumcenter_mapping == Dict{Int, Int}() end @testset "enqueue_new_edge" begin @@ -541,7 +607,7 @@ end d = (4.0, 0.0) e = (1.0, 1.5) pts = [a, b, c, d, e] - tri = triangulate(pts, delete_ghosts=false) + tri = triangulate(pts, delete_ghosts = false) vorn = voronoi(tri) lock_convex_hull!(tri) edges_to_process, polygon_edge_queue = DT.initialise_clipping_arrays(vorn) @@ -581,7 +647,7 @@ end @testset "add_to_intersected_edge_cache" begin u, v, a, b = 1, 7, 5, 9 - intersected_edge_cache = Pair{NTuple{2,Int},NTuple{2,Int}}[] + intersected_edge_cache = Pair{NTuple{2, Int}, NTuple{2, Int}}[] DT.add_to_intersected_edge_cache!(intersected_edge_cache, u, v, a, b) @test intersected_edge_cache == [(u, v) => (a, b)] u, v, a, b = -2, 5, 10, 17 @@ -596,20 +662,20 @@ end d = (4.0, 0.0) e = (1.0, 1.5) pts = [a, b, c, d, e] - tri = triangulate(pts, delete_ghosts=false, randomise=false) + tri = triangulate(pts, delete_ghosts = false, randomise = false) vorn = voronoi(tri) lock_convex_hull!(tri) edges_to_process, - polygon_edge_queue, - boundary_sites, - segment_intersections, - processed_pairs, - intersected_edge_cache, - exterior_circumcenters, - left_edge_intersectors, - right_edge_intersectors, - current_edge_intersectors, - equal_circumcenter_mapping = DT.initialise_clipping_arrays(vorn) + polygon_edge_queue, + boundary_sites, + segment_intersections, + processed_pairs, + intersected_edge_cache, + exterior_circumcenters, + left_edge_intersectors, + right_edge_intersectors, + current_edge_intersectors, + equal_circumcenter_mapping = DT.initialise_clipping_arrays(vorn) e = DT.convert_to_edge_adjoining_ghost_vertex(vorn, first(edges_to_process)) DT.enqueue_new_edge!(polygon_edge_queue, vorn, e) @@ -658,15 +724,17 @@ end @test intersected_edge_cache == [(-3, 3) => e, (u, v) => right_edge] DT.classify_intersections!(intersected_edge_cache, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, left_edge, right_edge, e) - @test left_edge_intersectors == Set{NTuple{2,Int}}() + @test left_edge_intersectors == Set{NTuple{2, Int}}() @test right_edge_intersectors == Set([(u, v)]) @test current_edge_intersectors == Set([(-3, 3)]) - DT.process_intersection_points!(polygon_edge_queue, vorn, incident_polygon, + DT.process_intersection_points!( + polygon_edge_queue, vorn, incident_polygon, left_edge_intersectors, right_edge_intersectors, current_edge_intersectors, - left_edge, right_edge, e, processed_pairs, segment_intersections, boundary_sites) + left_edge, right_edge, e, processed_pairs, segment_intersections, boundary_sites, + ) - _queue = DT.Queue{Tuple{NTuple{2,Int},Int}}() + _queue = DT.Queue{Tuple{NTuple{2, Int}, Int}}() push!(_queue, ((3, 2), 3)) push!(_queue, ((3, 2), 2)) push!(_queue, ((3, 2), 5)) @@ -679,22 +747,24 @@ end d = (4.0, 0.0) e = (1.0, 1.5) pts = [a, b, c, d, e] - tri = triangulate(pts, delete_ghosts=false, randomise=false) + tri = triangulate(pts, delete_ghosts = false, randomise = false) vorn = voronoi(tri) lock_convex_hull!(tri) boundary_sites, segment_intersections, exterior_circumcenters = DT.find_all_intersections(vorn) - @test collect.(segment_intersections) ≈ collect.([ - (1.5, 3.0) - (0.0, 1.9166666666666665) - (0.0, 3.0) - (0.0, 1.0833333333333333) - (1.625, 0.0) - (0.0, 0.0) - (2.125, 0.0) - (3.5, 1.5) - (3.0, 3.0) - (4.0, 0.0) - ]) + @test collect.(segment_intersections) ≈ collect.( + [ + (1.5, 3.0) + (0.0, 1.9166666666666665) + (0.0, 3.0) + (0.0, 1.0833333333333333) + (1.625, 0.0) + (0.0, 0.0) + (2.125, 0.0) + (3.5, 1.5) + (3.0, 3.0) + (4.0, 0.0) + ], + ) @test boundary_sites[4] == Set((7, 10, 8)) @test boundary_sites[2] == Set((2, 3, 1)) @test boundary_sites[1] == Set((9, 8, 1)) @@ -706,28 +776,30 @@ end @test isempty(vorn.unbounded_polygons) @test validate_tessellation(vorn) @test DT.points_are_unique(vorn.polygon_points) - @test collect.(DT.get_polygon_points(vorn)) ≈ collect.([ - (2.0, -0.25) - (-0.625, 1.5) - (1.5, 2.9166666666666665) - (2.75, 1.25) - (1.5, 3.0) - (0.0, 1.9166666666666665) - (0.0, 3.0) - (0.0, 1.0833333333333333) - (1.625, 0.0) - (0.0, 0.0) - (2.125, 0.0) - (3.5, 1.5) - (3.0, 3.0) - (4.0, 0.0) - ]) + @test collect.(DT.get_polygon_points(vorn)) ≈ collect.( + [ + (2.0, -0.25) + (-0.625, 1.5) + (1.5, 2.9166666666666665) + (2.75, 1.25) + (1.5, 3.0) + (0.0, 1.9166666666666665) + (0.0, 3.0) + (0.0, 1.0833333333333333) + (1.625, 0.0) + (0.0, 0.0) + (2.125, 0.0) + (3.5, 1.5) + (3.0, 3.0) + (4.0, 0.0) + ], + ) @test vorn.polygons == Dict( 5 => [8, 9, 11, 4, 3, 6, 8], 4 => [11, 14, 12, 4, 11], 2 => [6, 3, 5, 7, 6], 3 => [10, 9, 8, 10], - 1 => [4, 12, 13, 5, 3, 4] + 1 => [4, 12, 13, 5, 3, 4], ) @test DT.get_boundary_polygons(vorn) == Set((4, 2, 1, 3, 5)) end @@ -738,7 +810,7 @@ end tri = triangulate(points) vorn = voronoi(tri) @test validate_tessellation(vorn) - vorn = voronoi(tri, clip=true) + vorn = voronoi(tri, clip = true) @test validate_tessellation(vorn) @test vorn.polygon_points == [ (0.5, 0.5), @@ -747,7 +819,7 @@ end (0.0, 0.5), (1.0, 0.0), (0.0, 1.0), - (0.0, 0.0) + (0.0, 0.0), ] end @@ -756,25 +828,29 @@ end 0.290978 0.830755 0.0139574 0.386411 0.630008 0.803881 ] - tri = triangulate(points, delete_ghosts=false) - vorn = voronoi(tri, clip=true) + tri = triangulate(points, delete_ghosts = false) + vorn = voronoi(tri, clip = true) @test validate_tessellation(vorn) - @test collect.(sort(vorn.polygon_points)) ≈ collect.(sort([ - (0.43655799581398663, 0.7836598194374879) - (0.5608665, 0.5082095) - (0.4713751999728193, 0.7065097477648392) - (0.1524677, 0.595146) - (0.35698797851173, 0.7308595369379512) - (0.830755, 0.630008) - (0.0139574, 0.803881) - (0.290978, 0.386411) - ])) + @test collect.(sort(vorn.polygon_points)) ≈ collect.( + sort( + [ + (0.43655799581398663, 0.7836598194374879) + (0.5608665, 0.5082095) + (0.4713751999728193, 0.7065097477648392) + (0.1524677, 0.595146) + (0.35698797851173, 0.7308595369379512) + (0.830755, 0.630008) + (0.0139574, 0.803881) + (0.290978, 0.386411) + ], + ), + ) end for _ in 1:1000 pts = rand(2, 3) tri = triangulate(pts) - vorn = voronoi(tri, clip=true) + vorn = voronoi(tri, clip = true) @test validate_tessellation(vorn) end end @@ -792,7 +868,7 @@ end pts = [a, b, c, d, e, f, g, h] tri = triangulate(pts) vorn = voronoi(tri) - _vorn = voronoi(tri, clip=true) + _vorn = voronoi(tri, clip = true) @test validate_tessellation(vorn) @test validate_tessellation(_vorn) orig_pt = [ @@ -835,7 +911,7 @@ end C = get_polygon(_vorn, i) for (j, v) in pairs(C) δ = DT.distance_to_polygon(get_polygon_point(_vorn, v), get_points(tri), get_convex_hull_vertices(tri)) - @test δ ≥ -1e-14 + @test δ ≥ -1.0e-14 end end @test DT.get_boundary_polygons(_vorn) == Set((4, 6, 3, 5, 2, 8, 1, 7)) @@ -850,7 +926,7 @@ end tri = triangulate(pts; rng) vorn = voronoi(tri) flag1 = validate_tessellation(vorn) - vorn = voronoi(tri, clip=true) + vorn = voronoi(tri, clip = true) flag2 = validate_tessellation(vorn) @test flag1 @test flag2 @@ -864,21 +940,21 @@ end for i in 1:25 @info "Testing centroidal tessellation: Run: $i" p1 = randn(2, 50) - p2 = rand(SVector{2,Float64}, 30) + p2 = rand(SVector{2, Float64}, 30) p3 = rand(Point2f, 250) p4 = randn(Float32, 2, 70) p5 = randn(2, 4) - p6 = rand(SVector{2,Float64}, 7) + p6 = rand(SVector{2, Float64}, 7) p7 = rand(Point2f, 5) p8 = randn(Float32, 2, 15) _pts = (p1, p2, p3, p4, p5, p6, p7, p8) for jj in eachindex(_pts) points = _pts[jj] tri = triangulate(points) - vorn = voronoi(tri, clip=true) - @test validate_tessellation(vorn, check_convex=!(jj ∈ (3, 4, 7, 8))) - for smooth_vorn in (centroidal_smooth(vorn, maxiters=5000), voronoi(tri, clip=true, smooth=true, maxiters=5000)) - @test validate_tessellation(smooth_vorn, check_convex=!(jj ∈ (3, 4, 7, 8))) + vorn = voronoi(tri, clip = true) + @test validate_tessellation(vorn, check_convex = !(jj ∈ (3, 4, 7, 8))) + for smooth_vorn in (centroidal_smooth(vorn, maxiters = 5000), voronoi(tri, clip = true, smooth = true, maxiters = 5000)) + @test validate_tessellation(smooth_vorn, check_convex = !(jj ∈ (3, 4, 7, 8))) for i in each_polygon_index(smooth_vorn) p = get_generator(smooth_vorn, i) c = DT.get_centroid(smooth_vorn, i) @@ -886,7 +962,7 @@ end cx, cy = DT.getxy(c) dx, dy = px - cx, py - cy ℓ = sqrt(dx^2 + dy^2) - _flag = ℓ ≤ 1e-1 + _flag = ℓ ≤ 1.0e-1 flag += _flag tot += 1 end @@ -899,45 +975,57 @@ end if !USE_INEXACTPREDICATES @testset "Lattice" begin for _ in 1:100 - tri = triangulate_rectangle(0, 1, 0, 1, 11, 11, delete_ghosts=false) + tri = triangulate_rectangle(0, 1, 0, 1, 11, 11, delete_ghosts = false) tri = triangulate(tri.points) vorn = voronoi(tri) - @test validate_tessellation(vorn; check_convex=false) - vorn = voronoi(tri, clip=true) - @test validate_tessellation(vorn; check_convex=false, check_adjacent=false) + @test validate_tessellation(vorn; check_convex = false) + vorn = voronoi(tri, clip = true) + @test validate_tessellation(vorn; check_convex = false, check_adjacent = false) end end end @testset "Example that used to previously break: Plotting a Voronoi tile with unbounded edges intersecting over non-neighbouring sides" begin - pts = [0.508812 0.656662 0.785124 0.63427 0.444969 0.609253 0.0826304 0.265388 0.830807 0.658346 - 0.647732 0.482994 0.809909 0.482046 0.0170022 0.821742 0.835057 0.591724 0.881006 0.97652] + pts = [ + 0.508812 0.656662 0.785124 0.63427 0.444969 0.609253 0.0826304 0.265388 0.830807 0.658346 + 0.647732 0.482994 0.809909 0.482046 0.0170022 0.821742 0.835057 0.591724 0.881006 0.97652 + ] tri = triangulate(pts) vorn = voronoi(tri) clip = DT.get_polygon_coordinates(vorn, 9, DT.polygon_bounds(vorn, 0.1)) - @test DT.circular_equality(collect.(clip), collect.([ - (0.8374509236290323, 1.0964579554357115) - (0.7271857522962732, 0.8973620981454822) - (1.7423743304675243, 0.24505806539308744) - (2.0053766736553027, 0.1299847935961671) - (2.0053766736553027, 1.0964579554357115) - (0.8374509236290323, 1.0964579554357115) - ]), ≈) + @test DT.circular_equality( + collect.(clip), collect.( + [ + (0.8374509236290323, 1.0964579554357115) + (0.7271857522962732, 0.8973620981454822) + (1.7423743304675243, 0.24505806539308744) + (2.0053766736553027, 0.1299847935961671) + (2.0053766736553027, 1.0964579554357115) + (0.8374509236290323, 1.0964579554357115) + ], + ), ≈, + ) end @testset "Example that used to previously break: Plotting a Voronoi tile with unbounded edges intersecting over non-neighbouring sides, needing THREE corners" begin - pts = [0.279402 0.874842 0.163028 - 0.274178 0.831658 0.223709] + pts = [ + 0.279402 0.874842 0.163028 + 0.274178 0.831658 0.223709 + ] tri = triangulate(pts) vorn = voronoi(tri) clip = DT.get_polygon_coordinates(vorn, 2, DT.polygon_bounds(vorn, 2.0)) - @test DT.circular_equality(collect.(clip), collect.([ - (-2.551580488601045, 4.122780970352073) - (-0.3314903102646037, 1.5233996567840244) - (3.2875066205292076, -2.3420224793856605) - (3.2875066205292076, 4.122780970352073) - (-2.551580488601045, 4.122780970352073) - ]), ≈) + @test DT.circular_equality( + collect.(clip), collect.( + [ + (-2.551580488601045, 4.122780970352073) + (-0.3314903102646037, 1.5233996567840244) + (3.2875066205292076, -2.3420224793856605) + (3.2875066205292076, 4.122780970352073) + (-2.551580488601045, 4.122780970352073) + ], + ), ≈, + ) end @testset "Issue #72" begin @@ -966,7 +1054,7 @@ end Float32[0.90867966, 0.55974066], Float32[0.580766, 0.7668439], Float32[0.8563475, 0.88143903], - Float32[0.18311942, 0.8367877] + Float32[0.18311942, 0.8367877], ] tri = triangulate(points) vorn = voronoi(tri) @@ -992,7 +1080,7 @@ end [0.19257814f0, 0.30570602f0], [0.12954468f0, 0.11141288f0], [0.28790158f0, 0.39447558f0], - [0.6525599f0, 0.6425986f0] + [0.6525599f0, 0.6425986f0], ] tri = triangulate(points) vorn = voronoi(tri) @@ -1003,7 +1091,7 @@ end points = rand(2, 50) tri = triangulate(points) vorn = voronoi(tri) - xmin, xmax, ymin, ymax = DT.polygon_bounds(vorn, 0.1; include_polygon_vertices=false) + xmin, xmax, ymin, ymax = DT.polygon_bounds(vorn, 0.1; include_polygon_vertices = false) _xmin, _xmax = extrema(points[1, :]) _ymin, _ymax = extrema(points[2, :]) @test xmin == _xmin - 0.1(_xmax - _xmin) @@ -1027,47 +1115,57 @@ end a, b, c, d = -4.0, 6.0, -2.0, 4.0 bounding_box = (a, b, c, d) new_vertices, new_points = DT.grow_polygon_outside_of_box(vorn, 1, bounding_box) - @test collect.(new_points) ≈ collect.([ - (-1.1363636363636365, 5.954545454545455) - (-0.2999999999999998, 9.3) - (-2.3999999999999986, 21.900000000000006) - (-61.96153846153845, 7.846153846153847) - (-10.807692307692307, 2.730769230769231) - ]) + @test collect.(new_points) ≈ collect.( + [ + (-1.1363636363636365, 5.954545454545455) + (-0.2999999999999998, 9.3) + (-2.3999999999999986, 21.900000000000006) + (-61.96153846153845, 7.846153846153847) + (-10.807692307692307, 2.730769230769231) + ], + ) @test new_vertices == [1, 2, 3, 4, 5] new_vertices, new_points = DT.grow_polygon_outside_of_box(vorn, 5, bounding_box) - @test collect.(new_points) ≈ collect.([ - (2.710526315789474, 1.868421052631579) - (-0.7307692307692308, -0.8846153846153846) - (1.1153846153846159, -13.807692307692308) - (13.026315789473683, -1.0789473684210529) - ]) + @test collect.(new_points) ≈ collect.( + [ + (2.710526315789474, 1.868421052631579) + (-0.7307692307692308, -0.8846153846153846) + (1.1153846153846159, -13.807692307692308) + (13.026315789473683, -1.0789473684210529) + ], + ) @test new_vertices == [1, 2, 3, 4] new_vertices, new_points = DT.grow_polygon_outside_of_box(vorn, 6, bounding_box) - @test collect.(new_points) ≈ collect.([ - (23.34210526315789, -4.026315789473685) - (17.5, 15.499999999999995) - (3.1, 5.9) - (2.357142857142857, 2.9285714285714284) - (2.710526315789474, 1.868421052631579) - ]) + @test collect.(new_points) ≈ collect.( + [ + (23.34210526315789, -4.026315789473685) + (17.5, 15.499999999999995) + (3.1, 5.9) + (2.357142857142857, 2.9285714285714284) + (2.710526315789474, 1.868421052631579) + ], + ) @test new_vertices == [1, 2, 3, 4, 5] new_vertices, new_points = DT.grow_polygon_outside_of_box(vorn, 7, bounding_box) - @test collect.(new_points) ≈ collect.([ - (-0.7307692307692308, -0.8846153846153846) - (-4.166666666666666, 0.8333333333333335) - (-10.807692307692307, 2.730769230769231) - (-61.96153846153845, 7.846153846153847) - (1.1153846153846159, -13.807692307692308) - ]) + @test collect.(new_points) ≈ collect.( + [ + (-0.7307692307692308, -0.8846153846153846) + (-4.166666666666666, 0.8333333333333335) + (-10.807692307692307, 2.730769230769231) + (-61.96153846153845, 7.846153846153847) + (1.1153846153846159, -13.807692307692308) + ], + ) @test new_vertices == [1, 2, 3, 4, 5] new_vertices, new_points = DT.grow_polygon_outside_of_box(vorn, 8, bounding_box) - @test collect.(new_points) ≈ collect.([ - (17.5, 15.499999999999995) - (-4.799999999999997, 36.30000000000001) - (-0.2999999999999998, 9.3) - (3.1, 5.9) - ]) + @test collect.(new_points) ≈ collect.( + [ + (17.5, 15.499999999999995) + (-4.799999999999997, 36.30000000000001) + (-0.2999999999999998, 9.3) + (3.1, 5.9) + ], + ) @test new_vertices == [1, 2, 3, 4] @inferred DT.grow_polygon_outside_of_box(vorn, 8, bounding_box) end @@ -1094,14 +1192,14 @@ end _pf = get_polygon_coordinates(vorn, 6, bounding_box) _pg = get_polygon_coordinates(vorn, 7, bounding_box) _ph = get_polygon_coordinates(vorn, 8, bounding_box) - pa = NTuple{2,Float64}[] + pa = NTuple{2, Float64}[] pb = [(0.75, 4.0), (2.357142857142857, 2.9285714285714284), (2.625, 4.0), (0.75, 4.0)] pc = [(2.710526315789474, 1.868421052631579), (2.357142857142857, 2.9285714285714284), (0.75, 4.0), (-1.0, 4.0), (-4.0, 1.0), (-4.0, 0.75), (-0.7307692307692308, -0.8846153846153846), (2.710526315789474, 1.868421052631579)] pd = [(-4.0, 4.0), (-4.0, 1.0), (-1.0, 4.0), (-4.0, 4.0)] pe = [(6.0, 0.9285714285714279), (2.710526315789474, 1.868421052631579), (-0.7307692307692308, -0.8846153846153846), (-0.5714285714285712, -2.0), (6.0, -2.0), (6.0, 0.9285714285714279)] pf = [(6.0, 0.9285714285714284), (6.0, 4.0), (2.625, 4.0), (2.357142857142857, 2.9285714285714284), (2.710526315789474, 1.868421052631579), (6.0, 0.9285714285714284)] pg = [(-0.5714285714285721, -2.0), (-0.7307692307692308, -0.8846153846153846), (-4.0, 0.75), (-4.0, -2.0), (-0.5714285714285721, -2.0)] - ph = NTuple{2,Float64}[] + ph = NTuple{2, Float64}[] @test DT.circular_equality(collect.(pa), collect.(_pa), ≈) @test DT.circular_equality(collect.(pb), collect.(_pb), ≈) @test DT.circular_equality(collect.(pc), collect.(_pc), ≈) @@ -1151,10 +1249,10 @@ end # but then later it does! So just using the Liang-Barsky algorithm by itself is not sufficient. # To fix this, I added the stuff about maximum_distance_to_box inside grow_polygon_outside_of_box _ph = get_polygon_coordinates(vorn, 8, bounding_box) - pa = NTuple{2,Float64}[] + pa = NTuple{2, Float64}[] pb = [(0.0, 4.499999999999998), (2.357142857142857, 2.9285714285714284), (3.1, 5.9), (0.0, 9.000000000000002), (0.0, 4.499999999999998)] pc = [(0.0, -0.3000000000000007), (2.710526315789474, 1.868421052631579), (2.357142857142857, 2.9285714285714284), (0.0, 4.499999999999998), (0.0, -0.3000000000000007)] - pd = NTuple{2,Float64}[] + pd = NTuple{2, Float64}[] pe = [(5.0, 1.2142857142857117), (2.710526315789474, 1.868421052631579), (0.0, -0.3000000000000007), (0.0, -6.0), (1.2857142857142865, -15.0), (5.0, -15.0), (5.0, 1.2142857142857117)] pf = [(5.0, 1.2142857142857153), (5.0, 7.166666666666664), (3.1, 5.9), (2.357142857142857, 2.9285714285714284), (2.710526315789474, 1.868421052631579), (5.0, 1.2142857142857153)] pg = [(1.2857142857142865, -15.0), (0.0, -6.0), (0.0, -15.0), (1.2857142857142865, -15.0)] @@ -1186,10 +1284,10 @@ end # The points were duplicated from refine and not included in tri, but # retriangulate kept trying to use them points = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] - tri = triangulate(points; boundary_nodes=[1, 2, 3, 4, 1]) - refine!(tri; max_area=1e-2, min_angle=29.871) + tri = triangulate(points; boundary_nodes = [1, 2, 3, 4, 1]) + refine!(tri; max_area = 1.0e-2, min_angle = 29.871) vorn = voronoi(tri) - smooth_vorn = centroidal_smooth(vorn; maxiters=250) + smooth_vorn = centroidal_smooth(vorn; maxiters = 250) @test validate_tessellation(smooth_vorn) end @@ -1199,4 +1297,4 @@ end @test !DT.INF_WARN[] DT.toggle_inf_warn!() @test DT.INF_WARN[] -end \ No newline at end of file +end