pchandler.geometry.spherical.fov

Fields of View (FoVs) and hierarchical FoV trees for spherical-coordinate spatial partitioning.

This module provides classes and methods for defining and manipulating Fields of View (FoVs) and hierarchical FoV trees. It is designed to facilitate the spatial partitioning, tiling, and merging of 3D regions based on angular constraints. The module supports flexible representation of angular units and integrates with external tools to enable hierarchical partitioning of FoVs.

Key Features:

  • FoV Class: - Represents rectangular angular regions in 3D space. - Supports unit conversion between radians, degrees, and gradians (gon). - Provides methods for splitting, merging, and calculating geometric properties such as aspect ratios and centers.

  • FoVTree Class: - Implements a hierarchical tree structure for managing FoVs. - Enables efficient spatial partitioning, depth-based querying, and merging operations. - Compatible with tile-based FoV organization for large-scale datasets.

  • Utility Methods: - Split a single FoV into multiple tiles or quadrants. - Convert between tuple, dictionary, or NumPy array representations of FoV boundaries. - Calculate optimal partitioning schemes for FoVs based on aspect ratios and angular extents.

Dependencies:

  • numpy: For numerical computations.

  • pchandler.util: Provides utilities for angle unit conversion and numerical constants.

Usage:

Example: Create an FoV and convert it between different representations:

from pchandler.fov import FoV

# Define a field of view in degrees
fov = FoV(horizontal_min=0, horizontal_max=90, elevation_min=-30, elevation_max=30, unit="deg")

# Convert to radians
fov_rad = fov.as_tuple(unit="rad")
print("FoV in radians:", fov_rad)

# Split the FoV into a 2x2 grid
sub_fovs = fov.split(shape=(2, 2))
print("Sub-FoVs:", sub_fovs)

Example: Use a hierarchical FoV tree for spatial partitioning:

from pchandler.fov import FoV, FoVTree

# Create a base FoV
base_fov = FoV(horizontal_min=0, horizontal_max=90, elevation_min=-30, elevation_max=30, unit="deg")

# Split into tiles and build a tree
tiles = base_fov.tile(FoV(horizontal_min=0, horizontal_max=30, elevation_min=-10, elevation_max=10))
fov_tree = FoVTree.build_from_tiles(tiles)

# Query the depth of the tree
print("Tree depth:", fov_tree.depth())

Classes

FoV

A rectangular angular region (Field of View) in spherical coordinates.

FoVTree

A hierarchical tree structure for spatial partitioning of FoVs.

class pchandler.geometry.spherical.fov.FoV

Bases: BaseModel

A rectangular angular region (Field of View) in spherical coordinates.

Defined by left/right horizontal bounds and top/bottom vertical bounds. Horizontal angles wrap on the +/- pi discontinuity (left > right indicates a wrapping FoV).

left: Angle
right: Angle
top: Angle
bottom: Angle
__init__(*, left, top, right, bottom)

Build an FoV from four angular limits.

Parameters:
  • left (Angle) – Hz ∈ [–π, +π].

  • right (Angle) – Hz ∈ [–π, +π].

  • top (Angle) – V ∈ [0, +π].

  • bottom (Angle) – V ∈ [0, +π].

classmethod construct_without_bounds_check(*, left, right, top, bottom)

Construct a FoV without bounds check.

Enables construction of an FoV whose angular limits cross over the standard wraparound boundary (e.g., a horizontal FoV spanning 350 to 10 degrees).

Parameters:
  • left (AngleLikeT) – Left horizontal bound. May be greater than right to denote a wraparound region.

  • right (AngleLikeT) – Right horizontal bound.

  • top (AngleLikeT) – Top vertical bound.

  • bottom (AngleLikeT) – Bottom vertical bound. May be less than top for wraparound.

Returns:

A new FoV constructed via pydantic.BaseModel.model_construct(), bypassing the _check_elevation and _check_bottom_and_top model validators.

Return type:

FoV

Notes

This method bypasses the _check_elevation and _check_bottom_and_top model validators via model_construct(). It exists for legitimate use cases – FoVs that cross the angular wraparound (e.g., a horizontal FoV spanning 350 to 10 degrees). The caller is responsible for ensuring the (left, right, top, bottom) quadruple represents a meaningful angular region; downstream FoV operations may produce surprising results if the invariant is violated.

This is FRAG-06 documentation (Plan 02-06 / D-22): the model_construct call below is deliberate and the design is correct as-is. The method is not a security bypass – construct_without_bounds_check is callable only by code that already has full control over the FoV construction, and the validators it skips are domain-shape checks (angular ordering), not security-shape checks.

classmethod from_angles(horizontal, vertical)

Construct a FoV from horizontal and vertical angles.

Parameters:
Return type:

FoV

property crosses_pi: bool

Check whether the FoV horizontal range crosses the +/- pi boundary.

Returns:

True if left > right (wrapping FoV).

Return type:

bool

width()

Return the angular width (horizontal extent) of the FoV.

Returns:

The horizontal extent (accounting for wrap at +/- pi).

Return type:

Angle

height()

Return the angular height (vertical extent) of the FoV.

Returns:

The vertical extent.

Return type:

Angle

extent()

Return the angular extent (width, height) of the FoV.

Returns:

(width, height) pair.

Return type:

tuple[Angle, Angle]

center()

Return the center of the FoV.

Return type:

tuple[Angle, Angle]

classmethod from_center_with_extent(centerpoint, extent)

Build an FoV from a center point and angular extent.

Parameters:
  • centerpoint (tuple[float, float]) – (horizontal_center, vertical_center) for the FoV.

  • extent (tuple[float, float]) – (width, height) extent for the FoV.

