To start gently, let us consider the following grey shape :
Mathematicians call it a square, which is a particularly case of a rectangle, which is itself a polygon. A simple way of describing a polygon is to list the coordinates of its corners :
Corner 0 coordinates are (0,0)
Corner 1 coordinates are (0,1)
Corner 2 coordinates are (1,1)
Corner 3 coordinates are (1,0)
And Corner 4 = Corner 0
One of the most compact way of describing that polygon in GML 3.2 is the use of the gml:Polygon element :
<?xml version="1.0"?>We can forget the XML namespaces declaration and just concentrate on the fact that a Polygon is made of an exterior ring described by a list of positions. For those who wonder why we need to specify the "exterior", you must know that polygons may have holes in them, and those holes are called "interior rings", but we will not explore that level of complexity.
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
The documentation of the gml:LinearRing element shows that there are other ways of expressing the coordinates. We can isolate each corner in a separate gml:pos element :
<?xml version="1.0"?>
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<gml:pos>0 0</gml:pos>
<gml:pos>0 1</gml:pos>
<gml:pos>1 1</gml:pos>
<gml:pos>1 0</gml:pos>
<gml:pos>0 0</gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
Or we can use a gml:Point inside a gml:pointProperty :
<?xml version="1.0"?>Those who carefully look at the above snippet realize that the content of the last pointProperty is the same as the first one. So we can use xlink:href power to optimize that a bit :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<gml:pointProperty>
<gml:Point gml:id="ID2">
<gml:pos>0 0</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID3">
<gml:pos>0 1</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID4">
<gml:pos>1 1</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID5">
<gml:pos>1 0</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID6">
<gml:pos>0 0</gml:pos>
</gml:Point>
</gml:pointProperty>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>People nostalgic of the GML 2.1.2 era will probably want to use the now deprecated (but still valid) gml:coordinates element :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<gml:pointProperty>
<gml:Point gml:id="ID2">
<gml:pos>0 0</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID3">
<gml:pos>0 1</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID4">
<gml:pos>1 1</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID5">
<gml:pos>1 0</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty xlink:href="#ID2"/>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>We could play with cs (coordinate separator) and ts (tuple separator) attributes of gml:coordinates to generate alternate encoding for the coordinate list, but we will not do that. Enough with deprecated features ! Let us concentrate on modernity.
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<!-- deprecated -->
<gml:coordinates>0,0 0,1 1,1 1,0 0,0</gml:coordinates>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
Our shape is a gml:Rectangle, isn'it ?
<?xml version="1.0"?>Careful observers will notice that we have not simply substituted Polygon by Rectangle, but we have also removed the gml:id attribute. Why so ? Because a Polygon is a first citizen GML object deriving from gml:AbstractGMLType, whereas Rectangle just derives from gml:AbstractSurfacePatchType. Poor gml:Rectangle... We will come back to it later.
<gml:Rectangle xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd">
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Rectangle>
Until now, we have restricted the interior to be a LinearRing. But a LinearRing is a particular case of a gml:Ring :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"As before we can use a series of gml:pos instead of gml:posList :
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:LineString gml:id="ID2">
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LineString>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>But we could also use several gml:curveMember with a simple 2-point gml:LineString :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:LineString gml:id="ID2">
<gml:pos>0 0</gml:pos>
<gml:pos>0 1</gml:pos>
<gml:pos>1 1</gml:pos>
<gml:pos>1 0</gml:pos>
<gml:pos>0 0</gml:pos>
</gml:LineString>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>Instead of a single gml:LineString, we could use a more powerful gml:Curve :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:LineString gml:id="ID2">
<gml:posList>0 0 0 1</gml:posList>
</gml:LineString>
</gml:curveMember>
<gml:curveMember>
<gml:LineString gml:id="ID3">
<gml:posList>0 1 1 1</gml:posList>
</gml:LineString>
</gml:curveMember>
<gml:curveMember>
<gml:LineString gml:id="ID4">
<gml:posList>1 1 1 0</gml:posList>
</gml:LineString>
</gml:curveMember>
<gml:curveMember>
<gml:LineString gml:id="ID5">
<gml:posList>1 0 0 0</gml:posList>
</gml:LineString>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>But it is a bit of a shame to use a single gml:LineStringSegment inside a gml:segments. Let us fix that :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:Curve gml:id="ID2">
<gml:segments>
<gml:LineStringSegment>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>Of course we can still use gml:pointProperty to avoid repeating the same coordinate tuples :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:Curve gml:id="ID2">
<gml:segments>
<gml:LineStringSegment>
<gml:posList>0 0 0 1</gml:posList>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:posList>0 1 1 1</gml:posList>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:posList>1 1 1 0</gml:posList>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:posList>1 0 0 0</gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>Another child element of gml:curveMember is a gml:CompositeCurve :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:Curve gml:id="ID2">
<gml:segments>
<gml:LineStringSegment>
<gml:pointProperty>
<gml:Point gml:id="ID3">
<gml:pos>0 0</gml:pos>
</gml:Point>
</gml:pointProperty>
<gml:pointProperty>
<gml:Point gml:id="ID4">
<gml:pos>0 1</gml:pos>
</gml:Point>
</gml:pointProperty>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:pointProperty xlink:href="#ID4"/>
<gml:pointProperty>
<gml:Point gml:id="ID5">
<gml:pos>1 1</gml:pos>
</gml:Point>
</gml:pointProperty>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:pointProperty xlink:href="#ID5"/>
<gml:pointProperty>
<gml:Point gml:id="ID6">
<gml:pos>1 0</gml:pos>
</gml:Point>
</gml:pointProperty>
</gml:LineStringSegment>
<gml:LineStringSegment>
<gml:pointProperty xlink:href="#ID5"/>
<gml:pointProperty xlink:href="#ID3"/>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>But, you may have noticed that the child of a CompositeCurve is a curveMember, which is also the parent of the CompositeCurve. So we may put a CompositeCurve inside a CompositeCurve :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:CompositeCurve gml:id="ID2">
<gml:curveMember>
<gml:LineString gml:id="ID3">
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LineString>
</gml:curveMember>
</gml:CompositeCurve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>You have probably understood now that we could nest CompositeCurve as many times as wished. So we have now the answer to the initial question : there is an infinity of ways of expressing a polygon in GML 3.2 !
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:CompositeCurve gml:id="ID2">
<gml:curveMember>
<gml:CompositeCurve gml:id="ID3">
<gml:curveMember>
<gml:LineString gml:id="ID4">
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LineString>
</gml:curveMember>
</gml:CompositeCurve>
</gml:curveMember>
</gml:CompositeCurve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
Another child element of gml:curveMember is a gml:OrientableCurve :
<?xml version="1.0"?>But the full power of OrientableCurve is to be able to express the orientation of the curve. So let us split the ring into 2 pieces, one with positive orientation and one with negative orientation :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:OrientableCurve gml:id="ID2">
<gml:baseCurve>
<gml:LineString gml:id="ID3">
<gml:pos>0 0</gml:pos>
<gml:pos>0 1</gml:pos>
<gml:pos>1 1</gml:pos>
<gml:pos>1 0</gml:pos>
<gml:pos>0 0</gml:pos>
</gml:LineString>
</gml:baseCurve>
</gml:OrientableCurve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>Enough with polygons. A polygon is just a particular case of a gml:Surface :
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:OrientableCurve gml:id="ID2">
<gml:baseCurve>
<gml:LineString gml:id="ID3">
<gml:pos>0 0</gml:pos>
<gml:pos>0 1</gml:pos>
<gml:pos>1 1</gml:pos>
</gml:LineString>
</gml:baseCurve>
</gml:OrientableCurve>
</gml:curveMember>
<gml:curveMember>
<gml:OrientableCurve gml:id="ID4" orientation="-">
<gml:baseCurve>
<gml:LineString gml:id="ID5">
<gml:pos>0 0</gml:pos>
<gml:pos>1 0</gml:pos>
<gml:pos>1 1</gml:pos>
</gml:LineString>
</gml:baseCurve>
</gml:OrientableCurve>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
<?xml version="1.0"?>
<gml:Surface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
Instead of a gml:PolygonPatch as a child of a gml:patches, we can use the gml:Rectangle we have used before :
<?xml version="1.0"?>A Surface seems to be too simple. Why not using a gml:CompositeSurface ?
<gml:Surface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:patches>
<gml:Rectangle>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Rectangle>
</gml:patches>
</gml:Surface>
<?xml version="1.0"?>But it looks a bit dumb to use only one gml:surfaceMember. Let us divide our square into 2 triangles :
<gml:CompositeSurface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:surfaceMember>
<gml:Surface gml:id="ID2">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMember>
</gml:CompositeSurface>
<?xml version="1.0"?>Instead of a gml:CompositeSurface, why not using a gml:MultiSurface ?
<gml:CompositeSurface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:surfaceMember>
<gml:Surface gml:id="ID2">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Surface gml:id="ID3">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMember>
</gml:CompositeSurface>
<?xml version="1.0"?>or maybe you prefer to use gml:surfaceMembers (with a final 's') instead of a gml:surfaceMember :
<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:surfaceMember>
<gml:Surface gml:id="ID2">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMember>
</gml:MultiSurface>
<?xml version="1.0"?>
<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:surfaceMembers>
<gml:Surface gml:id="ID2">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMembers>
</gml:MultiSurface>
Similarly to gml:CompositeCurve, we can arbitrary nest as many gml:CompositeSurface as wished :
<?xml version="1.0"?>So we have now two different kind of infinities ! That we could combine together. But, do not hope to have discovered more ways of expressing polygons. The cardinality of the set of natural numbers times the set of natural numbers ( N x N ) is just the cardinality of the set of natural numbers...
<gml:CompositeSurface xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:surfaceMember>
<gml:CompositeSurface gml:id="ID2">
<gml:surfaceMember>
<gml:Surface gml:id="ID3">
<gml:patches>
<gml:PolygonPatch>
<gml:exterior>
<gml:LinearRing>
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:PolygonPatch>
</gml:patches>
</gml:Surface>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:surfaceMember>
</gml:CompositeSurface>
To conclude, we should mention that the authors of the GML specification have admitted that encoding polygons was a bit too complicated. So they have invented a "compact encoding" in the extended schemas of GML 3.3 :
<?xml version="1.0"?>But our SimplePolygon is indeed a SimpleRectangle. So let us use instead :
<gmlce:SimplePolygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:gmlce="http://www.opengis.net/gml/3.3/ce"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd
http://www.opengis.net/gml/3.3/ce
http://schemas.opengis.net/gml/3.3/geometryCompact.xsd"
gml:id="ID1">
<!-- we may, or not, close the ring -->
<gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
</gmlce:SimplePolygon>
<?xml version="1.0"?>You can found the above 25 snippets at the following URL : http://even.rouault.free.fr/gml/
<gmlce:SimpleRectangle xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:gmlce="http://www.opengis.net/gml/3.3/ce"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd
http://www.opengis.net/gml/3.3/ce
http://schemas.opengis.net/gml/3.3/geometryCompact.xsd"
gml:id="ID1">
<!-- caution : we should NOT clause with the first vertex ! -->
<gml:posList>0 0 0 1 1 1 1 0</gml:posList>
</gmlce:SimpleRectangle>
They are all valid GML 3.2 snippets that validate the XML schemas and pass the GML 3.2 Conformance Test Suite (except gml4.xsd which uses the deprecated gml:coordinates element).
Oh, final fun, as GML is XML, we can also use XML substitutable entities ...
<?xml version="1.0"?>Those who wonder why I decided to write this article might want to have a look at the following simplified GML sample of a real-world use case where a PolygonPatch has only an interior ring (a hole), but no exterior ring... Standalone holes : interesting concept, isn't it ?
<!DOCTYPE points [
<!ENTITY pt0 "0 0">
<!ENTITY pt1 "0 1">
<!ENTITY pt2 "1 1">
<!ENTITY pt3 "1 0">
]>
<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/gml/3.2
http://schemas.opengis.net/gml/3.2.1/gml.xsd"
gml:id="ID1">
<gml:exterior>
<gml:LinearRing>
<gml:posList>&pt0; &pt1; &pt2; &pt3; &pt0;</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
Even,
RépondreSupprimerthis is probably why shapefiles are still used so much...
Is the OGR GML driver able to process all this cases ?
Fred.
Not all of them, but most of them.
SupprimerEven - Great information!
RépondreSupprimerYour example of a polygon is why communities develop profiles or application schemas for using GML in their specific domains. For example, the IETF uses a GML application schema with a single allowed approach to defining a polygon. This way, the IETF community has removed the "infinity" of possible approaches and simplified life for developers. Also, have you considered the compact form for polygon that is defined in GML 3.3? Section 7: Compact Encodings of Commonly Used GML Geometries. OASIS (another standards organization) has defined a GML profile using the compact encodings for use in many of their standards).
Cheers!
Whoops - should have read all the way to the end. I see you covered the compact encoding!
RépondreSupprimerThanks for the education..
RépondreSupprimerApart from the standards issues, the standalone hole is interesting.
I would guess that the concept has potential use.
Thinking geometrically (rather than geographically) at first, you could define the hole with an implicit exterior ring at infinity, which makes it an all, except definition. The standalone hole can of course contain (positive) rings.
Going geographical, the all-except notion still has validity, although the domain-definition becomes leading (instead of infinity), e.g. 2.5D earth or 3D earth.
Questions about the limits of the 3D domain remind me of the origin of fractals: the attempt to define and measure the circumference of England..
cheers, I hope you don't mind my loose off-topicness..,
Jan