Skip to content

Geodesy & navigation

Bearings, destinations, route interpolation, and cross-track distance.

Related: CRS, units & measurement

bearing

Accepted call forms
bearing(left: Point, right: Point, *, path: Literal['geodesic', 'rhumb'] = 'geodesic') -> float
bearing(left: GeometryArray[Point | None], right: Point | GeometryArray[Point | None], *, path: Literal['geodesic', 'rhumb'] = 'geodesic') -> NDArray[float64]
bearing(left: Point, right: GeometryArray[Point | None], *, path: Literal['geodesic', 'rhumb'] = 'geodesic') -> NDArray[float64]
bearing(left: Point | GeometryArray[Point | None], right: Point | GeometryArray[Point | None], *, path: Literal['geodesic', 'rhumb'] = 'geodesic') -> float | NDArray[float64]

Initial bearing from one point to another, in degrees clockwise from north (0..360).

Geodesic by default on a geographic CRS (on the CRS ellipsoid); grid azimuth on a projected or CRS-free point. path='rhumb' selects the constant compass course on a geographic CRS. An empty point yields nan.

Parameters:

Name Type Description Default
left Point or GeometryArray

Origin and destination; must share a CRS.

required
right Point or GeometryArray

Origin and destination; must share a CRS.

required
path ('geodesic', 'rhumb')

Route model. Rhumb bearings require a geographic CRS.

'geodesic'

Returns:

Type Description
float or ndarray

One bearing per input pair.

Raises:

Type Description
GeometryTypeError

If either operand is not a Point.

CRSMismatchError

If the operands' CRS or coordinate-epoch metadata differ.

CRSError

If a coordinate is outside the longitude/latitude domain.

Examples:

>>> import gometry as gm
>>> gm.bearing(gm.Point(0, 0), gm.Point(1, 0))
90.0

cross_track_distance

Accepted call forms
cross_track_distance(point: Point, start: Point, end: Point) -> float
cross_track_distance(point: GeometryArray[Point | None], start: Point | GeometryArray[Point | None], end: Point | GeometryArray[Point | None]) -> NDArray[float64]
cross_track_distance(point: Point, start: GeometryArray[Point | None], end: Point | GeometryArray[Point | None]) -> NDArray[float64]
cross_track_distance(point: Point, start: Point, end: GeometryArray[Point | None]) -> NDArray[float64]
cross_track_distance(point: Point | GeometryArray[Point | None], start: Point | GeometryArray[Point | None], end: Point | GeometryArray[Point | None]) -> float | NDArray[float64]

Signed distance from a point to the great circle through start and end, in meters.

Positive when the point lies left of the directed path start -> end, negative right, zero on it. Spherical on the CRS ellipsoid's mean radius. Geographic CRS only. An empty point yields nan.

Parameters:

Name Type Description Default
point Point or GeometryArray

The probe point and two distinct endpoints defining the directed path; all must share a CRS.

required
start Point or GeometryArray

The probe point and two distinct endpoints defining the directed path; all must share a CRS.

required
end Point or GeometryArray

The probe point and two distinct endpoints defining the directed path; all must share a CRS.

required

Returns:

Type Description
float or ndarray

Signed meters off-path.

Raises:

Type Description
GeometryTypeError

If any operand is not a Point.

CRSMismatchError

If the operands' CRS or coordinate-epoch metadata differ.

CRSError

If the CRS is missing or not geographic.

InvalidGeometryError

If start and end are coincident or antipodal and therefore do not define a unique great circle.

Examples:

>>> import gometry as gm
>>> a, b = gm.Point(0, 0, crs=4326), gm.Point(1, 0, crs=4326)
>>> probe = gm.Point(0.5, 0.1, crs=4326)
>>> round(gm.cross_track_distance(probe, a, b) / 1000, 1)
11.1

point_between

Accepted call forms
point_between(left: Point, right: Point, distance: ScalarFloatArray, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> Point
point_between(left: Point, right: Point, distance: FloatScalar | ScalarFloatArray, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> Point
point_between(left: GeometryArray[Point], right: Point | GeometryArray[Point], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> GeometryArray[Point]
point_between(left: Point, right: GeometryArray[Point], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> GeometryArray[Point]
point_between(left: Point, right: Point, distance: ScalarFloatArray, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> Point
point_between(left: Point, right: Point, distance: FloatColumn | ndarray[tuple[int], dtype[floating[Any] | signedinteger[Any] | unsignedinteger[Any]]], *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> GeometryArray[Point]
point_between(left: Point, right: Point, distance: FloatScalar | ScalarFloatArray, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> Point
point_between(left: GeometryArray[Point], right: Point | GeometryArray[Point], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> GeometryArray[Point]
point_between(left: Point, right: GeometryArray[Point], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> GeometryArray[Point]
point_between(left: Point, right: Point, distance: FloatColumn | ndarray[tuple[int], dtype[floating[Any] | signedinteger[Any] | unsignedinteger[Any]]], *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> GeometryArray[Point]
point_between(left: GeometryArray[Point | None], right: Point | GeometryArray[Point | None], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> GeometryArray[Point | None]
point_between(left: Point, right: GeometryArray[Point | None], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic'] = 'geodesic', unit: Literal['planar', 'meters'] | None = None) -> GeometryArray[Point | None]
point_between(left: GeometryArray[Point | None], right: Point | GeometryArray[Point | None], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> GeometryArray[Point | None]
point_between(left: Point, right: GeometryArray[Point | None], distance: FloatInput, *, normalized: bool = False, path: Literal['geodesic', 'rhumb'] = 'geodesic', unit: None = None) -> GeometryArray[Point | None]

Return a point interpolated from left towards right.

CRS-aware like every metric: geodesic on a geographic CRS, planar on a projected CRS, and raw coordinate units when CRS-free. path='rhumb' follows the constant-bearing track on a geographic CRS. Z/M interpolate. An empty endpoint yields POINT EMPTY.

Parameters:

Name Type Description Default
left Point or GeometryArray

Endpoints; must share a CRS.

required
right Point or GeometryArray

Endpoints; must share a CRS.

required
distance float or sequence of float

Finite distance(s) from left (or fractions if normalized). Values outside the segment clamp to its endpoints.

required
normalized bool

Treat distance as a fraction of the total distance.

False
path ('geodesic', 'rhumb')

Route model. Rhumb paths require a geographic CRS and use meters.

'geodesic'
unit ('planar', 'meters')

None (the default) follows the CRS: geographic shape area and length use ellipsoidal chart-edge measures while point distances use geodesics; projected measurements use native linear units, and CRS-free measurements use raw coordinate units (area results square the corresponding unit). 'planar' uses Cartesian coordinate space, with geographic coordinates in their native angular units. 'meters' uses the CRS-aware metric and requires a CRS.

path='rhumb' uses meters and does not accept a unit override.

'planar'

Returns:

Type Description
Point or GeometryArray

One interpolated point per input pair.

Raises:

Type Description
GeometryTypeError

If either operand is not a Point.

CRSMismatchError

If the operands' CRS or coordinate-epoch metadata differ.

GeometryError

If distance is non-finite.

Examples:

>>> import gometry as gm
>>> gm.point_between(gm.Point(0, 0), gm.Point(2, 0), 0.5).to_wkt()
'POINT (0.5 0)'