Search by

longitude-one / spatial-core

Alexandre-T

Core classes for other LongitudeOne spatial libraries.

Package info

github.com/longitude-one/spatial-core

pkg:composer/longitude-one/spatial-core

Statistics

Installs: 4 244

Dependents: 2

Suggesters: 0

Stars: 1

Open Issues: 1

1.3.0 2026-10-03 20:49 UTC

README

longitude-one/spatial-core Stable release PHP CI Minimum PHP Version Downloads codecov

Shared spatial primitives for LongitudeOne spatial libraries.

The package provides spatial models, geometry types, coordinate and topological dimensions, geographic axis conventions, and exceptions for values outside their valid range.

Installation

composer require longitude-one/spatial-core:1.3.0

Support policy

This package supports PHP 8.3 and later. Its public API includes the enums documented below, DiagnosticValueFormatter, ExceptionInterface, and RangeException.

Geographic axes

AxisEnum describes the two axes of a geographic coordinate:

Axis Abbr. Positive direction Negative direction Valid range
Latitude lat North (N). South (S). -90 to 90 degrees
Longitude lon East (E) West (W) -180 to 180 degrees
use LongitudeOne\Core\Enum\AxisEnum;

$latitude = AxisEnum::LATITUDE;

assert('lat' === $latitude->abbreviation());
assert('N' === $latitude->positiveCardinal());
assert('S' === $latitude->negativeCardinal());
assert(90 === $latitude->rangeLimit());

assert(AxisEnum::LONGITUDE === $latitude->other());

Range exceptions

RangeException creates the appropriate exception for an axis. All library exceptions implement ExceptionInterface, allowing callers to handle library failures through one common type.

use LongitudeOne\Core\Enum\AxisEnum;
use LongitudeOne\Core\Exception\ExceptionInterface;
use LongitudeOne\Core\Exception\RangeException;

$axis = AxisEnum::LATITUDE;
$value = 91;

try {
    if (abs($value) > $axis->rangeLimit()) {
        throw RangeException::forAxis($axis, (string) $value);
    }
} catch (ExceptionInterface $exception) {
    // Handle a LongitudeOne spatial-core exception.
}

Enumerations

AxisEnum

AxisEnum identifies the geographic axis being handled: latitude or longitude. It centralizes each axis's abbreviation, cardinal directions, and allowed range, so validation and error messages use the same convention everywhere.

use LongitudeOne\Core\Enum\AxisEnum;

$axis = AxisEnum::LONGITUDE;

assert('E' === $axis->positiveCardinal());
assert(180 === $axis->rangeLimit());

CoordinateDimensionEnum

CoordinateDimensionEnum describes the ordinates stored for every position in a geometry. It follows the SQL/MM Spatial layouts: planar coordinates (XY), altitude (Z), and/or an arbitrary measure (M), with WKT modifiers Z, M, and ZM. It lets a parser, serializer, or validator handle layouts such as XYZM without scattering special cases; M is an arbitrary measure, commonly used for linear referencing, not inherently time.

use LongitudeOne\Core\Enum\CoordinateDimensionEnum;

$layout = CoordinateDimensionEnum::XYZM;

assert($layout->hasM());
assert($layout->hasZ());
assert(4 === $layout->coordinateDimension());
assert('ZM' === $layout->wktModifier());

UnitTypeEnum

UnitTypeEnum classifies the unit of measure of a spatial reference system as angular or linear. It prevents a value in degrees or radians from being treated as a distance in metres.

use LongitudeOne\Core\Enum\UnitTypeEnum;

$unitType = UnitTypeEnum::ANGULAR;

assert('ANGULAR' === $unitType->value);

CoordinateReferenceSystemKindEnum

CoordinateReferenceSystemKindEnum identifies whether a spatial reference system is geographic, projected, or geocentric. Unlike SpatialModelEnum, it classifies the actual reference system rather than the model selected for spatial calculations.

use LongitudeOne\Core\Enum\CoordinateReferenceSystemKindEnum;

$kind = CoordinateReferenceSystemKindEnum::PROJECTED;

assert('PROJECTED' === $kind->value);

TopologicalDimensionEnum

