Skip to main content

Spatial validators

View Markdown versionEdit this page on GitHub

Next version — This documentation describes a major version that is not yet the current stable release of spatial-types.

View the library roadmap

Symfony Validator ^5.4 || ^6.0 || ^7.0 || ^8.0 is supported. Versions below 5.4 and future major versions such as 9.x are not accepted. The library still requires PHP 8.4 or later within PHP 8.x, independently of Symfony's requirements. CI explicitly installs and verifies Validator 5.4.x, 6.4.x, 7.4.x and 8.1.x, then runs the complete test suite for each version.

This library exposes Symfony Validator constraints for checking spatial values. They are useful in two complementary situations:

  • Internal invariants protect a value while it is built or updated. The library invokes the relevant validator and throws InvalidValueException or a compatibility exception when the invariant is not met.
  • Application rules are opt-in. Create a Symfony validator and apply the constraint yourself; validation returns a ConstraintViolationList and does not alter the spatial value.

The second category is deliberately not imposed by constructors. For example, a LineString can be non-simple when an application needs to retain imported or invalid geometry for later review.

Summary​

ConstraintRule
NoConsecutiveDuplicatePointsAdjacent points must differ.
MinimumPointCountRequires at least the configured number of points (four by default).
FirstPointEqualsLastPointFirst and last points are equal.
RingComposes minimum point count, closure, and no consecutive duplicate points.
TriangleEmpty or one four-position exterior ring, validated through Ring, without holes.
PolyhedralSurfaceEmpty or connected planar 3D faces with simple rings and consistent shared edges; free edges are allowed.
SameFamilyUses the requested Geometry or Geography family.
SameDimensionUses the requested XY, XYZ, XYM, or XYZM layout.
SameSpatialReferenceUses the requested complete spatial reference.
SimpleLineStringIs simple in the XY projection; Z and M are ignored.
SimpleThreeDimensionalLineStringIs simple in XYZ space; M is ignored.

Application of constraints​

ConstraintValueApplied internallyTypical external use
NoConsecutiveDuplicatePointsLineStringYes: LineString construction and coordinate replacement.Audit an implementation of LineStringInterface.
MinimumPointCountLineStringThrough Ring when a polygon receives a ring.Validate a candidate ring before building a polygon.
FirstPointEqualsLastPointLineStringThrough Ring when a polygon receives a ring.Validate a candidate ring.
RingLineStringYes: polygon boundaries.Validate a ring independently.
TrianglePolygonInterfaceYes: triangle construction and coordinate replacement.Check whether a polygon has triangle structure.
PolyhedralSurfacePolyhedralSurfaceInterfaceYes: construction and coordinate replacement.Audit patch boundaries without requiring a closed solid.
SameFamilySpatial valueYes: aggregate membership.Validate an incoming member against an expected family.
SameDimensionSpatial valueYes: aggregate membership.Validate an incoming member against an expected layout.
SameSpatialReferenceSpatial valueYes: aggregate membership.Validate an incoming member against an expected reference.
SimpleLineStringLineStringNo.Apply the usual two-dimensional simplicity rule.
SimpleThreeDimensionalLineStringXYZ/XYZM LineStringNo.Apply a three-dimensional simplicity rule.

“Applied internally” describes the library's public constructors and immutable replacement methods. It does not mean every constraint is automatically run when Symfony validates an object.

Using a constraint externally​

Create Symfony's validator, validate the value, then inspect the violation list. No exception is thrown merely because the rule fails.

use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\LineString;
use LongitudeOne\SpatialTypes\Validator\Constraints\SimpleLineString;
use Symfony\Component\Validator\Validation;

$line = new LineString([[0, 0], [2, 2], [0, 2], [2, 0]]);
$violations = Validation::createValidator()->validate($line, new SimpleLineString());

if (0 !== count($violations)) {
// The line self-intersects in XY.
}

Several constraints may be evaluated together:

