• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / geo / 17456208570

04 Sep 2025 07:10AM UTC coverage: 50.432%. Remained the same
17456208570

push

github

BenMorel
Use @extends and @implements instead of @template-* variants

For consistency with the rest of the project.

1867 of 3702 relevant lines covered (50.43%)

1140.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.11
/src/Geometry.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Geo;
6

7
use Brick\Geo\Attribute\NoProxy;
8
use Brick\Geo\Exception\CoordinateSystemException;
9
use Brick\Geo\Exception\GeometryIoException;
10
use Brick\Geo\Exception\InvalidGeometryException;
11
use Brick\Geo\Exception\UnexpectedGeometryException;
12
use Brick\Geo\Io\WkbReader;
13
use Brick\Geo\Io\WkbWriter;
14
use Brick\Geo\Io\WktReader;
15
use Brick\Geo\Io\WktWriter;
16
use Brick\Geo\Projector\Projector;
17
use Brick\Geo\Projector\RemoveZmProjector;
18
use Brick\Geo\Projector\RoundCoordinatesProjector;
19
use Brick\Geo\Projector\SridProjector;
20
use Brick\Geo\Projector\SwapXyProjector;
21
use Override;
22
use Stringable;
23

24
/**
25
 * Geometry is the root class of the hierarchy.
26
 */
27
abstract class Geometry implements Stringable
28
{
29
    final public const GEOMETRY = 0;
30
    final public const POINT = 1;
31
    final public const LINESTRING = 2;
32
    final public const POLYGON = 3;
33
    final public const MULTIPOINT = 4;
34
    final public const MULTILINESTRING = 5;
35
    final public const MULTIPOLYGON = 6;
36
    final public const GEOMETRYCOLLECTION = 7;
37
    final public const CIRCULARSTRING = 8;
38
    final public const COMPOUNDCURVE = 9;
39
    final public const CURVEPOLYGON = 10;
40
    final public const MULTICURVE = 11;
41
    final public const MULTISURFACE = 12;
42
    final public const CURVE = 13;
43
    final public const SURFACE = 14;
44
    final public const POLYHEDRALSURFACE = 15;
45
    final public const TIN = 16;
46
    final public const TRIANGLE = 17;
47

48
    /**
49
     * The coordinate system of this geometry.
50
     */
51
    protected CoordinateSystem $coordinateSystem;
52

53
    /**
54
     * Whether this geometry is empty.
55
     */
56
    protected bool $isEmpty;
57

58
    /**
59
     * @param CoordinateSystem $coordinateSystem The coordinate system of this geometry.
60
     * @param bool             $isEmpty          Whether this geometry is empty.
61
     */
62
    protected function __construct(CoordinateSystem $coordinateSystem, bool $isEmpty)
63
    {
64
        $this->coordinateSystem = $coordinateSystem;
28,663✔
65
        $this->isEmpty = $isEmpty;
28,663✔
66
    }
67

68
    /**
69
     * Builds a Geometry from a WKT representation.
70
     *
71
     * If the resulting geometry is valid but is not an instance of the class this method is called on,
72
     * for example passing a Polygon WKT to Point::fromText(), an exception is thrown.
73
     *
74
     * @param string $wkt  The Well-Known Text representation.
75
     * @param int    $srid The optional SRID to use.
76
     *
77
     * @return static
78
     *
79
     * @throws GeometryIoException         If the given string is not a valid WKT representation.
80
     * @throws CoordinateSystemException   If the WKT contains mixed coordinate systems.
81
     * @throws InvalidGeometryException    If the WKT represents an invalid geometry.
82
     * @throws UnexpectedGeometryException If the resulting geometry is not an instance of the current class.
83
     */
84
    public static function fromText(string $wkt, int $srid = 0): Geometry
85
    {
86
        /** @var WktReader|null $wktReader */
87
        static $wktReader;
8,263✔
88

89
        if ($wktReader === null) {
8,263✔
90
            $wktReader = new WktReader();
8✔
91
        }
92

93
        $geometry = $wktReader->read($wkt, $srid);
8,263✔
94

95
        if ($geometry instanceof static) {
8,207✔
96
            return $geometry;
8,135✔
97
        }
98

99
        throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry);
72✔
100
    }
101

