# Two-and-a-half-D extensions for Simple Features

## Introduction

There is a requirement for handling height information in geographic information systems, in a way that falls short of full 3D modeling.  This simple method of handling heights is sometimes called "two and a half D", or 2.5D.

This document:
1) Defines 2.5D in abstract terms
2) Suggests how Simple Features could be extended for 2.5D

This document defines 2.5D in a way which is a simple extension of the existing 2D OpenGIS Simple Features specification.

It does NOT cover full 3D geometry (e.g. solids), or 3D coordinate systems.  Handling these topics thoroughly is a more complicated job, and is outside the scope of this document.

## Abstract

### Definition of 2.5D geometry

a) Height is modeled by storing a Z value at each point.
b) Heights are linearly interpolated between consecutive curve vertices.
c) Heights are undefined within surface interiors.

Any 2.5D geometry can be converted into a 2D geometry by discarding all its Z values.  The resulting 2D geometry is the "shadow" of the 2.5D geometry.  By convention, shadows are assumed to lie on the (X,Y,0) plane.  So any 2D geometry can be converted into a 2.5D geometry by adding Z=0 to all its vertices.

### Simple Geometry

The OpenGIS Simple Features specification defines the term "simple geometry".  In general, a 2D geometry is simple if it contains no self-intersection.

The term "simple geometry" is important, since Spatial Relationships and Spatial Operators are undefined on non-simple geometries.

