This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 3337cb71bae057805ce04f831a34d3e6c10f65c4
Author: jsorel <[email protected]>
AuthorDate: Mon Oct 19 11:50:04 2026 +0200

    feat(Geometry): add draft topology interfaces
---
 .../org.apache.sis.geometry/main/module-info.java  |   1 +
 .../org/apache/sis/geometries/package-info.java    |   3 +-
 .../apache/sis/geometries/topology/Complex.java    | 116 ++++++++++++
 .../sis/geometries/topology/ComplexData.java       |  45 +++++
 .../sis/geometries/topology/DirectedEdge.java      | 101 +++++++++++
 .../sis/geometries/topology/DirectedFace.java      |  97 +++++++++++
 .../sis/geometries/topology/DirectedNode.java      |  97 +++++++++++
 .../sis/geometries/topology/DirectedSolid.java     |  98 +++++++++++
 .../sis/geometries/topology/DirectedTopo.java      |  94 ++++++++++
 .../org/apache/sis/geometries/topology/Edge.java   |  87 +++++++++
 .../apache/sis/geometries/topology/Expression.java | 194 +++++++++++++++++++++
 .../sis/geometries/topology/ExpressionTerm.java    |  69 ++++++++
 .../org/apache/sis/geometries/topology/Face.java   | 104 +++++++++++
 .../org/apache/sis/geometries/topology/Node.java   |  75 ++++++++
 .../apache/sis/geometries/topology/Primitive.java  | 140 +++++++++++++++
 .../sis/geometries/topology/PrimitiveData.java     |  34 ++++
 .../org/apache/sis/geometries/topology/Solid.java  |  87 +++++++++
 .../apache/sis/geometries/topology/Topology.java   | 167 ++++++++++++++++++
 .../sis/geometries/topology/TopologyData.java      |  72 ++++++++
 .../sis/geometries/topology/package-info.java      |  65 +++++++
 20 files changed, 1745 insertions(+), 1 deletion(-)