102
    /**
103
     * Builds a Geometry from a WKB representation.
104
     *
105
     * If the resulting geometry is valid but is not an instance of the class this method is called on,
106
     * for example passing a Polygon WKB to Point::fromBinary(), an exception is thrown.
107
     *
108
     * @param string $wkb  The Well-Known Binary representation.
109
     * @param int    $srid The optional SRID to use.
110
     *
111
     * @return static
112
     *
113
     * @throws GeometryIoException         If the given string is not a valid WKB representation.
114
     * @throws CoordinateSystemException   If the WKB contains mixed coordinate systems.
115
     * @throws InvalidGeometryException    If the WKB represents an invalid geometry.
116
     * @throws UnexpectedGeometryException If the resulting geometry is not an instance of the current class.
117
     */
118
    public static function fromBinary(string $wkb, int $srid = 0): Geometry
119
    {
120
        /** @var WkbReader|null $wkbReader */
121
        static $wkbReader;
528✔
122

123
        if ($wkbReader === null) {
528✔
124
            $wkbReader = new WkbReader();
8✔
125
        }
126

127
        $geometry = $wkbReader->read($wkb, $srid);
528✔
128

129
        if ($geometry instanceof static) {
528✔
130
            return $geometry;
448✔
131
        }
132

133
        throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry);
80✔
134
    }
135

136
    /**
137
     * Returns the inherent dimension of this geometry.
138
     *
139
     * This dimension must be less than or equal to the coordinate dimension.
140
     * In non-homogeneous collections, this will return the largest topological dimension of the contained objects.
141
     */
142
    abstract public function dimension(): int;
143

144
    /**
145
     * Returns the coordinate dimension of this geometry.
146
     *
147
     * The coordinate dimension is the total number of coordinates in the coordinate system.
148
     *
149
     * The coordinate dimension can be 2 (for x and y), 3 (with z or m added), or 4 (with both z and m added).
150
     * The ordinates x, y and z are spatial, and the ordinate m is a measure.
151
     *
152
     * @return int<2, 4>
153
     */
154
    public function coordinateDimension(): int
155
    {
156
        return $this->coordinateSystem->coordinateDimension();
96✔
157
    }
158

159
    /**
160
     * Returns the spatial dimension of this geometry.
161
     *
162
     * The spatial dimension is the number of measurements or axes needed to describe the
163
     * spatial position of this geometry in a coordinate system.
164
     *
165
     * The spatial dimension is 3 if the coordinate system has a Z coordinate, 2 otherwise.
166
     *
167
     * @return int<2, 3>
168
     */
169
    public function spatialDimension(): int
170
    {
171
        return $this->coordinateSystem->spatialDimension();
96✔
172
    }
173

174
    /**
175
     * Returns the name of the instantiable subtype of Geometry of which this Geometry is an instantiable member.
176
     */
177
    abstract public function geometryType(): string;
178

179
    abstract public function geometryTypeBinary(): int;
180

181
    /**
182
     * Returns the Spatial Reference System ID for this geometry.
183
     *
184
     * @return int The SRID, zero if not set.
185
     */
186
    #[NoProxy]
187
    public function srid(): int
188
    {
189
        return $this->coordinateSystem->srid();
17,320✔
190
    }
191

192
    /**
193
     * Returns the WKT representation of this geometry.
194
     */
195
    #[NoProxy]
196
    public function asText(): string
197
    {
198
        /** @var WktWriter|null $wktWriter */
199
        static $wktWriter;
4,804✔
200

201
        if ($wktWriter === null) {
4,804✔
202
            $wktWriter = new WktWriter();
8✔
203
        }
204

205
        return $wktWriter->write($this);
4,804✔
206
    }
207

208
    /**
209
     * Returns the WKB representation of this geometry.
210
     */
211
    #[NoProxy]
212
    public function asBinary(): string
213
    {
214
        /** @var WkbWriter|null $wkbWriter */
215
        static $wkbWriter;
1,691✔
216

217
        if ($wkbWriter === null) {
1,691✔
218
            $wkbWriter = new WkbWriter();
8✔
219
        }
220

221
        return $wkbWriter->write($this);
1,691✔
222
    }
223

224
    /**
225
     * Returns whether this geometry is the empty Geometry.
226
     *
227
     * If true, then this geometry represents the empty point set for the coordinate space.
228
     */
229
    public function isEmpty(): bool
230
    {
231
        return $this->isEmpty;
17,585✔
232
    }
233

234
    /**
235
     * Returns whether this geometry has z coordinate values.
236
     */
237
    public function is3D(): bool
