# Geometry Module

The TerraLib Geometry module is compliant with spatial standards from ISO (International Organization for Standardization) and OGC (Open Geospatial Consortium). The latest OGC Simple Feature Specification, version 1.2, is closely related to ISO SQL/MM Spatial and readers of this section should be familiar with OGC Simple Feature Specification - Part 1: Common Architecture at least.

It is important to notice that this module refers to a geometry model to be used in main memory and it doesn't assume any kind of persistence or data storage management. This section explains the basic concepts, design behind this module ad how to use it.

All the types offered by Geometry module are in the namespace `te::gm`. Check the Doxygen documentation of this module, where these and other classes are documented in details.

## General Concepts

This module relies on some basic definitions from the OGC and ISO specifications:

• Object dimension:
• From Wikipedia: “in mathematics, the dimension of an object is an intrinsic property, independent of the space in which the object may happen to be embedded”.
• A 0-dimensional geometry is one with a geometric dimension of 0 (zero). Points are 0-dimensional objects.
• A 1-dimensional geometry is one with a geometric dimension of 1 (one). Curves (lines) are 1-dimensional objects.
• A 2-dimensional geometry is one with a geometric dimension of 2 (two). Surfaces (polygons) are 2-dimensional objects.
• We can have geometries in ℜ2, ℜ3 or ℜ4 coordinate spaces.
• The z coordinate value not necessarely represents altitude.
• The m coordinate value represents arbitrary measurement.
• The term ring is applied to a closed curve (the first and last points are coincident).

## Geometry Class Hierarchy

The following class diagram shows the geometric classes provided in TerraLib1):

This model implements the classes defined in OGC SFS and ISO SQL/MM Spatial. Following, each class from the above diagram is discussed in detail.

### Geometry

Geometry is the base class for all geometry types. It is an abstract class and though not instantiable.

As one can see, every geometry has an associated Spatial Reference System identifier or srid. This identifier can be used when converting between Spatial Reference Systems 2).

Another important information associated to a geometry is its minimum bounding rectangle (mar) or envelope (according to OGC definition). Actually, the mbr is not automatically computed for a geometry. Instead the mbr is computed just when an mbr accessor method is first called. If a client of a geometry class changes its coordinates the mbr will not be automatically adjusted. The method `computeMBR()` can be used to control when the MBR should be computed.

For an in depth explanation, see Doxygen documentation of this class.

### Point

A Point has at least a x and y coordinate values. It is possible to represent points with a z coordinate value (class PointZ) or points with an associated measure m (class PointM) or with z and m values (class PointZM).

`te::gm::Point p(-54.0, -12.0, 4326);`

Due to optimization issues, we have subclassified the class Point in: PointM, PointZ and PointZM. This doesn't violate any standard principle.

Another class introduced by TerraLib is PointKd, that can be used to represent more than 4-dimensions.

For an in depth explanation, see Doxygen documentation of this class.

### Curve

The OGC SFS specification defines only one subclass of Curve which uses linear interpolation between Points: LineString, Line, LinearRing. The ISO SQL/MM specifies CircularString and CompoundCurve.

Curve is an abstract class and though not instantiable.

For an in depth explanation, see Doxygen documentation of this class.

### LineString

The class LineString can be used to represent curves with linear interpolation between points. A LineString can have M or Z coordinates.

In a LineString each consecutive pair of points defines a line segment.

```te::gm::LineString l(2, te::gm::LineStringType);

l.setPoint(0, -54.0, -12.0);
l.setPoint(1, -55.0, -13.0);```

Internally, we store an array of coordinates and separate arrays for points with z and m.

All OGC interface is supported based on points through the method getPointN. But the extended methods, for coordinates, will be faster than the same versions of OGC methods because they work with less complex structures (coordinates) than points.

For an in depth explanation, see Doxygen documentation of this class.

### Line

A Line is a LineString restricted to 2 points.

For an in depth explanation, see Doxygen documentation of this class.

### LinearRing

A LinearRing is a LineString that is both closed and simple.

```te::gm::LinearRing r(5, te::gm::LineStringType, 0);

r.setPoint(0, 1, 2);
r.setPoint(1, 1, 7);
r.setPoint(2, 7, 7);
r.setPoint(3, 7, 2);
r.setPoint(4, 1, 2);```

