Skip to main content

Collections and EMPTY members

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-validator.

View the library roadmap

A collection groups spatial objects without discarding their identities. A MultiPoint can retain an EMPTY Point alongside a measured position; validation checks both members and does not normalize the collection. General GeometryCollection also permits valid EMPTY members and heterogeneous spatial types.

All-EMPTY and mixed members​

use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\LineString;
use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\MultiLineString;
use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\MultiPoint;
use LongitudeOne\SpatialTypes\Types\Dimension2\Geometry\Point;
use LongitudeOne\SpatialValidator\Validator\Constraints as SpatialAssert;
use Symfony\Component\Validator\Validation;

$validator = Validation::createValidator();
$emptyPoint = new Point();
$emptyLine = new LineString([]);
$allEmpty = new MultiPoint([$emptyPoint, $emptyPoint]);
$mixed = new MultiPoint([$emptyPoint, new Point(10, 20)]);
$allEmptyLines = new MultiLineString([$emptyLine]);
$mixedLines = new MultiLineString([$emptyLine, new LineString([[0, 0], [1, 1]])]);

foreach ([$allEmpty, $mixed, $allEmptyLines, $mixedLines] as $value) {
echo count($validator->validate($value, new SpatialAssert\Spatial())); // 0 each
}
echo count($allEmpty->getPoints()); // 2: members are preserved

For GeometryCollection, MultiPoint, MultiLineString and MultiPolygon, an empty list and an all-EMPTY member list both represent the empty set under the validation profile. A mixed list represents the non-empty members' spatial content while retaining its EMPTY members. The validator computes the relevant aggregate state from members; it does not rewrite the object's isEmpty() accessor. In the inspected model revision, some collection accessors report list emptiness, so a retained all-EMPTY list can still have isEmpty() === false.

Aggregate or componentPermitted membersEMPTY membersAdditional ordinary requirements
GeometryCollectionAny spatial type✅ AllowedAvailable recursive validity; no cross-member disjointness
MultiPointPoints✅ AllowedPoint rules and metadata
MultiLineStringLineStrings✅ AllowedLineString rules and metadata
MultiPolygonPolygons or Triangles✅ AllowedComplete surfaces and pair topology
LineString componentsPointsEMPTY policyComponent rules
LineString positionsPoints❌ RejectedEvery Point in the position sequence must be non-EMPTY
CircularString componentsDefining PointsEMPTY policyComponent rules
CircularString positionsPoints❌ RejectedEvery arc-defining Point must be non-EMPTY
CompoundCurve componentsContributing curvesEMPTY policyComponent rules
CompoundCurve membersLineStrings or CircularStrings❌ RejectedEvery contributing curve must be non-EMPTY and joins must be continuous
Polygon componentsBoundary ringsEMPTY policyComponent rules
Polygon exteriorLineString ring❌ RejectedA non-empty Polygon requires a non-EMPTY exterior ring
Polygon holesLineString rings❌ RejectedEvery interior ring must be non-EMPTY
Triangle componentsBoundary ringsEMPTY policyComponent rules
Triangle exteriorLineString ring❌ RejectedExactly four positions A–B–C–A; three distinct non-collinear vertices
Triangle holesNone permitted❌ RejectedInterior rings are forbidden, whether EMPTY or non-empty
PolyhedralSurface componentsSurface patchesEMPTY policyComponent rules
PolyhedralSurface patchesPolygons or Triangles❌ RejectedEvery patch must be non-EMPTY and valid; the surface requires XYZ or XYZM

All members must keep the parent's Geometry/Geography family, exact XY/XYZ/XYM/XYZM variant, and full spatial-reference identity: authority and identifier. Numeric SRID equality alone is insufficient if authorities differ. Validation neither converts nor reprojects mismatched members.

The ❌ entries prohibit EMPTY components, not a genuinely EMPTY geometry with no components. A LineString or CircularString with no Points, a CompoundCurve with no curves, and a Polygon or Triangle with no rings are valid EMPTY objects. A memberless XYZ/XYZM PolyhedralSurface is also valid EMPTY; a stored list of EMPTY patches is rejected. A Point has no component geometries: it is valid EMPTY when all its declared ordinates are absent, rather than only some of them. An EMPTY Point is still prohibited inside a non-empty LineString; neither the exterior nor the holes of a Polygon may be EMPTY rings. Likewise a contributing CompoundCurve member or PolyhedralSurface patch cannot be EMPTY. Typed EMPTY collection membership does not remove these separate per-type rules.

Optional aggregate properties​

Continue with the validator and collections above:

$duplicates = new MultiPoint([new Point(1, 2), new Point(1, 2)]);
echo count($validator->validate($duplicates, new SpatialAssert\MultiPoint())); // 0
echo count($validator->validate($duplicates, new SpatialAssert\SimpleMultiPoint())); // 1
echo count($validator->validate($allEmptyLines, new SpatialAssert\ClosedMultiLineString())); // 1

SimpleMultiPoint ignores absent EMPTY positions and rejects repeated non-empty spatial positions. SimpleMultiLineString first validates and checks each member's simplicity, then permits inter-member contacts only at both members' boundaries. A closed line has an empty boundary, so its closing vertex is not an allowed inter-member endpoint contact.

ClosedMultiLineString requires a non-empty aggregate and every member closed. An EMPTY member fails explicit closure in a mixed aggregate. Simplicity and closure remain independent. Non-empty Geography simplicity and closure calculations that are unavailable produce warnings; available structural checks still run.

SQL/MM methods have a separate scope​

ISO/IEC 13249-3 describes member well-formedness in 9.2.1 Description 7 for MultiPoint and 9.4.1 Description 3 for MultiLineString.

The approved LongitudeOne geometric profile permits valid EMPTY members rather than applying a blanket prohibition. OGC SFA 1.2.1, 6.1.5 and 6.1.8–6.1.9 are the related collection definitions.

Specific SQL/MM mutation/cast paths impose stricter input restrictions:

Inspected pathConsequence
ST_MultiPoint.ST_Geometries(array), 9.2.3 → ST_ToPointAry, 16.1.8 → ST_CheckNulls, 16.1.6Rejects null or EMPTY elements
ST_MultiLineString.ST_Geometries(array), 9.4.3 → ST_ToLineStringAry, 16.1.10 → ST_CheckNulls, 16.1.6Rejects null or EMPTY elements

Constructor or mutation operations that traverse those support paths inherit their restrictions. These are method-specific acceptance rules, not proof that every spatial object containing an EMPTY member is geometrically invalid. The Symfony API validates spatial objects; it does not execute these SQL routines or promise their construction behavior.