Skip to content

Story: Implement COMPOUNDCURVE spatial type #25

Closed

Description

@Alexandre-T

Implement COMPOUNDCURVE spatial type

As a developer using spatial-types,
I want COMPOUNDCURVE to be fully implemented as a concrete spatial type,
so that continuous curves composed of multiple curve components can be represented and consumed by downstream libraries such as the EWKT decoder.

Context

COMPOUNDCURVE is an instantiable subtype of CURVE.

It is required for the spatial-types 1.0.0 release because it belongs to the geometry set required to complete the targeted EWKT decoding support in spatial-decoder.

A CompoundCurve represents a continuous curve constructed from an ordered sequence of curve components.

For the spatial-types 1.0.0 scope, the supported components required by the current spatial model are:

  • LINESTRING;
  • CIRCULARSTRING.

The components are connected end to end.

For every pair of consecutive components, the end point of the preceding component must be equal to the start point of the following component.

This continuity requirement is an invariant of the CompoundCurve and must be enforced by spatial-types.

All components must also satisfy the coordinate-dimension and spatial-reference consistency rules established by the library.

Functional Requirements

COMPOUNDCURVE must follow the existing spatial-types architecture and expose the public contracts appropriate for an instantiable CURVE.

The implementation must support the coordinate dimensions supported by the LongitudeOne spatial model:

  • XY;
  • XYZ;
  • XYM;
  • XYZM.

A CompoundCurve is represented as an ordered collection of supported curve components.

The order of the components is significant and defines the traversal of the CompoundCurve.

For consecutive components:

end(component[n]) == start(component[n + 1])

must hold according to the point equality semantics established by spatial-types.

The CompoundCurve must preserve its component curves. It must not flatten a CIRCULARSTRING into a LINESTRING or approximate circular interpolation using linear segments.

An empty CompoundCurve must be representable consistently with the existing empty-geometry model.

Component Types

For the 1.0.0 implementation, a CompoundCurve must accept:

  • LINESTRING;
  • CIRCULARSTRING.

The public design should rely on the appropriate curve abstraction where possible and must not unnecessarily prevent additional compatible curve implementations from being supported in future backward-compatible releases.

A component must itself represent a valid curve according to its own spatial type contract.

Continuity

The components of a non-empty CompoundCurve must form a continuous sequence.

For each pair of consecutive components:

  • the preceding component must have an end point;
  • the following component must have a start point;
  • both points must be equal.

A discontinuity between two components makes the CompoundCurve invalid.

For example:

LINESTRING(A, B, C)
                   \
                    C
                     \
                      CIRCULARSTRING(C, D, E)

is continuous because both components meet at C.

Conversely:

LINESTRING(A, B, C)

CIRCULARSTRING(D, E, F)

is not a valid CompoundCurve when C != D.

Coordinate Dimension

All components of a CompoundCurve must use the same coordinate dimension.

The implementation must support:

  • XY;
  • XYZ;
  • XYM;
  • XYZM.

Mixing components with different coordinate dimensions in the same CompoundCurve must be rejected according to the existing dimension-consistency rules of spatial-types.

Spatial Reference

All components of a CompoundCurve must use compatible spatial references according to the existing spatial-reference rules of spatial-types.

A CompoundCurve containing components with incompatible spatial references must be rejected.

Closure

A non-empty CompoundCurve is closed when the start point of its first component is equal to the end point of its last component.

Closure does not remove the continuity requirement between intermediate components.

The implementation must preserve the distinction between:

  • an open CompoundCurve;
  • a closed CompoundCurve.

Any ring semantics applicable to a closed and simple CompoundCurve must remain consistent with the normative spatial model and the existing curve contracts.

Public Contract

The implementation must provide the same architectural guarantees as the other concrete curve types exposed by spatial-types.

The public API must allow consumers to:

  • construct an empty CompoundCurve;
  • construct a CompoundCurve from supported curve components;
  • access its components in their original order;
  • access its start and end points through the applicable curve contract;
  • determine whether it is closed according to the applicable curve contract;
  • determine its coordinate dimension;
  • determine its spatial reference according to the existing spatial type contracts;
  • identify its geometry type as COMPOUNDCURVE;
  • use it through the applicable spatial and curve interfaces.

The API must preserve the distinction between the component curve types.

It must not expose implementation details that would unnecessarily constrain future internal evolution after spatial-types 1.0.0.

Validation

Validation must reject a CompoundCurve when:

  • consecutive components are not continuous;
  • components use inconsistent coordinate dimensions;
  • components use incompatible spatial references;
  • a component violates an invariant required by its own spatial type;
  • another existing invariant inherited from the applicable spatial-types contracts is violated.

Validation must not alter, linearize or otherwise normalize valid component curves merely to establish continuity.

Implementation Status

Once this Story is completed, COMPOUNDCURVE is no longer considered a not-yet-implemented geometry type.

SpatialTypeImplementationStatus::isFullyImplemented() must return true for GeometryTypeEnum::COMPOUNDCURVE.