The boundary of a linear ring is empty.

This class is the basic building block of class Polygon.

For an in depth explanation, see Doxygen documentation of this class.

### CircularString

CircularString is a curve with circular interpolation between points and it may consist of one or more circular arc segments connected end to end.

A CircularString must have an odd number of points and this number must be greater than 1.

When representing more than one arc the last point of the previous arc becomes the first point of the next arc.

According to ISO SQL-MM Part 3 - Spatial:
“The first three points define the first segment. The first point is the start point of the arc. The second point is any intermediate point on the arc other than the start or end point. The third point is the end point of the arc. Subsequent segments are defined by their intermediate and end points only, as the start point is implicitly defined as the previous segment's end point. In the special case where a segment is a complete circle, that is, the start and end points are coincident, then the intermediate point shall be the midpoint of the segment”.

Notes:

• A CircularString value with exactly three points is a circular arc.
• A circular ring is a CircularString value that is both closed and simple.

For an in depth explanation, see Doxygen documentation of this class.

### CompoundCurve

A CompoundCurve is a curve that may have circular and linear segments.

For an in depth explanation, see Doxygen documentation of this class.

### Surface

Surface is an abstract class that represents a 2-dimensional geometric object.

For an in depth explanation, see Doxygen documentation of this class.

### CurvePolygon

CurvePolygon is a planar surface defined by 1 exterior boundary and 0 or more interior boundaries. The boundary of each ring can be any closed and simple curve.

For an in depth explanation, see Doxygen documentation of this class.

### Polygon

Polygon is a subclass of CurvePolygon whose rings are defined by linear rings.

The code snippet below shows how to create a polygon with just one outer boundary (a LinearRing):

```std::unique_ptr<te::gm::LinearRing> r = std::make_unique<te::gm::LinearRing>(5, te::gm::LineStringType, 4326);

r->setPoint(0, 1, 2);
r->setPoint(1, 1, 7);
r->setPoint(2, 7, 7);
r->setPoint(3, 7, 2);
r->setPoint(4, 1, 2);

te::gm::Polygon p(1, te::gm::PolygonType, 4326);

p.setRingN(0, r.release());```

You have also methods that allows to add rings incrementally:

```std::unique_ptr<te::gm::Polygon> p = std::make_unique<te::gm::Polygon>(0, te::gm::PolygonType);

p->push_back(createSquare(5, 5, 10)); // external square
p->push_back(createSquare(5, 5, 5));  // internal square (the hole!)```

For an in depth explanation, see Doxygen documentation of this class.

### Triangle

Triangle is a polygon with 3 distinct, non-collinear vertices and no interior boundary.

For an in depth explanation, see Doxygen documentation of this class.

### PolyhedralSurface

PolyhedralSurface is a contiguous collection of polygons, which share common boundary segments.

For an in depth explanation, see Doxygen documentation of this class.

### TIN

TIN (triangulated irregular network) is a PolyhedralSurface consisting only of Triangle patches.

For an in depth explanation, see Doxygen documentation of this class.

### GeometryCollection

A GeometryCollection is a collection of other geometric objects.

It can contains any combination of geometric elements. Thus its is a heterogeneous collection of geometries.

In the above picture we have one GeometryCollection that contains one MultiPolygon, one Point and one LineString.

```te::gm::GeometryCollection* gColl = new te::gm::GeometryCollection(0, te::gm::GeometryCollectionType);

For an in depth explanation, see Doxygen documentation of this class.

### MultiPoint

MultiPoint is a GeometryCollection whose elements are restricted to points. In other words, it is a homogeneous collection of points.

For an in depth explanation, see Doxygen documentation of this class.

### MultiCurve

MultiCurve is a class that represents a 1-dimensional GeometryCollection whose elements are curves.

For an in depth explanation, see Doxygen documentation of this class.

### MultiLineString

MultiLineString is a MultiCurve whose elements are LineStrings. In other words, it is a homogeneous collection of lines.

For an in depth explanation, see Doxygen documentation of this class.

### MultiSurface

MultiSurface is a class that represents a 2-dimensional GeometryCollection whose elements are surfaces.

For an in depth explanation, see Doxygen documentation of this class.

### MultiPolygon

MultiPolygon is a MultiSurface whose elements are Polygons. In other words, it is a homogeneous collection of polygons.

For an in depth explanation, see Doxygen documentation of this class.

## Auxiliary Classes

### Coord2D

A Coord2D is an utility struct for representing 2D coordinates.

### Envelope

An Envelope defines a 2D rectangular region that is useful for representing objects bounding box (or minimum bouding rectangles).

## Spatial Relationships

1. Does the red polygon contains the blue one?

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (9 2, 9 7, 15 7, 15 2, 9 2) )") );

std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (10 4, 10 7, 14 7, 14 4, 10 4) )") );

bool result = red->contains( blue() );

std::cout << std::boolalpha << result << std::end;```

