Bounding-Boxes
Given the coordinates start=(xmin,ymin)
and stop=(xmax,ymax)
of the first and last 2-dimensional position in a rectangular region whose axes are aligned with the coordinate axes, a 2-D bounding-box representing this region is built by one of:
box = BoundingBox(start, stop)
box = BoundingBox(; start=..., stop=...)
box = BoundingBox((xmin,ymin), (xmax,ymax))
box = BoundingBox(; xmin=..., ymin=..., xmax=..., ymax=...)
All points of coordinates (x,y)
such that xmin ≤ x ≤ xmax
and ymin ≤ y ≤ ymax
are considered as being part of the bounding-box. Hence, if xmin ≤ xmax
and ymin ≤ ymax
do not both hold, the box is empty as can be tested by isempty(box)
.
Arguments start
and stop
may also be two points (of type Point
) or, for integer-valued coordinates, two Cartesian indices or two unit ranges:
box = BoundingBox(Point(xmin,ymin), Point(xmax,ymax))
box = BoundingBox(xmin:xmax, ymin:ymax)
As a convenience, all arguments can be given by a single tuple. For example:
box = BoundingBox((start, stop))
box = BoundingBox((xmin:xmax, ymin:ymax))
Coordinate type
The coordinate type, say T
, can be explicitly specified with the constructor, for example:
box = BoundingBox{T}(start, stop)
If T
is unspecified, it is inferred from the coordinate type of the arguments promoted to a common type.
The coordinate type of a bounding-box can be retrieved by the coord_type
and eltype
methods.
Converting an existing bounding-box to another coordinate type can done by convert_coord_type
.
Aliases
Call:
using TwoDimensional: BoundingBox2D
instead of:
using TwoDimensional
to have BoundingBox2D
provided as an alias to TwoDimensional.BoundingBox
and possibly avoid conflict with other packages.
Construction
The coordinates of a bounding-box can be specified by keywords:
There are no default values for keywords xmin
, xmax
, ymin
and ymax
so all must be specified.
A bounding-box can be constructed from a 4-tuple of coordinates and conversely:
BoundingBox((x0,x1,y0,y1)) # yields BoundingBox(x0,x1,y0,y1)
Tuple(BoundingBox(x0,x1,y0,y1)) # yields (x0,x1,y0,y1)
A bounding-box can be constructed from its first and last points (i.e. at the lower-left and upper right opposite corners) specified as instances of Point
, of CartesianIndex{2}
or of Tuple{Real,Real}
:
BoundingBox(Point(x0,y0), Point(x1,y1))
BoundingBox(CartesianIndex(x0,y0), CartesianIndex(x1,y1))
BoundingBox((x0,y0), (x1,y1))
which all yield the same result:
BoundingBox(x0,x1,y0,y1)
Conversely, methods first(B)
and last(B)
respectively yield the lower left and upper right corners of the bounding-box B
(as a Point
instance):
first(BoundingBox(x0,x1,y0,y1)) # yields Point(x0,y0)
last(BoundingBox(x0,x1,y0,y1)) # yields Point(x1,y1)
Integer-valued unit-ranges can be specified to define a bounding-box. For example:
BoundingBox(x0:x1, y0:y1) # 2 unit-range
BoundingBox((x0:x1, y0:y1)) # a 2-tuple of unit range
This makes possible writing:
BoundingBox(axes(A))
to get the bounding-box corresponding to all indices of array A
. Conversely:
axes(BoundingBox(x0,x1,y0,y1))
yields the axes of a bounding-box with integer coordinates, that is (x0:x1,y0:y1)
. To get the k
-th axis of a bounding-box B
, call axes(B,k)
.
To loop over the Cartesian indices defined by a bounding-box B
with integer coordinates, you can just write:
for I in CartesianIndices(B)
...
end
A bounding-box may also be constructed by applying a predicate function to the elements of a 2-dimensional array:
BoundingBox(f, A)
yields the bounding-box of all integer coordinates (x,y)
such that f(A[x,y])
yields true
. If the elements of A
are booleans (of type Bool
), then BoundingBox(A)
is equivalent to BoundingBox(identity,A)
.
Fields
The fields of a BoundingBox
, say box
, can be retrieved in different ways:
xmin = box.xmin
xmax = box.xmax
ymin = box.ymin
ymax = box.ymax
or:
xmin = box[1]
xmax = box[2]
ymin = box[3]
ymax = box[4]
or:
xmin, xmax, ymin, ymax = box
Conversion
Coordinate type conversion, say to type T
, is done by:
B = BoundingBox(x0,x1,y0,y1)
BoundingBox{T}(B)
convert(BoundingBox{T}, B)
T.(B)
The latter form involves broadcasting rules and may be a bit slower.
Union and Intersection of Bounding-Boxes
The union of bounding-boxes b1
, b2
, ... is given by one of:
B1 ∪ B2 ∪ ...
union(B1, B2, ...)
which both yield the largest bounding-box contained into the bounding-boxes B1
, B2
, ...
The intersection of bounding-boxes B1
, B2
, ... is given by one of:
B1 ∩ B2 ∩ ...
intersect(B1, B2, ...)
which both yield the smallest bounding-box containing the bounding-boxes B1
, B2
, ...
The maximal or minimal bounding-box with coordinates of type T
that can be constructed are respectively given by typemax(BoundingBox{T})
and typemin(BoundingBox{T})
. These can be useful to initiate a shrinking or a growing bounding-box. The call:
BoundingBox{T}(nothing)
yields the same result as typemin(BoundingBox{T})
.
Interior, Exterior, Nearest, etc.
Given the bounding-box B
, interior(B)
and exterior(B)
respectively yield the largest interior and smallest exterior bounding-boxes with integer bounds.
round(B)
, round(T,B)
, or round(T,B,r)
yield a bounding-box whose limits are those of the bounding-box B
rounded to the nearest integral values of type T
with rounding-mode r
. Default type T
is eltype(B)
and default rounding-mode r
is RoundingNearest
.
center(B)
yields the Point
whose coordinates are the geometrical center of the bounding-box B
.
area(B)
yields the area of a bounding-box B
.
Arithmetic and Basic Methods
Adding or subtracting a scalar δ
to a bounding-box B
adds or removes a margin δ
to the bounding-box B
:
BoundingBox((x0,y0),(x1,y1)) + δ -> BoundingBox((x0-δ,y0-δ),(x1+δ,y1+δ))
BoundingBox((x0,y0),(x1,y1)) - δ -> BoundingBox((x0+δ,y0+δ),(x1-δ,y1-δ))
Adding or subtracting a point P
to a bounding-box B
shifts the limits of the bounding-box B
:
BoundingBox((x0,y0),(x1,y1)) + Point(x,y) -> BoundingBox((x0+x,y0+y),(x1+x,y1+y))
A bounding-box B
can be negated:
-BoundingBox((x0,y0),(x1,y1)) -> BoundingBox((-x1,-y1),(-x0,-y0))
eltype(B)
yields the type of the coordinates of a bounding-box B
.
Basic methods size(B[,k])
and axes(B[,k])
can be applied to an integer-valued bounding-box B
. These two methods are type-stable: size(B)
yields a 2-tuple of Int
, size(B,k)
yields an Int
, axes(B)
yields a 2-tuple of UnitRange{Int}
and axes(B,k)
yields a UnitRange{Int}
.
Method in
and operator ∈
, obtained by \in
-tab, yield whether a point pnt
is inside a bounding-box box
:
pnt ∈ box
is a shortcut for:
(box.xmin ≤ pnt.x ≤ box.xmax) & (box.ymin ≤ pnt.y ≤ box.ymax)
Method issubset
or operator ⊆
, obtained by \subseteq
-tab, yield whether a bounding-box, say A
, is inside another one, say B
. That is issubset(A, B)
and A ⊆ B
are shortcuts for:
(isempty(A) | ((A.xmin ≥ B.xmin) & (A.xmax ≤ B.xmax) &
(A.ymin ≥ B.ymin) & (A.ymax ≤ B.ymax)))