use LongitudeOne\SpatialTypes\Validator\Constraints\FirstPointEqualsLastPoint;
use LongitudeOne\SpatialTypes\Validator\Constraints\MinimumPointCount;
use LongitudeOne\SpatialTypes\Validator\Constraints\NoConsecutiveDuplicatePoints;
use LongitudeOne\SpatialTypes\Validator\Constraints\SimpleLineString;

$violations = Validation::createValidator()->validate($line, [
new MinimumPointCount(),
new FirstPointEqualsLastPoint(),
new NoConsecutiveDuplicatePoints(),
new SimpleLineString(),
]);

Use Ring instead of its three structural components when simplicity is not a requirement. Add SimpleLineString separately when it is. PolyhedralSurface composes Ring and SimpleThreeDimensionalLineString for each face boundary, checks face planarity and tests oriented edge incidence and global connectivity. Empty surfaces and single faces are accepted, but empty member faces are not. The edge test splits common segments at existing vertices and ignores M. It uses exact XYZ arithmetic, including in Geography, without geodesic modelling. It does not validate arbitrary face-interior intersections, hole containment or vertex-manifold topology. A surface can have free boundary edges; closure around a solid is not required.

Two-dimensional and three-dimensional simplicity​

SimpleLineString checks only X/Y. An XY crossing is a violation even when the segments use different elevations. This corresponds to the usual 2D topological predicate.

SimpleThreeDimensionalLineString accepts only line strings with a Z ordinate (XYZ or XYZM) and checks X/Y/Z. Two segments that cross in projection but are at different elevations do not meet in 3D. M is not a spatial coordinate for this rule and is ignored.

use LongitudeOne\SpatialTypes\Types\Dimension3z\Geometry\LineString;
use LongitudeOne\SpatialTypes\Validator\Constraints\SimpleThreeDimensionalLineString;

$line = new LineString([[0, 0, 0], [2, 2, 0], [0, 2, 1], [2, 0, 1]]);
$violations = Validation::createValidator()->validate($line, new SimpleThreeDimensionalLineString());

// No violation: the projected crossing occurs at two different elevations.

Compatibility constraints​

The three compatibility constraints use the expected value as their constructor argument. This mirrors the checks performed when a spatial value is added to an aggregate.

use LongitudeOne\Core\Enum\CoordinateDimensionEnum;
use LongitudeOne\Core\Enum\SpatialModelEnum;
use LongitudeOne\SpatialTypes\Reference\SpatialReference;
use LongitudeOne\SpatialTypes\Validator\Constraints\SameDimension;
use LongitudeOne\SpatialTypes\Validator\Constraints\SameFamily;
use LongitudeOne\SpatialTypes\Validator\Constraints\SameSpatialReference;

$violations = Validation::createValidator()->validate($line, [
new SameFamily(SpatialModelEnum::GEOMETRY),
new SameDimension(CoordinateDimensionEnum::XYZ),
new SameSpatialReference(SpatialReference::fromSrid(2154), 'line string'),
]);

An SRID of 0 is a concrete unnamed spatial reference, not a wildcard. See Spatial reference systems for the membership rules and their rationale.

Triangle structure​

Triangle validates any PolygonInterface, including ordinary polygons and third-party implementations. It accepts an empty boundary; otherwise it requires exactly one exterior ring containing four positions and no interior rings (ISO/IEC CD 13249-3, section 8.4). It composes Ring to check closure and consecutive duplicate points. It does not test non-collinearity or full polygon topology.

use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\Polygon;
use LongitudeOne\SpatialTypes\Validator\Constraints\Triangle;
use Symfony\Component\Validator\Validation;

$polygon = new Polygon([[[0, 0], [4, 0], [0, 4], [0, 0]]]);
$violations = Validation::createValidator()->validate($polygon, new Triangle());

Triangle values invoke this constraint through TriangleValidation during construction and immutable coordinate replacements, in both families and all four coordinate layouts. Invalid values raise InvalidValueException.