You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
11 KiB
361 lines
11 KiB
<?php |
|
|
|
declare(strict_types=1); |
|
|
|
namespace Brick\Geo; |
|
|
|
use Brick\Geo\Attribute\NoProxy; |
|
use Brick\Geo\Exception\CoordinateSystemException; |
|
use Brick\Geo\Exception\GeometryIOException; |
|
use Brick\Geo\Exception\InvalidGeometryException; |
|
use Brick\Geo\Exception\UnexpectedGeometryException; |
|
use Brick\Geo\IO\WKTReader; |
|
use Brick\Geo\IO\WKTWriter; |
|
use Brick\Geo\IO\WKBReader; |
|
use Brick\Geo\IO\WKBWriter; |
|
use Brick\Geo\Projector\Projector; |
|
use Brick\Geo\Projector\RemoveZMProjector; |
|
use Brick\Geo\Projector\SRIDProjector; |
|
use Brick\Geo\Projector\SwapXYProjector; |
|
|
|
/** |
|
* Geometry is the root class of the hierarchy. |
|
*/ |
|
abstract class Geometry implements \Countable, \IteratorAggregate, \Stringable |
|
{ |
|
final public const GEOMETRY = 0; |
|
final public const POINT = 1; |
|
final public const LINESTRING = 2; |
|
final public const POLYGON = 3; |
|
final public const MULTIPOINT = 4; |
|
final public const MULTILINESTRING = 5; |
|
final public const MULTIPOLYGON = 6; |
|
final public const GEOMETRYCOLLECTION = 7; |
|
final public const CIRCULARSTRING = 8; |
|
final public const COMPOUNDCURVE = 9; |
|
final public const CURVEPOLYGON = 10; |
|
final public const MULTICURVE = 11; |
|
final public const MULTISURFACE = 12; |
|
final public const CURVE = 13; |
|
final public const SURFACE = 14; |
|
final public const POLYHEDRALSURFACE = 15; |
|
final public const TIN = 16; |
|
final public const TRIANGLE = 17; |
|
|
|
/** |
|
* The coordinate system of this geometry. |
|
*/ |
|
protected CoordinateSystem $coordinateSystem; |
|
|
|
/** |
|
* Whether this geometry is empty. |
|
*/ |
|
protected bool $isEmpty; |
|
|
|
/** |
|
* @param CoordinateSystem $coordinateSystem The coordinate system of this geometry. |
|
* @param bool $isEmpty Whether this geometry is empty. |
|
*/ |
|
protected function __construct(CoordinateSystem $coordinateSystem, bool $isEmpty) |
|
{ |
|
$this->coordinateSystem = $coordinateSystem; |
|
$this->isEmpty = $isEmpty; |
|
} |
|
|
|
/** |
|
* Builds a Geometry from a WKT representation. |
|
* |
|
* If the resulting geometry is valid but is not an instance of the class this method is called on, |
|
* for example passing a Polygon WKT to Point::fromText(), an exception is thrown. |
|
* |
|
* @param string $wkt The Well-Known Text representation. |
|
* @param int $srid The optional SRID to use. |
|
* |
|
* @return static |
|
* |
|
* @throws GeometryIOException If the given string is not a valid WKT representation. |
|
* @throws CoordinateSystemException If the WKT contains mixed coordinate systems. |
|
* @throws InvalidGeometryException If the WKT represents an invalid geometry. |
|
* @throws UnexpectedGeometryException If the resulting geometry is not an instance of the current class. |
|
*/ |
|
public static function fromText(string $wkt, int $srid = 0) : Geometry |
|
{ |
|
/** @var WKTReader|null $wktReader */ |
|
static $wktReader; |
|
|
|
if ($wktReader === null) { |
|
$wktReader = new WKTReader(); |
|
} |
|
|
|
$geometry = $wktReader->read($wkt, $srid); |
|
|
|
if ($geometry instanceof static) { |
|
return $geometry; |
|
} |
|
|
|
throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry); |
|
} |
|
|
|
/** |
|
* Builds a Geometry from a WKB representation. |
|
* |
|
* If the resulting geometry is valid but is not an instance of the class this method is called on, |
|
* for example passing a Polygon WKB to Point::fromBinary(), an exception is thrown. |
|
* |
|
* @param string $wkb The Well-Known Binary representation. |
|
* @param int $srid The optional SRID to use. |
|
* |
|
* @return static |
|
* |
|
* @throws GeometryIOException If the given string is not a valid WKB representation. |
|
* @throws CoordinateSystemException If the WKB contains mixed coordinate systems. |
|
* @throws InvalidGeometryException If the WKB represents an invalid geometry. |
|
* @throws UnexpectedGeometryException If the resulting geometry is not an instance of the current class. |
|
*/ |
|
public static function fromBinary(string $wkb, int $srid = 0) : Geometry |
|
{ |
|
/** @var WKBReader|null $wkbReader */ |
|
static $wkbReader; |
|
|
|
if ($wkbReader === null) { |
|
$wkbReader = new WKBReader(); |
|
} |
|
|
|
$geometry = $wkbReader->read($wkb, $srid); |
|
|
|
if ($geometry instanceof static) { |
|
return $geometry; |
|
} |
|
|
|
throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry); |
|
} |
|
|
|
/** |
|
* Returns the inherent dimension of this geometry. |
|
* |
|
* This dimension must be less than or equal to the coordinate dimension. |
|
* In non-homogeneous collections, this will return the largest topological dimension of the contained objects. |
|
*/ |
|
abstract public function dimension() : int; |
|
|
|
/** |
|
* Returns the coordinate dimension of this geometry. |
|
* |
|
* The coordinate dimension is the total number of coordinates in the coordinate system. |
|
* |
|
* The coordinate dimension can be 2 (for x and y), 3 (with z or m added), or 4 (with both z and m added). |
|
* The ordinates x, y and z are spatial, and the ordinate m is a measure. |
|
* |
|
* @return int<2, 4> |
|
*/ |
|
public function coordinateDimension() : int |
|
{ |
|
return $this->coordinateSystem->coordinateDimension(); |
|
} |
|
|
|
/** |
|
* Returns the spatial dimension of this geometry. |
|
* |
|
* The spatial dimension is the number of measurements or axes needed to describe the |
|
* spatial position of this geometry in a coordinate system. |
|
* |
|
* The spatial dimension is 3 if the coordinate system has a Z coordinate, 2 otherwise. |
|
* |
|
* @return int<2, 3> |
|
*/ |
|
public function spatialDimension() : int |
|
{ |
|
return $this->coordinateSystem->spatialDimension(); |
|
} |
|
|
|
/** |
|
* Returns the name of the instantiable subtype of Geometry of which this Geometry is an instantiable member. |
|
*/ |
|
abstract public function geometryType() : string; |
|
|
|
abstract public function geometryTypeBinary() : int; |
|
|
|
/** |
|
* Returns the Spatial Reference System ID for this geometry. |
|
* |
|
* @return int The SRID, zero if not set. |
|
*/ |
|
#[NoProxy] |
|
public function SRID() : int |
|
{ |
|
return $this->coordinateSystem->SRID(); |
|
} |
|
|
|
/** |
|
* Returns the WKT representation of this geometry. |
|
*/ |
|
#[NoProxy] |
|
public function asText() : string |
|
{ |
|
/** @var WKTWriter|null $wktWriter */ |
|
static $wktWriter; |
|
|
|
if ($wktWriter === null) { |
|
$wktWriter = new WKTWriter(); |
|
} |
|
|
|
return $wktWriter->write($this); |
|
} |
|
|
|
/** |
|
* Returns the WKB representation of this geometry. |
|
*/ |
|
#[NoProxy] |
|
public function asBinary() : string |
|
{ |
|
/** @var WKBWriter|null $wkbWriter */ |
|
static $wkbWriter; |
|
|
|
if ($wkbWriter === null) { |
|
$wkbWriter = new WKBWriter(); |
|
} |
|
|
|
return $wkbWriter->write($this); |
|
} |
|
|
|
/** |
|
* Returns whether this geometry is the empty Geometry. |
|
* |
|
* If true, then this geometry represents the empty point set for the coordinate space. |
|
*/ |
|
public function isEmpty() : bool |
|
{ |
|
return $this->isEmpty; |
|
} |
|
|
|
/** |
|
* Returns whether this geometry has z coordinate values. |
|
*/ |
|
public function is3D() : bool |
|
{ |
|
return $this->coordinateSystem->hasZ(); |
|
} |
|
|
|
/** |
|
* Returns whether this geometry has m coordinate values. |
|
*/ |
|
public function isMeasured() : bool |
|
{ |
|
return $this->coordinateSystem->hasM(); |
|
} |
|
|
|
/** |
|
* Returns the coordinate system of this geometry. |
|
*/ |
|
public function coordinateSystem() : CoordinateSystem |
|
{ |
|
return $this->coordinateSystem; |
|
} |
|
|
|
/** |
|
* Returns a copy of this Geometry, with the SRID altered. |
|
* |
|
* Note that only the SRID value is changed, the coordinates are not reprojected. |
|
* Use GeometryEngine::transform() to reproject the Geometry to another SRID. |
|
* |
|
* @return static |
|
*/ |
|
public function withSRID(int $srid) : Geometry |
|
{ |
|
if ($srid === $this->SRID()) { |
|
return $this; |
|
} |
|
|
|
return $this->project(new SRIDProjector($srid)); |
|
} |
|
|
|
/** |
|
* Returns a copy of this Geometry, with Z and M coordinates removed. |
|
* |
|
* @return static |
|
*/ |
|
public function toXY(): Geometry |
|
{ |
|
if ($this->coordinateDimension() === 2) { |
|
return $this; |
|
} |
|
|
|
return $this->project(new RemoveZMProjector(removeZ: true, removeM: true)); |
|
} |
|
|
|
/** |
|
* Returns a copy of this Geometry, with the Z coordinate removed. |
|
* |
|
* @return static |
|
*/ |
|
public function withoutZ() : Geometry |
|
{ |
|
if (! $this->coordinateSystem->hasZ()) { |
|
return $this; |
|
} |
|
|
|
return $this->project(new RemoveZMProjector(removeZ: true)); |
|
} |
|
|
|
/** |
|
* Returns a copy of this Geometry, with the M coordinate removed. |
|
* |
|
* @return static |
|
*/ |
|
public function withoutM() : Geometry |
|
{ |
|
if (! $this->coordinateSystem->hasM()) { |
|
return $this; |
|
} |
|
|
|
return $this->project(new RemoveZMProjector(removeM: true)); |
|
} |
|
|
|
/** |
|
* Returns the bounding box of the Geometry. |
|
*/ |
|
abstract public function getBoundingBox() : BoundingBox; |
|
|
|
/** |
|
* Returns the raw coordinates of this geometry as an array. |
|
*/ |
|
abstract public function toArray() : array; |
|
|
|
/** |
|
* Returns a copy of this Geometry, with the X and Y coordinates swapped. |
|
* |
|
* @return static |
|
*/ |
|
public function swapXY() : Geometry |
|
{ |
|
return $this->project(new SwapXYProjector()); |
|
} |
|
|
|
/** |
|
* Projects this geometry to a different coordinate system. |
|
*/ |
|
abstract public function project(Projector $projector): Geometry; |
|
|
|
/** |
|
* Returns whether this Geometry is identical to another Geometry. |
|
* |
|
* This method will only return true if the geometries are of the same type, with the exact same coordinates, |
|
* in the same order, and with the same SRID. |
|
* |
|
* This is different from the concept of spatially equal; if you need to check for spatial equality, |
|
* please see `GeometryEngine::equals()` instead. |
|
*/ |
|
public function isIdenticalTo(Geometry $that) : bool |
|
{ |
|
return $this->SRID() === $that->SRID() && $this->asText() === $that->asText(); |
|
} |
|
|
|
/** |
|
* Returns a text representation of this geometry. |
|
*/ |
|
#[NoProxy] |
|
final public function __toString() : string |
|
{ |
|
return $this->asText(); |
|
} |
|
}
|
|
|