238
    {
239
        return $this->coordinateSystem->hasZ();
6,403✔
240
    }
241

242
    /**
243
     * Returns whether this geometry has m coordinate values.
244
     */
245
    public function isMeasured(): bool
246
    {
247
        return $this->coordinateSystem->hasM();
6,371✔
248
    }
249

250
    /**
251
     * Returns the coordinate system of this geometry.
252
     */
253
    public function coordinateSystem(): CoordinateSystem
254
    {
255
        return $this->coordinateSystem;
23,736✔
256
    }
257

258
    /**
259
     * Returns a copy of this Geometry, with the SRID altered.
260
     *
261
     * Note that only the SRID value is changed, the coordinates are not reprojected.
262
     * Use GeometryEngine::transform() to reproject the Geometry to another SRID.
263
     *
264
     * @return static
265
     */
266
    public function withSrid(int $srid): Geometry
267
    {
268
        if ($srid === $this->srid()) {
224✔
269
            return $this;
×
270
        }
271

272
        return $this->project(new SridProjector($srid));
224✔
273
    }
274

275
    /**
276
     * Returns a copy of this Geometry, with Z and M coordinates removed.
277
     *
278
     * @return static
279
     */
280
    public function toXy(): Geometry
281
    {
282
        if ($this->coordinateDimension() === 2) {
×
283
            return $this;
×
284
        }
285

286
        return $this->project(new RemoveZmProjector(removeZ: true, removeM: true));
×
287
    }
288

289
    /**
290
     * Returns a copy of this Geometry, with the Z coordinate removed.
291
     *
292
     * @return static
293
     */
294
    public function withoutZ(): Geometry
295
    {
296
        if (! $this->coordinateSystem->hasZ()) {
×
297
            return $this;
×
298
        }
299

300
        return $this->project(new RemoveZmProjector(removeZ: true));
×
301
    }
302

303
    /**
304
     * Returns a copy of this Geometry, with the M coordinate removed.
305
     *
306
     * @return static
307
     */
308
    public function withoutM(): Geometry
309
    {
310
        if (! $this->coordinateSystem->hasM()) {
472✔
311
            return $this;
464✔
312
        }
313

314
        return $this->project(new RemoveZmProjector(removeM: true));
8✔
315
    }
316

317
    /**
318
     * Returns a copy of this Geometry, with coordinates rounded to the given precision.
319
     *
320
     * @return static
321
     */
322
    public function withRoundedCoordinates(int $precision): Geometry
323
    {
324
        return $this->project(new RoundCoordinatesProjector($precision));
72✔
325
    }
326

327
    /**
328
     * Returns the bounding box of the Geometry.
329
     */
330
    abstract public function getBoundingBox(): BoundingBox;
331

332
    /**
333
     * Returns the raw coordinates of this geometry as an array.
334
     *
335
     * This returns potentially nested lists of floats.
336
     *
337
     * Examples:
338
     * - a Point will return list<float>
339
     * - a LineString will return list<list<float>>
340
     * - a Polygon will return list<list<list<float>>>
341
     *
342
     * Subclasses will narrow down the return type as appropriate.
343
     *
344
     * @return list<mixed>
345
     */
346
    abstract public function toArray(): array;
347

348
    /**
349
     * Returns a copy of this Geometry, with the X and Y coordinates swapped.
350
     *
351
     * @return static
352
     */
353
    public function swapXy(): Geometry
354
    {
355
        return $this->project(new SwapXyProjector());
14✔
356
    }
357

358
    /**
359
     * Projects this geometry to a different coordinate system.
360
     */
361
    abstract public function project(Projector $projector): Geometry;
362

363
    /**
364
     * Returns whether this Geometry is identical to another Geometry.
365
     *
366
     * This method will only return true if the geometries are of the same type, with the exact same coordinates,
367
     * in the same order, and with the same SRID.
368
     *
369
     * This is different from the concept of spatially equal; if you need to check for spatial equality,
370
     * please see `GeometryEngine::equals()` instead.
371
     */
372
    public function isIdenticalTo(Geometry $that): bool
373
    {
374
        return $this->srid() === $that->srid() && $this->asText() === $that->asText();
224✔
375
    }
376

377
    /**
378
     * Returns a text representation of this geometry.
379
     */
380
    #[NoProxy, Override]
381
    final public function __toString(): string
382
    {
383
        return $this->asText();
32✔
384
    }
385
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc