Skip to content

Commit

Permalink
Merge pull request #3796 from JuliaReach/schillic/doc
Browse files Browse the repository at this point in the history
Improve documentation
  • Loading branch information
schillic authored Jan 27, 2025
2 parents 25a485a + a87ffbc commit aa51758
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 20 deletions.
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

0 comments on commit aa51758

Please sign in to comment.