├── .gitignore
├── phpstan.neon
├── cs-fixer.sh
├── phpstan.sh
├── docker-compose.yaml
├── phpunit.xml
├── src
├── exceptions
│ ├── SettingPointException.php
│ ├── NotEnoughPointsException.php
│ └── FirstAndLastPointNotEqualException.php
├── Line.php
├── Point.php
└── Polygon.php
├── .php-cs-fixer.dist.php
├── composer.json
├── Dockerfile
├── LICENSE
├── CONTRIBUTING.md
├── README.md
├── tests
├── LineTest.php
├── PointTest.php
└── PolygonTest.php
└── composer.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | .idea
3 | .phpunit.result.cache
4 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 9
3 | paths:
4 | - src
5 | - tests
6 | phpVersion: 80000
--------------------------------------------------------------------------------
/cs-fixer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sudo docker run --rm --name geophp8-cs-fixer -v $(pwd):/data ghcr.io/php-cs-fixer/php-cs-fixer:3-php8.1 fix /data
--------------------------------------------------------------------------------
/phpstan.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | exec sudo docker run --rm -v "$(pwd)":/app ghcr.io/phpstan/phpstan:latest-php8.3 analyse --configuration=/app/phpstan.neon
3 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '3.1'
2 |
3 | services:
4 | geophp:
5 | build:
6 | context: .
7 | image: custom-php
8 | volumes:
9 | - ./:/home/devuser/geophp/
10 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./tests/
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/exceptions/SettingPointException.php:
--------------------------------------------------------------------------------
1 | in(__DIR__."/src")
5 | ->in(__DIR__."/tests");
6 |
7 | return (new PhpCsFixer\Config())
8 | ->setRules([
9 | '@PHP81Migration' => true,
10 | '@PhpCsFixer' => true,
11 | 'array_syntax' => [
12 | 'syntax' => 'short',
13 | ],
14 | ])
15 | ->setFinder($finder);
16 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "loveyu/geophp8",
3 | "description": "A little geo spatial library for PHP based on Geo Rust and Turf.js",
4 | "type": "library",
5 | "license": "MIT",
6 | "version": "2.0.0",
7 | "authors": [
8 | {
9 | "name": "JWare",
10 | "email": "jware.organization@gmail.com"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=8.1"
15 | },
16 | "autoload": {
17 | "psr-4": {
18 | "JWare\\GeoPHP\\": "src/",
19 | "JWare\\GeoPHP\\Exceptions\\": "src/exceptions/"
20 | }
21 | },
22 | "require-dev": {
23 | "phpunit/phpunit": "^10.5.39"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.1-bookworm
2 |
3 | # Installs dependences
4 | RUN apt update \
5 | && apt install -y git
6 |
7 | # Create non root user
8 | RUN useradd -ms /bin/bash devuser
9 |
10 | USER devuser
11 | WORKDIR /home/devuser
12 |
13 | # Installs Composer
14 | RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
15 | && php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
16 | && php composer-setup.php \
17 | && php -r "unlink('composer-setup.php');"
18 |
19 | # Allows to run 'source' command
20 | SHELL ["/bin/bash", "-c"]
21 |
22 | # Adds composer to .bashrc
23 | RUN echo 'export PATH=$PATH:/home/devuser/' >> ~/.bashrc \
24 | && echo 'alias composer="composer.phar" ' >> ~/.bashrc \
25 | && source ~/.bashrc \
26 | && chown -R devuser ~/.composer/
27 |
28 | # Is positioned in the main folder
29 | WORKDIR /home/devuser/geophp
30 |
31 | CMD [ "bash" ]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 JWare Solutions
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contibuting
2 |
3 | It's nice to have people like you interested in this project. In this document we specify all the things to be considered for developing in this library.
4 |
5 | ## Preparing the environment
6 |
7 | ### With Docker
8 |
9 | You have available a **Docker Compose** file with a custom image with all installed if It's of your preference. Just run inside the project's root folder:
10 |
11 | `docker-compose run geophp`
12 |
13 | The image specified in `Dockerfile` file will be compiled and run.
14 |
15 | ### Without Docker
16 |
17 | You need the following tools installed:
18 |
19 | - PHP 8.x
20 | - [Composer](https://getcomposer.org/)
21 |
22 |
23 | ## Developing
24 |
25 | All the code and test are at `src` and `test` folders respectively.
26 |
27 | There is no standard convention about code and comments, but It would really appreciate that you respect the convention used until now, specifying docs for all the methods indicating types and description for their parameters and returned values.
28 |
29 | All the public method (except some getters and setters) are covered with unit test. Once you have added some code and want to run the tests you can execute [PHPUnit](https://phpunit.de/) with the following command:
30 |
31 | `./vendor/bin/phpunit`
32 |
33 | To check that all is OK.
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GeoPHP
2 |
3 | GeoPHP is a library of geospatial functions based on GeoRust and Turf.js.
4 |
5 | ## Installation
6 |
7 | Install the library running:
8 |
9 | `composer require loveyu/geophp8`
10 |
11 | ## Usage
12 |
13 | ```
14 | use \JWare\GeoPHP\Polygon;
15 | use \JWare\GeoPHP\Point;
16 |
17 | $polygon = new Polygon([
18 | new Point(1, -1),
19 | new Point(2, 1),
20 | new Point(3, -1),
21 | new Point(2, -2),
22 | new Point(1, -1)
23 | ]);
24 |
25 | $point = new Point(-1, 2);
26 | $point2 = new Point(2, 2);
27 |
28 | $polygon->containsPoint($point); // False
29 | $polygon->containsPoint($point2); // True
30 | ```
31 |
32 | Please read the [documentation][documentation_site] to see the full method list available.
33 |
34 | ## Why another Geospatial library?
35 |
36 | GeoPHP was born due to the lack of a modern geospatial library for PHP. The tools available today are not published in the Composer repositories and are not easy to use (some requires DB drivers or constructs the Geometries from complex Strings). GeoPHP offers:
37 |
38 | - 🚀 Modern and fast: made in PHP 7 with fast algorithms
39 | - 🥳 Friendly and simple interface: implemented with the Object Oriented Paradigm, allows its easy and fast use by the developer.
40 | - 👨🏼💻 Easy access: the library is published in Composer for quick import into your projects.
41 | - 🛠 Tested: all methods are covered by unit tests.
42 | - 🌟 A lot of examples!
43 |
44 | ## Contributing
45 |
46 | First of all, thanks for consider contributing to the project! Please, read [CONTRIBUTING.md](/CONTRIBUTING.md) for more.
47 |
48 | [documentation_site]: https://jware-solutions.github.io/geophp-documentation/ "Full documentation"
--------------------------------------------------------------------------------
/tests/LineTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf('\JWare\GeoPHP\Line', new Line(
18 | new Point(0, 0),
19 | new Point(1, 1)
20 | ));
21 | }
22 |
23 | /**
24 | * Tests clone method.
25 | */
26 | public function testClone(): void
27 | {
28 | $line = new Line(
29 | new Point(0, 0),
30 | new Point(1, 1)
31 | );
32 | $clone = $line->clone();
33 | $this->assertEquals($clone->getPoints(), $line->getPoints());
34 | }
35 |
36 | /**
37 | * Tests the determinant of the line.
38 | */
39 | public function testDeterminant(): void
40 | {
41 | $line1 = new Line(
42 | new Point(1.34, 2.87),
43 | new Point(3.23, 4.5)
44 | );
45 |
46 | $line2 = new Line(
47 | new Point(3.23, 4.5),
48 | new Point(1.34, 2.87)
49 | );
50 |
51 | $this->assertEquals('-3.2401', (string) $line1->determinant());
52 |
53 | // NOTE: Line(a, b).determinant() == -Line(b, a).determinant()
54 | $this->assertEquals($line1->determinant(), -$line2->determinant());
55 | }
56 |
57 | /**
58 | * Tests the difference in 'x' components (Δx).
59 | */
60 | public function testDx(): void
61 | {
62 | $line1 = new Line(
63 | new Point(2.77, 4.23),
64 | new Point(2.77, 7.23)
65 | );
66 |
67 | $line2 = new Line(
68 | new Point(2.77, 4.23),
69 | new Point(3.77, 7.23)
70 | );
71 |
72 | $this->assertEquals(0, $line1->dx());
73 |
74 | $this->assertEquals(1, $line2->dx());
75 | }
76 |
77 | /**
78 | * Tests the difference in 'y' components (Δy).
79 | */
80 | public function testDy(): void
81 | {
82 | $line1 = new Line(
83 | new Point(2.77, 4.23),
84 | new Point(2.77, 7.23)
85 | );
86 |
87 | $line2 = new Line(
88 | new Point(2.77, 14.32),
89 | new Point(3.77, 9.55)
90 | );
91 |
92 | $this->assertEquals(3, $line1->dy());
93 |
94 | $this->assertEquals(-4.77, $line2->dy());
95 | }
96 |
97 | /**
98 | * Tests the slope of a line.
99 | */
100 | public function testSlope(): void
101 | {
102 | $line1 = new Line(
103 | new Point(2.87, 4.23),
104 | new Point(2.77, 7)
105 | );
106 |
107 | $line2 = new Line(
108 | new Point(3.45, 11.3),
109 | new Point(0.87, 34.243)
110 | );
111 |
112 | $line3 = new Line(
113 | new Point(0.87, 34.243),
114 | new Point(3.45, 11.3)
115 | );
116 |
117 | $line4 = new Line(
118 | new Point(2, 34),
119 | new Point(2, 11)
120 | );
121 |
122 | $this->assertEquals('-27.7', (string) $line1->slope());
123 | $this->assertEquals('-8.8926356589147', (string) $line2->slope());
124 |
125 | // NOTE: Line(a, b).slope() == Line(b, a).slope()
126 | $this->assertEquals($line2->slope(), $line3->slope());
127 | $this->assertEquals(INF, $line4->slope());
128 | }
129 |
130 | /**
131 | * Test intersection method.
132 | */
133 | public function testIntersects(): void
134 | {
135 | // Lines
136 | $line1 = new Line(
137 | new Point(1, 1),
138 | new Point(5, 5)
139 | );
140 |
141 | $line2 = new Line(
142 | new Point(3, 3),
143 | new Point(5, 1)
144 | );
145 |
146 | $line3 = new Line(
147 | new Point(-1, 1),
148 | new Point(-5, -10)
149 | );
150 |
151 | // Points
152 | $point1 = new Point(3, 3);
153 | $point2 = new Point(-1, 1);
154 | $point3 = new Point(-5, -10);
155 |
156 | // Polygons
157 | $polygon1 = new Polygon([
158 | new Point(2, 4),
159 | new Point(4, 4),
160 | new Point(4, 2),
161 | new Point(3, 1),
162 | new Point(2.5, 3),
163 | new Point(2, 4),
164 | ]);
165 |
166 | $polygon2 = new Polygon([
167 | new Point(-3, -4),
168 | new Point(-1, -5),
169 | new Point(-2, -6),
170 | new Point(-3, -4),
171 | ]);
172 |
173 | // With Point
174 | $this->assertTrue($line1->intersectsPoint($point1));
175 | $this->assertTrue($line2->intersectsPoint($point1));
176 | $this->assertFalse($line3->intersectsPoint($point1));
177 | $this->assertTrue($line3->intersectsPoint($point2));
178 | $this->assertTrue($line3->intersectsPoint($point3));
179 |
180 | // With Line
181 | $this->assertTrue($line1->intersectsLine($line2));
182 | $this->assertTrue($line2->intersectsLine($line1));
183 | $this->assertTrue($line1->intersectsLine($line1));
184 | $this->assertFalse($line1->intersectsLine($line3));
185 | $this->assertFalse($line2->intersectsLine($line3));
186 | $this->assertFalse($line3->intersectsLine($line2));
187 |
188 | // With Polygon
189 | $this->assertTrue($line1->intersectsPolygon($polygon1));
190 | $this->assertTrue($line2->intersectsPolygon($polygon1));
191 | $this->assertTrue($line3->intersectsPolygon($polygon2));
192 | $this->assertFalse($line1->intersectsPolygon($polygon2));
193 | $this->assertFalse($line2->intersectsPolygon($polygon2));
194 | $this->assertFalse($line3->intersectsPolygon($polygon1));
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/Line.php:
--------------------------------------------------------------------------------
1 | start = $start;
16 | $this->end = $end;
17 | }
18 |
19 | /**
20 | * Clone method.
21 | *
22 | * @return Line New instance
23 | */
24 | public function clone(): Line
25 | {
26 | return new Line($this->start, $this->end);
27 | }
28 |
29 | /**
30 | * Getter of the starting point of the line.
31 | *
32 | * @return Point starting point of the line
33 | */
34 | public function getStart(): Point
35 | {
36 | return $this->start;
37 | }
38 |
39 | /**
40 | * Setter of the starting point of the line.
41 | *
42 | * @param Point $start starting point of the line
43 | *
44 | * @return Line Current instance
45 | */
46 | public function setStart(Point $start): Line
47 | {
48 | $this->start = $start;
49 |
50 | return $this;
51 | }
52 |
53 | /**
54 | * Getter of the ending point of the line.
55 | *
56 | * @return Point ending point of the line
57 | */
58 | public function getEnd(): Point
59 | {
60 | return $this->end;
61 | }
62 |
63 | /**
64 | * Setter of the ending point of the line.
65 | *
66 | * @param Point $end ending point of the line
67 | *
68 | * @return Line Instance
69 | */
70 | public function setEnd(Point $end): Line
71 | {
72 | $this->end = $end;
73 |
74 | return $this;
75 | }
76 |
77 | /**
78 | * Computes the determinant of the line:
79 | * line.start.x * line.end.y - line.start.y * line.end.x.
80 | *
81 | * @return float The determinant of the line
82 | */
83 | public function determinant(): float
84 | {
85 | return $this->start->getX() * $this->end->getY() - $this->start->getY() * $this->end->getX();
86 | }
87 |
88 | /**
89 | * Computes the difference in 'x' components (Δx):
90 | * line.end.x - line.start.x.
91 | *
92 | * @return float The difference in 'x' components (Δx)
93 | */
94 | public function dx(): float
95 | {
96 | return $this->end->getX() - $this->start->getX();
97 | }
98 |
99 | /**
100 | * Computes the difference in 'y' components (Δy):
101 | * line.end.y - line.start.y.
102 | *
103 | * @return float The difference in 'y' components (Δy)
104 | */
105 | public function dy(): float
106 | {
107 | return $this->end->getY() - $this->start->getY();
108 | }
109 |
110 | /**
111 | * Computes the slope of a line:
112 | * line.dy() / line.dx().
113 | *
114 | * @return float The slope of a line
115 | */
116 | public function slope(): float
117 | {
118 | $dx = $this->dx();
119 |
120 | return (0 != $dx) ? $this->dy() / $dx : INF;
121 | }
122 |
123 | /**
124 | * Getter for starting and ending points.
125 | *
126 | * @return Point[] Array with the starting point (0) and the ending point (1)
127 | */
128 | public function getPoints(): array
129 | {
130 | return [$this->start, $this->end];
131 | }
132 |
133 | /**
134 | * Checks whether the line intersects a point.
135 | *
136 | * @param Point $point Point to check
137 | *
138 | * @return bool True if the line intersects with the point, false otherwise
139 | */
140 | public function intersectsPoint(Point $point): bool
141 | {
142 | $dx = $this->dx();
143 | $tx = (0 != $dx) ? ($point->getX() - $this->start->getX()) / $this->dx() : null;
144 |
145 | $dy = $this->dy();
146 | $ty = (0 != $dy) ? ($point->getY() - $this->start->getY()) / $this->dy() : null;
147 |
148 | $txIsNull = is_null($tx);
149 | $tyIsNull = is_null($ty);
150 |
151 | // If I don't have $tx nor $ty
152 | if ($txIsNull && $tyIsNull) {
153 | return $point->isEqual($this->start);
154 | }
155 |
156 | // If I have $tx
157 | if (!$txIsNull && $tyIsNull) {
158 | return $point->getY() == $this->start->getY() && 0 <= $tx && $tx <= 1;
159 | }
160 |
161 | // If I have $ty
162 | if ($txIsNull && !$tyIsNull) {
163 | return $point->getX() == $this->start->getX() && 0 <= $ty && $ty <= 1;
164 | }
165 |
166 | // If I have $tx and $ty...
167 | return abs($tx - $ty) <= 0.000001 && 0 <= $tx && $tx <= 1;
168 | }
169 |
170 | /**
171 | * Checks whether the line intersects another line.
172 | *
173 | * @param Line $line Line to check
174 | *
175 | * @return bool True if the line intersects with the point, false otherwise
176 | */
177 | public function intersectsLine(Line $line): bool
178 | {
179 | // Using Cramer's Rule:
180 | // https://en.wikipedia.org/wiki/Intersection_%28Euclidean_geometry%29#Two_line_segments
181 | $a1 = $this->dx();
182 | $a2 = $this->dy();
183 | $b1 = -$line->dx();
184 | $b2 = -$line->dy();
185 | $c1 = $line->start->getX() - $this->start->getX();
186 | $c2 = $line->start->getY() - $this->start->getY();
187 |
188 | $d = $a1 * $b2 - $a2 * $b1;
189 | if (!$d) {
190 | $thisPoints = $this->getPoints();
191 | $selfStartPoint = $thisPoints[0];
192 | $selfEndPoint = $thisPoints[1];
193 | $otherPoints = $line->getPoints();
194 | $otherStartPoint = $otherPoints[0];
195 | $otherEndPoint = $otherPoints[1];
196 |
197 | // Lines are parallel
198 | // Return true if at least one end point intersects the other line
199 | return $selfStartPoint->intersectsLine($line)
200 | || $selfEndPoint->intersectsLine($line)
201 | || $otherStartPoint->intersectsLine($this)
202 | || $otherEndPoint->intersectsLine($this);
203 | }
204 |
205 | $s = ($c1 * $b2 - $c2 * $b1) / $d;
206 | $t = ($a1 * $c2 - $a2 * $c1) / $d;
207 |
208 | return (0 <= $s) && ($s <= 1) && (0 <= $t) && ($t <= 1);
209 | }
210 |
211 | /**
212 | * Checks whether the line intersects a polygon.
213 | *
214 | * @param Polygon $polygon Polygon to check
215 | *
216 | * @return bool True if the line intersects with the polygon, false otherwise
217 | */
218 | public function intersectsPolygon(Polygon $polygon): bool
219 | {
220 | return $polygon->intersectsLine($this);
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/tests/PointTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf('\JWare\GeoPHP\Point', new Point(0, 0));
18 | }
19 |
20 | /**
21 | * Tests clone method.
22 | */
23 | public function testClone(): void
24 | {
25 | $point = new Point(3, 4);
26 | $clone = $point->clone();
27 | $this->assertEquals($clone->getXAndY(), $point->getXandY());
28 | }
29 |
30 | /**
31 | * Tests X and Y getter.
32 | */
33 | public function testGetXandY(): void
34 | {
35 | $point = new Point(3, 4);
36 | $this->assertEquals([3, 4], $point->getXandY());
37 | }
38 |
39 | /**
40 | * Tests whether two points are the same.
41 | */
42 | public function testIsEqual(): void
43 | {
44 | $point1 = new Point(1, 2);
45 | $point2 = new Point(1, 2);
46 | $point3 = new Point(3, 23.3);
47 |
48 | $this->assertTrue($point1->isEqual($point1));
49 | $this->assertTrue($point1->isEqual($point2));
50 | $this->assertTrue($point2->isEqual($point1));
51 | $this->assertFalse($point2->isEqual($point3));
52 | }
53 |
54 | /**
55 | * Test magnitude computation.
56 | */
57 | public function testGetMagnitude(): void
58 | {
59 | $magnitude1 = (new Point(0, 0))->getMagnitude();
60 | $this->assertEquals(0, $magnitude1);
61 | $magnitude2 = (new Point(1, 2))->getMagnitude();
62 | $this->assertEquals(2.236067977, round($magnitude2, $precision = 9));
63 | }
64 |
65 | /**
66 | * Test conversion from radians to degrees.
67 | */
68 | public function fromRadiansToDegrees(): void
69 | {
70 | $point1 = new Point(1, 0);
71 | $point2 = new Point(2, 3);
72 | $point1Converted = $point1->fromRadiansToDegrees();
73 | $point2Converted = $point2->fromRadiansToDegrees();
74 |
75 | // Converted instances are also Points
76 | $this->assertInstanceOf('\JWare\GeoPHP\Point', $point1Converted);
77 | $this->assertInstanceOf('\JWare\GeoPHP\Point', $point2Converted);
78 |
79 | // Checks converted values
80 | $this->assertEquals(57.29578, $point1Converted->getX());
81 | $this->assertEquals(0, $point1Converted->getY());
82 | $this->assertEquals(114.5916, $point2Converted->getX());
83 | $this->assertEquals(171.8873, $point2Converted->getY());
84 | }
85 |
86 | /**
87 | * Test conversion from degrees to radians.
88 | */
89 | public function fromDegreesToRadians(): void
90 | {
91 | $point1 = new Point(57.29578, 0);
92 | $point2 = new Point(114.5916, 171.8873);
93 | $point1Converted = $point1->fromDegreesToRadians();
94 | $point2Converted = $point2->fromDegreesToRadians();
95 |
96 | // Converted instances are also Points
97 | $this->assertInstanceOf('\JWare\GeoPHP\Point', $point1Converted);
98 | $this->assertInstanceOf('\JWare\GeoPHP\Point', $point2Converted);
99 |
100 | // Checks converted values
101 | $this->assertEquals(1, $point1Converted->getX());
102 | $this->assertEquals(0, $point1Converted->getY());
103 | $this->assertEquals(2, $point2Converted->getX());
104 | $this->assertEquals(3, $point2Converted->getY());
105 | }
106 |
107 | /**
108 | * Tests getting the angle between two points.
109 | */
110 | public function testGetAngle(): void
111 | {
112 | $point1 = new Point(2, 0);
113 | $point2 = new Point(2, 2);
114 | $point3 = new Point(0, 2);
115 |
116 | $this->assertEquals('45', (string) $point2->getAngle($point3));
117 | $this->assertEquals('45', (string) $point1->getAngle($point2));
118 | $this->assertEquals('90', (string) $point1->getAngle($point3));
119 | }
120 |
121 | /**
122 | * Tests the dot product of the two points:
123 | * dot = x1 * x2 + y1 * y2.
124 | */
125 | public function testDotProduct(): void
126 | {
127 | $point1 = new Point(2, 4.5);
128 | $dot = $point1->dotProduct(new Point(1.5, 0.5));
129 | $this->assertEquals(5.25, $dot);
130 | }
131 |
132 | /**
133 | * Tests the cross product of three point.
134 | */
135 | public function testCrossProduct(): void
136 | {
137 | $pointA = new Point(1, 2);
138 | $pointB = new Point(3, 5);
139 | $pointC = new Point(7, 12);
140 |
141 | $cross = $pointA->crossProduct($pointB, $pointC);
142 | $this->assertEquals(2, $cross);
143 | }
144 |
145 | /**
146 | * Tests the euclidean distance between two points.
147 | */
148 | public function testEuclideanDistance(): void
149 | {
150 | $point1 = new Point(1, 2);
151 | $this->assertEquals(4.243, round($point1->euclideanDistance(new Point(4, 5)), $precision = 3));
152 |
153 | $point2 = new Point(1, 4);
154 | $this->assertEquals(1.414, round($point2->euclideanDistance(new Point(2, 5)), $precision = 3));
155 | }
156 |
157 | /**
158 | * Test intersection method.
159 | */
160 | public function testIntersects(): void
161 | {
162 | // Lines
163 | $line1 = new Line(
164 | new Point(1, 1),
165 | new Point(5, 5)
166 | );
167 |
168 | // Points
169 | $point1 = new Point(3, 3);
170 | $point2 = new Point(3, 3);
171 | $point3 = new Point(3, 4);
172 | $point4 = new Point(5, 5);
173 |
174 | // Polygons
175 | $polygon = new Polygon([
176 | new Point(1, 1),
177 | new Point(3, 3),
178 | new Point(2, 7),
179 | new Point(4, 5),
180 | new Point(7, 5),
181 | new Point(1, 1),
182 | ]);
183 |
184 | // With Point
185 | $this->assertTrue($point1->intersectsPoint($point2));
186 | $this->assertTrue($point2->intersectsPoint($point1));
187 | $this->assertFalse($point1->intersectsPoint($point3));
188 |
189 | // With Line
190 | $this->assertTrue($point1->intersectsLine($line1));
191 | $this->assertTrue($point4->intersectsLine($line1)); // Extreme
192 | $this->assertFalse($point3->intersectsLine($line1));
193 |
194 | // With Polygon
195 | $this->assertTrue($point1->intersectsPolygon($polygon));
196 | $this->assertTrue($point4->intersectsPolygon($polygon));
197 | $this->assertFalse($point3->intersectsPolygon($polygon));
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/Point.php:
--------------------------------------------------------------------------------
1 | x = $x;
22 | $this->y = $y;
23 | }
24 |
25 | /**
26 | * Clone method.
27 | *
28 | * @return Point New instance
29 | */
30 | public function clone(): Point
31 | {
32 | return new Point($this->x, $this->y);
33 | }
34 |
35 | /**
36 | * Getter of x.
37 | *
38 | * @return float Value of x
39 | */
40 | public function getX(): float
41 | {
42 | return $this->x;
43 | }
44 |
45 | /**
46 | * Setter of x.
47 | *
48 | * @param float $newX New value for x
49 | *
50 | * @return Point Instance
51 | */
52 | public function setX(float $newX): Point
53 | {
54 | $this->x = $newX;
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * Getter of y.
61 | *
62 | * @return float Value of y
63 | */
64 | public function getY(): float
65 | {
66 | return $this->y;
67 | }
68 |
69 | /**
70 | * Setter of y.
71 | *
72 | * @param float $newY New value for y
73 | *
74 | * @return Point Instance
75 | */
76 | public function setY(float $newY): Point
77 | {
78 | $this->y = $newY;
79 |
80 | return $this;
81 | }
82 |
83 | /**
84 | * Getter for x and y.
85 | *
86 | * @return float[] Array with two values: X (0) and Y (1)
87 | */
88 | public function getXandY(): array
89 | {
90 | return [$this->x, $this->y];
91 | }
92 |
93 | /**
94 | * Checks whether two points are equals
95 | * (i.e. have the same coordinates).
96 | *
97 | * @param Point $otherPoint The second point to compare
98 | *
99 | * @return bool True if are equals, false otherwise
100 | */
101 | public function isEqual(Point $otherPoint): bool
102 | {
103 | return $this->x === $otherPoint->getX()
104 | && $this->y === $otherPoint->getY();
105 | }
106 |
107 | /**
108 | * Computes the magnitude of the point's vector.
109 | *
110 | * @return float Magnitude of the point's vector
111 | */
112 | public function getMagnitude(): float
113 | {
114 | return sqrt($this->x ** 2 + $this->y ** 2);
115 | }
116 |
117 | /**
118 | * Converts x and y components of the Point from radians to degrees.
119 | *
120 | * @return Point Point with its components in degrees
121 | */
122 | public function fromRadiansToDegrees(): Point
123 | {
124 | return new Point(
125 | rad2deg($this->x),
126 | rad2deg($this->y)
127 | );
128 | }
129 |
130 | /**
131 | * Converts x and y components of the Point from degrees to radians.
132 | *
133 | * @return Point Point with its components in radians
134 | */
135 | public function fromDegreesToRadians(): Point
136 | {
137 | return new Point(
138 | rad2deg($this->x),
139 | rad2deg($this->y)
140 | );
141 | }
142 |
143 | /**
144 | * Computes the angle between two points.
145 | *
146 | * @param Point $otherPoint Other point to get the angle
147 | * @param bool $inDegrees If true the result is returned in degrees. In radians otherwise
148 | *
149 | * @return float The angle between the two points
150 | */
151 | public function getAngle(Point $otherPoint, bool $inDegrees = true): float
152 | {
153 | // Get magnitudes
154 | $magnitudeThis = $this->getMagnitude();
155 | $magnitudeOtherPoint = $otherPoint->getMagnitude();
156 |
157 | // Computes angle
158 | $angleInRadians = acos(($this->x * $otherPoint->getX() + $this->y * $otherPoint->getY()) / ($magnitudeThis * $magnitudeOtherPoint));
159 |
160 | return $inDegrees ? rad2deg($angleInRadians) : $angleInRadians;
161 | }
162 |
163 | /**
164 | * Computes the dot product of the two points.
165 | *
166 | * @param Point $otherPoint Other point to compute the dot product
167 | *
168 | * @return float Dot product = x1 * x2 + y1 * y2
169 | */
170 | public function dotProduct(Point $otherPoint): float
171 | {
172 | return $this->x * $otherPoint->getX() + $this->y * $otherPoint->getY();
173 | }
174 |
175 | /**
176 | * Computes the cross product of the three points.
177 | *
178 | * @param Point $point2 second point to compare
179 | * @param Point $point3 third point to compare
180 | *
181 | * @return float a positive value implies $this → #point2 → $point3 is counter-clockwise, negative implies clockwise
182 | */
183 | public function crossProduct(Point $point2, Point $point3): float
184 | {
185 | return ($point2->getX() - $this->x) * ($point3->getY() - $this->y)
186 | - ($point2->getY() - $this->y) * ($point3->getX() - $this->x);
187 | }
188 |
189 | /**
190 | * Computes the euclidean distance between two points.
191 | *
192 | * @param Point $otherPoint Other point to compute the euclidean distance
193 | *
194 | * @return float Euclidean distance between the two points
195 | */
196 | public function euclideanDistance(Point $otherPoint): float
197 | {
198 | return sqrt(
199 | (($otherPoint->getX() - $this->x) ** 2)
200 | + (($otherPoint->getY() - $this->y) ** 2)
201 | );
202 | }
203 |
204 | /**
205 | * Checks whether the point intersects a line.
206 | *
207 | * @param Line $line Line to check
208 | *
209 | * @return bool true if the point intersects with the line, false otherwise
210 | */
211 | public function intersectsLine(Line $line): bool
212 | {
213 | return $line->intersectsPoint($this);
214 | }
215 |
216 | /**
217 | * Checks whether the point intersects with another point.
218 | *
219 | * @param Point $point Point to check
220 | *
221 | * @return bool true if the point intersects with the other point, false otherwise
222 | */
223 | public function intersectsPoint(Point $point): bool
224 | {
225 | return $this->isEqual($point);
226 | }
227 |
228 | /**
229 | * Checks whether the point intersects with a polygon.
230 | *
231 | * @param Polygon $polygon Polygon to check
232 | *
233 | * @return bool true if the point intersects with the polygon, false otherwise
234 | */
235 | public function intersectsPolygon(Polygon $polygon): bool
236 | {
237 | return $polygon->intersectsPoint($this);
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/tests/PolygonTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf('\JWare\GeoPHP\Polygon', new Polygon([
26 | $somePoint,
27 | $otherPoint,
28 | $otherPoint2,
29 | $somePoint,
30 | ]));
31 |
32 | // Checks invalid Polygons
33 | // Has only 2 different points
34 | $this->expectException(NotEnoughPointsException::class);
35 | $invalidPolygon2 = new Polygon([
36 | new Point(0, 1),
37 | new Point(3, 1),
38 | new Point(1, 1),
39 | ]);
40 |
41 | $this->expectException(FirstAndLastPointNotEqualException::class);
42 | $invalidPolygon = new Polygon([
43 | new Point(0, 1),
44 | new Point(3, 1),
45 | new Point(4, 2),
46 | new Point(1, 1), // Not equals to first point
47 | ]);
48 | }
49 |
50 | /**
51 | * Tests clone method.
52 | */
53 | public function testClone(): void
54 | {
55 | $polygon = new Polygon([
56 | new Point(0, 0),
57 | new Point(4, 0),
58 | new Point(4, 4),
59 | new Point(0, 4),
60 | new Point(0, 0),
61 | ]);
62 | $clone = $polygon->clone();
63 | $this->assertEquals($clone->getPoints(), $polygon->getPoints());
64 | }
65 |
66 | /**
67 | * Tests setPoint method.
68 | */
69 | public function testSetPoint(): void
70 | {
71 | $polygon = new Polygon([
72 | new Point(0, 0),
73 | new Point(4, 0),
74 | new Point(4, 4),
75 | new Point(0, 4),
76 | new Point(0, 0),
77 | ]);
78 | $newPoint = new Point(4, 1);
79 | $polygon->setPoint(1, $newPoint);
80 | $this->assertEquals($polygon->getPoints()[1], $newPoint);
81 |
82 | // Checks invalid Polygon's point setting: It's not allowed to set
83 | // the first or last Point. You must create a new Polygon
84 | $this->expectException(SettingPointException::class);
85 | $polygon->setPoint(0, $newPoint);
86 | $polygon->setPoint(4, $newPoint);
87 | }
88 |
89 | /**
90 | * Tests getCentroid method.
91 | */
92 | public function testGetCentroid(): void
93 | {
94 | $polygon = new Polygon([
95 | new Point(-81, 41),
96 | new Point(-88, 36),
97 | new Point(-84, 31),
98 | new Point(-80, 33),
99 | new Point(-77, 39),
100 | new Point(-81, 41),
101 | ]);
102 | $centroid = $polygon->getCentroid();
103 | $this->assertEquals(new Point(-82, 36), $centroid);
104 | }
105 |
106 | /**
107 | * Test the area computation.
108 | */
109 | public function testArea(): void
110 | {
111 | $polygon1 = new Polygon([
112 | new Point(0, 0),
113 | new Point(4, 0),
114 | new Point(4, 4),
115 | new Point(0, 4),
116 | new Point(0, 0),
117 | ]);
118 |
119 | $polygon2 = new Polygon([
120 | new Point(0, 0),
121 | new Point(4, 0),
122 | new Point(2, 4),
123 | new Point(0, 0),
124 | ]);
125 |
126 | $this->assertEquals(16, $polygon1->area());
127 | $this->assertEquals(8, $polygon2->area());
128 | }
129 |
130 | /**
131 | * Test contains method.
132 | */
133 | public function testContains(): void
134 | {
135 | $polygon1 = new Polygon([
136 | new Point(0, 0),
137 | new Point(4, 0),
138 | new Point(4, 4),
139 | new Point(0, 4),
140 | new Point(0, 0),
141 | ]);
142 |
143 | $polygon2 = new Polygon([
144 | new Point(4, 0),
145 | new Point(8, 0),
146 | new Point(8, 4),
147 | new Point(4, 4),
148 | new Point(4, 0),
149 | ]);
150 |
151 | $polygon3 = new Polygon([
152 | new Point(1, 2),
153 | new Point(2, 2),
154 | new Point(2, 3),
155 | new Point(1, 2),
156 | ]);
157 |
158 | $polygon4 = new Polygon([
159 | new Point(3, 4),
160 | new Point(4, 5),
161 | new Point(3, 5),
162 | new Point(3, 4),
163 | ]);
164 |
165 | $polygon5 = new Polygon([
166 | new Point(1, -1),
167 | new Point(2, 1),
168 | new Point(3, -1),
169 | new Point(2, -2),
170 | new Point(1, -1),
171 | ]);
172 |
173 | $line1 = new Line(
174 | new Point(2, 2),
175 | new Point(3, 3)
176 | );
177 |
178 | $line2 = new Line(
179 | new Point(-1, -1),
180 | new Point(2, 3)
181 | );
182 |
183 | // With Point
184 | $this->assertTrue($polygon1->containsPoint(new Point(2, 2)));
185 | $this->assertTrue($polygon1->containsPoint(new Point(4, 4)));
186 | $this->assertTrue($polygon1->containsPoint(new Point(0, 2)));
187 | $this->assertFalse($polygon1->containsPoint(new Point(10, 12)));
188 | $this->assertFalse($polygon1->containsPoint(new Point(-1, 2)));
189 | $this->assertFalse($polygon1->containsPoint(new Point(5, -2)));
190 |
191 | // With Line
192 | $this->assertTrue($polygon1->containsLine($line1));
193 | $this->assertFalse($polygon1->containsLine($line2));
194 |
195 | // With Polygon
196 | $this->assertTrue($polygon1->containsPolygon($polygon3));
197 | $this->assertFalse($polygon1->containsPolygon($polygon2));
198 | $this->assertFalse($polygon1->containsPolygon($polygon4));
199 | $this->assertFalse($polygon1->containsPolygon($polygon5));
200 | }
201 |
202 | /**
203 | * Test intersection method.
204 | */
205 | public function testIntersects(): void
206 | {
207 | // Polygons
208 | $polygon1 = new Polygon([
209 | new Point(2, 4),
210 | new Point(4, 4),
211 | new Point(5, 2),
212 | new Point(3, 1),
213 | new Point(2.5, 3),
214 | new Point(2, 4),
215 | ]);
216 |
217 | $polygon2 = new Polygon([
218 | new Point(-3, -4),
219 | new Point(-1, -5),
220 | new Point(-2, -6),
221 | new Point(-3, -4),
222 | ]);
223 |
224 | $polygon3 = new Polygon([
225 | new Point(4, 3),
226 | new Point(6, 2.5),
227 | new Point(6, 1.5),
228 | new Point(4.5, 1.25),
229 | new Point(4, 3),
230 | ]);
231 |
232 | $polygon4 = new Polygon([
233 | new Point(-1.5, -5.5),
234 | new Point(-0.5, -6.5),
235 | new Point(-2, -7),
236 | new Point(-1.5, -5.5),
237 | ]);
238 |
239 | // With Point
240 | $this->assertTrue($polygon1->intersectsPoint(new Point(3, 4)));
241 | $this->assertFalse($polygon1->intersectsPoint(new Point(5, 4)));
242 |
243 | // With lines is already tested in LineTest
244 |
245 | // With Polygon
246 | $this->assertTrue($polygon1->intersectsPolygon($polygon3));
247 | $this->assertTrue($polygon4->intersectsPolygon($polygon2));
248 | $this->assertFalse($polygon1->intersectsPolygon($polygon2));
249 | $this->assertFalse($polygon3->intersectsPolygon($polygon2));
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/src/Polygon.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | private array $points;
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param array $points Array of points that make up the polygon
23 | *
24 | * @throws FirstAndLastPointNotEqualException
25 | * @throws NotEnoughPointsException
26 | */
27 | public function __construct(array $points)
28 | {
29 | // A polygon has at least three points
30 | $pointsCount = count($points);
31 | // '< 4' because the last point has to be the same as first point
32 | if ($pointsCount < 4) {
33 | throw new NotEnoughPointsException('The polygon has to have at least three diferent points', 1);
34 | }
35 |
36 | // Checks first/last equality
37 | $lastPosition = $pointsCount - 1;
38 | if (!$points[0]->isEqual($points[$lastPosition])) {
39 | throw new FirstAndLastPointNotEqualException('First and last point must have the same values', 1);
40 | }
41 |
42 | $this->points = $points;
43 | }
44 |
45 | /**
46 | * Clone method.
47 | *
48 | * @return Polygon New instance
49 | */
50 | public function clone(): Polygon
51 | {
52 | return new Polygon($this->points);
53 | }
54 |
55 | /**
56 | * Getter of the points of the polygon.
57 | *
58 | * @return Point[] Array of points that make up the polygon
59 | */
60 | public function getPoints(): array
61 | {
62 | return $this->points;
63 | }
64 |
65 | /**
66 | * Setter for one point of the polygon.
67 | *
68 | * @param int $idx Index in the array of the polygon to replace
69 | * @param Point $point Point to put in the specified position
70 | *
71 | * @return Polygon Current instance
72 | */
73 | public function setPoint(int $idx, Point $point): Polygon
74 | {
75 | if (0 == $idx || $idx == count($this->getPoints())) {
76 | throw new SettingPointException('First or last Point cannot be changed, you should create a new Polygon', 1);
77 | }
78 |
79 | $this->points[$idx] = $point;
80 |
81 | return $this;
82 | }
83 |
84 | /**
85 | * Computes the polygon's centroid.
86 | *
87 | * @return Point Polygon's centroid point
88 | */
89 | public function getCentroid(): Point
90 | {
91 | $x = 0.0;
92 | $y = 0.0;
93 | $pointsCount = 0;
94 | $elemCount = count($this->points);
95 | // We don't need the last element
96 | for (; $pointsCount < $elemCount - 1; ++$pointsCount) {
97 | $point = $this->points[$pointsCount];
98 | $x += $point->getX();
99 | $y += $point->getY();
100 | }
101 |
102 | return new Point(
103 | $x / $pointsCount,
104 | $y / $pointsCount
105 | );
106 | }
107 |
108 | /**
109 | * Get the Polygon's area
110 | * Uses the Shoelace Formula:
111 | * https://en.wikipedia.org/wiki/Shoelace_formula.
112 | */
113 | public function area(): float
114 | {
115 | // Initialze area
116 | $area = 0.0;
117 |
118 | // Sorted vertices are required
119 | $sortedVertices = $this->getSortedVerticies();
120 |
121 | // Calculate value of Shoelace formula
122 | $j = $n = count($sortedVertices) - 1;
123 | for ($i = 0; $i <= $n; ++$i) {
124 | $point1 = $sortedVertices[$i];
125 | $point2 = $sortedVertices[$j];
126 | $area += ($point2->getX() + $point1->getX()) * ($point2->getY() - $point1->getY());
127 | // j is previous vertex to i
128 | $j = $i;
129 | }
130 |
131 | // Return absolute value
132 | return abs($area / 2.0);
133 | }
134 |
135 | /**
136 | * Checks whether the polygon intersects a point. A Polygon intersects a Point if
137 | * at least one of its lines intersects the Point.
138 | *
139 | * @param Point $point Point to check
140 | *
141 | * @return bool True if the polygon intersects with the point, false otherwise
142 | */
143 | public function intersectsPoint(Point $point): bool
144 | {
145 | $n = sizeof($this->points);
146 | $polygonPoints = $this->points;
147 |
148 | $i = 0;
149 | do {
150 | $next = ($i + 1) % $n;
151 |
152 | // Check if the line segment from 'p' to 'extreme' intersects
153 | // with the line segment from 'polygonPoints[i]' to 'polygonPoints[next]'
154 | $lineIToNext = new Line($polygonPoints[$i], $polygonPoints[$next]);
155 | if ($lineIToNext->intersectsPoint($point)) {
156 | return true;
157 | }
158 | $i = $next;
159 | } while (0 != $i);
160 |
161 | return false;
162 | }
163 |
164 | /**
165 | * Checks whether the polygon intersects a line.
166 | *
167 | * @param Line $line Line to check
168 | *
169 | * @return bool True if the polygon intersects with the line, false otherwise
170 | */
171 | public function intersectsLine(Line $line): bool
172 | {
173 | $n = sizeof($this->points);
174 | $polygonPoints = $this->points;
175 |
176 | $i = 0;
177 | do {
178 | $next = ($i + 1) % $n;
179 |
180 | // Check if the line segment from 'p' to 'extreme' intersects
181 | // with the line segment from 'polygonPoints[i]' to 'polygonPoints[next]'
182 | $lineIToNext = new Line($polygonPoints[$i], $polygonPoints[$next]);
183 | if ($line->intersectsLine($lineIToNext)) {
184 | return true;
185 | }
186 | $i = $next;
187 | } while (0 != $i);
188 |
189 | return false;
190 | }
191 |
192 | /**
193 | * Checks whether the polygon intersects another polygon.
194 | *
195 | * @param Polygon $polygon Polygon to check
196 | *
197 | * @return bool True if the polygon intersects with the polygon, false otherwise
198 | */
199 | public function intersectsPolygon(Polygon $polygon): bool
200 | {
201 | $n = sizeof($this->points);
202 | $polygonPoints = $this->points;
203 |
204 | $i = 0;
205 | do {
206 | $next = ($i + 1) % $n;
207 |
208 | // Check if the line segment from 'p' to 'extreme' intersects
209 | // with the line segment from 'polygonPoints[i]' to 'polygonPoints[next]'
210 | $lineIToNext = new Line($polygonPoints[$i], $polygonPoints[$next]);
211 | if ($polygon->intersectsLine($lineIToNext)) {
212 | return true;
213 | }
214 | $i = $next;
215 | } while (0 != $i);
216 |
217 | return false;
218 | }
219 |
220 | /**
221 | * Checks whether a point is inside a polygon.
222 | *
223 | * @param Point $point Point to check
224 | *
225 | * @return bool True if the point is inside the polygon, false otherwise
226 | */
227 | public function containsPoint(Point $point): bool
228 | {
229 | $n = sizeof($this->points);
230 | $polygonPoints = $this->points;
231 |
232 | // Create a line segment from p to infinite
233 | $extremePoint = new Point(PHP_INT_MAX, $point->getY());
234 | $linePointToExtreme = new Line($point, $extremePoint);
235 |
236 | // Count intersections of the above line with sides of polygon
237 | $count = 0;
238 | $i = 0;
239 | do {
240 | $next = ($i + 1) % $n;
241 |
242 | // Check if the line segment from 'p' to 'extreme' intersects
243 | // with the line segment from 'polygonPoints[i]' to 'polygonPoints[next]'
244 | $lineIToNext = new Line($polygonPoints[$i], $polygonPoints[$next]);
245 | if ($linePointToExtreme->intersectsLine($lineIToNext)) {
246 | // If the $point is colinear with line segment 'i-next',
247 | // then check if it lies on segment. If it lies, return true,
248 | // otherwise false
249 | if (0 == $this->orientation($polygonPoints[$i], $point, $polygonPoints[$next])) {
250 | return $lineIToNext->intersectsPoint($point);
251 | }
252 |
253 | ++$count;
254 | }
255 | $i = $next;
256 | } while (0 != $i);
257 |
258 | // Return true if count is odd, false otherwise
259 | return 1 == $count % 2;
260 | }
261 |
262 | /**
263 | * Checks whether the polygon contains a line.
264 | *
265 | * @param Line $line Line to check
266 | *
267 | * @return bool True if the line is inside the polygon, false otherwise
268 | */
269 | public function containsLine(Line $line): bool
270 | {
271 | return $this->containsPoint($line->getStart())
272 | && $this->containsPoint($line->getEnd())
273 | && !$this->intersectsLine($line);
274 | }
275 |
276 | /**
277 | * Checks whether the polygon contains another polygon.
278 | *
279 | * @param Polygon $polygon Polygon to check
280 | *
281 | * @return bool True if the Polygon is inside the polygon, false otherwise
282 | */
283 | public function containsPolygon(Polygon $polygon): bool
284 | {
285 | $polygonPoints = $polygon->getPoints();
286 | $n = sizeof($polygonPoints);
287 |
288 | $i = 0;
289 | do {
290 | $next = ($i + 1) % $n;
291 |
292 | // Check if the line segment from 'p' to 'extreme' intersects
293 | // with the line segment from 'polygonPoints[i]' to 'polygonPoints[next]'
294 | $lineIToNext = new Line($polygonPoints[$i], $polygonPoints[$next]);
295 | if (!$this->containsLine($lineIToNext)) {
296 | return false;
297 | }
298 | $i = $next;
299 | } while (0 != $i);
300 |
301 | return true;
302 | }
303 |
304 | /**
305 | * Sorts the polygon's vertices in clockwise order.
306 | *
307 | * @return Point[] Array with the sorted vertices
308 | */
309 | private function getSortedVerticies(): array
310 | {
311 | // Gets polygon centroid
312 | $center = $this->getCentroid();
313 | $subArray = array_slice($this->points, 0, count($this->points) - 1);
314 | usort($subArray, function ($point1, $point2) use ($center) {
315 | $a1 = (rad2deg(atan2($point1->getX() - $center->getX(), $point1->getY() - $center->getY())) + 360) % 360;
316 | $a2 = (rad2deg(atan2($point2->getX() - $center->getX(), $point2->getY() - $center->getY())) + 360) % 360;
317 |
318 | return $a2 - $a1;
319 | });
320 | $subArray[] = $subArray[0];
321 |
322 | return $subArray;
323 | }
324 |
325 | /**
326 | * To find orientation of ordered triplet (p, q, r).
327 | * The function returns following values.
328 | *
329 | * @param Point $p Point 1
330 | * @param Point $q Point 2
331 | * @param Point $r Point 3
332 | *
333 | * @return int 0 --> p, q and r are colinear, 1 --> Clockwise, 2 --> Counterclockwise
334 | */
335 | private function orientation(Point $p, Point $q, Point $r): int
336 | {
337 | $val = ($q->getY() - $p->getY()) * ($r->getX() - $q->getX()) - ($q->getX() - $p->getX()) * ($r->getY() - $q->getY());
338 | if (0 == $val) {
339 | return 0;
340 | } // colinear
341 |
342 | return ($val > 0) ? 1 : 2; // clock or counterclock wise
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "d80d88ba265846e3b375286340984afc",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "myclabs/deep-copy",
12 | "version": "1.12.1",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/myclabs/DeepCopy.git",
16 | "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
21 | "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^7.1 || ^8.0"
26 | },
27 | "conflict": {
28 | "doctrine/collections": "<1.6.8",
29 | "doctrine/common": "<2.13.3 || >=3 <3.2.2"
30 | },
31 | "require-dev": {
32 | "doctrine/collections": "^1.6.8",
33 | "doctrine/common": "^2.13.3 || ^3.2.2",
34 | "phpspec/prophecy": "^1.10",
35 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
36 | },
37 | "type": "library",
38 | "autoload": {
39 | "files": [
40 | "src/DeepCopy/deep_copy.php"
41 | ],
42 | "psr-4": {
43 | "DeepCopy\\": "src/DeepCopy/"
44 | }
45 | },
46 | "notification-url": "https://packagist.org/downloads/",
47 | "license": [
48 | "MIT"
49 | ],
50 | "description": "Create deep copies (clones) of your objects",
51 | "keywords": [
52 | "clone",
53 | "copy",
54 | "duplicate",
55 | "object",
56 | "object graph"
57 | ],
58 | "support": {
59 | "issues": "https://github.com/myclabs/DeepCopy/issues",
60 | "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
61 | },
62 | "funding": [
63 | {
64 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
65 | "type": "tidelift"
66 | }
67 | ],
68 | "time": "2024-11-08T17:47:46+00:00"
69 | },
70 | {
71 | "name": "nikic/php-parser",
72 | "version": "v5.3.1",
73 | "source": {
74 | "type": "git",
75 | "url": "https://github.com/nikic/PHP-Parser.git",
76 | "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
77 | },
78 | "dist": {
79 | "type": "zip",
80 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
81 | "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
82 | "shasum": ""
83 | },
84 | "require": {
85 | "ext-ctype": "*",
86 | "ext-json": "*",
87 | "ext-tokenizer": "*",
88 | "php": ">=7.4"
89 | },
90 | "require-dev": {
91 | "ircmaxell/php-yacc": "^0.0.7",
92 | "phpunit/phpunit": "^9.0"
93 | },
94 | "bin": [
95 | "bin/php-parse"
96 | ],
97 | "type": "library",
98 | "extra": {
99 | "branch-alias": {
100 | "dev-master": "5.0-dev"
101 | }
102 | },
103 | "autoload": {
104 | "psr-4": {
105 | "PhpParser\\": "lib/PhpParser"
106 | }
107 | },
108 | "notification-url": "https://packagist.org/downloads/",
109 | "license": [
110 | "BSD-3-Clause"
111 | ],
112 | "authors": [
113 | {
114 | "name": "Nikita Popov"
115 | }
116 | ],
117 | "description": "A PHP parser written in PHP",
118 | "keywords": [
119 | "parser",
120 | "php"
121 | ],
122 | "support": {
123 | "issues": "https://github.com/nikic/PHP-Parser/issues",
124 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
125 | },
126 | "time": "2024-10-08T18:51:32+00:00"
127 | },
128 | {
129 | "name": "phar-io/manifest",
130 | "version": "2.0.4",
131 | "source": {
132 | "type": "git",
133 | "url": "https://github.com/phar-io/manifest.git",
134 | "reference": "54750ef60c58e43759730615a392c31c80e23176"
135 | },
136 | "dist": {
137 | "type": "zip",
138 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
139 | "reference": "54750ef60c58e43759730615a392c31c80e23176",
140 | "shasum": ""
141 | },
142 | "require": {
143 | "ext-dom": "*",
144 | "ext-libxml": "*",
145 | "ext-phar": "*",
146 | "ext-xmlwriter": "*",
147 | "phar-io/version": "^3.0.1",
148 | "php": "^7.2 || ^8.0"
149 | },
150 | "type": "library",
151 | "extra": {
152 | "branch-alias": {
153 | "dev-master": "2.0.x-dev"
154 | }
155 | },
156 | "autoload": {
157 | "classmap": [
158 | "src/"
159 | ]
160 | },
161 | "notification-url": "https://packagist.org/downloads/",
162 | "license": [
163 | "BSD-3-Clause"
164 | ],
165 | "authors": [
166 | {
167 | "name": "Arne Blankerts",
168 | "email": "arne@blankerts.de",
169 | "role": "Developer"
170 | },
171 | {
172 | "name": "Sebastian Heuer",
173 | "email": "sebastian@phpeople.de",
174 | "role": "Developer"
175 | },
176 | {
177 | "name": "Sebastian Bergmann",
178 | "email": "sebastian@phpunit.de",
179 | "role": "Developer"
180 | }
181 | ],
182 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
183 | "support": {
184 | "issues": "https://github.com/phar-io/manifest/issues",
185 | "source": "https://github.com/phar-io/manifest/tree/2.0.4"
186 | },
187 | "funding": [
188 | {
189 | "url": "https://github.com/theseer",
190 | "type": "github"
191 | }
192 | ],
193 | "time": "2024-03-03T12:33:53+00:00"
194 | },
195 | {
196 | "name": "phar-io/version",
197 | "version": "3.2.1",
198 | "source": {
199 | "type": "git",
200 | "url": "https://github.com/phar-io/version.git",
201 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
202 | },
203 | "dist": {
204 | "type": "zip",
205 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
206 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
207 | "shasum": ""
208 | },
209 | "require": {
210 | "php": "^7.2 || ^8.0"
211 | },
212 | "type": "library",
213 | "autoload": {
214 | "classmap": [
215 | "src/"
216 | ]
217 | },
218 | "notification-url": "https://packagist.org/downloads/",
219 | "license": [
220 | "BSD-3-Clause"
221 | ],
222 | "authors": [
223 | {
224 | "name": "Arne Blankerts",
225 | "email": "arne@blankerts.de",
226 | "role": "Developer"
227 | },
228 | {
229 | "name": "Sebastian Heuer",
230 | "email": "sebastian@phpeople.de",
231 | "role": "Developer"
232 | },
233 | {
234 | "name": "Sebastian Bergmann",
235 | "email": "sebastian@phpunit.de",
236 | "role": "Developer"
237 | }
238 | ],
239 | "description": "Library for handling version information and constraints",
240 | "support": {
241 | "issues": "https://github.com/phar-io/version/issues",
242 | "source": "https://github.com/phar-io/version/tree/3.2.1"
243 | },
244 | "time": "2022-02-21T01:04:05+00:00"
245 | },
246 | {
247 | "name": "phpunit/php-code-coverage",
248 | "version": "10.1.16",
249 | "source": {
250 | "type": "git",
251 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
252 | "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
253 | },
254 | "dist": {
255 | "type": "zip",
256 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
257 | "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
258 | "shasum": ""
259 | },
260 | "require": {
261 | "ext-dom": "*",
262 | "ext-libxml": "*",
263 | "ext-xmlwriter": "*",
264 | "nikic/php-parser": "^4.19.1 || ^5.1.0",
265 | "php": ">=8.1",
266 | "phpunit/php-file-iterator": "^4.1.0",
267 | "phpunit/php-text-template": "^3.0.1",
268 | "sebastian/code-unit-reverse-lookup": "^3.0.0",
269 | "sebastian/complexity": "^3.2.0",
270 | "sebastian/environment": "^6.1.0",
271 | "sebastian/lines-of-code": "^2.0.2",
272 | "sebastian/version": "^4.0.1",
273 | "theseer/tokenizer": "^1.2.3"
274 | },
275 | "require-dev": {
276 | "phpunit/phpunit": "^10.1"
277 | },
278 | "suggest": {
279 | "ext-pcov": "PHP extension that provides line coverage",
280 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
281 | },
282 | "type": "library",
283 | "extra": {
284 | "branch-alias": {
285 | "dev-main": "10.1.x-dev"
286 | }
287 | },
288 | "autoload": {
289 | "classmap": [
290 | "src/"
291 | ]
292 | },
293 | "notification-url": "https://packagist.org/downloads/",
294 | "license": [
295 | "BSD-3-Clause"
296 | ],
297 | "authors": [
298 | {
299 | "name": "Sebastian Bergmann",
300 | "email": "sebastian@phpunit.de",
301 | "role": "lead"
302 | }
303 | ],
304 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
305 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
306 | "keywords": [
307 | "coverage",
308 | "testing",
309 | "xunit"
310 | ],
311 | "support": {
312 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
313 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
314 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
315 | },
316 | "funding": [
317 | {
318 | "url": "https://github.com/sebastianbergmann",
319 | "type": "github"
320 | }
321 | ],
322 | "time": "2024-08-22T04:31:57+00:00"
323 | },
324 | {
325 | "name": "phpunit/php-file-iterator",
326 | "version": "4.1.0",
327 | "source": {
328 | "type": "git",
329 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
330 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
331 | },
332 | "dist": {
333 | "type": "zip",
334 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
335 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
336 | "shasum": ""
337 | },
338 | "require": {
339 | "php": ">=8.1"
340 | },
341 | "require-dev": {
342 | "phpunit/phpunit": "^10.0"
343 | },
344 | "type": "library",
345 | "extra": {
346 | "branch-alias": {
347 | "dev-main": "4.0-dev"
348 | }
349 | },
350 | "autoload": {
351 | "classmap": [
352 | "src/"
353 | ]
354 | },
355 | "notification-url": "https://packagist.org/downloads/",
356 | "license": [
357 | "BSD-3-Clause"
358 | ],
359 | "authors": [
360 | {
361 | "name": "Sebastian Bergmann",
362 | "email": "sebastian@phpunit.de",
363 | "role": "lead"
364 | }
365 | ],
366 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
367 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
368 | "keywords": [
369 | "filesystem",
370 | "iterator"
371 | ],
372 | "support": {
373 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
374 | "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
375 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
376 | },
377 | "funding": [
378 | {
379 | "url": "https://github.com/sebastianbergmann",
380 | "type": "github"
381 | }
382 | ],
383 | "time": "2023-08-31T06:24:48+00:00"
384 | },
385 | {
386 | "name": "phpunit/php-invoker",
387 | "version": "4.0.0",
388 | "source": {
389 | "type": "git",
390 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
391 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
392 | },
393 | "dist": {
394 | "type": "zip",
395 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
396 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
397 | "shasum": ""
398 | },
399 | "require": {
400 | "php": ">=8.1"
401 | },
402 | "require-dev": {
403 | "ext-pcntl": "*",
404 | "phpunit/phpunit": "^10.0"
405 | },
406 | "suggest": {
407 | "ext-pcntl": "*"
408 | },
409 | "type": "library",
410 | "extra": {
411 | "branch-alias": {
412 | "dev-main": "4.0-dev"
413 | }
414 | },
415 | "autoload": {
416 | "classmap": [
417 | "src/"
418 | ]
419 | },
420 | "notification-url": "https://packagist.org/downloads/",
421 | "license": [
422 | "BSD-3-Clause"
423 | ],
424 | "authors": [
425 | {
426 | "name": "Sebastian Bergmann",
427 | "email": "sebastian@phpunit.de",
428 | "role": "lead"
429 | }
430 | ],
431 | "description": "Invoke callables with a timeout",
432 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
433 | "keywords": [
434 | "process"
435 | ],
436 | "support": {
437 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
438 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
439 | },
440 | "funding": [
441 | {
442 | "url": "https://github.com/sebastianbergmann",
443 | "type": "github"
444 | }
445 | ],
446 | "time": "2023-02-03T06:56:09+00:00"
447 | },
448 | {
449 | "name": "phpunit/php-text-template",
450 | "version": "3.0.1",
451 | "source": {
452 | "type": "git",
453 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
454 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
455 | },
456 | "dist": {
457 | "type": "zip",
458 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
459 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
460 | "shasum": ""
461 | },
462 | "require": {
463 | "php": ">=8.1"
464 | },
465 | "require-dev": {
466 | "phpunit/phpunit": "^10.0"
467 | },
468 | "type": "library",
469 | "extra": {
470 | "branch-alias": {
471 | "dev-main": "3.0-dev"
472 | }
473 | },
474 | "autoload": {
475 | "classmap": [
476 | "src/"
477 | ]
478 | },
479 | "notification-url": "https://packagist.org/downloads/",
480 | "license": [
481 | "BSD-3-Clause"
482 | ],
483 | "authors": [
484 | {
485 | "name": "Sebastian Bergmann",
486 | "email": "sebastian@phpunit.de",
487 | "role": "lead"
488 | }
489 | ],
490 | "description": "Simple template engine.",
491 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
492 | "keywords": [
493 | "template"
494 | ],
495 | "support": {
496 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
497 | "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
498 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
499 | },
500 | "funding": [
501 | {
502 | "url": "https://github.com/sebastianbergmann",
503 | "type": "github"
504 | }
505 | ],
506 | "time": "2023-08-31T14:07:24+00:00"
507 | },
508 | {
509 | "name": "phpunit/php-timer",
510 | "version": "6.0.0",
511 | "source": {
512 | "type": "git",
513 | "url": "https://github.com/sebastianbergmann/php-timer.git",
514 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
515 | },
516 | "dist": {
517 | "type": "zip",
518 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
519 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
520 | "shasum": ""
521 | },
522 | "require": {
523 | "php": ">=8.1"
524 | },
525 | "require-dev": {
526 | "phpunit/phpunit": "^10.0"
527 | },
528 | "type": "library",
529 | "extra": {
530 | "branch-alias": {
531 | "dev-main": "6.0-dev"
532 | }
533 | },
534 | "autoload": {
535 | "classmap": [
536 | "src/"
537 | ]
538 | },
539 | "notification-url": "https://packagist.org/downloads/",
540 | "license": [
541 | "BSD-3-Clause"
542 | ],
543 | "authors": [
544 | {
545 | "name": "Sebastian Bergmann",
546 | "email": "sebastian@phpunit.de",
547 | "role": "lead"
548 | }
549 | ],
550 | "description": "Utility class for timing",
551 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
552 | "keywords": [
553 | "timer"
554 | ],
555 | "support": {
556 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
557 | "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
558 | },
559 | "funding": [
560 | {
561 | "url": "https://github.com/sebastianbergmann",
562 | "type": "github"
563 | }
564 | ],
565 | "time": "2023-02-03T06:57:52+00:00"
566 | },
567 | {
568 | "name": "phpunit/phpunit",
569 | "version": "10.5.39",
570 | "source": {
571 | "type": "git",
572 | "url": "https://github.com/sebastianbergmann/phpunit.git",
573 | "reference": "4e89eff200b801db58f3d580ad7426431949eaa9"
574 | },
575 | "dist": {
576 | "type": "zip",
577 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4e89eff200b801db58f3d580ad7426431949eaa9",
578 | "reference": "4e89eff200b801db58f3d580ad7426431949eaa9",
579 | "shasum": ""
580 | },
581 | "require": {
582 | "ext-dom": "*",
583 | "ext-json": "*",
584 | "ext-libxml": "*",
585 | "ext-mbstring": "*",
586 | "ext-xml": "*",
587 | "ext-xmlwriter": "*",
588 | "myclabs/deep-copy": "^1.12.1",
589 | "phar-io/manifest": "^2.0.4",
590 | "phar-io/version": "^3.2.1",
591 | "php": ">=8.1",
592 | "phpunit/php-code-coverage": "^10.1.16",
593 | "phpunit/php-file-iterator": "^4.1.0",
594 | "phpunit/php-invoker": "^4.0.0",
595 | "phpunit/php-text-template": "^3.0.1",
596 | "phpunit/php-timer": "^6.0.0",
597 | "sebastian/cli-parser": "^2.0.1",
598 | "sebastian/code-unit": "^2.0.0",
599 | "sebastian/comparator": "^5.0.3",
600 | "sebastian/diff": "^5.1.1",
601 | "sebastian/environment": "^6.1.0",
602 | "sebastian/exporter": "^5.1.2",
603 | "sebastian/global-state": "^6.0.2",
604 | "sebastian/object-enumerator": "^5.0.0",
605 | "sebastian/recursion-context": "^5.0.0",
606 | "sebastian/type": "^4.0.0",
607 | "sebastian/version": "^4.0.1"
608 | },
609 | "suggest": {
610 | "ext-soap": "To be able to generate mocks based on WSDL files"
611 | },
612 | "bin": [
613 | "phpunit"
614 | ],
615 | "type": "library",
616 | "extra": {
617 | "branch-alias": {
618 | "dev-main": "10.5-dev"
619 | }
620 | },
621 | "autoload": {
622 | "files": [
623 | "src/Framework/Assert/Functions.php"
624 | ],
625 | "classmap": [
626 | "src/"
627 | ]
628 | },
629 | "notification-url": "https://packagist.org/downloads/",
630 | "license": [
631 | "BSD-3-Clause"
632 | ],
633 | "authors": [
634 | {
635 | "name": "Sebastian Bergmann",
636 | "email": "sebastian@phpunit.de",
637 | "role": "lead"
638 | }
639 | ],
640 | "description": "The PHP Unit Testing framework.",
641 | "homepage": "https://phpunit.de/",
642 | "keywords": [
643 | "phpunit",
644 | "testing",
645 | "xunit"
646 | ],
647 | "support": {
648 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
649 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
650 | "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.39"
651 | },
652 | "funding": [
653 | {
654 | "url": "https://phpunit.de/sponsors.html",
655 | "type": "custom"
656 | },
657 | {
658 | "url": "https://github.com/sebastianbergmann",
659 | "type": "github"
660 | },
661 | {
662 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
663 | "type": "tidelift"
664 | }
665 | ],
666 | "time": "2024-12-11T10:51:07+00:00"
667 | },
668 | {
669 | "name": "sebastian/cli-parser",
670 | "version": "2.0.1",
671 | "source": {
672 | "type": "git",
673 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
674 | "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
675 | },
676 | "dist": {
677 | "type": "zip",
678 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
679 | "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
680 | "shasum": ""
681 | },
682 | "require": {
683 | "php": ">=8.1"
684 | },
685 | "require-dev": {
686 | "phpunit/phpunit": "^10.0"
687 | },
688 | "type": "library",
689 | "extra": {
690 | "branch-alias": {
691 | "dev-main": "2.0-dev"
692 | }
693 | },
694 | "autoload": {
695 | "classmap": [
696 | "src/"
697 | ]
698 | },
699 | "notification-url": "https://packagist.org/downloads/",
700 | "license": [
701 | "BSD-3-Clause"
702 | ],
703 | "authors": [
704 | {
705 | "name": "Sebastian Bergmann",
706 | "email": "sebastian@phpunit.de",
707 | "role": "lead"
708 | }
709 | ],
710 | "description": "Library for parsing CLI options",
711 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
712 | "support": {
713 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
714 | "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
715 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
716 | },
717 | "funding": [
718 | {
719 | "url": "https://github.com/sebastianbergmann",
720 | "type": "github"
721 | }
722 | ],
723 | "time": "2024-03-02T07:12:49+00:00"
724 | },
725 | {
726 | "name": "sebastian/code-unit",
727 | "version": "2.0.0",
728 | "source": {
729 | "type": "git",
730 | "url": "https://github.com/sebastianbergmann/code-unit.git",
731 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
732 | },
733 | "dist": {
734 | "type": "zip",
735 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
736 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
737 | "shasum": ""
738 | },
739 | "require": {
740 | "php": ">=8.1"
741 | },
742 | "require-dev": {
743 | "phpunit/phpunit": "^10.0"
744 | },
745 | "type": "library",
746 | "extra": {
747 | "branch-alias": {
748 | "dev-main": "2.0-dev"
749 | }
750 | },
751 | "autoload": {
752 | "classmap": [
753 | "src/"
754 | ]
755 | },
756 | "notification-url": "https://packagist.org/downloads/",
757 | "license": [
758 | "BSD-3-Clause"
759 | ],
760 | "authors": [
761 | {
762 | "name": "Sebastian Bergmann",
763 | "email": "sebastian@phpunit.de",
764 | "role": "lead"
765 | }
766 | ],
767 | "description": "Collection of value objects that represent the PHP code units",
768 | "homepage": "https://github.com/sebastianbergmann/code-unit",
769 | "support": {
770 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
771 | "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
772 | },
773 | "funding": [
774 | {
775 | "url": "https://github.com/sebastianbergmann",
776 | "type": "github"
777 | }
778 | ],
779 | "time": "2023-02-03T06:58:43+00:00"
780 | },
781 | {
782 | "name": "sebastian/code-unit-reverse-lookup",
783 | "version": "3.0.0",
784 | "source": {
785 | "type": "git",
786 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
787 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
788 | },
789 | "dist": {
790 | "type": "zip",
791 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
792 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
793 | "shasum": ""
794 | },
795 | "require": {
796 | "php": ">=8.1"
797 | },
798 | "require-dev": {
799 | "phpunit/phpunit": "^10.0"
800 | },
801 | "type": "library",
802 | "extra": {
803 | "branch-alias": {
804 | "dev-main": "3.0-dev"
805 | }
806 | },
807 | "autoload": {
808 | "classmap": [
809 | "src/"
810 | ]
811 | },
812 | "notification-url": "https://packagist.org/downloads/",
813 | "license": [
814 | "BSD-3-Clause"
815 | ],
816 | "authors": [
817 | {
818 | "name": "Sebastian Bergmann",
819 | "email": "sebastian@phpunit.de"
820 | }
821 | ],
822 | "description": "Looks up which function or method a line of code belongs to",
823 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
824 | "support": {
825 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
826 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
827 | },
828 | "funding": [
829 | {
830 | "url": "https://github.com/sebastianbergmann",
831 | "type": "github"
832 | }
833 | ],
834 | "time": "2023-02-03T06:59:15+00:00"
835 | },
836 | {
837 | "name": "sebastian/comparator",
838 | "version": "5.0.3",
839 | "source": {
840 | "type": "git",
841 | "url": "https://github.com/sebastianbergmann/comparator.git",
842 | "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
843 | },
844 | "dist": {
845 | "type": "zip",
846 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
847 | "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
848 | "shasum": ""
849 | },
850 | "require": {
851 | "ext-dom": "*",
852 | "ext-mbstring": "*",
853 | "php": ">=8.1",
854 | "sebastian/diff": "^5.0",
855 | "sebastian/exporter": "^5.0"
856 | },
857 | "require-dev": {
858 | "phpunit/phpunit": "^10.5"
859 | },
860 | "type": "library",
861 | "extra": {
862 | "branch-alias": {
863 | "dev-main": "5.0-dev"
864 | }
865 | },
866 | "autoload": {
867 | "classmap": [
868 | "src/"
869 | ]
870 | },
871 | "notification-url": "https://packagist.org/downloads/",
872 | "license": [
873 | "BSD-3-Clause"
874 | ],
875 | "authors": [
876 | {
877 | "name": "Sebastian Bergmann",
878 | "email": "sebastian@phpunit.de"
879 | },
880 | {
881 | "name": "Jeff Welch",
882 | "email": "whatthejeff@gmail.com"
883 | },
884 | {
885 | "name": "Volker Dusch",
886 | "email": "github@wallbash.com"
887 | },
888 | {
889 | "name": "Bernhard Schussek",
890 | "email": "bschussek@2bepublished.at"
891 | }
892 | ],
893 | "description": "Provides the functionality to compare PHP values for equality",
894 | "homepage": "https://github.com/sebastianbergmann/comparator",
895 | "keywords": [
896 | "comparator",
897 | "compare",
898 | "equality"
899 | ],
900 | "support": {
901 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
902 | "security": "https://github.com/sebastianbergmann/comparator/security/policy",
903 | "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3"
904 | },
905 | "funding": [
906 | {
907 | "url": "https://github.com/sebastianbergmann",
908 | "type": "github"
909 | }
910 | ],
911 | "time": "2024-10-18T14:56:07+00:00"
912 | },
913 | {
914 | "name": "sebastian/complexity",
915 | "version": "3.2.0",
916 | "source": {
917 | "type": "git",
918 | "url": "https://github.com/sebastianbergmann/complexity.git",
919 | "reference": "68ff824baeae169ec9f2137158ee529584553799"
920 | },
921 | "dist": {
922 | "type": "zip",
923 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
924 | "reference": "68ff824baeae169ec9f2137158ee529584553799",
925 | "shasum": ""
926 | },
927 | "require": {
928 | "nikic/php-parser": "^4.18 || ^5.0",
929 | "php": ">=8.1"
930 | },
931 | "require-dev": {
932 | "phpunit/phpunit": "^10.0"
933 | },
934 | "type": "library",
935 | "extra": {
936 | "branch-alias": {
937 | "dev-main": "3.2-dev"
938 | }
939 | },
940 | "autoload": {
941 | "classmap": [
942 | "src/"
943 | ]
944 | },
945 | "notification-url": "https://packagist.org/downloads/",
946 | "license": [
947 | "BSD-3-Clause"
948 | ],
949 | "authors": [
950 | {
951 | "name": "Sebastian Bergmann",
952 | "email": "sebastian@phpunit.de",
953 | "role": "lead"
954 | }
955 | ],
956 | "description": "Library for calculating the complexity of PHP code units",
957 | "homepage": "https://github.com/sebastianbergmann/complexity",
958 | "support": {
959 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
960 | "security": "https://github.com/sebastianbergmann/complexity/security/policy",
961 | "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
962 | },
963 | "funding": [
964 | {
965 | "url": "https://github.com/sebastianbergmann",
966 | "type": "github"
967 | }
968 | ],
969 | "time": "2023-12-21T08:37:17+00:00"
970 | },
971 | {
972 | "name": "sebastian/diff",
973 | "version": "5.1.1",
974 | "source": {
975 | "type": "git",
976 | "url": "https://github.com/sebastianbergmann/diff.git",
977 | "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
978 | },
979 | "dist": {
980 | "type": "zip",
981 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
982 | "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
983 | "shasum": ""
984 | },
985 | "require": {
986 | "php": ">=8.1"
987 | },
988 | "require-dev": {
989 | "phpunit/phpunit": "^10.0",
990 | "symfony/process": "^6.4"
991 | },
992 | "type": "library",
993 | "extra": {
994 | "branch-alias": {
995 | "dev-main": "5.1-dev"
996 | }
997 | },
998 | "autoload": {
999 | "classmap": [
1000 | "src/"
1001 | ]
1002 | },
1003 | "notification-url": "https://packagist.org/downloads/",
1004 | "license": [
1005 | "BSD-3-Clause"
1006 | ],
1007 | "authors": [
1008 | {
1009 | "name": "Sebastian Bergmann",
1010 | "email": "sebastian@phpunit.de"
1011 | },
1012 | {
1013 | "name": "Kore Nordmann",
1014 | "email": "mail@kore-nordmann.de"
1015 | }
1016 | ],
1017 | "description": "Diff implementation",
1018 | "homepage": "https://github.com/sebastianbergmann/diff",
1019 | "keywords": [
1020 | "diff",
1021 | "udiff",
1022 | "unidiff",
1023 | "unified diff"
1024 | ],
1025 | "support": {
1026 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1027 | "security": "https://github.com/sebastianbergmann/diff/security/policy",
1028 | "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
1029 | },
1030 | "funding": [
1031 | {
1032 | "url": "https://github.com/sebastianbergmann",
1033 | "type": "github"
1034 | }
1035 | ],
1036 | "time": "2024-03-02T07:15:17+00:00"
1037 | },
1038 | {
1039 | "name": "sebastian/environment",
1040 | "version": "6.1.0",
1041 | "source": {
1042 | "type": "git",
1043 | "url": "https://github.com/sebastianbergmann/environment.git",
1044 | "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
1045 | },
1046 | "dist": {
1047 | "type": "zip",
1048 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
1049 | "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
1050 | "shasum": ""
1051 | },
1052 | "require": {
1053 | "php": ">=8.1"
1054 | },
1055 | "require-dev": {
1056 | "phpunit/phpunit": "^10.0"
1057 | },
1058 | "suggest": {
1059 | "ext-posix": "*"
1060 | },
1061 | "type": "library",
1062 | "extra": {
1063 | "branch-alias": {
1064 | "dev-main": "6.1-dev"
1065 | }
1066 | },
1067 | "autoload": {
1068 | "classmap": [
1069 | "src/"
1070 | ]
1071 | },
1072 | "notification-url": "https://packagist.org/downloads/",
1073 | "license": [
1074 | "BSD-3-Clause"
1075 | ],
1076 | "authors": [
1077 | {
1078 | "name": "Sebastian Bergmann",
1079 | "email": "sebastian@phpunit.de"
1080 | }
1081 | ],
1082 | "description": "Provides functionality to handle HHVM/PHP environments",
1083 | "homepage": "https://github.com/sebastianbergmann/environment",
1084 | "keywords": [
1085 | "Xdebug",
1086 | "environment",
1087 | "hhvm"
1088 | ],
1089 | "support": {
1090 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1091 | "security": "https://github.com/sebastianbergmann/environment/security/policy",
1092 | "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
1093 | },
1094 | "funding": [
1095 | {
1096 | "url": "https://github.com/sebastianbergmann",
1097 | "type": "github"
1098 | }
1099 | ],
1100 | "time": "2024-03-23T08:47:14+00:00"
1101 | },
1102 | {
1103 | "name": "sebastian/exporter",
1104 | "version": "5.1.2",
1105 | "source": {
1106 | "type": "git",
1107 | "url": "https://github.com/sebastianbergmann/exporter.git",
1108 | "reference": "955288482d97c19a372d3f31006ab3f37da47adf"
1109 | },
1110 | "dist": {
1111 | "type": "zip",
1112 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
1113 | "reference": "955288482d97c19a372d3f31006ab3f37da47adf",
1114 | "shasum": ""
1115 | },
1116 | "require": {
1117 | "ext-mbstring": "*",
1118 | "php": ">=8.1",
1119 | "sebastian/recursion-context": "^5.0"
1120 | },
1121 | "require-dev": {
1122 | "phpunit/phpunit": "^10.0"
1123 | },
1124 | "type": "library",
1125 | "extra": {
1126 | "branch-alias": {
1127 | "dev-main": "5.1-dev"
1128 | }
1129 | },
1130 | "autoload": {
1131 | "classmap": [
1132 | "src/"
1133 | ]
1134 | },
1135 | "notification-url": "https://packagist.org/downloads/",
1136 | "license": [
1137 | "BSD-3-Clause"
1138 | ],
1139 | "authors": [
1140 | {
1141 | "name": "Sebastian Bergmann",
1142 | "email": "sebastian@phpunit.de"
1143 | },
1144 | {
1145 | "name": "Jeff Welch",
1146 | "email": "whatthejeff@gmail.com"
1147 | },
1148 | {
1149 | "name": "Volker Dusch",
1150 | "email": "github@wallbash.com"
1151 | },
1152 | {
1153 | "name": "Adam Harvey",
1154 | "email": "aharvey@php.net"
1155 | },
1156 | {
1157 | "name": "Bernhard Schussek",
1158 | "email": "bschussek@gmail.com"
1159 | }
1160 | ],
1161 | "description": "Provides the functionality to export PHP variables for visualization",
1162 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1163 | "keywords": [
1164 | "export",
1165 | "exporter"
1166 | ],
1167 | "support": {
1168 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1169 | "security": "https://github.com/sebastianbergmann/exporter/security/policy",
1170 | "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2"
1171 | },
1172 | "funding": [
1173 | {
1174 | "url": "https://github.com/sebastianbergmann",
1175 | "type": "github"
1176 | }
1177 | ],
1178 | "time": "2024-03-02T07:17:12+00:00"
1179 | },
1180 | {
1181 | "name": "sebastian/global-state",
1182 | "version": "6.0.2",
1183 | "source": {
1184 | "type": "git",
1185 | "url": "https://github.com/sebastianbergmann/global-state.git",
1186 | "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
1187 | },
1188 | "dist": {
1189 | "type": "zip",
1190 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
1191 | "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
1192 | "shasum": ""
1193 | },
1194 | "require": {
1195 | "php": ">=8.1",
1196 | "sebastian/object-reflector": "^3.0",
1197 | "sebastian/recursion-context": "^5.0"
1198 | },
1199 | "require-dev": {
1200 | "ext-dom": "*",
1201 | "phpunit/phpunit": "^10.0"
1202 | },
1203 | "type": "library",
1204 | "extra": {
1205 | "branch-alias": {
1206 | "dev-main": "6.0-dev"
1207 | }
1208 | },
1209 | "autoload": {
1210 | "classmap": [
1211 | "src/"
1212 | ]
1213 | },
1214 | "notification-url": "https://packagist.org/downloads/",
1215 | "license": [
1216 | "BSD-3-Clause"
1217 | ],
1218 | "authors": [
1219 | {
1220 | "name": "Sebastian Bergmann",
1221 | "email": "sebastian@phpunit.de"
1222 | }
1223 | ],
1224 | "description": "Snapshotting of global state",
1225 | "homepage": "https://www.github.com/sebastianbergmann/global-state",
1226 | "keywords": [
1227 | "global state"
1228 | ],
1229 | "support": {
1230 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1231 | "security": "https://github.com/sebastianbergmann/global-state/security/policy",
1232 | "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
1233 | },
1234 | "funding": [
1235 | {
1236 | "url": "https://github.com/sebastianbergmann",
1237 | "type": "github"
1238 | }
1239 | ],
1240 | "time": "2024-03-02T07:19:19+00:00"
1241 | },
1242 | {
1243 | "name": "sebastian/lines-of-code",
1244 | "version": "2.0.2",
1245 | "source": {
1246 | "type": "git",
1247 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1248 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
1249 | },
1250 | "dist": {
1251 | "type": "zip",
1252 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
1253 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
1254 | "shasum": ""
1255 | },
1256 | "require": {
1257 | "nikic/php-parser": "^4.18 || ^5.0",
1258 | "php": ">=8.1"
1259 | },
1260 | "require-dev": {
1261 | "phpunit/phpunit": "^10.0"
1262 | },
1263 | "type": "library",
1264 | "extra": {
1265 | "branch-alias": {
1266 | "dev-main": "2.0-dev"
1267 | }
1268 | },
1269 | "autoload": {
1270 | "classmap": [
1271 | "src/"
1272 | ]
1273 | },
1274 | "notification-url": "https://packagist.org/downloads/",
1275 | "license": [
1276 | "BSD-3-Clause"
1277 | ],
1278 | "authors": [
1279 | {
1280 | "name": "Sebastian Bergmann",
1281 | "email": "sebastian@phpunit.de",
1282 | "role": "lead"
1283 | }
1284 | ],
1285 | "description": "Library for counting the lines of code in PHP source code",
1286 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1287 | "support": {
1288 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1289 | "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
1290 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
1291 | },
1292 | "funding": [
1293 | {
1294 | "url": "https://github.com/sebastianbergmann",
1295 | "type": "github"
1296 | }
1297 | ],
1298 | "time": "2023-12-21T08:38:20+00:00"
1299 | },
1300 | {
1301 | "name": "sebastian/object-enumerator",
1302 | "version": "5.0.0",
1303 | "source": {
1304 | "type": "git",
1305 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1306 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
1307 | },
1308 | "dist": {
1309 | "type": "zip",
1310 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
1311 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
1312 | "shasum": ""
1313 | },
1314 | "require": {
1315 | "php": ">=8.1",
1316 | "sebastian/object-reflector": "^3.0",
1317 | "sebastian/recursion-context": "^5.0"
1318 | },
1319 | "require-dev": {
1320 | "phpunit/phpunit": "^10.0"
1321 | },
1322 | "type": "library",
1323 | "extra": {
1324 | "branch-alias": {
1325 | "dev-main": "5.0-dev"
1326 | }
1327 | },
1328 | "autoload": {
1329 | "classmap": [
1330 | "src/"
1331 | ]
1332 | },
1333 | "notification-url": "https://packagist.org/downloads/",
1334 | "license": [
1335 | "BSD-3-Clause"
1336 | ],
1337 | "authors": [
1338 | {
1339 | "name": "Sebastian Bergmann",
1340 | "email": "sebastian@phpunit.de"
1341 | }
1342 | ],
1343 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1344 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1345 | "support": {
1346 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1347 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
1348 | },
1349 | "funding": [
1350 | {
1351 | "url": "https://github.com/sebastianbergmann",
1352 | "type": "github"
1353 | }
1354 | ],
1355 | "time": "2023-02-03T07:08:32+00:00"
1356 | },
1357 | {
1358 | "name": "sebastian/object-reflector",
1359 | "version": "3.0.0",
1360 | "source": {
1361 | "type": "git",
1362 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1363 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
1364 | },
1365 | "dist": {
1366 | "type": "zip",
1367 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
1368 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
1369 | "shasum": ""
1370 | },
1371 | "require": {
1372 | "php": ">=8.1"
1373 | },
1374 | "require-dev": {
1375 | "phpunit/phpunit": "^10.0"
1376 | },
1377 | "type": "library",
1378 | "extra": {
1379 | "branch-alias": {
1380 | "dev-main": "3.0-dev"
1381 | }
1382 | },
1383 | "autoload": {
1384 | "classmap": [
1385 | "src/"
1386 | ]
1387 | },
1388 | "notification-url": "https://packagist.org/downloads/",
1389 | "license": [
1390 | "BSD-3-Clause"
1391 | ],
1392 | "authors": [
1393 | {
1394 | "name": "Sebastian Bergmann",
1395 | "email": "sebastian@phpunit.de"
1396 | }
1397 | ],
1398 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1399 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1400 | "support": {
1401 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1402 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
1403 | },
1404 | "funding": [
1405 | {
1406 | "url": "https://github.com/sebastianbergmann",
1407 | "type": "github"
1408 | }
1409 | ],
1410 | "time": "2023-02-03T07:06:18+00:00"
1411 | },
1412 | {
1413 | "name": "sebastian/recursion-context",
1414 | "version": "5.0.0",
1415 | "source": {
1416 | "type": "git",
1417 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1418 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
1419 | },
1420 | "dist": {
1421 | "type": "zip",
1422 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712",
1423 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712",
1424 | "shasum": ""
1425 | },
1426 | "require": {
1427 | "php": ">=8.1"
1428 | },
1429 | "require-dev": {
1430 | "phpunit/phpunit": "^10.0"
1431 | },
1432 | "type": "library",
1433 | "extra": {
1434 | "branch-alias": {
1435 | "dev-main": "5.0-dev"
1436 | }
1437 | },
1438 | "autoload": {
1439 | "classmap": [
1440 | "src/"
1441 | ]
1442 | },
1443 | "notification-url": "https://packagist.org/downloads/",
1444 | "license": [
1445 | "BSD-3-Clause"
1446 | ],
1447 | "authors": [
1448 | {
1449 | "name": "Sebastian Bergmann",
1450 | "email": "sebastian@phpunit.de"
1451 | },
1452 | {
1453 | "name": "Jeff Welch",
1454 | "email": "whatthejeff@gmail.com"
1455 | },
1456 | {
1457 | "name": "Adam Harvey",
1458 | "email": "aharvey@php.net"
1459 | }
1460 | ],
1461 | "description": "Provides functionality to recursively process PHP variables",
1462 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1463 | "support": {
1464 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1465 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0"
1466 | },
1467 | "funding": [
1468 | {
1469 | "url": "https://github.com/sebastianbergmann",
1470 | "type": "github"
1471 | }
1472 | ],
1473 | "time": "2023-02-03T07:05:40+00:00"
1474 | },
1475 | {
1476 | "name": "sebastian/type",
1477 | "version": "4.0.0",
1478 | "source": {
1479 | "type": "git",
1480 | "url": "https://github.com/sebastianbergmann/type.git",
1481 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
1482 | },
1483 | "dist": {
1484 | "type": "zip",
1485 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
1486 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
1487 | "shasum": ""
1488 | },
1489 | "require": {
1490 | "php": ">=8.1"
1491 | },
1492 | "require-dev": {
1493 | "phpunit/phpunit": "^10.0"
1494 | },
1495 | "type": "library",
1496 | "extra": {
1497 | "branch-alias": {
1498 | "dev-main": "4.0-dev"
1499 | }
1500 | },
1501 | "autoload": {
1502 | "classmap": [
1503 | "src/"
1504 | ]
1505 | },
1506 | "notification-url": "https://packagist.org/downloads/",
1507 | "license": [
1508 | "BSD-3-Clause"
1509 | ],
1510 | "authors": [
1511 | {
1512 | "name": "Sebastian Bergmann",
1513 | "email": "sebastian@phpunit.de",
1514 | "role": "lead"
1515 | }
1516 | ],
1517 | "description": "Collection of value objects that represent the types of the PHP type system",
1518 | "homepage": "https://github.com/sebastianbergmann/type",
1519 | "support": {
1520 | "issues": "https://github.com/sebastianbergmann/type/issues",
1521 | "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
1522 | },
1523 | "funding": [
1524 | {
1525 | "url": "https://github.com/sebastianbergmann",
1526 | "type": "github"
1527 | }
1528 | ],
1529 | "time": "2023-02-03T07:10:45+00:00"
1530 | },
1531 | {
1532 | "name": "sebastian/version",
1533 | "version": "4.0.1",
1534 | "source": {
1535 | "type": "git",
1536 | "url": "https://github.com/sebastianbergmann/version.git",
1537 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
1538 | },
1539 | "dist": {
1540 | "type": "zip",
1541 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
1542 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
1543 | "shasum": ""
1544 | },
1545 | "require": {
1546 | "php": ">=8.1"
1547 | },
1548 | "type": "library",
1549 | "extra": {
1550 | "branch-alias": {
1551 | "dev-main": "4.0-dev"
1552 | }
1553 | },
1554 | "autoload": {
1555 | "classmap": [
1556 | "src/"
1557 | ]
1558 | },
1559 | "notification-url": "https://packagist.org/downloads/",
1560 | "license": [
1561 | "BSD-3-Clause"
1562 | ],
1563 | "authors": [
1564 | {
1565 | "name": "Sebastian Bergmann",
1566 | "email": "sebastian@phpunit.de",
1567 | "role": "lead"
1568 | }
1569 | ],
1570 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1571 | "homepage": "https://github.com/sebastianbergmann/version",
1572 | "support": {
1573 | "issues": "https://github.com/sebastianbergmann/version/issues",
1574 | "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
1575 | },
1576 | "funding": [
1577 | {
1578 | "url": "https://github.com/sebastianbergmann",
1579 | "type": "github"
1580 | }
1581 | ],
1582 | "time": "2023-02-07T11:34:05+00:00"
1583 | },
1584 | {
1585 | "name": "theseer/tokenizer",
1586 | "version": "1.2.3",
1587 | "source": {
1588 | "type": "git",
1589 | "url": "https://github.com/theseer/tokenizer.git",
1590 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
1591 | },
1592 | "dist": {
1593 | "type": "zip",
1594 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1595 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1596 | "shasum": ""
1597 | },
1598 | "require": {
1599 | "ext-dom": "*",
1600 | "ext-tokenizer": "*",
1601 | "ext-xmlwriter": "*",
1602 | "php": "^7.2 || ^8.0"
1603 | },
1604 | "type": "library",
1605 | "autoload": {
1606 | "classmap": [
1607 | "src/"
1608 | ]
1609 | },
1610 | "notification-url": "https://packagist.org/downloads/",
1611 | "license": [
1612 | "BSD-3-Clause"
1613 | ],
1614 | "authors": [
1615 | {
1616 | "name": "Arne Blankerts",
1617 | "email": "arne@blankerts.de",
1618 | "role": "Developer"
1619 | }
1620 | ],
1621 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1622 | "support": {
1623 | "issues": "https://github.com/theseer/tokenizer/issues",
1624 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
1625 | },
1626 | "funding": [
1627 | {
1628 | "url": "https://github.com/theseer",
1629 | "type": "github"
1630 | }
1631 | ],
1632 | "time": "2024-03-03T12:36:25+00:00"
1633 | }
1634 | ],
1635 | "aliases": [],
1636 | "minimum-stability": "stable",
1637 | "stability-flags": {},
1638 | "prefer-stable": false,
1639 | "prefer-lowest": false,
1640 | "platform": {
1641 | "php": ">=8.1"
1642 | },
1643 | "platform-dev": {},
1644 | "plugin-api-version": "2.6.0"
1645 | }
1646 |
--------------------------------------------------------------------------------