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

brick / geo / 13753277563

09 Mar 2025 10:43PM UTC coverage: 49.787% (+2.5%) from 47.295%
13753277563

push

github

BenMorel
Prepare for release

1749 of 3513 relevant lines covered (49.79%)

975.53 hits per line

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

80.77
/src/GeometryCollection.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Geo;
6

7
use ArrayIterator;
8
use Brick\Geo\Attribute\NoProxy;
9
use Brick\Geo\Exception\CoordinateSystemException;
10
use Brick\Geo\Exception\NoSuchGeometryException;
11
use Brick\Geo\Exception\UnexpectedGeometryException;
12
use Brick\Geo\Projector\Projector;
13
use Override;
14

15
/**
16
 * A GeometryCollection is a geometric object that is a collection of some number of geometric objects.
17
 *
18
 * All the elements in a GeometryCollection shall be in the same Spatial Reference System. This is also the Spatial
19
 * Reference System for the GeometryCollection.
20
 *
21
 * GeometryCollection places no other constraints on its elements. Subclasses of GeometryCollection may restrict
22
 * membership based on dimension and may also place other constraints on the degree of spatial overlap between
23
 * elements.
24
 *
25
 * By the nature of digital representations, collections are inherently ordered by the underlying storage mechanism.
26
 * Two collections whose difference is only this order are spatially equal and will return equivalent results in any
27
 * geometric-defined operations.
28
 *
29
 * @template T of Geometry
30
 * @template-implements \IteratorAggregate<int<0, max>, T>
31
 */
