* Integer_Geometry: Unlimited intervals

This commit is contained in:
Vovanium 2024-03-07 02:23:11 +03:00
parent ddfc137cf5
commit a5dc433e07
1 changed files with 39 additions and 11 deletions

View File

@ -53,10 +53,16 @@ package Video.Integer_Geometry with Pure is
-- Scale down a vector by D
--
--
-- An Interval
--
type Interval is record
First, Last : Coordinate;
end record;
-- A type like an Ada range (but a type)
-- Values Coordinate'First at First and Coordinate'Last at Last
-- are treated specially as 'no limit'
function Empty_Interval return Interval is (Coordinate'Last, Coordinate'First);
-- Interval with nothing in
@ -66,10 +72,16 @@ package Video.Integer_Geometry with Pure is
-- Note: many operations on Full_Interval could cause overflow
-- Note that transformations can cause overflow when applied to
-- Empty and Full intervals. User code should detect that corner cases.
-- Empty and Full intervals. Library should treat these corner cases correctly.
function Is_Empty (A : Interval) return Boolean is (A.First >= A.Last);
-- Test is interval have nothing in
-- Test if interval have nothing in
function Is_Negative_Unlimited (A : Interval) return Boolean is (A.First <= Coordinate'First);
-- Test if there's no lower limit
function Is_Positive_Unlimited (A : Interval) return Boolean is (A.Last >= Coordinate'Last);
-- Test if there's no upper limit
subtype Nonempty_Interval is Interval with Dynamic_Predicate => not Is_Empty (Nonempty_Interval);
-- A type for an interval that is not empty
@ -90,29 +102,42 @@ package Video.Integer_Geometry with Pure is
-- Identity function
function "-" (A : Interval) return Interval
is (if Is_Empty (A) then Empty_Interval else (-A.Last, -A.First));
is (if Is_Empty (A) then Empty_Interval else (
(if A.Last >= Coordinate'Last then Coordinate'First else -A.Last),
(if A.First <= Coordinate'First then Coordinate'First else -A.First)));
-- Negate inverval by flipping it over zero
function "+" (A : Interval; B : Coordinate) return Interval
is (if Is_Empty (A) then Empty_Interval else (A.First + B, A.Last + B));
is (if Is_Empty (A) then Empty_Interval else (
(if A.First <= Coordinate'First then A.First else A.First + B),
(if A.Last >= Coordinate'Last then A.Last else A.Last + B)));
-- Translate interval
function "+" (A : Coordinate; B : Interval) return Interval
is (if Is_Empty (B) then Empty_Interval else (A + B.First, A + B.Last));
is (if Is_Empty (B) then Empty_Interval else (
(if B.First <= Coordinate'First then B.First else A + B.First),
(if B.Last >= Coordinate'Last then B.Last else A + B.Last)));
-- Translate interval (other form)
function "+" (A, B : Interval) return Interval
is (if Is_Empty (A) or else Is_Empty (B) then Empty_Interval else (A.First + B.First, A.Last + B.Last));
is (if Is_Empty (A) or else Is_Empty (B) then Empty_Interval else (
(if A.First <= Coordinate'First or B.First <= Coordinate'First then
Coordinate'First else A.First + B.First),
(if A.Last >= Coordinate'Last or B.Last >= Coordinate'Last then
Coordinate'Last else A.Last + B.Last)));
-- Minkowski sum
-- The area sweeped by one interval when offset by values in other interval.
function "-" (A : Interval; B : Coordinate) return Interval
is (if Is_Empty (A) then Empty_Interval else (A.First - B, A.Last - B));
-- Translate interval
function "-" (A : Interval; B : Nonempty_Interval) return Interval
is (if Is_Empty (A) then Empty_Interval else (A.First - B.First, A.Last - B.Last));
is (if Is_Empty (A) then Empty_Interval else (
(if A.First <= Coordinate'First then A.First else A.First - B.First),
(if A.Last >= Coordinate'Last then A.Last else A.Last - B.Last)));
-- Minkowski difference
-- That is the result (if not empty) is the argument to minkowski sum with B to get A
-- That is the result (if not empty) is the argument to minkowski sum with B to get A.
-- Note: Minkowski difference is not the same as sum with negated interval
function "and" (A, B : Interval) return Interval
@ -127,11 +152,14 @@ package Video.Integer_Geometry with Pure is
function Center (A : Nonempty_Interval) return Coordinate
is (A.First / 2 + A.Last / 2 + (A.First rem 2 + A.Last rem 2) / 2);
-- Central point (equidistant to both limits)
function Center (A, B : Nonempty_Interval) return Coordinate
is ((B.First + B.Last - A.First - A.Last) / 2);
-- Offset to translate interval A to match center of interval B
--
-- Box
--
type Box is record
@ -196,11 +224,11 @@ package Video.Integer_Geometry with Pure is
-- Note: Minkowski difference is not the same as sum with negated box
function "and" (A, B : Box) return Box
is (A.X and B.X, A.Y and B.Y);
is (X => A.X and B.X, Y => A.Y and B.Y);
-- Intersection (like in sets)
function "or" (A, B : Box) return Box
is (A.X or B.X, A.Y or B.Y);
is (X => A.X or B.X, Y => A.Y or B.Y);
-- Minimal box enclosing both arguments
-- Note: contrary to "and" it is not an set union
@ -208,6 +236,6 @@ package Video.Integer_Geometry with Pure is
is (X => Center (P.X), Y => Center (P.Y));
function Center (A, B : Nonempty_Box) return Point
is (Center (A.X, B.X), Center (A.Y, B.Y));
is (X => Center (A.X, B.X), Y => Center (A.Y, B.Y));
end Video.Integer_Geometry;