• 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

70.21
/src/CompoundCurve.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\InvalidGeometryException;
12
use Brick\Geo\Exception\NoSuchGeometryException;
13
use Brick\Geo\Projector\Projector;
14
use Countable;
15
use IteratorAggregate;
16
use Override;
17

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

23
/**
24
 * A CompoundCurve is a collection of zero or more continuous CircularString or LineString instances.
25
 *
26
 * @implements IteratorAggregate<int<0, max>, LineString|CircularString>
27
 *
28
 * @final
29
 */
30
class CompoundCurve extends Curve implements Countable, IteratorAggregate
31
{
32
    /**
33
     * The Curves that compose this CompoundCurve.
34
     *
35
     * This array can be empty.
36
     *
37
     * @var list<LineString|CircularString>
38
     */
39
    protected array $curves = [];
40

41
    /**
42
     * The coordinate system of each of the curves must match the one of the CompoundCurve.
43
     *
44
     * @param CoordinateSystem          $cs        The coordinate system of the CompoundCurve.
45
     * @param LineString|CircularString ...$curves The curves that compose the CompoundCurve.
46
     *
47
     * @throws EmptyGeometryException    If any of the input curves is empty.
48
     * @throws InvalidGeometryException  If the compound curve is not continuous.
49
     * @throws CoordinateSystemException If different coordinate systems are used.
50
     */
51
    public function __construct(CoordinateSystem $cs, LineString|CircularString ...$curves)
52
    {
53
        parent::__construct($cs, ! $curves);
2,568✔
54

55
        if (! $curves) {
2,568✔
56
            return;
984✔
57
        }
58

59
        CoordinateSystem::check($this, ...$curves);
1,600✔
60

61
        $previousCurve = null;
1,600✔
62

63
        foreach ($curves as $curve) {
1,600✔
64
            if ($previousCurve) {
1,600✔
65
                $endPoint = $previousCurve->endPoint();
1,488✔
66
                $startPoint = $curve->startPoint();
1,488✔
67

68
                if ($endPoint != $startPoint) { // on purpose by-value comparison!
1,488✔
69
                    throw new InvalidGeometryException('Incontinuous compound curve.');
8✔
70
                }
71
            }
72

73
            $previousCurve = $curve;
1,600✔
74
        }
75

76
        $this->curves = array_values($curves);
1,592✔
77
    }
78

79
    /**
80
     * Creates a non-empty CompoundCurve composed of the given curves.
81
     *
82
     * @param LineString|CircularString $curve1    The first curve.
83
     * @param LineString|CircularString ...$curveN The subsequent curves, if any.
84
     *
85
     * @throws EmptyGeometryException    If any of the input curves is empty.
86
     * @throws InvalidGeometryException  If the compound curve is not continuous.
87
     * @throws CoordinateSystemException If the curves use different coordinate systems.
88
     */
89
    public static function of(LineString|CircularString $curve1, LineString|CircularString ...$curveN): CompoundCurve
90
    {
91
        return new CompoundCurve($curve1->coordinateSystem(), $curve1, ...$curveN);
×
92
    }
93

94
    #[Override]
95
    public function startPoint(): Point
96
    {
97
        if (count($this->curves) === 0) {
128✔
98
            throw new EmptyGeometryException('The CompoundCurve is empty and has no start point.');
64✔
99
        }
100

101
        return $this->curves[0]->startPoint();
64✔
102
    }
103

104
    #[Override]
105
    public function endPoint(): Point
106
    {
107
        $count = count($this->curves);
128✔
108

109
        if ($count === 0) {
128✔
110
            throw new EmptyGeometryException('The CompoundCurve is empty and has no end point.');
64✔
111
        }
112

113
        return $this->curves[$count - 1]->endPoint();
64✔
114
    }
115

116
    /**
117
     * Returns the number of Curves in this CompoundCurve.
118
     */
119
    public function numCurves(): int
120
    {
121
        return count($this->curves);
64✔
122
    }
123

124
    /**
125
     * Returns the specified Curve N in this CompoundCurve.
126
     *
127
     * @param int $n The curve number, 1-based.
128
     *
129
     * @throws NoSuchGeometryException If there is no Curve at this index.
130
     */
131
    public function curveN(int $n): LineString|CircularString
132
    {
133
        if (! isset($this->curves[$n - 1])) {
376✔
134
            throw new NoSuchGeometryException('There is no Curve in this CompoundCurve at index ' . $n);
256✔
135
        }
136

137
        return $this->curves[$n - 1];
120✔
138
    }
139

140
    /**
141
     * Returns the curves that compose this CompoundCurve.
142
     *
143
     * @return list<LineString|CircularString>
144
     */
145
    public function curves(): array
146
    {
147
        return $this->curves;
×
148
    }
149

150
    #[NoProxy, Override]
151
    public function geometryType(): string
152
    {
153
        return 'CompoundCurve';
1,020✔
154
    }
155

156
    #[NoProxy, Override]
157
    public function geometryTypeBinary(): int
158
    {
159
        return Geometry::COMPOUNDCURVE;
508✔
160
    }
161

162
    #[Override]
163
    public function getBoundingBox(): BoundingBox
164
    {
165
        return array_reduce(
×
166
            $this->curves,
×
167
            fn (BoundingBox $boundingBox, Curve $curve) => $boundingBox->extendedWithBoundingBox($curve->getBoundingBox()),
×
168
            BoundingBox::new(),
×
169
        );
×
170
    }
171

172
    /**
173
     * @return list<list<list<float>>>
174
     */
175
    #[Override]
176
    public function toArray(): array
177
    {
178
        return array_map(
288✔
179
            fn (Curve $curve) => $curve->toArray(),
288✔
180
            $this->curves,
288✔
181
        );
288✔
182
    }
183

184
    #[Override]
185
    public function project(Projector $projector): CompoundCurve
186
    {
187
        return new CompoundCurve(
×
188
            $projector->getTargetCoordinateSystem($this->coordinateSystem),
×
189
            ...array_map(
×
190
                fn (Curve $curve) => $curve->project($projector),
×
191
                $this->curves,
×
192
            ),
×
193
        );
×
194
    }
195

196
    /**
197
     * Returns the number of curves in this CompoundCurve.
198
     */
199
    #[Override]
200
    public function count(): int
201
    {
202
        return count($this->curves);
516✔
203
    }
204

205
    /**
206
     * Returns an iterator for the curves in this CompoundCurve.
207
     *
208
     * @return ArrayIterator<int<0, max>, LineString|CircularString>
209
     */
210
    #[Override]
211
    public function getIterator(): ArrayIterator
212
    {
213
        return new ArrayIterator($this->curves);
1,182✔
214
    }
215

216
    /**
217
     * Returns a copy of this CompoundCurve, with the given curves added.
218
     */
219
    public function withAddedCurves(LineString|CircularString ...$curves): CompoundCurve
220
    {
221
        return new CompoundCurve($this->coordinateSystem, ...$this->curves, ...$curves);
64✔
222
    }
223
}
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