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

brick / geo / 13861446053

14 Mar 2025 04:52PM UTC coverage: 50.781% (+2.7%) from 48.122%
13861446053

push

github

BenMorel
fixup! Implement GeometryEngine::concaveHull()

1852 of 3647 relevant lines covered (50.78%)

1002.02 hits per line

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

84.78
/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\WKTReader;
13
use Brick\Geo\IO\WKTWriter;
14
use Brick\Geo\IO\WKBReader;
15
use Brick\Geo\IO\WKBWriter;
16
use Brick\Geo\Projector\Projector;
17
use Brick\Geo\Projector\RemoveZMProjector;
18
use Brick\Geo\Projector\SRIDProjector;
19
use Brick\Geo\Projector\SwapXYProjector;
20
use Override;
21

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

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

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

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

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

87
        if ($wktReader === null) {
7,159✔
88
            $wktReader = new WKTReader();
7✔
89
        }
90

91
        $geometry = $wktReader->read($wkt, $srid);
7,159✔
92

93
        if ($geometry instanceof static) {
7,110✔
94
            return $geometry;
7,047✔
95
        }
96

97
        throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry);
63✔
98
    }
99

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

121
        if ($wkbReader === null) {
402✔
122
            $wkbReader = new WKBReader();
7✔
123
        }
124

125
        $geometry = $wkbReader->read($wkb, $srid);
402✔
126

127
        if ($geometry instanceof static) {
402✔
128
            return $geometry;
332✔
129
        }
130

131
        throw UnexpectedGeometryException::unexpectedGeometryType(static::class, $geometry);
70✔
132
    }
133

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

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

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

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

177
    abstract public function geometryTypeBinary() : int;
178

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

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

199
        if ($wktWriter === null) {
4,100✔
200
            $wktWriter = new WKTWriter();
7✔
201
        }
202

203
        return $wktWriter->write($this);
4,100✔
204
    }
205

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

215
        if ($wkbWriter === null) {
1,409✔
216
            $wkbWriter = new WKBWriter();
7✔
217
        }
218

219
        return $wkbWriter->write($this);
1,409✔
220
    }
221

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

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

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

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

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

270
        return $this->project(new SRIDProjector($srid));
196✔
271
    }
272

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

284
        return $this->project(new RemoveZMProjector(removeZ: true, removeM: true));
×
285
    }
286

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

298
        return $this->project(new RemoveZMProjector(removeZ: true));
×
299
    }
300

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

312
        return $this->project(new RemoveZMProjector(removeM: true));
7✔
313
    }
314

315
    /**
316
     * Returns the bounding box of the Geometry.
317
     */
318
    abstract public function getBoundingBox() : BoundingBox;
319

320
    /**
321
     * Returns the raw coordinates of this geometry as an array.
322
     *
323
     * This returns potentially nested lists of floats.
324
     *
325
     * Examples:
326
     * - a Point will return list<float>
327
     * - a LineString will return list<list<float>>
328
     * - a Polygon will return list<list<list<float>>>
329
     *
330
     * Subclasses will narrow down the return type as appropriate.
331
     *
332
     * @return list<mixed>
333
     */
334
    abstract public function toArray() : array;
335

336
    /**
337
     * Returns a copy of this Geometry, with the X and Y coordinates swapped.
338
     *
339
     * @return static
340
     */
341
    public function swapXY() : Geometry
342
    {
343
        return $this->project(new SwapXYProjector());
14✔
344
    }
345

346
    /**
347
     * Projects this geometry to a different coordinate system.
348
     */
349
    abstract public function project(Projector $projector): Geometry;
350

351
    /**
352
     * Returns whether this Geometry is identical to another Geometry.
353
     *
354
     * This method will only return true if the geometries are of the same type, with the exact same coordinates,
355
     * in the same order, and with the same SRID.
356
     *
357
     * This is different from the concept of spatially equal; if you need to check for spatial equality,
358
     * please see `GeometryEngine::equals()` instead.
359
     */
360
    public function isIdenticalTo(Geometry $that) : bool
361
    {
362
        return $this->SRID() === $that->SRID() && $this->asText() === $that->asText();
196✔
363
    }
364

365
    /**
366
     * Returns a text representation of this geometry.
367
     */
368
    #[NoProxy, Override]
369
    final public function __toString() : string
370
    {
371
        return $this->asText();
28✔
372
    }
373
}
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