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

brick / geo / 13766209603

09 Mar 2025 10:35PM UTC coverage: 87.414% (+3.3%) from 84.117%
13766209603

push

github

BenMorel
Add Point::isEqualTo() (WIP: finish? keep?)

8 of 8 new or added lines in 2 files covered. (100.0%)

73 existing lines in 16 files now uncovered.

1653 of 1891 relevant lines covered (87.41%)

1946.79 hits per line

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

96.77
/src/IO/AbstractWKTReader.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Geo\IO;
6

7
use Brick\Geo\Curve;
8
use Brick\Geo\Geometry;
9
use Brick\Geo\Point;
10
use Brick\Geo\LineString;
11
use Brick\Geo\CircularString;
12
use Brick\Geo\CompoundCurve;
13
use Brick\Geo\Polygon;
14
use Brick\Geo\CurvePolygon;
15
use Brick\Geo\MultiPoint;
16
use Brick\Geo\MultiLineString;
17
use Brick\Geo\MultiPolygon;
18
use Brick\Geo\GeometryCollection;
19
use Brick\Geo\PolyhedralSurface;
20
use Brick\Geo\TIN;
21
use Brick\Geo\Triangle;
22
use Brick\Geo\CoordinateSystem;
23
use Brick\Geo\Exception\GeometryIOException;
24

25
/**
26
 * Base class for WKTReader and EWKTReader.
27
 *
28
 * @internal
29
 */