Acceptance Criteria

  • A public concrete implementation exists for COMPOUNDCURVE.
  • COMPOUNDCURVE follows the applicable CURVE and spatial type contracts.
  • Empty CompoundCurves are supported consistently with the existing empty-geometry model.
  • A CompoundCurve can contain LINESTRING components.
  • A CompoundCurve can contain CIRCULARSTRING components.
  • A CompoundCurve can contain a combination of LINESTRING and CIRCULARSTRING components.
  • Component order is preserved.
  • Consecutive components are required to be continuous.
  • Discontinuous components are rejected.
  • The original component curve types are preserved and are not linearized.
  • XY CompoundCurves are supported.
  • XYZ CompoundCurves are supported.
  • XYM CompoundCurves are supported.
  • XYZM CompoundCurves are supported.
  • Components with inconsistent coordinate dimensions are rejected.
  • Components with incompatible spatial references are rejected.
  • Open CompoundCurves are supported.
  • Closed CompoundCurves are supported.
  • The geometry type is reported as COMPOUNDCURVE.
  • SpatialTypeImplementationStatus::isFullyImplemented() returns true for COMPOUNDCURVE.
  • Unit tests cover CompoundCurves composed only of LINESTRING components.
  • Unit tests cover CompoundCurves composed only of CIRCULARSTRING components.
  • Unit tests cover mixed LINESTRING and CIRCULARSTRING components.
  • Unit tests cover continuity and discontinuity between components.
  • Unit tests cover open and closed CompoundCurves.
  • Unit tests cover XY, XYZ, XYM and XYZM.
  • Dimension and spatial-reference inconsistencies are covered by tests.
  • The public implementation can be consumed without relying on internal APIs.
  • The complete test suite passes.
  • All project quality checks pass.

Dependencies

This Story depends on the implementation of CIRCULARSTRING.

CIRCULARSTRING must therefore be completed before COMPOUNDCURVE can be considered fully implemented for the spatial-types 1.0.0 release.

Out of Scope

This Story does not implement:

  • CIRCULARSTRING itself;
  • CURVEPOLYGON;
  • additional curve types;
  • EWKT parsing or decoding;
  • WKT, WKB, EWKB or other serialization formats;
  • curve linearization or rendering.

Those concerns belong to their respective Stories or libraries.

Activity

  1. added this to the Version 1.0.0 milestone on Oct 4, 2026
  2. added theissue type on Oct 4, 2026
  3. Alexandre-T commented on Oct 4, 2026

    @Alexandre-T
    ContributorAuthor

    Pre-checks completed: Story #25 is Ready, type Story, 5 points, priority P2; parent #23 reviewed; dependency #24 is Closed / Done. No files were modified.

    API decision required before implementation

    CurveInterface is currently a marker interface with no methods. The Story requires endpoints and closure semantics, and the approval of #24 requires CompoundCurve to depend on CurveInterface, while explicitly requiring another API Gate for any new contract decision.

    Two concrete options:

    • Recommended before 1.0: add getStartPoint(): ?PointInterface, getEndPoint(): ?PointInterface, and isClosed(): bool to CurveInterface, with implementations for LineString, CircularString, and CompoundCurve. This requires both an API Gate and a Breaking Gate: third-party implementations of these interfaces will need to implement the new methods.
    • Keep CurveInterface as a marker interface: expose these methods only on a new CompoundCurveInterface, then use internal adaptations for the two allowed component types. This is backward-compatible, but provides no common endpoint contract.

    Standard consulted

    The standard actually consulted was ISO/IEC CD 13249-3:201x(E), clauses 4.2.7, 7.4.1 rules 7–10, and 7.4.6–7.4.7.

    It confirms the use of LineString and CircularString components, continuity requirements, and null endpoints for EMPTY geometries. It does not prescribe the PHP API contract.

    Reason for stopping

    Implementation was stopped in accordance with longitudeone-spatial-governance/SKILL.md:

    “A Breaking Gate always requires explicit human approval.”

    This is also consistent with the human approval recorded for #24, as described above.

    No PR was created. The reviewer should be run after this gate is resolved and the PR has been created.

  4. Alexandre-T commented on Oct 4, 2026

    @Alexandre-T
    ContributorAuthor

    API Gate and Breaking Gate approved.

    Proceed with the recommended solution.

    Add the following common curve contract to CurveInterface:

    public function getStartPoint(): ?PointInterface;
    
    public function getEndPoint(): ?PointInterface;
    
    public function isClosed(): bool;

    Implement this contract consistently for LineString, CircularString, and the new CompoundCurve.

    For EMPTY curves, the start and end points must be null, consistently with the normative behavior identified during the review.

    I explicitly approve the backward-incompatible change to the existing public interfaces. We are still before the 1.0.0 stable API boundary, and establishing a meaningful common curve abstraction now is preferable to keeping CurveInterface as a marker interface.

    CompoundCurve must depend on CurveInterface for its curve components rather than on a union of the currently supported concrete curve interfaces.

    This approval is limited to this common endpoint and closure contract. Any additional public API or breaking-contract decision that cannot be derived from the approved Story, existing architecture, or normative requirements must go through a new API/Breaking Gate.

  5. self-assigned this
    on Oct 4, 2026
  6. changed the title [-]Implement `COMPOUNDCURVE` spatial type[/-] [+]Story: Implement `COMPOUNDCURVE` spatial type[/+] on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

impact:apiAffects the public APIimpact:breakingIntroduces a backward-incompatible changespatial:geometryRelated to geometry models or typesstandard:isoRelated to ISO spatial standards

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions