Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow set_point! to work for e.g. StaticArrays and Point2f, and fix Float32 examples for many cases #74

Merged
merged 4 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DelaunayTriangulation"
uuid = "927a84f5-c5f4-47a5-9785-b46e178433df"
authors = ["Daniel VandenHeuvel <[email protected]>"]
version = "0.8.2"
version = "0.8.3"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Expand Down
13 changes: 12 additions & 1 deletion src/data_structures/statistics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ function triangle_area(ℓ₁²::Number, ℓ₂²::Number, ℓ₃²::Number)
return A
end
squared_triangle_area(ℓ₁²::Number, ℓ₂²::Number, ℓ₃²::Number) = (4ℓ₁² * ℓ₂² - (ℓ₁² + ℓ₂² - ℓ₃²)^2) / 16 # Heron's formula
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
triangle_circumradius(A, ℓmin², ℓmed², ℓmax²) = sqrt(ℓmin² * ℓmed² * ℓmax²) / (4A)
triangle_perimeter(ℓmin::Number, ℓmed::Number, ℓmax::Number) = ℓmin + ℓmed + ℓmax
triangle_inradius(A, perimeter) = 2A / perimeter
Expand Down Expand Up @@ -340,8 +343,16 @@ function triangle_angles(p, q, r)
end

function squared_triangle_area(p, q, r)
F = number_type(p)
p = f64_getxy(p)
q = f64_getxy(q)
r = f64_getxy(r) # Issue 72: Float32 is just a terrible choice for computing tessellations ...
ℓ₁², ℓ₂², ℓ₃² = squared_triangle_lengths(p, q, r)
return squared_triangle_area(ℓ₁², ℓ₂², ℓ₃²)
A² = squared_triangle_area(ℓ₁², ℓ₂², ℓ₃²)
if A² ≤ zero(A²)
A² = squared_triangle_area_v2(ℓ₁², ℓ₂², ℓ₃²)
end
return F(A²)
end
function triangle_area(p, q, r)
A² = squared_triangle_area(p, q, r)
Expand Down
9 changes: 6 additions & 3 deletions src/interfaces/points.jl
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,19 @@ end
Sets the point at index `i` in `points` to `(x, y)`. The only methods currently
defined are

set_point!(points::AbstractVector{T}, i, x, y) where {F,T<:NTuple{2,F}} = points[i] = (F(x), F(y))
set_point!(points::AbstractVector{T}, i, x, y) = (points[i] = (x, y))
set_point!(points::AbstractMatrix{T}, i, x, y) where {T} = (points[1, i] = x; points[2, i] = y)

You can extend this function as needed. We also define