2. Does the red polygon contains the blue one?

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (2 3, 2 6, 6 6, 6 3, 2 3) )") );

std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (1 2, 1 7, 7 7, 7 2, 1 2) )") );

bool result =  red->within( blue() );

std::cout << std::boolalpha << result << std::endl;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (10 4, 10 7, 14 7, 14 4, 10 4) )") );

std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (9 2, 9 7, 15 7, 15 2, 9 2) )") );

bool result =  red->within( blue() );

std::cout << std::boolalpha << result << std::endl;```

3. Does the red line touches the blue one?

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("LINESTRING (1 5, 1 7, 3 7)") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("LINESTRING (4 5, 4 7, 6 7)") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("LINESTRING (1 3, 3 4)") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```

3. Does the red polygon touches the blue one?

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (1 0, 1 2, 4 2, 4 0, 1 0) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (4 0, 4 2, 7 2, 7 0, 4 0) )") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (8 5, 8 7, 11 7, 11 5, 8 5) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (11 6, 13 8, 15 6, 13 4, 11 6) )") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (9 1, 9 3, 12 3, 12 1, 9 1) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (11 2, 13 3, 15 2, 13 1, 11 2) )") );

bool result = red->touches( blue.get() );

std::cout << std::boolalpha << result << std::endl ;```

## Set Operations

1. Polygon intersection:

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (2 2, 2 4, 5 4, 5 2, 2 2) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (4 1, 4 3, 7 3, 7 1, 4 1) )") );

std::unique_ptr<te::gm::Geometry> result( red->intersection( blue.get() ) );

std::cout << result->toString()  << std::end;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (2 5, 2 7, 5 7, 5 5, 2 5) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (5 5, 5 7, 8 7, 8 5, 5 5) )") );

std::unique_ptr<te::gm::Geometry> result( red->intersection( blue.get() ) );

std::cout << result->toString()  << std::endl;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (9 2, 9 4, 11 4, 11 2, 9 2) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (12 1, 12 3, 15 3, 15 1, 12 1) )") );

std::unique_ptr<te::gm::Geometry> result( red->intersection( blue.get() ) );

std::cout << result->toString()  << std::endl;```

2. Polygon union:

```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (2 2, 2 4, 5 4, 5 2, 2 2) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (4 1, 4 3, 7 3, 7 1, 4 1) )") );

std::unique_ptr<te::gm::Geometry> result( red->Union( blue.get() ) );

std::cout << result->toString()  << std::endl;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (2 5, 2 7, 5 7, 5 5, 2 5) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (5 5, 5 7, 8 7, 8 5, 5 5) )") );

std::unique_ptr<te::gm::Geometry> result( red->Union( blue.get() ) );

std::cout << result->toString()  << std::endl;```
```std::unique_ptr<te::gm::Geometry> red( te::gm::WKTReader::read("POLYGON ( (9 2, 9 4, 11 4, 11 2, 9 2) )") );
std::unique_ptr<te::gm::Geometry> blue( te::gm::WKTReader::read("POLYGON ( (12 1, 12 3, 15 3, 15 1, 12 1) )") );

std::unique_ptr<te::gm::Geometry> result( red->Union( blue.get() ) );

std::cout << result->toString()  << std::endl;```

## Buffer

```std::unique_ptr<te::gm::Geometry> poly( te::gm::WKTReader::read("POLYGON ( (6 3, 6 5, 9 5, 9 3, 6 3) )") );

std::unique_ptr<te::gm::Geometry> result( poly->buffer(2.0) );

std::cout << result->toString()  << std::endl;```

## Metric Operators

1) This diagram follows OGC Simple Feature Specification
2) See the SRS module for more detail on this 