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

Improve documentation #3796

Merged
merged 2 commits into from
Jan 27, 2025
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
40 changes: 23 additions & 17 deletions src/Approximations/overapproximate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -606,52 +606,58 @@ end
"""
overapproximate(P::VPolygon, ::Type{<:LinearMap{N,<:Hyperrectangle}}) where {N}

Overapproximate polygon with minimal-area rotated hyperrectangle.
Overapproximate a convex polygon with a minimal-area rotated rectangle.

### Input

- `P` -- polygon
- `LinearMap{N,<:Hyperrectangle}` -- target type (a linear map of a hyperrectangle)
- `P` -- convex polygon
- `LinearMap{N,<:Hyperrectangle}` -- target type

### Output
### Output

A LinearMap of a Hyperrectangle that represents the minimal area rotated bounding rectangle
of the polygon P.
A `LinearMap` of a `Hyperrectangle`.

### Algorithm

This method uses an approach described in [Finding Minimum Area Rectangle for Given Points](https://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points/22934)
This method follows an approach described in
[this post](https://gis.stackexchange.com/a/22934), which itself is based on
[this post](https://gis.stackexchange.com/a/22904).

Generally, the idea is that the rotated rectangle must share at least one edge
with the polygon. Thus, it suffices to try out finitely many rectangles. Some
tricks from linear algebra allow to construct the corresponding rotations and
rectangles elegantly.
"""

function overapproximate(P::VPolygon, ::Type{<:LinearMap{N,<:Hyperrectangle}}) where {N}
min_area = N(Inf)
vert_P = P.vertices
n = length(vert_P)
m = length(vert_P)

center = Vector{N}(undef, 2)
radius = Vector{N}(undef, 2)
R = Matrix{N}(undef, 2, 2)
R = Matrix{N}(undef, 2, 2)

# iterate over all polygon edges
@inbounds for i in eachindex(vert_P)
# edge (v_i, v_{i+1})
a = vert_P[i]
next_idx = i % n + 1
next_idx = i % m + 1
b = vert_P[next_idx]
e = b - a
v = normalize(e)
w = [-v[2], v[1]]
v = normalize(e)
w = [-v[2], v[1]]

min_x, max_x = extrema(dot(vertex, v) for vertex in vert_P)
min_y, max_y = extrema(dot(vertex, w) for vertex in vert_P)
min_x, max_x = extrema(dot(vertex, v) for vertex in vert_P)
min_y, max_y = extrema(dot(vertex, w) for vertex in vert_P)

current_area = (max_x - min_x) * (max_y - min_y)

if current_area < min_area
min_area = current_area
center .= ((max_x + min_x) / 2, (max_y + min_y) / 2)
radius .= ((max_x - min_x) / 2, (max_y - min_y) / 2)
R[:, 1] = v
R[:, 2] = w
R[:, 1] = v
R[:, 2] = w
end
end

Expand Down
6 changes: 3 additions & 3 deletions test/Approximations/overapproximate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,10 @@ for N in [Float64, Rational{Int}, Float32]

# overapproximate polygon with minimal-area rotated hyperrectangle
P = VPolygon([N[1, 0], N[0, 1], N[-1, 0], N[0, -1]])
R = overapproximate(P, LinearMap{N, Hyperrectangle{N}})
R = overapproximate(P, LinearMap{N,Hyperrectangle{N}})
@test set(R).center == N[0, 0]
@test set(R).radius == N[1 / √2, 1 / √2]
@test R.M == N[-1/sqrt(2) -1/sqrt(2); 1/sqrt(2) -1/sqrt(2)]
@test set(R).radius == N[1 / √2, 1 / √2]
@test R.M == N[-1/sqrt(2) -1/sqrt(2); 1/sqrt(2) -1/sqrt(2)]
if N <: AbstractFloat
@test isequivalent(P, R)
end
Expand Down
Loading