32
class GeometryCollection extends Geometry implements \Countable, \IteratorAggregate
33
{
34
    /**
35
     * The geometries that compose this GeometryCollection.
36
     *
37
     * This array can be empty.
38
     *
39
     * @var list<T>
40
     */
41
    protected array $geometries = [];
42

43
    /**
44
     * @param T ...$geometries
45
     *
46
     * @throws CoordinateSystemException   If different coordinate systems are used.
47
     * @throws UnexpectedGeometryException If a geometry is not a valid type for a subclass of GeometryCollection.
48
     */
49
    public function __construct(CoordinateSystem $cs, Geometry ...$geometries)
50
    {
51
        $isEmpty = true;
7,561✔
52

53
        foreach ($geometries as $geometry) {
7,561✔
54
            if (! $geometry->isEmpty()) {
4,777✔
55
                $isEmpty = false;
4,700✔
56
                break;
4,700✔
57
            }
58
        }
59

60
        parent::__construct($cs, $isEmpty);
7,561✔
61

62
        if (! $geometries) {
7,561✔
63
            return;
2,833✔
64
        }
65

66
        CoordinateSystem::check($this, ...$geometries);
4,777✔
67

68
        $containedGeometryType = $this->containedGeometryType();
4,777✔
69

70
        foreach ($geometries as $geometry) {
4,777✔
71
            /**
72
             * @psalm-suppress DocblockTypeContradiction We do want to enforce this in code, as not everyone uses static analysis!
73
             * @psalm-suppress MixedArgument It looks like due to this check, Psalm considers that $geometry no longer has a type.
74
             */
75
            if (! $geometry instanceof $containedGeometryType) {
4,777✔
76
                throw new UnexpectedGeometryException(sprintf(
×
77
                    '%s expects instance of %s, instance of %s given.',
×
78
                    static::class,
×
79
                    $containedGeometryType,
×
80
                    $geometry::class
×
81
                ));
×
82
            }
83
        }
84

85
        $this->geometries = array_values($geometries);
4,777✔
86
    }
87

88
    /**
89
     * Creates a non-empty GeometryCollection composed of the given geometries.
90
     *
91
     * @psalm-suppress UnsafeInstantiation
92
     *
93
     * @param Geometry    $geometry1 The first geometry.
94
     * @param Geometry ...$geometryN The subsequent geometries, if any.
95
     *
96
     * @return static
97
     *
98
     * @throws CoordinateSystemException   If the geometries use different coordinate systems.
99
     * @throws UnexpectedGeometryException If a geometry is not a valid type for a subclass of GeometryCollection.
100
     */
101
    public static function of(Geometry $geometry1, Geometry ...$geometryN) : GeometryCollection
102
    {
103
        return new static($geometry1->coordinateSystem(), $geometry1, ...$geometryN);
220✔
104
    }
105

106
    /**
107
     * Returns the number of geometries in this GeometryCollection.
108
     */
109
    public function numGeometries() : int
110
    {
111
        return count($this->geometries);
3,332✔
112
    }
113

114
    /**
115
     * Returns the specified geometry N in this GeometryCollection.
116
     *
117
     * @param int $n The geometry number, 1-based.
118
     *
119
     * @return T
120
     *
121
     * @throws NoSuchGeometryException If there is no Geometry at this index.
122
     */
123
    public function geometryN(int $n) : Geometry
124
    {
125
        if (! isset($this->geometries[$n - 1])) {
126✔
126
            throw new NoSuchGeometryException('There is no Geometry in this GeometryCollection at index ' . $n);
84✔
127
        }
128

129
        return $this->geometries[$n - 1];
42✔
130
    }
131

132
    /**
133
     * Returns the geometries that compose this GeometryCollection.
134
     *
135
     * @return list<T>
136
     */
137
    public function geometries() : array
138
    {
139
        return $this->geometries;
84✔
140
    }
141

142
    #[NoProxy, Override]
143
    public function geometryType() : string
144
    {
145
        return 'GeometryCollection';
841✔
146
    }
147

148
    #[NoProxy, Override]
149
    public function geometryTypeBinary() : int
150
    {
151
        return Geometry::GEOMETRYCOLLECTION;
336✔
152
    }
153

154
    #[Override]
155
    public function dimension() : int
156
    {
157
        $dimension = 0;
56✔
158

159
        foreach ($this->geometries as $geometry) {
56✔
160
            $dim = $geometry->dimension();
28✔
161

162
            if ($dim > $dimension) {
28✔
163
                $dimension = $dim;
21✔
164
            }
165
        }
166

167
        return $dimension;
56✔
168
    }
169

170
    #[Override]
171
    public function getBoundingBox() : BoundingBox
172
    {
173
        $boundingBox = BoundingBox::new();
×
174

175
        foreach ($this->geometries as $geometry) {
×
176
            $boundingBox = $boundingBox->extendedWithBoundingBox($geometry->getBoundingBox());
×
177
        }
178

179
        return $boundingBox;
×
180
    }
181

182
    #[Override]
183
    public function toArray() : array
184
    {
185
        return array_map(
350✔
186
            fn (Geometry $geometry) => $geometry->toArray(),
350✔
187
            $this->geometries,
350✔
188
        );
350✔
189
    }
190

191
    #[Override]
192
    public function project(Projector $projector): GeometryCollection
193
    {
194
        return new GeometryCollection(
28✔
195
            $projector->getTargetCoordinateSystem($this->coordinateSystem),
28✔
196
            ...array_map(
28✔
197
                fn (Geometry $geometry) => $geometry->project($projector),
28✔
198
                $this->geometries,
28✔
199
            ),
28✔
200
        );
28✔
201
    }
202

203
    /**
204
     * Returns the number of geometries in this GeometryCollection.
205
     */
206
    #[Override]
207
    public function count() : int
208
    {
209
        return count($this->geometries);
2,071✔
210
    }
211

212
    /**
213
     * Returns an iterator for the geometries in this GeometryCollection.
214
     *
215
     * @return ArrayIterator<int<0, max>, T>
216
     */
217
    #[Override]
218
    public function getIterator() : ArrayIterator
219
    {
220
        return new ArrayIterator($this->geometries);
4,182✔
221
    }
222

223
    /**
224
     * Returns the FQCN of the contained Geometry type.
225
     *
226
     * @return class-string<T>
227
     */
228
    protected function containedGeometryType() : string
229
    {
230
        return Geometry::class;
1,047✔
231
    }
232

233
    /**
234
     * Returns a copy of this GeometryCollection, with the given geometries added.
235
     *
236
     * @psalm-suppress UnsafeInstantiation
237
     *
238
     * @param T ...$geometries
239
     *
240
     * @return GeometryCollection<T>
241
     */
242
    public function withAddedGeometries(Geometry ...$geometries): GeometryCollection
243
    {
244
        return new static($this->coordinateSystem, ...$this->geometries, ...$geometries);
147✔
245
    }
246
}
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