TopologicalDimensionEnum expresses what a geometry represents independently of its coordinate layout: an empty set (-1), point (0), curve (1), or surface (2). It is useful when selecting operations that apply to routes or areas, regardless of whether their coordinates include altitude or measures: an XYZM point remains topologically zero-dimensional, while an XY curve remains one-dimensional.

use LongitudeOne\Core\Enum\TopologicalDimensionEnum;

$dimension = TopologicalDimensionEnum::SURFACE;

assert($dimension->isSurface());
assert(!$dimension->isCurve());

GeometryTypeEnum

GeometryTypeEnum identifies geometry types and exposes their homogeneous component and topological dimension. Its isInstantiable() method returns false for GEOMETRY, CURVE, SOLID, and SURFACE, and true for every other case, including MULTICURVE and MULTISURFACE.

The additional types BREPSOLID, CIRCLE, CLOTHOID, COMPOUNDSURFACE, ELLIPTICALCURVE, GEODESICSTRING, NURBSCURVE, and SPIRALCURVE are instantiable. BREPSOLID has volume dimension, COMPOUNDSURFACE has surface dimension, and the remaining types have curve dimension. None is a multi-geometry or a geometry collection. CIRCLE and GEODESICSTRING have POINT components. The other additions have no single concrete component type exposed by this enum: compound surfaces and solid shells can use different surface subtypes, while NURBS curves use weighted control points and knots, and the other curves use constructive parameters.

These additions follow ISO/IEC DIS 13249-3, fifth-edition ballot text N2593 dated 2015-01-25, clauses 4.2.7–4.2.12, 4.2.20, 4.2.22, 7.4.1–7.9.1, 8.7.1, and 9.2.1. Enum membership does not imply concrete geometry classes or support for encoding or decoding these types.

use LongitudeOne\Core\Enum\GeometryTypeEnum;
use LongitudeOne\Core\Enum\TopologicalDimensionEnum;

$type = GeometryTypeEnum::MULTIPOLYGON;

assert($type->isMulti());
assert($type->isInstantiable());
assert(GeometryTypeEnum::POLYGON === $type->componentType());
assert(TopologicalDimensionEnum::SURFACE === $type->topologicalDimension());

ByteOrderEnum

ByteOrderEnum provides the standard byte-order marker for a Well-Known Binary (WKB) serializer or parser. Big endian is encoded as 0; little endian is encoded as 1.

use LongitudeOne\Core\Enum\ByteOrderEnum;

$byteOrder = ByteOrderEnum::LITTLE_ENDIAN;

assert(1 === $byteOrder->value);

SpatialModelEnum

SpatialModelEnum distinguishes a planar GEOMETRY from a terrestrial GEOGRAPHY value. It tells a caller whether longitude and latitude must be checked against their geographic ranges before building or persisting a value.

use LongitudeOne\Core\Enum\SpatialModelEnum;

$model = SpatialModelEnum::GEOGRAPHY;

assert($model->isGeography());
assert($model->requiresGeographicCoordinateRanges());

Diagnostic value formatter

DiagnosticValueFormatter produces a safe, single-line and bounded representation of an untrusted value before it is placed in an exception message, log entry, or terminal output. It makes control and problematic invisible Unicode characters visible, neutralizes terminal escape sequences, preserves valid UTF-8 where possible, and limits the result to 2,048 characters. It does not validate spatial data or escape data for HTML, JSON, XML, or SQL.

use LongitudeOne\Core\Diagnostic\DiagnosticValueFormatter;

$value = "POINT(2.3522 48.8566)\n";

assert('POINT(2.3522 48.8566)\\n' === DiagnosticValueFormatter::format($value));

Exception factories can use the formatter while retaining their package-specific exception hierarchy:

use LongitudeOne\Core\Diagnostic\DiagnosticValueFormatter;

final class InvalidValueException extends \InvalidArgumentException implements ExceptionInterface
{
    public static function invalidCoordinate(string $coordinate): self
    {
        return new self(sprintf(
            'Invalid coordinate "%s".',
            DiagnosticValueFormatter::format($coordinate),
        ));
    }
}

Development

Run the test suite:

composer test

Generate the coverage reports:

composer test-coverage

The coverage outputs are written to .phpunit.cache/code-coverage/, including clover.xml and an HTML report at html/index.html.