A 2.5D geometry is simple if
1) Its 2D shadow is simple
2) There is at most one Z value at each 2D location: (So wherever two of the geometry's vertices match in (X,Y), they also match in Z.  For example, this rule applies to the end-points of a LinearRing, and the tangential points of a multi-looped Polygon.  Also, wherever the (X,Y) shadow of one of the geometry’s vertices lies in the interior of the (X,Y) shadow of another of the geometry’s line segments, then the vertex Z value matches the line segments interpolated Z value.  This rule applies to the tangential point of a multi-looped polygon.)

With this definition, a sloping road centerline is simple, but a vertical flagpole is not.  The fact that a flagpole is not simple is one of the limitations of 2.5D, whereas in a 3D system the flagpole could be considered simple.

### Spatial Relationships

The OpenGIS Simple Features specification defines spatial relationships in terms of a dimensionally extended nine-intersection matrix (DE9-IM).

The DE9IM rules for spatial queries are applied to the 2D shadows of all 2.5D geometries. So a 2.5D point is inside a 2.5D polygon if its (X,Y) location is inside the polygon's 2D shadow. (For example, this allows testing whether a 3D GPS location is inside a land-parcel that is defined as a loop of 3D points.)

Spatial Operators
The OpenGIS Simple Features specification defines various spatial operators, which can be used to generate new geometries from existing geometries.

The operators Union, Intersect, SymmetricDifference and Difference are defined on 2.5D geometries by working on their 2D shadows.  This will produce a 2D output.  However, the 2D output can be converted back to 2.5D by assigning a Z value to each output vertex.  This can be done in a well-defined way, since each output vertex will either match an input vertex, or it will lie on a curve of an input geometry, where the Z is defined using linear interpolation.  If an output vertex lies on both of the input geometries, then the "this" geometry object is used for the Z value.

The output of the convex-hull operator on a 2.5D geometry takes its Z values from the original 2.5D geometry.  Each vertex in the convex-hull output will correspond to a vertex in the input geometry, so its Z-value is well defined for simple geometries.

The buffer operator will work on the 2D shadow of 2.5D geometries, and every vertex of the output geometry will have a Z value of 0.

Compatibility with existing OpenGIS Simple Features

### Compatibility of Abstract Model

The geometries defined in the existing OpenGIS Simple Features specification are all two-dimensional (2D).

The abstract section of this document carefully defines spatial relationships and spatial operators on 2.5D geometries, to ensure backwards-compatibility with Simple Features.

Backwards-compatibility at the abstract level can be shown with a mathematical argument along the following lines:

Define geometrical systems G, H and SF where
G = {Simple 2.5D geometries}
H = {Simple 2.5D geometries where all Z values are 0}
SF = {Simple 2D geometries, as defined by the OpenGIS Simple Features}

Then H is a subsystem of G, and H is isomorphic to SF, preserving the spatial relationship functions and the spatial operator functions.

### Extensions to Well-Known-Binary format

The existing OpenGIS Simple Features specification has the following 2D geometry types:

enum wkbGeometryType {
wkbPoint = 1,
wkbLineString = 2,
wkbPolygon = 3,
wkbMultiPoint = 4,
wkbMultiLineString = 5,
wkbMultiPolygon = 6,
wkbGeometryCollection = 7
}

This type-code is put in the header of a WKB blob.  To reflect that all of these 2D geometry types have a 2.5D analogue, we would add a flag to the type-code to indicate that all following points include a Z value.  So the new enumeration would become:

enum wkbGeometryTypeZ {
wkbPoint = 1,
wkbLineString = 2,
wkbPolygon = 3,
wkbMultiPoint = 4,
wkbMultiLineString = 5,
wkbMultiPolygon = 6,
wkbGeometryCollection = 7,
wkbZ = 0x80000000
}

Alternatively, this could be less efficiently coded as:

enum wkbGeometryTypeZ {
wkbPoint = 1,
wkbLineString = 2,
wkbPolygon = 3,
wkbMultiPoint = 4,
wkbMultiLineString = 5,
wkbMultiPolygon = 6,
wkbGeometryCollection = 7,
wkbPoint25D = 0x80000001,
wkbLineString25D = 0x80000002,
wkbPolygon25D = 0x80000003,
wkbMultiPoint25D = 0x80000004,
wkbMultiLineString25D = 0x80000005,
wkbMultiPolygon25D = 0x80000006,
wkbGeometryCollection25D = 0x80000007,
}

For example, a 2.5D Point geometry at the location (10,20,30) would be:

WKBPoint {
byte                    byteOrder;      // wkbXDR or wkbNDR
uint32          wkbType;        // (wkbPoint+wkbZ) = 0x80000001
Point   {
Double  x;              // 10.0
Double  y;              // 20.0
Double  z;              // 30.0
}
}

If all Z values in a 2.5D geometry object happen to be 0, then its WKB representation could be the same as for the existing Simple Features specification (i.e. does not use the wkbZ flag, and does not include Z values).  We suggest that 2.5D server-implementations drop the wkbZ flag whenever all the Z values are zero.  This would allow 2D clients to interoperate with the 2.5D server whenever the data happens to lie on the (X,Y,0) plane.

### Extensions to Well-Known-Text format

A 2.5D point at (10,20,30) would be represented as "POINT(10 20 30)".

A 2.5D line-string from (10,20,30) to (40,50,60) would be represented as "LINESTRING(10 20 30,40 50 60)".

Notice that in the line-string, each vertex is terminated by either a comma, or a bracket.  This means that a vertex that happens to have a Z value of 0 could simply not print its Z value.  So a line-string from (1,2,3) to (4,5,0) could be represented as "LINESTRING(1 2 3,4 5)".   We suggest that 2.5D server-implementations skips printing the Z value whenever it is zero.  This would allow 2D clients to interoperate with the 2.5D server whenever the data happens to lie on the (X,Y,0) plane.

### Extensions to Microsoft COM Simple Features interfaces

Since we have not needed to introduce any new geometry classes, and we have not changed the abstract behavior of any existing 2D geometry objects, we should not need to change any existing COM Interface Definition Language (IDL) files.

All we need to do is add a new optional IDL file for 2.5D interoperability:

// File: ZIdl.idl
// Extension to Simple Features for 2.5D Z values.
import "ocidl.idl", "GeometryIdl.idl";

interface IPointZ;

[ object, uuid(D4579E2D-1D2B-11d3-80BE-00C04F680FFF) ]
interface IPointZ : IPoint
{
[propget] HRESULT Z([out, retval] double * z);
};

Since the new interface IPointZ inherits from IPoint,  whenever a 2.5D aware component is asked for a point value (e.g. when getting a vertex from a line-string), the component can return an IPointZ interface pointer.

Any 2D client will work with a 2.5D server unchanged.

In Visual Basic, a 2.5D client which knows it is interoperating with a 2.5D server, could ask for the point locations with an IPointZ typed variable, and then pass this IPointZ variable back into other methods.  For example:

Dim line As ILineString
Set line = CreateFromWKT("LINESTRING(10 11 12,20 21,30 31 32)", sref)
Dim sr As ISpatialRelation
Set sr = line
For i = 0 To 2
' Get line vertex as 3D point.
Dim ptz As IPointZ
Set ptz = line.Point(i)

' Re-use 3D point in other Simple Features methods.
Debug.Print i; ") "; ptz.x, ptz.y, ptz.Z
Debug.Print sr.Contains(ptz)
Next i

Document converted from word 8 by MSWordView (mswordview 0.4.2)
MSWordView written by Caolan McNamara