BoundingBox#

class rapidtools.core.BoundingBox(min_x: float, min_y: float, max_x: float, max_y: float)[source]#

Bases: Region

Represents an axis-aligned rectangular region.

This class acts as a wrapper around a Shapely BaseGeometry that is strictly rectangular. It provides specialized initialization methods and optimized properties for rectangular math.

Methods

buffer

Return a new BoundingBox expanded (or shrunk) by a constant distance.

contains

Check if the region completely encloses another geometry.

distance

Calculate the minimum Euclidean distance to another region or geometry.

from_geojson

Create a BoundingBox covering the total spatial extent of a GeoJSON file.

from_geometry

Create a BoundingBox that exactly encloses a geometry.

from_raster

Create a BoundingBox representing the spatial extent of a raster file.

from_union

Create a box covering the total extent of two regions.

get_bounding_box

Return the bounding box of this region.

intersects

Determine if the region spatially intersects with another geometry.

split

Splits the bounding box into four equal-sized quadrants.

tile_by_area

Split the bounding box into a grid of smaller boxes.

property area: float#

Return the area of the bounding box.

Overridden from Region to use simple float math instead of Shapely logic for performance.

Returns:

float – The area in the squared units of the coordinate system.

Note

  • If coordinates are in meters (e.g., UTM), result is sq. meters.

  • If coordinates are in degrees (e.g., WGS84), result is sq. degrees. Square degrees are generally not useful for physical size estimates.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox(0, 0, 5, 5)
>>> bbox.area
25.0
property centroid: tuple[float, float]#

Return the center point of the bounding box.

Overridden from Region to use simple float math instead of Shapely logic for performance.

Returns:

tuple[float, float] – The (longitude, latitude) center coordinates.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox(0, 0, 10, 20)
>>> bbox.centroid
(5.0, 10.0)
classmethod from_geojson(filepath: str | Path) → BoundingBox[source]#

Create a BoundingBox covering the total spatial extent of a GeoJSON file.

The method uses a pre-computed top-level bbox member when one is present (the fastest path) and otherwise streams the bounds of every feature without building large in-memory geometry lists. Feature-level bbox members are honoured before falling back to the geometry. Empty geometries are skipped. If the file declares a legacy crs member that is not EPSG:4326, the resulting bounds are reprojected to WGS84.

Parameters:

filepath (str | Path) – Path to a GeoJSON file containing a FeatureCollection, a single Feature, or a bare geometry object.

Returns:

BoundingBox – A box covering the entire extent of the GeoJSON content, in WGS84 (EPSG:4326) coordinates.

Raises:

ValueError – If the top-level type is not a supported GeoJSON type, or if the file contains no valid, non-empty geometries.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox.from_geojson('data.geojson')
>>> print(bbox.bounds)
(-118.5, 34.0, -118.0, 34.5)
classmethod from_geometry(geometry: BaseGeometry) → BoundingBox[source]#

Create a BoundingBox that exactly encloses a geometry.

Parameters:

geometry (BaseGeometry) – Any Shapely geometry (Polygon, Point, LineString, etc.) to wrap.

Returns:

BoundingBox – A new instance covering the extent of the input geometry.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> from shapely.geometry import LineString
>>> line = LineString([(0, 0), (10, 10)])
>>> bbox = BoundingBox.from_geometry(line)
>>> bbox.bounds
(0.0, 0.0, 10.0, 10.0)
classmethod from_raster(filepath: str | Path) → BoundingBox[source]#

Create a BoundingBox representing the spatial extent of a raster file.

Automatically reprojects the bounds to WGS84 (EPSG:4326) if the source raster is in a different coordinate reference system (e.g., a localized UTM zone). Rasters without a CRS are assumed to already be in WGS84.

Parameters:

filepath (str | Path) – Path to the georeferenced raster file.

Returns:

BoundingBox – A WGS84 bounding box covering the extent of the raster.

Raises:

RasterioIOError – If the file cannot be opened.

Example

>>> from rapidtools.core import BoundingBox
>>> from rapidtools import download_dataset
>>>
>>> # Download a sample drone flight:
>>> [raster_path] = download_dataset('eaton_patch1')
>>>
>>> # Extract its spatial bounds instantly:
>>> bbox = BoundingBox.from_raster(raster_path)
>>> print(bbox.bounds)
(-118.0934, 34.1842, -118.0911, 34.1858)
classmethod from_union(region1: Region, region2: Region) → BoundingBox[source]#

Create a box covering the total extent of two regions.

This calculates the “envelope union” (min of mins, max of maxs) of two regions

Parameters:
  • region1 (Region) – The first region.

  • region2 (Region) – The second region.

Returns:

BoundingBox – A new instance large enough to cover both inputs.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> b1 = BoundingBox(0, 0, 1, 1)
>>> b2 = BoundingBox(10, 10, 11, 11)
>>> union_box = BoundingBox.from_union(b1, b2)
>>> union_box.bounds
(0.0, 0.0, 11.0, 11.0)
buffer(distance: float) → BoundingBox[source]#

Return a new BoundingBox expanded (or shrunk) by a constant distance.

This operation pushes the box boundaries outward by the specified distance.

Parameters:

distance (float) – The amount to expand the box edges. Use negative values to shrink the box.

Returns:

BoundingBox – A new BoundingBox instance with adjusted boundaries.

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox(0, 0, 10, 10)
>>> expanded = bbox.buffer(1.0)
>>> expanded.bounds
(-1.0, -1.0, 11.0, 11.0)
get_bounding_box() → BoundingBox[source]#

Return the bounding box of this region.

Since this object is already a BoundingBox, this method simply returns self.

Returns:

BoundingBox – The object itself.

split() → list[BoundingBox][source]#

Splits the bounding box into four equal-sized quadrants.

This method is used by the API client for adaptive tiling when a tile is too dense with features and needs to be subdivided.

Returns:

A list of four new BoundingBox objects for the quadrants – [bottom-left, bottom-right, top-left, top-right].

Example

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox(0, 0, 10, 10)
>>> quads = bbox.split()
>>> quads[0].bounds  # Bottom-Left
(0.0, 0.0, 5.0, 5.0)
>>> quads[3].bounds  # Top-Right
(5.0, 5.0, 10.0, 10.0)
tile_by_area(max_area: float = 0.01) → list[BoundingBox][source]#

Split the bounding box into a grid of smaller boxes.

The grid dimensions are calculated to maintain the aspect ratio of the original box as closely as possible while ensuring every tile has an area less than or equal to max_area.

Parameters:

max_area (float) – The maximum allowed area for a single tile. Defaults to 0.01.

Returns:

list[BoundingBox] – A flattened list of the resulting sub-boxes.

Example

Initialize a bounding box with an area of 100 square units:

>>> from rapidtools.core import BoundingBox
>>>
>>> bbox = BoundingBox(0, 0, 10, 10)

Split the bounding box into tiles with a maximum area of 25 square units:

>>> tiles = bbox.tile_by_area(max_area=25)
INFO: Tiling BoundingBox into 2x2 grid (Target Area: 25, Total
Tiles: 4)
>>> len(tiles)
4