Returns:

FoV centered on centerpoint with the requested extent.

Return type:

FoV

union(fov2)

Return the union of this FoV with another (handles wrap at +/- pi).

Parameters:

fov2 (FoV) – The other FoV to union with.

Returns:

The smallest FoV containing both inputs.

Return type:

FoV

intersect(fov2)

Return the intersection of this FoV with another, or None if disjoint.

Parameters:

fov2 (FoV) – The other FoV to intersect with.

Returns:

The intersection FoV, or None if the two are disjoint.

Return type:

FoV or None

encompasses(fov2)

Check whether self fully surrounds fov2.

Parameters:

fov2 (FoV) – Candidate inner FoV.

Returns:

True if fov2 is fully contained inside self (within EPS tolerance).

Return type:

bool

find_points_inside(horizontal, vertical)

Return a boolean mask of the input points that fall inside the FoV.

ratio()

Return the width-to-height ratio of the FoV.

Returns:

width() / height().

Return type:

NonNegativeFloat

extend_to_ratio(ratio)

Extend the FoV to match a specified width-to-height ratio.

Parameters:

ratio (float) – Target width-to-height ratio.

Returns:

New FoV matching the requested ratio (or self if already at ratio).

Return type:

FoV

split(shape)

Split the FoV into smaller FoVs based on a grid shape.

Parameters:

shape (tuple[int, int]) – The number of horizontal and vertical splits respectively.

Return type:

list[FoV]

Notes

split((1, 1)) returns [self] – the original instance is reused by identity (not value-equality). Downstream code may rely on splits[0] is fov for this single-tile case (e.g., FoVTree’s no-op-split short-circuit).

equal_tiles(width, height)

Divides a region into equal tiles based on a specified width and height.

Parameters:
Return type:

list[FoV]

tile(target_extent, expand_to_integer_multiple=False)

Divides the current field of view (FOV) into smaller tiles based on the specified target extent/FoV.

If expand_to_integer_multiple is True, the method ensures that the field of view is expanded to the nearest integer multiple of the target_extent dimensions before tiling.

Parameters:
  • target_extent (FoV) – FoV object representing the target extent for tiling.

  • expand_to_integer_multiple (bool, optional)

Return type:

list[list[FoV]]

quadrants()

Split the FoV into four equal quadrants.

Returns:

The four quadrant FoVs (top-left, top-right, bottom-left, bottom-right).

Return type:

tuple of Self

classmethod merge(fovs)

Merge multiple FoVs into one that encompasses the total area covered.

Parameters:

fovs (Iterable[FoV]) – All FoV objects to be merged.

Returns:

Smallest FoV containing all inputs.

Return type:

FoV

property horizontal_min: Angle

Horizontal minimum angle value. Equivalent to the left attribute.

Warning

DeprecationWarning

This property is deprecated. Use the ‘left’ property instead.

Return type:

Angle

property horizontal_max: Angle

Horizontal maximum angle value. Equivalent to the right attribute.

Warning

DeprecationWarning

This property is deprecated. Use the ‘right’ property instead.

Return type:

Angle

property elevation_min: Angle

Elevation minimum angle value. Equivalent to the top attribute.

Warning

DeprecationWarning

This property is deprecated. Use the ‘top’ property instead.

Return type:

Angle

property elevation_max: Angle

Elevation maximum angle value. Equivalent to the bottom attribute.

Warning

DeprecationWarning

This property is deprecated. Use the ‘bottom’ property instead.

Return type:

Angle

class pchandler.geometry.spherical.fov.FoVTree

Bases: object

A hierarchical tree structure for spatial partitioning of FoVs.

Parameters:
  • identifier (str) – Unique identifier for this tree node.

  • node (FoV) – The FoV associated with this tree node.

  • children (dict[str, FoVTree] | None) – Dictionary of child nodes, if any.

identifier: str
node: FoV
children: dict[str, Self] | None
static add_identifier(fovs, shape)

Add unique identifier(s) to each field of view (FoV) in the list.

Parameters:
  • fovs (list[FoV])

  • shape (tuple[int, int]) – Shape dimensions used to calculate the identifier length.

Returns:

A tuple containing tuples, each consisting of a unique identifier and the corresponding FoV object.

Return type:

tuple[tuple[str | Any, FoV], …]

depth()

Return the depth of the FoVTree from the current node.

Leaf nodes have a depth of 1.

Return type:

int

to_list()

Convert tree structure into a flattened list.

Returns:

Each tuple consists of the identifier and the FoV node

Return type:

list[(str, FoV)]

classmethod build_from_tiles(tiles, min_children=4, identifier='')

Construct a tree from a 2D grid of FoVs by recursive quad-splitting.

Parameters:
  • tiles (list[list[FoV]]) – Grid of FoVs.

  • min_children (int, default=4) – The minimum number of children to avoid further splitting.

  • identifier (str, default="") – Unique identifier for this node.

Returns:

Root of the constructed tree, or None if tiles is empty.

Return type:

FoVTree

is_leaf()

Check whether this FoVTree node is a leaf (has no child nodes).

Returns:

True if the node has no children, False otherwise.

Return type:

bool

static calculate_optimal_shape(fov, target_ratio, max_denominator)

Calculate the optimal shape based on a given field of view (FoV), target ratio, and maximum denominator.

Parameters:
  • fov (FoV)

  • target_ratio (float)

  • max_denominator (float) – Maximum number of FoV tree should be split into along a direction

Return type:

tuple[int, int]

__init__(identifier, node, children=<factory>)