-
-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathGeometry.php
373 lines (326 loc) · 10.9 KB
/
Geometry.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
<?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;
use Override;
/**
* Geometry is the root class of the hierarchy.
*/
abstract class Geometry implements \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.
*
* This returns potentially nested lists of floats.
*
* Examples:
* - a Point will return list<float>
* - a LineString will return list<list<float>>
* - a Polygon will return list<list<list<float>>>
*
* Subclasses will narrow down the return type as appropriate.
*
* @return list<mixed>
*/
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, Override]
final public function __toString() : string
{
return $this->asText();
}
}