diff --git a/incubator/src/org.apache.sis.geometry/main/module-info.java 
b/incubator/src/org.apache.sis.geometry/main/module-info.java
index a7a0f82480..2a2df363ce 100644
--- a/incubator/src/org.apache.sis.geometry/main/module-info.java
+++ b/incubator/src/org.apache.sis.geometry/main/module-info.java
@@ -40,6 +40,7 @@ module org.apache.sis.geometry {
     exports org.apache.sis.geometries.solid;
     exports org.apache.sis.geometries.solid.polyhedron;
     exports org.apache.sis.geometries.spherical;
+    exports org.apache.sis.geometries.topology;
     exports org.apache.sis.gml;
     exports org.apache.sis.maths;
     exports org.apache.sis.scene;
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java
index 17330bc505..f7f41d86f9 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java
@@ -66,7 +66,8 @@
  * Geometry.getMaximalComplex returns a Geometry until this interface exists.
  *
  * <h3>TODO : ISO 19107 Topology (Section 10)</h3>
- * No interface or implementation yet.
+ * {@link org.apache.sis.geometries.topology} declares the interfaces, no 
implementation yet.
+ * The derived topological relations (Section 10.8) are not declared.
  * This work would be interesting to formalize delaunay classes.
  *
  * <h3>TODO : ISO 19107 Simplex (Section 11.1)</h3>
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Complex.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Complex.java
new file mode 100644
index 0000000000..a90c35fcf1
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Complex.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.Set;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+import org.apache.sis.geometries.Geometry;
+
+
+/**
+ * A set of topological primitives, organized so that set operations on its 
elements perform the equivalent
+ * operations on the positions of its geometric realization.
+ *
+ * <p>A complex of dimension <var>n</var> contains primitives of every 
dimension up to <var>n</var>:
+ * a 2-dimensional complex contains faces, edges and nodes, while a 
1-dimensional complex, or graph,
+ * contains only edges and nodes.</p>
+ *
+ * <p>The default construction of a topological complex is from a geometric 
collection, which then becomes
+ * its geometric realization. Only a collection of geometric primitives with 
mutually disjoint interiors
+ * gives a complex without error. Java interfaces have no constructor, so this 
is left to implementations.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.7.2
+ */
+@UML(identifier="Complex", specification=ISO_19107)
+public interface Complex extends Topology {
+
+    /**
+     * The primitives of this complex. This association makes a complex a set 
of primitives,
+     * and the set operations of the {@linkplain #getSubComplexes() Contains} 
association agree with it.
+     *
+     * @return primitives of this complex, at least one.
+     *
+     * @see ISO 19107:2019 - 10.7.2.7
+     */
+    @UML(identifier="element", specification=ISO_19107)
+    Set<Primitive> getElements();
+
+    /**
+     * Returns {@code true} if this complex is not contained in any larger 
complex.
+     *
+     * <p>The default implementation tests whether this complex is its own
+     * {@linkplain #getMaximalComplex() maximal complex}.</p>
+     *
+     * @return whether this complex is maximal.
+     *
+     * @see ISO 19107:2019 - 10.7.2.4
+     */
+    @UML(identifier="isMaximal", specification=ISO_19107)
+    default boolean isMaximal() {
+        return equals(getMaximalComplex());
+    }
+
+    /**
+     * Returns {@code true} if this complex is topologically connected, which 
implies that its geometric
+     * realization is connected too. It is the case when every primitive of 
this complex is linked to every
+     * other one by a sequence of boundary, co-boundary and isolated-in 
associations whose intermediate
+     * primitives all belong to this complex.
+     *
+     * @return whether this complex is connected.
+     *
+     * @see ISO 19107:2019 - 10.7.2.5
+     */
+    @UML(identifier="isConnected", specification=ISO_19107)
+    boolean isConnected();
+
+    /**
+     * The complexes contained in this complex, as sets of primitives.
+     *
+     * @return complexes contained in this complex.
+     *
+     * @see ISO 19107:2019 - 10.7.2.6
+     */
+    @UML(identifier="subComplex", specification=ISO_19107)
+    Set<Complex> getSubComplexes();
+
+    /**
+     * The complexes containing this complex, as sets of primitives.
+     *
+     * @return complexes containing this complex.
+     *
+     * @see ISO 19107:2019 - 10.7.2.6
+     */
+    @UML(identifier="superComplex", specification=ISO_19107)
+    Set<Complex> getSuperComplexes();
+
+    /**
+     * The geometric complex this complex represents, or {@code null} if none.
+     *
+     * <p>Difference with ISO 19107: the standard returns a geometric complex,
+     * a type which does not exist yet in this module.</p>
+     *
+     * @return geometric realization of this complex, or {@code null} if none.
+     *
+     * @see ISO 19107:2019 - 10.7.2.8
+     */
+    @UML(identifier="geometry", specification=ISO_19107)
+    Geometry getGeometry();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ComplexData.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ComplexData.java
new file mode 100644
index 0000000000..e70008e29b
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ComplexData.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * Data for building a topological {@link Complex} from a set of related 
primitive data, such that all
+ * the primitive interiors are disjoint and every boundary is represented by 
other geometries.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.7
+ */
+@UML(identifier="ComplexData", specification=ISO_19107)
+public interface ComplexData extends TopologyData {
+
+    /**
+     * Data of the primitives of this complex.
+     *
+     * @return data of the primitives of this complex.
+     *
+     * @see ISO 19107:2019 - 10.1.7.2
+     */
+    @UML(identifier="primitive", specification=ISO_19107)
+    List<PrimitiveData> getPrimitives();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedEdge.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedEdge.java
new file mode 100644
index 0000000000..9de767a3c9
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedEdge.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * An {@link Edge} with an orientation, used in the terms of an {@link 
Expression}.
+ * It is the topological equivalent of an oriented {@link 
org.apache.sis.geometries.Curve},
+ * standing for the edge traversed in one direction or the other.
+ *
+ * <p>In a 2-dimensional planar complex, an oriented edge bounds at most one 
face, on its left.
+ * In 3 dimensions, or in a non-planar 2-dimensional complex, it may bound 
several faces.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.4.2
+ */
+@UML(identifier="DirectedEdge", specification=ISO_19107)
+public interface DirectedEdge extends DirectedTopo {
+
+    /**
+     * Returns 1: an edge is a curve.
+     *
+     * @see ISO 19107:2019 - 10.4.1.5
+     */
+    @UML(identifier="dimension", specification=ISO_19107)
+    @Override
+    default int getDimension() {
+        return 1;
+    }
+
+    /**
+     * The two oriented nodes bounding this oriented edge: the node where it 
ends is positive,
+     * and the node where it starts is negative.
+     *
+     * @return the two oriented nodes at the ends of this oriented edge.
+     *
+     * @see ISO 19107:2019 - 10.4.1.3
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedNode> getBoundary();
+
+    /**
+     * Oriented faces having this oriented edge on their boundary.
+     * See {@link Edge#getCoBoundary()} for the orientation and the order of 
the faces.
+     *
+     * @return oriented faces around this oriented edge.
+     *
+     * @see ISO 19107:2019 - 10.4.1.2
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedFace> getCoBoundary();
+
+    /**
+     * The same edge with the opposite orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.3
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    @Override
+    DirectedEdge getNegate();
+
+    /**
+     * The edge of which this object is one of the two orientations.
+     *
+     * @see ISO 19107:2019 - 10.4.1.4
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    Edge getTopo();
+
+    /**
+     * The two oriented edges standing for the edge, the positive one first.
+     *
+     * @see ISO 19107:2019 - 10.4.1.4
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    List<DirectedEdge> getProxy();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedFace.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedFace.java
new file mode 100644
index 0000000000..2359666209
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedFace.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * A {@link Face} with an orientation, used in the terms of an {@link 
Expression} and to define the boundary
+ * of a {@link Solid}. It is the topological equivalent of an oriented {@link 
org.apache.sis.geometries.Surface}.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.5.3
+ */
+@UML(identifier="DirectedFace", specification=ISO_19107)
+public interface DirectedFace extends DirectedTopo {
+
+    /**
+     * Returns 2: a face is a surface.
+     *
+     * @see ISO 19107:2019 - 10.5.2.4
+     */
+    @UML(identifier="dimension", specification=ISO_19107)
+    @Override
+    default int getDimension() {
+        return 2;
+    }
+
+    /**
+     * Oriented edges bounding this oriented face, positive when the face is 
on their left.
+     * See {@link Face#getBoundary()} for the organization in rings.
+     *
+     * @return oriented edges bounding this oriented face.
+     *
+     * @see ISO 19107:2019 - 10.5.2.1
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedEdge> getBoundary();
+
+    /**
+     * Oriented solids having this oriented face on their boundary, at most 
two.
+     * See {@link Face#getCoBoundary()} for the orientation of the solids.
+     *
+     * @return oriented solids on each side of this oriented face.
+     *
+     * @see ISO 19107:2019 - 10.5.2.2
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedSolid> getCoBoundary();
+
+    /**
+     * The same face with the opposite orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.3
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    @Override
+    DirectedFace getNegate();
+
+    /**
+     * The face of which this object is one of the two orientations.
+     *
+     * @see ISO 19107:2019 - 10.5.2.3
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    Face getTopo();
+
+    /**
+     * The two oriented faces standing for the face, the positive one first.
+     *
+     * @see ISO 19107:2019 - 10.5.2.3
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    List<DirectedFace> getProxy();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedNode.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedNode.java
new file mode 100644
index 0000000000..a67d87bcd9
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedNode.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * A {@link Node} with an orientation, used in the terms of an {@link 
Expression}.
+ * The end node of an edge appears positively in the boundary of that edge, 
and its start node negatively.
+ * There is no separate geometric equivalent, since a point has no orientation.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.3.3
+ */
+@UML(identifier="DirectedNode", specification=ISO_19107)
+public interface DirectedNode extends DirectedTopo {
+
+    /**
+     * Returns 0: a node is a point.
+     *
+     * @see ISO 19107:2019 - 10.3.2.4
+     */
+    @UML(identifier="dimension", specification=ISO_19107)
+    @Override
+    default int getDimension() {
+        return 0;
+    }
+
+    /**
+     * Returns an empty list: a node has no boundary, which is a zero 
expression.
+     *
+     * @see ISO 19107:2019 - 10.3.2.3
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    default List<? extends DirectedTopo> getBoundary() {
+        return List.of();
+    }
+
+    /**
+     * Oriented edges having this oriented node on their boundary.
+     * See {@link Node#getCoBoundary()} for the orientation of the edges.
+     *
+     * @return oriented edges starting or ending at this node.
+     *
+     * @see ISO 19107:2019 - 10.3.2.1
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedEdge> getCoBoundary();
+
+    /**
+     * The same node with the opposite orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.3
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    @Override
+    DirectedNode getNegate();
+
+    /**
+     * The node of which this object is one of the two orientations.
+     *
+     * @see ISO 19107:2019 - 10.1.4.6
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    Node getTopo();
+
+    /**
+     * The two oriented nodes standing for the node, the positive one first.
+     *
+     * @see ISO 19107:2019 - 10.3.2.2
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    List<DirectedNode> getProxy();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedSolid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedSolid.java
new file mode 100644
index 0000000000..d8738bd666
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedSolid.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * A {@link Solid} with an orientation, used in the terms of an {@link 
Expression}.
+ * There is no separate geometric equivalent, since a geometric solid is not 
orientable.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.6.2
+ */
+@UML(identifier="DirectedSolid", specification=ISO_19107)
+public interface DirectedSolid extends DirectedTopo {
+
+    /**
+     * Returns 3: a solid is a volume.
+     *
+     * @see ISO 19107:2019 - 10.1.2.3
+     */
+    @UML(identifier="dimension", specification=ISO_19107)
+    @Override
+    default int getDimension() {
+        return 3;
+    }
+
+    /**
+     * Oriented faces bounding this oriented solid, positive when the solid is 
below them.
+     * See {@link Solid#getBoundary()} for the organization in shells.
+     *
+     * @return oriented faces bounding this oriented solid.
+     *
+     * @see ISO 19107:2019 - 10.6.1.2
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedFace> getBoundary();
+
+    /**
+     * Returns an empty list: a solid has the highest dimension, so it is on 
the boundary of nothing.
+     *
+     * <p>Difference with ISO 19107: the standard returns {@code NULL}.</p>
+     *
+     * @see ISO 19107:2019 - 10.6.1.3
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    default List<? extends DirectedTopo> getCoBoundary() {
+        return List.of();
+    }
+
+    /**
+     * The same solid with the opposite orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.3
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    @Override
+    DirectedSolid getNegate();
+
+    /**
+     * The solid of which this object is one of the two orientations.
+     *
+     * @see ISO 19107:2019 - 10.6.1.4
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    Solid getTopo();
+
+    /**
+     * The two oriented solids standing for the solid, the positive one first.
+     *
+     * @see ISO 19107:2019 - 10.6.1.4
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    List<DirectedSolid> getProxy();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedTopo.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedTopo.java
new file mode 100644
index 0000000000..4ca63c44a8
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/DirectedTopo.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+import org.apache.sis.geometries.Orientable;
+
+
+/**
+ * A topological primitive with an orientation, the topological equivalent of 
{@link Orientable}.
+ *
+ * <p>Since a primitive has only two orientations whatever its dimension, each 
primitive has two oriented
+ * primitives. Each primitive type extends its oriented type, so that a 
primitive is its own positive
+ * orientation, as in the algebraic <var>x</var> = +<var>x</var>. A {@link 
Node} is a positive
+ * {@link DirectedNode}, an {@link Edge} a positive {@link DirectedEdge}, and 
so on.</p>
+ *
+ * <p>Oriented primitives of adjacent dimensions agree on the orientation: if 
a positive edge is on the
+ * boundary of a face, the positive face is on the co-boundary of that 
edge.</p>
+ *
+ * <p>Constraints:</p>
+ * <ul>
+ *   <li>The {@linkplain #getBoundary() boundary} is the boundary of the 
{@linkplain #getTopo() primitive},
+ *       each term multiplied by the {@linkplain #getOrientationSign() 
orientation}. Likewise for the
+ *       {@linkplain #getCoBoundary() co-boundary}.</li>
+ *   <li>The {@linkplain #getNegate() opposite} has the same primitive and the 
other orientation.</li>
+ * </ul>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.4
+ */
+@UML(identifier="DirectedTopo", specification=ISO_19107)
+public interface DirectedTopo extends Primitive {
+
+    /**
+     * Whether this oriented primitive agrees with the orientation of its 
{@linkplain #getTopo() primitive}.
+     * The default is {@link Orientable.Sign#POSITIVE}, which is always the 
case of a primitive itself.
+     *
+     * @return orientation of this object relative to its primitive.
+     *
+     * @see ISO 19107:2019 - 10.1.4.2
+     */
+    @UML(identifier="orientation", specification=ISO_19107)
+    default Orientable.Sign getOrientationSign() {
+        return Orientable.Sign.POSITIVE;
+    }
+
+    /**
+     * The same primitive with the opposite orientation.
+     *
+     * @return this object with reversed orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.3
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    DirectedTopo getNegate();
+
+    /**
+     * This oriented primitive as an expression of a single term, keeping its 
orientation.
+     *
+     * @return expression made of this oriented primitive.
+     *
+     * @see ISO 19107:2019 - 10.1.4.4
+     */
+    @UML(identifier="expression", specification=ISO_19107)
+    Expression getExpression();
+
+    /**
+     * The primitive of which this object is one of the two orientations.
+     * A primitive returns itself.
+     *
+     * @return primitive underlying this object.
+     *
+     * @see ISO 19107:2019 - 10.1.4.5
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    Primitive getTopo();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Edge.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Edge.java
new file mode 100644
index 0000000000..f1d9b3ac43
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Edge.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * The 1-dimensional topological primitive, usually realized by a {@link 
org.apache.sis.geometries.Curve}.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.4.1
+ */
+@UML(identifier="Edge", specification=ISO_19107)
+public interface Edge extends DirectedEdge {
+
+    /**
+     * The start and end nodes of this edge, as the expression <var>end</var> 
− <var>start</var>:
+     * the end node is a positive {@link DirectedNode} and the start node a 
negative one.
+     * When both nodes are the same, the two terms cancel out in the 
expression.
+     *
+     * @return the two oriented nodes at the ends of this edge.
+     *
+     * @see ISO 19107:2019 - 10.4.1.3
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedNode> getBoundary();
+
+    /**
+     * Oriented faces using this edge on their boundary: positive when the 
face uses this edge,
+     * negative when it uses its negative orientation.
+     *
+     * <p>The faces are listed in clockwise circular order, as seen from the 
end of the edge
+     * in a geometric realization of the maximal complex containing this 
edge.</p>
+     *
+     * <p>In a 2-dimensional planar complex there are at most two faces, 
exactly two in a full topology:
+     * the positive one on the left of the edge, and the negative one on its 
right.</p>
+     *
+     * @return oriented faces around this edge, in clockwise order seen from 
its end.
+     *
+     * @see ISO 19107:2019 - 10.4.1.2
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedFace> getCoBoundary();
+
+    /**
+     * Returns this edge, which is its own positive orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.1
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    default Edge getTopo() {
+        return this;
+    }
+
+    /**
+     * Returns this edge then its {@linkplain #getNegate() negative 
orientation}.
+     *
+     * @see ISO 19107:2019 - 10.4.1.4
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    default List<DirectedEdge> getProxy() {
+        return List.of(this, getNegate());
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Expression.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Expression.java
new file mode 100644
index 0000000000..f340e46e76
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Expression.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * A multivariate polynomial of degree 1 whose variables are oriented 
primitives, such as
+ * 2<var>e₁</var> − <var>e₂</var>. It is the basis of computational topology: 
geometric problems
+ * are translated into algebraic ones, solved there, and the solutions are 
translated back.
+ *
+ * <p>The order of the terms does not change the value of a polynomial, so an 
expression is
+ * a set of {@linkplain ExpressionTerm terms}, each one an integer coefficient 
and an oriented primitive.
+ * Expressions behave as vectors having the oriented primitives as basis 
vectors.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.8
+ */
+@UML(identifier="Expression", specification=ISO_19107)
+public interface Expression {
+
+    /**
+     * The terms of this expression, in no particular order. Terms having the 
same underlying primitive
+     * are combined, and terms of coefficient zero are removed, so each 
primitive appears at most once.
+     *
+     * @return terms of this expression, empty for the zero expression.
+     *
+     * @see ISO 19107:2019 - 10.1.8.1
+     */
+    Collection<ExpressionTerm> getTerms();
+
+    /**
+     * Returns {@code true} if this expression has no term.
+     * This method is not in ISO 19107, which refers to the zero expression in 
several places.
+     *
+     * @return whether this expression is zero.
+     */
+    default boolean isZero() {
+        return getTerms().isEmpty();
+    }
+
+    /**
+     * This expression with every term reversed: the unary minus of 
polynomials.
+     *
+     * @return the opposite of this expression.
+     *
+     * @see ISO 19107:2019 - 10.1.8.2
+     */
+    @UML(identifier="negate", specification=ISO_19107)
+    Expression getNegate();
+
+    /**
+     * This expression with each primitive replaced by its boundary, then 
simplified.
+     * The boundary is made of primitives of the next lower dimension, and is 
zero
+     * if all primitives of this expression are nodes.
+     *
+     * @return boundary of this expression.
+     *
+     * @see ISO 19107:2019 - 10.1.8.3
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    Expression getBoundary();
+
+    /**
+     * This expression with each primitive replaced by its co-boundary, then 
simplified.
+     * The co-boundary is made of primitives of the next higher dimension, and 
is zero if the primitives
+     * of this expression have the dimension of their maximal complex.
+     *
+     * @return co-boundary of this expression.
+     *
+     * @see ISO 19107:2019 - 10.1.8.4
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    Expression getCoBoundary();
+
+    /**
+     * This expression as a set of primitives, for computing geometric 
operators: the primitives
+     * of the {@linkplain #asSet() oriented primitives set}. The support is a 
valid {@link Complex},
+     * and is empty for the zero expression.
+     *
+     * <p>The default implementation returns the {@linkplain 
DirectedTopo#getTopo() primitive}
+     * of each element of {@link #asSet()}.</p>
+     *
+     * @return primitives of this expression and of their boundaries.
+     *
+     * @see ISO 19107:2019 - 10.1.8.5
+     */
+    @UML(identifier="support", specification=ISO_19107)
+    default Set<Primitive> getSupport() {
+        final Set<Primitive> support = new LinkedHashSet<>();
+        for (final DirectedTopo element : asSet()) {
+            support.add(element.getTopo());
+        }
+        return support;
+    }
+
+    /**
+     * This expression as a set of oriented primitives, for computing 
geometric operators. The set contains
+     * the variable of each term, and every element of their boundaries 
recursively down to the nodes.
+     * It is empty for the zero expression.
+     *
+     * <p>The default implementation takes each variable with the sign of its 
coefficient,
+     * then adds the boundaries recursively.</p>
+     *
+     * @return oriented primitives of this expression and of their boundaries.
+     *
+     * @see ISO 19107:2019 - 10.1.8.6
+     */
+    @UML(identifier="asSet", specification=ISO_19107)
+    default Set<DirectedTopo> asSet() {
+        final Set<DirectedTopo> set = new LinkedHashSet<>();
+        final Deque<DirectedTopo> pending = new ArrayDeque<>();
+        for (final ExpressionTerm term : getTerms()) {
+            final DirectedTopo variable = term.getVariable();
+            pending.add(term.getCoefficient() < 0 ? variable.getNegate() : 
variable);
+        }
+        DirectedTopo next;
+        while ((next = pending.poll()) != null) {
+            if (set.add(next)) {
+                pending.addAll(next.getBoundary());
+            }
+        }
+        return set;
+    }
+
+    /**
+     * The vector sum of this expression and the given one. Terms having the 
same underlying primitive
+     * are combined by adding their coefficients, and terms of coefficient 
zero are removed.
+     *
+     * @param  other  the expression to add to this expression.
+     * @return sum of the two expressions.
+     *
+     * @see ISO 19107:2019 - 10.1.8.7
+     */
+    @UML(identifier="plus", specification=ISO_19107)
+    Expression plus(Expression other);
+
+    /**
+     * The vector difference of this expression and the given one. Terms 
having the same underlying primitive
+     * are combined by subtracting their coefficients, and terms of 
coefficient zero are removed.
+     *
+     * @param  other  the expression to subtract from this expression.
+     * @return difference of the two expressions.
+     *
+     * @see ISO 19107:2019 - 10.1.8.8
+     */
+    @UML(identifier="minus", specification=ISO_19107)
+    Expression minus(Expression other);
+
+    /**
+     * Returns {@code true} if the given object is an expression equal to this 
one as a polynomial.
+     * The order of the terms does not matter.
+     *
+     * @param  other  the object to compare with this expression.
+     * @return whether the given object is an equal polynomial.
+     *
+     * @see ISO 19107:2019 - 10.1.8.9
+     */
+    @UML(identifier="equals", specification=ISO_19107)
+    @Override
+    boolean equals(Object other);
+
+    /**
+     * Returns a hash code value consistent with {@link #equals(Object)},
+     * therefore independent of the order of the terms.
+     *
+     * @return hash code value of this expression.
+     */
+    @Override
+    int hashCode();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ExpressionTerm.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ExpressionTerm.java
new file mode 100644
index 0000000000..4e31a3a115
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/ExpressionTerm.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.Collection;
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * A term of an {@link Expression}: an oriented primitive with an integer 
coefficient, such as
+ * 2<var>e₁</var>. A term is a monomial, so it is also an expression of a 
single term.
+ * Arithmetic on terms is the usual vector arithmetic.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.9
+ */
+@UML(identifier="ExpressionTerm", specification=ISO_19107)
+public interface ExpressionTerm extends Expression {
+
+    /**
+     * The integer multiplying the {@linkplain #getVariable() variable}. The 
default is 1.
+     *
+     * @return coefficient of this term.
+     *
+     * @see ISO 19107:2019 - 10.1.9
+     */
+    @UML(identifier="coefficient", specification=ISO_19107)
+    default int getCoefficient() {
+        return 1;
+    }
+
+    /**
+     * The oriented primitive of this term.
+     *
+     * @return variable of this term.
+     *
+     * @see ISO 19107:2019 - 10.1.9
+     */
+    @UML(identifier="variable", specification=ISO_19107)
+    DirectedTopo getVariable();
+
+    /**
+     * Returns this term alone, or nothing if its {@linkplain 
#getCoefficient() coefficient} is zero.
+     *
+     * @return this term, or an empty list for the zero expression.
+     */
+    @Override
+    default Collection<ExpressionTerm> getTerms() {
+        return (getCoefficient() == 0) ? List.of() : List.of(this);
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Face.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Face.java
new file mode 100644
index 0000000000..b3753e065c
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Face.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * The 2-dimensional topological primitive, usually realized by a {@link 
org.apache.sis.geometries.Surface}.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.5.2
+ */
+@UML(identifier="Face", specification=ISO_19107)
+public interface Face extends DirectedFace {
+
+    /**
+     * Oriented edges bounding this face: positive for the edges having this 
face on their left,
+     * negative for those having it on their right. The edges of every ring 
are included,
+     * those of the {@linkplain #getExteriorRing() exterior ring} first.
+     *
+     * @return oriented edges bounding this face, at least one.
+     *
+     * @see ISO 19107:2019 - 10.5.2.1
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedEdge> getBoundary();
+
+    /**
+     * The ring of the {@linkplain #getBoundary() boundary} which is the 
exterior of this face,
+     * as oriented edges in traversal order.
+     *
+     * <p>The same restriction applies as for the geometric boundary of a 
surface: on a closed surface such
+     * as a sphere, no ring can be told to be the exterior one, and this 
method returns an empty list.</p>
+     *
+     * @return oriented edges of the exterior ring, or an empty list if it 
cannot be determined.
+     *
+     * @see ISO 19107:2019 - 10.5.2.1
+     */
+    List<DirectedEdge> getExteriorRing();
+
+    /**
+     * The rings of the {@linkplain #getBoundary() boundary} other than the 
{@linkplain #getExteriorRing() exterior one},
+     * each as oriented edges in traversal order.
+     *
+     * @return oriented edges of every interior ring, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.5.2.1
+     */
+    List<List<DirectedEdge>> getInteriorRings();
+
+    /**
+     * Oriented solids using this face on their boundary: positive when the 
solid uses this face,
+     * negative when it uses its negative orientation. A face separates at 
most two solids.
+     *
+     * @return oriented solids on each side of this face, at most two.
+     *
+     * @see ISO 19107:2019 - 10.5.2.2
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedSolid> getCoBoundary();
+
+    /**
+     * Returns this face, which is its own positive orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.1
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    default Face getTopo() {
+        return this;
+    }
+
+    /**
+     * Returns this face then its {@linkplain #getNegate() negative 
orientation}.
+     *
+     * @see ISO 19107:2019 - 10.5.2.3
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    default List<DirectedFace> getProxy() {
+        return List.of(this, getNegate());
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Node.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Node.java
new file mode 100644
index 0000000000..79b5df2df2
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Node.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * The 0-dimensional topological primitive, usually realized by a {@link 
org.apache.sis.geometries.Point}.
+ *
+ * <p>A node has no boundary. It may be isolated in a face while being the end 
of an edge, as long as that
+ * edge is not on the boundary of the face: the realization is a curve hanging 
in space and ending where it
+ * meets a surface.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.3.2
+ */
+@UML(identifier="Node", specification=ISO_19107)
+public interface Node extends DirectedNode {
+
+    /**
+     * Oriented edges having this node on their boundary: positive for the 
edges entering
+     * this node (ending at it), and negative for the edges leaving it 
(starting at it).
+     *
+     * <p>In a 2-dimensional maximal complex, the edges can be listed as a 
clockwise circular sequence
+     * around the node in any geometric realization. In a 3-dimensional 
complex the order is arbitrary.</p>
+     *
+     * @return oriented edges starting or ending at this node.
+     *
+     * @see ISO 19107:2019 - 10.3.2.1
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    @Override
+    List<DirectedEdge> getCoBoundary();
+
+    /**
+     * Returns this node, which is its own positive orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.1
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    default Node getTopo() {
+        return this;
+    }
+
+    /**
+     * Returns this node then its {@linkplain #getNegate() negative 
orientation}.
+     *
+     * @see ISO 19107:2019 - 10.3.2.2
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    default List<DirectedNode> getProxy() {
+        return List.of(this, getNegate());
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Primitive.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Primitive.java
new file mode 100644
index 0000000000..3c97f815ec
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Primitive.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import java.util.Set;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+import org.apache.sis.geometries.Orientable;
+
+
+/**
+ * A non-decomposed element of a topological {@link Complex}.
+ *
+ * <p>A topological primitive usually stands for a geometric primitive of the 
same dimension. When a
+ * geometric complex is the realization of a topological complex, the 
primitives of both are in a
+ * one-to-one correspondence which preserves the dimension.</p>
+ *
+ * <p>Unlike a geometric primitive, which may stand alone, a topological 
primitive is always part of at
+ * least one complex.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.3
+ */
+@UML(identifier="Primitive", specification=ISO_19107)
+public interface Primitive extends Topology {
+
+    /**
+     * Returns this primitive alone: a primitive is its own interior.
+     *
+     * @return a set containing only this primitive.
+     *
+     * @see ISO 19107:2019 - 10.1.2.6
+     */
+    @UML(identifier="interior", specification=ISO_19107)
+    @Override
+    default Set<Primitive> getInterior() {
+        return Set.of(this);
+    }
+
+    /**
+     * The geometric primitive this primitive represents in its maximal 
complex, or {@code null} if the
+     * maximal complex describes a logical structure without geometric 
realization.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>Either every primitive of a maximal complex has a geometry, or 
none has.</li>
+     *   <li>A geometric primitive is associated with at most one primitive of 
any given complex,
+     *       but may be associated with primitives of different complexes.</li>
+     * </ul>
+     *
+     * @return geometric realization of this primitive, or {@code null} if 
none.
+     *
+     * @see ISO 19107:2019 - 10.1.3.2
+     */
+    @UML(identifier="geometry", specification=ISO_19107)
+    org.apache.sis.geometries.Primitive getGeometry();
+
+    /**
+     * The complexes containing this primitive. They are all sub-complexes of 
the single
+     * maximal complex containing this primitive.
+     *
+     * @return complexes containing this primitive.
+     *
+     * @see ISO 19107:2019 - 10.1.3.3
+     */
+    @UML(identifier="complex", specification=ISO_19107)
+    Set<Complex> getComplexes();
+
+    /**
+     * Primitives isolated in this primitive: lying in its interior without 
any primitive of intermediate
+     * dimension between them. Examples are a node inside a face and not 
attached to the boundary of that face,
+     * or an edge inside a solid and not attached to its boundary faces.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>The dimension of every isolated primitive is lower than the 
dimension of this primitive minus one.</li>
+     * </ul>
+     *
+     * @return primitives isolated in this primitive, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.1.3.4
+     */
+    @UML(identifier="isolated", specification=ISO_19107)
+    Set<Primitive> getIsolated();
+
+    /**
+     * The primitive in which this primitive is isolated, or {@code null} if 
none.
+     * A primitive without container lies on the boundary of another primitive,
+     * unless it has the highest dimension of its complex.
+     *
+     * @return primitive in which this primitive is isolated, or {@code null} 
if none.
+     *
+     * @see ISO 19107:2019 - 10.1.3.4
+     */
+    @UML(identifier="container", specification=ISO_19107)
+    Primitive getContainer();
+
+    /**
+     * The two oriented primitives standing for this primitive,
+     * the {@linkplain Orientable.Sign#POSITIVE positive} one first.
+     *
+     * @return the positive then the negative oriented primitive.
+     *
+     * @see ISO 19107:2019 - 10.1.4.5
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    List<? extends DirectedTopo> getProxy();
+
+    /**
+     * Returns the oriented primitive standing for this primitive with the 
given orientation.
+     *
+     * <p>The default implementation returns the first or the second 
{@linkplain #getProxy() proxy}.</p>
+     *
+     * @param  orientation  orientation of the requested oriented primitive.
+     * @return the oriented primitive with the given orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.3
+     */
+    @UML(identifier="asDirectedTopo", specification=ISO_19107)
+    default DirectedTopo asDirectedTopo(final Orientable.Sign orientation) {
+        return getProxy().get(orientation == Orientable.Sign.POSITIVE ? 0 : 1);
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/PrimitiveData.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/PrimitiveData.java
new file mode 100644
index 0000000000..0a644c2581
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/PrimitiveData.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * Data for building a topological {@link Primitive} from its underlying 
geometric primitive, such that all
+ * the primitive interiors are disjoint and every primitive boundary is 
represented by other geometries.
+ * All its information comes from {@link TopologyData}.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.6
+ */
+@UML(identifier="PrimitiveData", specification=ISO_19107)
+public interface PrimitiveData extends TopologyData {
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Solid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Solid.java
new file mode 100644
index 0000000000..7dd18bde79
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Solid.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * The 3-dimensional topological primitive, usually realized by a {@link 
org.apache.sis.geometries.Solid}.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.6.1
+ */
+@UML(identifier="Solid", specification=ISO_19107)
+public interface Solid extends DirectedSolid {
+
+    /**
+     * Oriented faces bounding this solid: positive for the faces having this 
solid below them,
+     * negative for those having it above them. The faces of every shell are 
included,
+     * those of the {@linkplain #getExteriorShell() exterior shell} first.
+     *
+     * @return oriented faces bounding this solid, at least one.
+     *
+     * @see ISO 19107:2019 - 10.6.1.2
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    @Override
+    List<DirectedFace> getBoundary();
+
+    /**
+     * The shell of the {@linkplain #getBoundary() boundary} which is the 
exterior of this solid.
+     *
+     * @return oriented faces of the exterior shell.
+     *
+     * @see ISO 19107:2019 - 10.6.1.2
+     */
+    List<DirectedFace> getExteriorShell();
+
+    /**
+     * The shells of the {@linkplain #getBoundary() boundary} bounding the 
voids of this solid.
+     *
+     * @return oriented faces of every interior shell, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.6.1.2
+     */
+    List<List<DirectedFace>> getInteriorShells();
+
+    /**
+     * Returns this solid, which is its own positive orientation.
+     *
+     * @see ISO 19107:2019 - 10.1.4.1
+     */
+    @UML(identifier="topo", specification=ISO_19107)
+    @Override
+    default Solid getTopo() {
+        return this;
+    }
+
+    /**
+     * Returns this solid then its {@linkplain #getNegate() negative 
orientation}.
+     *
+     * @see ISO 19107:2019 - 10.6.1.4
+     */
+    @UML(identifier="proxy", specification=ISO_19107)
+    @Override
+    default List<DirectedSolid> getProxy() {
+        return List.of(this, getNegate());
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Topology.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Topology.java
new file mode 100644
index 0000000000..5e6387d4e5
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/Topology.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+
+
+/**
+ * Root type of the topological primitives and complexes.
+ *
+ * <p>Topology describes how objects are connected, independently of their 
coordinates. A topological
+ * complex turns geometric computations, such as containment, adjacency, 
boundaries or network tracing,
+ * into combinatorial ones. Its primitives usually have a geometric 
realization, but a complex may also
+ * describe a logical structure which has none.</p>
+ *
+ * <p>This type is not a {@link org.apache.sis.geometries.Geometry}. The 
topological boundary and the
+ * geometric boundary are two different operations, kept separate to avoid any 
confusion, even though
+ * they agree on any geometric realization of the topology.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.2
+ */
+@UML(identifier="Topology", specification=ISO_19107)
+public interface Topology {
+
+    /**
+     * Returns {@code true} if this topology contains nothing.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>An empty topology has a {@linkplain #getDimension() dimension} of 
−1.</li>
+     *   <li>An empty topology is realized only by empty geometries.</li>
+     *   <li>Every other attribute and operation behaves consistently on an 
empty topology.</li>
+     * </ul>
+     *
+     * <p>An empty topology is meant as a temporary state, for example until a 
transaction completes.</p>
+     *
+     * @return whether this topology is empty.
+     *
+     * @see ISO 19107:2019 - 10.1.2.2
+     */
+    @UML(identifier="isEmpty", specification=ISO_19107)
+    boolean isEmpty();
+
+    /**
+     * Topological dimension of this object: 0 for nodes, 1 for edges, 2 for 
faces and 3 for solids.
+     * It depends only on the type of this object, and is −1 for an empty 
topology.
+     *
+     * @return topological dimension of this object.
+     *
+     * @see ISO 19107:2019 - 10.1.2.3
+     */
+    @UML(identifier="dimension", specification=ISO_19107)
+    int getDimension();
+
+    /**
+     * Oriented primitives of the next lower dimension which bound this object.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>The dimension of the boundary is the dimension of this object 
minus one.</li>
+     *   <li>The orientations agree with the geometric realization of this 
object.</li>
+     * </ul>
+     *
+     * <p>This list is usually a valid {@link Expression}, except that a 
primitive may appear twice
+     * with opposite orientations, as a dangling edge which has the same face 
on both sides. Those two
+     * terms would cancel out in the expression.</p>
+     *
+     * @return boundary of this object, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.1.2.4
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
+    List<? extends DirectedTopo> getBoundary();
+
+    /**
+     * Oriented primitives of the next higher dimension having this object on 
their boundary.
+     *
+     * <p>This list is usually a valid {@link Expression}, except for an 
object lying on the boundary of a
+     * closed object, such as the node at both ends of a closed edge. That 
object appears twice, with
+     * opposite orientations, and would cancel out in the expression.</p>
+     *
+     * @return co-boundary of this object, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.1.2.5
+     */
+    @UML(identifier="coBoundary", specification=ISO_19107)
+    List<? extends DirectedTopo> getCoBoundary();
+
+    /**
+     * Primitives forming the interior of this object within its {@linkplain 
#getMaximalComplex() maximal complex}.
+     * A primitive is its own interior. The interior of a complex is made of 
its elements which are not on its
+     * boundary.
+     *
+     * @return interior of this object.
+     *
+     * @see ISO 19107:2019 - 10.1.2.6
+     */
+    @UML(identifier="interior", specification=ISO_19107)
+    Set<Primitive> getInterior();
+
+    /**
+     * Primitives forming the exterior of this object within its {@linkplain 
#getMaximalComplex() maximal complex}:
+     * those which are neither in the interior nor on the boundary of this 
object.
+     *
+     * @return exterior of this object.
+     *
+     * @see ISO 19107:2019 - 10.1.2.7
+     */
+    @UML(identifier="exterior", specification=ISO_19107)
+    Set<Primitive> getExterior();
+
+    /**
+     * Union of the {@linkplain #getInterior() interior} and of the 
{@linkplain #getBoundary() boundary} of this object.
+     *
+     * <p>The default implementation adds the interior, then the primitives on 
the boundary,
+     * then those on their boundaries down to the nodes.</p>
+     *
+     * @return closure of this object.
+     *
+     * @see ISO 19107:2019 - 10.1.2.8
+     */
+    @UML(identifier="closure", specification=ISO_19107)
+    default Set<Primitive> getClosure() {
+        final Set<Primitive> closure = new LinkedHashSet<>(getInterior());
+        final Deque<DirectedTopo> pending = new ArrayDeque<>(getBoundary());
+        DirectedTopo next;
+        while ((next = pending.poll()) != null) {
+            if (closure.add(next.getTopo())) {
+                pending.addAll(next.getBoundary());
+            }
+        }
+        return closure;
+    }
+
+    /**
+     * The largest complex containing this object. Every object is contained 
in exactly one maximal complex.
+     *
+     * @return maximal complex containing this object.
+     *
+     * @see ISO 19107:2019 - 10.1.2.9
+     */
+    @UML(identifier="maximalComplex", specification=ISO_19107)
+    Complex getMaximalComplex();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/TopologyData.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/TopologyData.java
new file mode 100644
index 0000000000..fd33f6a756
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/TopologyData.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.topology;
+
+import java.util.List;
+import static org.opengis.annotation.Specification.ISO_19107;
+import org.opengis.annotation.UML;
+import org.opengis.util.GenericName;
+import org.apache.sis.geometries.Geometry;
+
+
+/**
+ * Data for building a topology from its underlying geometry, such that all 
the geometry interiors
+ * are disjoint and every geometry boundary is represented by other geometries.
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 10.1.5
+ */
+@UML(identifier="TopologyData", specification=ISO_19107)
+public interface TopologyData {
+
+    /**
+     * Identifier by which other data of the same construction refer to this 
one.
+     * Its namespace component is unique within its maximal complex and its 
topological dimension.
+     *
+     * @return identifier of this data.
+     *
+     * @see ISO 19107:2019 - 10.1.5.2
+     */
+    @UML(identifier="id", specification=ISO_19107)
+    GenericName getId();
+
+    /**
+     * Data of the elements on the boundary of this element.
+     *
+     * @return data of the boundary elements, empty if none.
+     *
+     * @see ISO 19107:2019 - 10.1.5.3
+     */
+    @UML(identifier="boundaryData", specification=ISO_19107)
+    List<? extends TopologyData> getBoundaryData();
+
+    /**
+     * Geometry of the interior of this element. Its dimension usually matches 
the topological dimension,
+     * but not necessarily when the topology describes connections, as in a 
Poincaré dual graph.
+     *
+     * <p>Difference with ISO 19107: the standard type is {@code GeometryData},
+     * which does not exist in this module.</p>
+     *
+     * @return geometry of the interior of this element.
+     *
+     * @see ISO 19107:2019 - 10.1.5.4
+     */
+    @UML(identifier="geometryData", specification=ISO_19107)
+    Geometry getGeometryData();
+
+}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/package-info.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/package-info.java
new file mode 100644
index 0000000000..66abfd699d
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/topology/package-info.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Topology interfaces of ISO 19107:2019 section 10.
+ *
+ * <p>A topological complex describes how primitives are connected, 
independently of their coordinates,
+ * which turns geometric computations into combinatorial ones. Each primitive 
usually has a geometric
+ * realization of the same dimension in the {@link org.apache.sis.geometries} 
package.</p>
+ *
+ * <table class="sis">
+ *   <caption>Topological types</caption>
+ *   <tr><th>Dimension</th> <th>Primitive</th>                  <th>Oriented 
primitive</th>                 <th>Usual realization</th></tr>
+ *   <tr><td>0</td>         <td>{@link 
org.apache.sis.geometries.topology.Node}</td>  <td>{@link 
org.apache.sis.geometries.topology.DirectedNode}</td>  <td>{@link 
org.apache.sis.geometries.Point}</td></tr>
+ *   <tr><td>1</td>         <td>{@link 
org.apache.sis.geometries.topology.Edge}</td>  <td>{@link 
org.apache.sis.geometries.topology.DirectedEdge}</td>  <td>{@link 
org.apache.sis.geometries.Curve}</td></tr>
+ *   <tr><td>2</td>         <td>{@link 
org.apache.sis.geometries.topology.Face}</td>  <td>{@link 
org.apache.sis.geometries.topology.DirectedFace}</td>  <td>{@link 
org.apache.sis.geometries.Surface}</td></tr>
+ *   <tr><td>3</td>         <td>{@link 
org.apache.sis.geometries.topology.Solid}</td> <td>{@link 
org.apache.sis.geometries.topology.DirectedSolid}</td> <td>{@link 
org.apache.sis.geometries.Solid}</td></tr>
+ * </table>
+ *
+ * <p>As in the standard, each primitive extends its oriented type, so a 
primitive is its own positive
+ * orientation. Oriented primitives are the variables of {@link 
org.apache.sis.geometries.topology.Expression},
+ * the polynomials on which boundaries and co-boundaries are computed.</p>
+ *
+ * <h2>Differences with ISO 19107</h2>
+ * <ul>
+ *   <li>Attributes are getter methods, such as {@code getBoundary()} for 
{@code boundary}.</li>
+ *   <li>The orientation reuses {@link 
org.apache.sis.geometries.Orientable.Sign}, and is read by
+ *       {@code getOrientationSign()} as for geometric orientable 
primitives.</li>
+ *   <li>The two proxies of a primitive are listed with the positive one 
first.</li>
+ *   <li>The rings of a face and the shells of a solid are read by {@code 
getExteriorRing()}, {@code getInteriorRings()},
+ *       {@code getExteriorShell()} and {@code getInteriorShells()}, instead 
of {@code FaceBoundary} and
+ *       {@code SolidBoundary} types.</li>
+ *   <li>The co-boundary of a solid is an empty list instead of {@code 
NULL}.</li>
+ *   <li>The geometric complex realizing a topological complex, and the {@code 
GeometryData} of the construction
+ *       data types, are a {@link org.apache.sis.geometries.Geometry}, since 
neither type exists in this module yet.</li>
+ *   <li>The construction of a complex from a geometric collection is left to 
implementations,
+ *       since Java interfaces have no constructor.</li>
+ *   <li>{@code Expression} gives access to its terms, and tells whether it is 
zero.</li>
+ * </ul>
+ *
+ * <h2>Not covered</h2>
+ * <ul>
+ *   <li>The derived topological relations of section 10.8: aggregate 
boundaries, Boolean, Egenhofer
+ *       and full topological operators.</li>
+ *   <li>The simplicial complexes of section 11.1.</li>
+ *   <li>Editing operations, such as splitting an edge or a face, which the 
standard does not define.</li>
+ * </ul>
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+package org.apache.sis.geometries.topology;

Reply via email to