set_point!(points, i, p) = set_point!(points, i, getx(p), gety(p))
"""
function set_point! end
function set_point!(points::AbstractVector{T}, i, x, y) where {F,T<:NTuple{2,F}}
points[i] = (F(x), F(y))
function set_point!(points::AbstractVector, i, x, y)
points[i] = (x, y) # also works for eltype(points) <: Tuple, StaticArrays, etc.
end
function set_point!(points::AbstractVector{T}, i, x, y) where {T<:Vector}
points[i] = [x, y]
end
function set_point!(points::AbstractMatrix{T}, i, x, y) where {T}
points[1, i] = x
Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
ElasticArrays = "fdbdab4c-e67f-52f5-8c3f-e7b388dad3d4"
ExactPredicates = "429591f6-91af-11e9-00e2-59fbe8cec110"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
Expand Down
10 changes: 10 additions & 0 deletions test/geo_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ end
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
end

@testset "Distance to a segment" begin
p1 = [0.0, 0.0]
p2 = [10.0, 0.0]
Expand Down
17 changes: 17 additions & 0 deletions test/interfaces/points.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const DT = DelaunayTriangulation
using Test
using StaticArraysCore
using StatsBase
import GeometryBasics: Point2f

global p1 = [1.3, 2.5]
global p2 = (1.3, 2.5)
Expand Down Expand Up @@ -214,5 +215,21 @@ global pts3 = [2.0 1.7 -1.0; 3.5 23.3 0.0]
@test points == [1.0 3.0; 7.8 4.0]
DT.set_point!(points, 1, (6.0, 7.7))
@test points == [6.0 3.0; 7.7 4.0]

points = [[1.0, 5.0], [6.5, 2.3]]
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)]
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)]

points = [Float32[1.0, 5.0], Float32[2.3, -6.7]]
DT.set_point!(points, 1, 2.3, 6.9)
@test points == [Float32[2.3, 6.9], Float32[2.3, -6.7]]

points = [Point2f(2.0, 10.0), Point2f(3.0, 4.0)]
DT.set_point!(points, 2, 3.0, 4.0)
@test points == [Point2f(2.0, 10.0), Point2f(3.0, 4.0)]
end
end
109 changes: 91 additions & 18 deletions test/voronoi/voronoi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ using CairoMakie
using ColorSchemes
using DataStructures
using StableRNGs
import GeometryBasics: Point2f
using StaticArrays
using LinearAlgebra

include("../helper_functions.jl")
Expand Down Expand Up @@ -845,26 +847,38 @@ end
@testset "Centroidal tessellation" begin
flag = 0
tot = 0
for _ in 1:50
points = randn(2, 250)
tri = triangulate(points)
vorn = voronoi(tri, true)
@test validate_tessellation(vorn)
smooth_vorn = centroidal_smooth(vorn, maxiters=5000)
@test validate_tessellation(smooth_vorn)
for i in each_polygon_index(smooth_vorn)
p = get_generator(smooth_vorn, i)
c = DT.get_centroid(smooth_vorn, i)
px, py = getxy(p)
cx, cy = getxy(c)
dx, dy = px - cx, py - cy
ℓ = sqrt(dx^2 + dy^2)
_flag = ℓ ≤ 1e-1
flag += _flag
tot += 1
for i in 1:50
p1 = randn(2, 50)
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)
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]
println("Starting centroidal test at $((i, jj)).")
tri = triangulate(points)
vorn = voronoi(tri, true)
@test validate_tessellation(vorn, check_convex=!(jj ∈ (3, 4, 7, 8)))
smooth_vorn = centroidal_smooth(vorn, 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)
px, py = getxy(p)
cx, cy = getxy(c)
dx, dy = px - cx, py - cy
ℓ = sqrt(dx^2 + dy^2)
_flag = ℓ ≤ 1e-1
flag += _flag
tot += 1
end
end
end
@test flag / tot > 0.95
@test flag / tot > 0.9
end

@testset "Lattice" begin
Expand Down Expand Up @@ -909,4 +923,63 @@ end
(-2.7441549307938113, 9.321543597488171)
(-2.7441549307938113, 4.348255778263596)
]), ≈)
end

@testset "Issue #72" begin
points = [
Float32[0.32965052, 0.7966664],
Float32[0.015137732, 0.31555605],
Float32[0.54775107, 0.7222514],
Float32[0.687552, 0.6982844],
Float32[0.65762305, 0.5177773],
Float32[0.9649102, 0.8300816],
Float32[0.12174326, 0.82220316],
Float32[0.007668495, 0.7747718],
Float32[0.3144052, 0.5493178],
Float32[0.6848137, 0.12493092],
Float32[0.39197737, 0.6912688],
Float32[0.41400427, 0.025964081],
Float32[0.35919905, 0.7255166],
Float32[0.80712754, 0.3415957],
Float32[0.542679, 0.51094216],
Float32[0.092720866, 0.90151125],
Float32[0.90992355, 0.8814645],
Float32[0.02194357, 0.00064593554],
Float32[0.9616154, 0.10633117],
Float32[0.0044495463, 0.97074896],
Float32[0.4309939, 0.5323847],
Float32[0.90867966, 0.55974066],
Float32[0.580766, 0.7668439],
Float32[0.8563475, 0.88143903],
Float32[0.18311942, 0.8367877]
]
tri = triangulate(points)
vorn = voronoi(tri)
@test validate_tessellation(vorn)

points = [
[0.01877582f0, 0.33188105f0],
[0.57645035f0, 0.58131695f0],
[0.14916456f0, 0.37567925f0],
[0.87054604f0, 0.29108626f0],
[0.15384161f0, 0.80313444f0],
[0.66470474f0, 0.2547925f0],
[0.69431657f0, 0.42567456f0],
[0.43695337f0, 0.42649788f0],
[0.3316936f0, 0.18936294f0],
[0.98043495f0, 0.8360868f0],
[0.5788496f0, 0.103449225f0],
[0.5252029f0, 0.96790665f0],
[0.33206534f0, 0.88216203f0],
[0.07115775f0, 0.5983915f0],
[0.29895544f0, 0.103566706f0],
[0.52547264f0, 0.57929194f0],
[0.19257814f0, 0.30570602f0],
[0.12954468f0, 0.11141288f0],
[0.28790158f0, 0.39447558f0],
[0.6525599f0, 0.6425986f0]
]
tri = triangulate(points)
vorn = voronoi(tri)
@test validate_tessellation(vorn)
end