• 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

66.67
/src/CurvePolygon.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\EmptyGeometryException;
11
use Brick\Geo\Exception\NoSuchGeometryException;
12
use Brick\Geo\Projector\Projector;
13
use Countable;
14
use IteratorAggregate;
15
use Override;
16

17
use function array_map;
18
use function array_reduce;
19
use function array_slice;
20
use function array_values;
21
use function count;
22

23
/**
24
 * A CurvePolygon is a planar Surface defined by 1 exterior boundary and 0 or more interior boundaries.
25
 *
26
 * A CurvePolygon instance differs from a Polygon instance in that a CurvePolygon instance may contain
27
 * the following circular arc segments: CircularString and CompoundCurve in addition to LineString.
28
 *
29
 * @implements IteratorAggregate<int<0, max>, Curve>
30
 *
31
 * @final
32
 */
33
class CurvePolygon extends Surface implements Countable, IteratorAggregate
34
{
35
    /**
36
     * The rings that compose this CurvePolygon.
37
     *
38
     * The first one represents the exterior ring, and the
39
     * (optional) other ones represent the interior rings (holes) of the CurvePolygon.
40
     *
41
     * An empty CurvePolygon contains no rings.
42
     *
43
     * @var list<Curve>
44
     */
45
    protected array $rings = [];
46

47
    /**
48
     * The coordinate system of each of the rings must match the one of the CurvePolygon.
49
     *
50
     * @param CoordinateSystem $cs       The coordinate system of the CurvePolygon.
51
     * @param Curve            ...$rings The rings that compose the CurvePolygon.
52
     *
53
     * @throws CoordinateSystemException If different coordinate systems are used.
54
     */
55
    public function __construct(CoordinateSystem $cs, Curve ...$rings)
56
    {
57
        parent::__construct($cs, ! $rings);
1,976✔
58

59
        if (! $rings) {
1,976✔
60
            return;
912✔
61
        }
62

63
        CoordinateSystem::check($this, ...$rings);
1,080✔
64

65
        $this->rings = array_values($rings);
1,080✔
66
    }
67

68
    /**
69
     * Creates a non-empty CurvePolygon composed of the given rings.
70
     *
71
     * @param Curve $exteriorRing     The exterior ring.
72
     * @param Curve ...$interiorRings The interior rings, if any.
73
     *
74
     * @throws CoordinateSystemException If the rings use different coordinate systems.
75
     */
76
    public static function of(Curve $exteriorRing, Curve ...$interiorRings): CurvePolygon
77
    {
78
        return new static($exteriorRing->coordinateSystem(), $exteriorRing, ...$interiorRings);
×
79
    }
80

81
    /**
82
     * Returns the exterior ring of this CurvePolygon.
83
     *
84
     * @throws EmptyGeometryException
85
     */
86
    public function exteriorRing(): Curve
87
    {
88
        if ($this->isEmpty) {
160✔
89
            throw new EmptyGeometryException('An empty CurvePolygon has no exterior ring.');
32✔
90
        }
91

92
        return $this->rings[0];
128✔
93
    }
94

95
    /**
96
     * Returns the number of interior rings in this CurvePolygon.
97
     */
98
    public function numInteriorRings(): int
99
    {
100
        if ($this->isEmpty) {
72✔
101
            return 0;
32✔
102
        }
103

104
        return count($this->rings) - 1;
40✔
105
    }
106

107
    /**
108
     * Returns the specified interior ring N in this CurvePolygon.
109
     *
110
     * @param int $n The ring number, 1-based.
111
     *
112
     * @throws NoSuchGeometryException If there is no interior ring at this index.
113
     */
114
    public function interiorRingN(int $n): Curve
115
    {
116
        if ($n === 0 || ! isset($this->rings[$n])) {
352✔
117
            throw new NoSuchGeometryException('There is no interior ring in this CurvePolygon at index ' . $n);
288✔
118
        }
119

120
        return $this->rings[$n];
64✔
121
    }
122

123
    /**
124
     * Returns the interior rings in this CurvePolygon.
125
     *
126
     * @return list<Curve>
127
     */
128
    public function interiorRings(): array
129
    {
130
        return array_slice($this->rings, 1);
80✔
131
    }
132

133
    #[NoProxy, Override]
134
    public function geometryType(): string
135
    {
136
        return 'CurvePolygon';
768✔
137
    }
138

139
    #[NoProxy, Override]
140
    public function geometryTypeBinary(): int
141
    {
142
        return Geometry::CURVEPOLYGON;
398✔
143
    }
144

145
    #[Override]
146
    public function getBoundingBox(): BoundingBox
147
    {
148
        return array_reduce(
×
149
            $this->rings,
×
150
            fn (BoundingBox $boundingBox, Curve $ring) => $boundingBox->extendedWithBoundingBox($ring->getBoundingBox()),
×
151
            BoundingBox::new(),
×
152
        );
×
153
    }
154

155
    #[Override]
156
    public function toArray(): array
157
    {
158
        return array_map(
256✔
159
            fn (Curve $ring) => $ring->toArray(),
256✔
160
            $this->rings,
256✔
161
        );
256✔
162
    }
163

164
    #[Override]
165
    public function project(Projector $projector): CurvePolygon
166
    {
167
        return new CurvePolygon(
×
168
            $projector->getTargetCoordinateSystem($this->coordinateSystem),
×
169
            ...array_map(
×
170
                fn (Curve $ring) => $ring->project($projector),
×
171
                $this->rings,
×
172
            ),
×
173
        );
×
174
    }
175

176
    /**
177
     * Returns the number of rings (exterior + interior) in this CurvePolygon.
178
     */
179
    #[Override]
180
    public function count(): int
181
    {
182
        return count($this->rings);
398✔
183
    }
184

185
    /**
186
     * Returns an iterator for the rings (exterior + interior) in this CurvePolygon.
187
     *
188
     * @return ArrayIterator<int<0, max>, Curve>
189
     */
190
    #[Override]
191
    public function getIterator(): ArrayIterator
192
    {
193
        return new ArrayIterator($this->rings);
846✔
194
    }
195

196
    /**
197
     * Returns a copy of this CurvePolygon, with the exterior ring replaced with the given one.
198
     */
199
    public function withExteriorRing(Curve $exteriorRing): CurvePolygon
200
    {
201
        return new CurvePolygon($this->coordinateSystem, $exteriorRing, ...$this->interiorRings());
32✔
202
    }
203

204
    /**
205
     * Returns a copy of this CurvePolygon, with the interior rings replaced with the given ones.
206
     */
207
    public function withInteriorRings(Curve ...$interiorRings): CurvePolygon
208
    {
209
        return new CurvePolygon($this->coordinateSystem, $this->exteriorRing(), ...$interiorRings);
48✔
210
    }
211

212
    /**
213
     * Returns a copy of this CurvePolygon, with the given interior rings added.
214
     */
215
    public function withAddedInteriorRings(Curve ...$interiorRings): CurvePolygon
216
    {
217
        return new CurvePolygon($this->coordinateSystem, $this->exteriorRing(), ...$this->interiorRings(), ...$interiorRings);
48✔
218
    }
219
}
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