30
abstract class AbstractWKTReader
31
{
32
    /**
33
     * @throws GeometryIOException
34
     */
35
    protected function readGeometry(WKTParser $parser, int $srid) : Geometry
36
    {
37
        $geometryType = $parser->getNextWord();
15,578✔
38
        $word = $parser->getOptionalNextWord();
15,578✔
39

40
        $hasZ = false;
15,578✔
41
        $hasM = false;
15,578✔
42
        $isEmpty    = false;
15,578✔
43

44
        if ($word !== null) {
15,578✔
45
            if ($word === 'Z') {
11,502✔
46
                $hasZ = true;
3,529✔
47
            } elseif ($word === 'M') {
8,072✔
48
                $hasM = true;
3,243✔
49
            } elseif ($word === 'ZM') {
4,878✔
50
                $hasZ = true;
3,131✔
51
                $hasM = true;
3,131✔
52
            } elseif ($word === 'EMPTY') {
1,761✔
53
                $isEmpty = true;
1,761✔
54
            } else {
UNCOV
55
                throw new GeometryIOException('Unexpected word in WKT: ' . $word);
×
56
            }
57

58
            if (! $isEmpty) {
11,502✔
59
                $word = $parser->getOptionalNextWord();
9,798✔
60

61
                if ($word === 'EMPTY') {
9,798✔
62
                    $isEmpty = true;
4,017✔
63
                } elseif ($word !== null) {
5,826✔
UNCOV
64
                    throw new GeometryIOException('Unexpected word in WKT: ' . $word);
×
65
                }
66
            }
67
        }
68

69
        $cs = new CoordinateSystem($hasZ, $hasM, $srid);
15,578✔
70

71
        switch ($geometryType) {
72
            case 'POINT':
15,578✔
73
                if ($isEmpty) {
2,548✔
74
                    return new Point($cs);
619✔
75
                }
76

77
                return $this->readPointText($parser, $cs);
1,953✔
78

79
            case 'LINESTRING':
13,810✔
80
                if ($isEmpty) {
3,008✔
81
                    return new LineString($cs);
576✔
82
                }
83

84
                return $this->readLineStringText($parser, $cs);
2,438✔
85

86
            case 'CIRCULARSTRING':
11,530✔
87
                if ($isEmpty) {
2,296✔
88
                    return new CircularString($cs);
468✔
89
                }
90

91
                return $this->readCircularStringText($parser, $cs);
1,828✔
92

93
            case 'COMPOUNDCURVE':
10,452✔
94
                if ($isEmpty) {
1,490✔
95
                    return new CompoundCurve($cs);
580✔
96
                }
97

98
                return $this->readCompoundCurveText($parser, $cs);
910✔
99

100
            case 'POLYGON':
9,172✔
101
                if ($isEmpty) {
1,875✔
102
                    return new Polygon($cs);
426✔
103
                }
104

105
                return $this->readPolygonText($parser, $cs);
1,449✔
106

107
            case 'CURVEPOLYGON':
7,430✔
108
                if ($isEmpty) {
1,113✔
109
                    return new CurvePolygon($cs);
462✔
110
                }
111

112
                return $this->readCurvePolygonText($parser, $cs);
651✔
113

114
            case 'MULTIPOINT':
6,317✔
115
                if ($isEmpty) {
939✔
116
                    return new MultiPoint($cs);
357✔
117
                }
118

119
                return $this->readMultiPointText($parser, $cs);
582✔
120

121
            case 'MULTILINESTRING':
5,378✔
122
                if ($isEmpty) {
1,050✔
123
                    return new MultiLineString($cs);
350✔
124
                }
125

126
                return $this->readMultiLineStringText($parser, $cs);
700✔
127

128
            case 'MULTIPOLYGON':
4,335✔
129
                if ($isEmpty) {
1,064✔
130
                    return new MultiPolygon($cs);
357✔
131
                }
132

133
                return $this->readMultiPolygonText($parser, $cs);
707✔
134

135
            case 'GEOMETRYCOLLECTION':
3,271✔
136
                if ($isEmpty) {
975✔
137
                    return new GeometryCollection($cs);
443✔
138
                }
139

140
                return $this->readGeometryCollectionText($parser, $cs);
532✔
141

142
            case 'POLYHEDRALSURFACE':
2,296✔
143
                if ($isEmpty) {
1,057✔
144
                    return new PolyhedralSurface($cs);
483✔
145
                }
146

147
                return $this->readPolyhedralSurfaceText($parser, $cs);
574✔
148

149
            case 'TIN':
1,239✔
150
                if ($isEmpty) {
637✔
151
                    return new TIN($cs);
322✔
152
                }
153

154
                return $this->readTINText($parser, $cs);
315✔
155

156
            case 'TRIANGLE':
637✔
157
                if ($isEmpty) {
637✔
158
                    return new Triangle($cs);
308✔
159
                }
160

161
            return $this->readTriangleText($parser, $cs);
329✔
162
        }
163

UNCOV
164
        throw new GeometryIOException('Unknown geometry type: ' . $geometryType);
×
165
    }
166

167
    /**
168
     * x y
169
     */
170
    private function readPoint(WKTParser $parser, CoordinateSystem $cs) : Point
171
    {
172
        $dim = $cs->coordinateDimension();
10,035✔
173
        $coords = [];
10,035✔
174

175
        for ($i = 0; $i < $dim; $i++) {
10,035✔
176
            $coords[] = $parser->getNextNumber();
10,035✔
177
        }
178

179
        return new Point($cs, ...$coords);
10,035✔
180
    }
181

182
    /**
183
     * (x y)
184
     */
185
    private function readPointText(WKTParser $parser, CoordinateSystem $cs) : Point
186
    {
187
        $parser->matchOpener();
1,953✔
188
        $point = $this->readPoint($parser, $cs);
1,953✔
189
        $parser->matchCloser();
1,953✔
190

191
        return $point;
1,953✔
192
    }
193

194
    /**
195
     * (x y, ...)
196
     *
197
     * @return Point[]
198
     */
199
    private function readMultiPoint(WKTParser $parser, CoordinateSystem $cs) : array
200
    {
201
        $parser->matchOpener();
8,698✔
202
        $points = [];
8,698✔
203

204
        do {
205
            $points[] = $this->readPoint($parser, $cs);
8,698✔
206
            $nextToken = $parser->getNextCloserOrComma();
8,698✔
207
        } while ($nextToken === ',');
8,698✔
208

209
        return $points;
8,698✔
210
    }
211

212
    /**
213
     * (x y, ...)
214
     */
215
    private function readLineStringText(WKTParser $parser, CoordinateSystem $cs) : LineString
216
    {
217
        $points = $this->readMultiPoint($parser, $cs);
7,527✔
218

219
        return new LineString($cs, ...$points);
7,527✔
220
    }
221

222
    /**
223
     * (x y, ...)
224
     */
225
    private function readCircularStringText(WKTParser $parser, CoordinateSystem $cs) : CircularString
226
    {
227
        $points = $this->readMultiPoint($parser, $cs);
1,828✔
228

229
        return new CircularString($cs, ...$points);
1,828✔
230
    }
231

232
    /**
233
     * @throws GeometryIOException
234
     */
235
    private function readCompoundCurveText(WKTParser $parser, CoordinateSystem $cs) : CompoundCurve
236
    {
237
        $parser->matchOpener();
910✔
238
        $curves = [];
910✔
239

240
        do {
241
            if ($parser->isNextOpenerOrWord()) {
910✔
242
                $curves[] = $this->readLineStringText($parser, $cs);
889✔
243
            } else {
244
                $curve = $this->readGeometry($parser, $cs->srid);
847✔
245

246
                if (! $curve instanceof LineString && ! $curve instanceof CircularString) {
840✔
UNCOV
247
                    throw new GeometryIOException('Expected LineString|CircularString, got ' . $curve->geometryType());
×
248
                }
249

250
                $curves[] = $curve;
840✔
251
            }
252

253
            $nextToken = $parser->getNextCloserOrComma();
896✔
254
        } while ($nextToken === ',');
896✔
255

256
        return new CompoundCurve($cs, ...$curves);
896✔
257
    }
258

259
    /**
260
     * (x y, ...)
261
     */
262
    private function readMultiPointText(WKTParser $parser, CoordinateSystem $cs) : MultiPoint
263
    {
264
        $points = $this->readMultiPoint($parser, $cs);
582✔
265

266
        return new MultiPoint($cs, ...$points);
582✔
267
    }
268

269
    /**
270
     * ((x y, ...), ...)
271
     *
272
     * @return LineString[]
273
     */
274
    private function readMultiLineString(WKTParser $parser, CoordinateSystem $cs) : array
275
    {
276
        $parser->matchOpener();
4,018✔
277
        $lineStrings = [];
4,018✔
278

279
        do {
280
            $lineStrings[] = $this->readLineStringText($parser, $cs);
4,018✔
281
            $nextToken = $parser->getNextCloserOrComma();
4,018✔
282
        } while ($nextToken === ',');
4,018✔
283

284
        return $lineStrings;
4,018✔
285
    }
286

287
    /**
288
     * ((x y, ...), ...)
289
     */
290
    private function readPolygonText(WKTParser $parser, CoordinateSystem $cs) : Polygon
291
    {
292
        $rings = $this->readMultiLineString($parser, $cs);
2,695✔
293

294
        return new Polygon($cs, ...$rings);
2,695✔
295
    }
296

297
    /**
298
     * @throws GeometryIOException
299
     */
300
    private function readCurvePolygonText(WKTParser $parser, CoordinateSystem $cs) : CurvePolygon
301
    {
302
        $parser->matchOpener();
651✔
303
        $curves = [];
651✔
304

305
        do {
306
            if ($parser->isNextOpenerOrWord()) {
651✔
307
                $curves[] = $this->readLineStringText($parser, $cs);
616✔
308
            } else {
309
                $curve = $this->readGeometry($parser, $cs->srid);
518✔
310

311
                if (! $curve instanceof Curve) {
518✔
UNCOV
312
                    throw new GeometryIOException('Expected Curve, got ' . $curve->geometryType());
×
313
                }
314

315
                $curves[] = $curve;
518✔
316
            }
317

318
            $nextToken = $parser->getNextCloserOrComma();
651✔
319
        } while ($nextToken === ',');
651✔
320

321
        return new CurvePolygon($cs, ...$curves);
651✔
322
    }
323

324
    /**
325
     * ((x y, ...), ...)
326
     */
327
    private function readTriangleText(WKTParser $parser, CoordinateSystem $cs) : Triangle
328
    {
329
        $rings = $this->readMultiLineString($parser, $cs);
623✔
330

331
        return new Triangle($cs, ...$rings);
623✔
332
    }
333

334
    /**
335
     * ((x y, ...), ...)
336
     */
337
    private function readMultiLineStringText(WKTParser $parser, CoordinateSystem $cs) : MultiLineString
338
    {
339
        $lineStrings = $this->readMultiLineString($parser, $cs);
700✔
340

341
        return new MultiLineString($cs, ...$lineStrings);
700✔
342
    }
343

344
    /**
345
     * (((x y, ...), ...), ...)
346
     */
347
    private function readMultiPolygonText(WKTParser $parser, CoordinateSystem $cs) : MultiPolygon
348
    {
349
        $parser->matchOpener();
707✔
350
        $polygons = [];
707✔
351

352
        do {
353
            $polygons[] = $this->readPolygonText($parser, $cs);
707✔
354
            $nextToken = $parser->getNextCloserOrComma();
707✔
355
        } while ($nextToken === ',');
707✔
356

357
        return new MultiPolygon($cs, ...$polygons);
707✔
358
    }
359

360
    private function readGeometryCollectionText(WKTParser $parser, CoordinateSystem $cs) : GeometryCollection
361
    {
362
        $parser->matchOpener();
532✔
363
        $geometries = [];
532✔
364

365
        do {
366
            $geometries[] = $this->readGeometry($parser, $cs->srid);
532✔
367
            $nextToken = $parser->getNextCloserOrComma();
532✔
368
        } while ($nextToken === ',');
532✔
369

370
        return new GeometryCollection($cs, ...$geometries);
532✔
371
    }
372

373
    private function readPolyhedralSurfaceText(WKTParser $parser, CoordinateSystem $cs) : PolyhedralSurface
374
    {
375
        $parser->matchOpener();
574✔
376
        $patches = [];
574✔
377

378
        do {
379
            $patches[] = $this->readPolygonText($parser, $cs);
574✔
380
            $nextToken = $parser->getNextCloserOrComma();
574✔
381
        } while ($nextToken === ',');
574✔
382

383
        return new PolyhedralSurface($cs, ...$patches);
574✔
384
    }
385

386
    private function readTINText(WKTParser $parser, CoordinateSystem $cs) : TIN
387
    {
388
        $parser->matchOpener();
315✔
389
        $patches = [];
315✔
390

391
        do {
392
            $patches[] = $this->readTriangleText($parser, $cs);
315✔
393
            $nextToken = $parser->getNextCloserOrComma();
315✔
394
        } while ($nextToken === ',');
315✔
395

396
        return new TIN($cs, ...$patches);
315✔
397
    }
398
}
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