Merge pull request #18384 from kamil-tekiela/GisPolygon-shapes
Gis polygon shapes
This commit is contained in:
commit
25dd2fb236
63
libraries/classes/Gis/Ds/Point.php
Normal file
63
libraries/classes/Gis/Ds/Point.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis\Ds;
|
||||
|
||||
use function max;
|
||||
use function min;
|
||||
|
||||
final class Point
|
||||
{
|
||||
public function __construct(public readonly float $x, public readonly float $y)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given point is inside a given polygon.
|
||||
*/
|
||||
public function isInsidePolygon(Polygon $polygon): bool
|
||||
{
|
||||
$noOfPoints = $polygon->count();
|
||||
|
||||
// If first point is repeated at the end remove it
|
||||
if ($polygon->top() == $polygon->bottom()) {
|
||||
--$noOfPoints;
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
|
||||
// Use ray casting algorithm
|
||||
$p1 = $polygon->bottom();
|
||||
for ($i = 1; $i <= $noOfPoints; $i++) {
|
||||
$p2 = $polygon[$i % $noOfPoints];
|
||||
if ($this->y <= min($p1->y, $p2->y)) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->y > max($p1->y, $p2->y)) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->x > max($p1->x, $p2->x)) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($p1->y != $p2->y) {
|
||||
$xinters = ($this->y - $p1->y)
|
||||
* ($p2->x - $p1->x)
|
||||
/ ($p2->y - $p1->y) + $p1->x;
|
||||
if ($p1->x == $p2->x || $this->x <= $xinters) {
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
|
||||
$p1 = $p2;
|
||||
}
|
||||
|
||||
return $counter % 2 !== 0;
|
||||
}
|
||||
}
|
||||
132
libraries/classes/Gis/Ds/Polygon.php
Normal file
132
libraries/classes/Gis/Ds/Polygon.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis\Ds;
|
||||
|
||||
use SplDoublyLinkedList;
|
||||
|
||||
use function count;
|
||||
use function sqrt;
|
||||
|
||||
/** @extends SplDoublyLinkedList<Point> */
|
||||
final class Polygon extends SplDoublyLinkedList
|
||||
{
|
||||
/** @param non-empty-list<array{x: float, y: float}> $points */
|
||||
public static function fromXYArray(array $points): self
|
||||
{
|
||||
$polygon = new self();
|
||||
foreach ($points as $pointXY) {
|
||||
$polygon[] = new Point($pointXY['x'], $pointXY['y']);
|
||||
}
|
||||
|
||||
return $polygon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the area of a closed simple polygon.
|
||||
*/
|
||||
public function area(): float
|
||||
{
|
||||
$noOfPoints = $this->count();
|
||||
|
||||
// If the last point is same as the first point ignore it
|
||||
if ($this->top() == $this->bottom()) {
|
||||
--$noOfPoints;
|
||||
}
|
||||
|
||||
// _n-1
|
||||
// A = _1_ \ (X(i) * Y(i+1)) - (Y(i) * X(i+1))
|
||||
// 2 /__
|
||||
// i=0
|
||||
$area = 0;
|
||||
for ($i = 0; $i < $noOfPoints; $i++) {
|
||||
$j = ($i + 1) % $noOfPoints;
|
||||
$area += $this[$i]->x * $this[$j]->y;
|
||||
$area -= $this[$i]->y * $this[$j]->x;
|
||||
}
|
||||
|
||||
$area /= 2.0;
|
||||
|
||||
return $area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a set of points represents an outer ring.
|
||||
* If points are in clockwise orientation then, they form an outer ring.
|
||||
*/
|
||||
public function isOuterRing(): bool
|
||||
{
|
||||
// If area is negative then it's in clockwise orientation,
|
||||
// i.e. it's an outer ring
|
||||
return $this->area() < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a point that is guaranteed to be on the surface of the ring.
|
||||
* (for simple closed rings)
|
||||
*
|
||||
* @return Point|false a point on the surface of the ring
|
||||
*/
|
||||
public function getPointOnSurface(): Point|false
|
||||
{
|
||||
$points = $this->findTwoConsecutiveDistinctPoints();
|
||||
|
||||
if ($points === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pointPrev = $points[0];
|
||||
$pointNext = $points[1];
|
||||
|
||||
// Find the mid point
|
||||
$midPoint = new Point(($pointPrev->x + $pointNext->x) / 2, ($pointPrev->y + $pointNext->y) / 2);
|
||||
|
||||
// Always keep $epsilon < 1 to go with the reduction logic down here
|
||||
$epsilon = 0.1;
|
||||
$denominator = sqrt(($pointNext->y - $pointPrev->y) ** 2 + ($pointPrev->x - $pointNext->x) ** 2);
|
||||
|
||||
while (true) {
|
||||
// Get the points on either sides of the line
|
||||
// with a distance of epsilon to the mid point
|
||||
$x = $midPoint->x + ($epsilon * ($pointNext->y - $pointPrev->y)) / $denominator;
|
||||
$y = $midPoint->y + ($x - $midPoint->x) * ($pointPrev->x - $pointNext->x) / ($pointNext->y - $pointPrev->y);
|
||||
$pointA = new Point($x, $y);
|
||||
|
||||
$x = $midPoint->x + ($epsilon * ($pointNext->y - $pointPrev->y)) / (0 - $denominator);
|
||||
$y = $midPoint->y + ($x - $midPoint->x) * ($pointPrev->x - $pointNext->x) / ($pointNext->y - $pointPrev->y);
|
||||
$pointB = new Point($x, $y);
|
||||
|
||||
// One of the points should be inside the polygon,
|
||||
// unless epsilon chosen is too large
|
||||
if ($pointA->isInsidePolygon($this)) {
|
||||
return $pointA;
|
||||
}
|
||||
|
||||
if ($pointB->isInsidePolygon($this)) {
|
||||
return $pointB;
|
||||
}
|
||||
|
||||
//If both are outside the polygon reduce the epsilon and
|
||||
//recalculate the points(reduce exponentially for faster convergence)
|
||||
$epsilon **= 2;
|
||||
if ($epsilon == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array{Point, Point}|false */
|
||||
private function findTwoConsecutiveDistinctPoints(): array|false
|
||||
{
|
||||
for ($i = 0, $nb = count($this) - 1; $i < $nb; $i++) {
|
||||
$pointPrev = $this->offsetGet($i);
|
||||
$pointNext = $this->offsetGet($i + 1);
|
||||
if ($pointPrev->y !== $pointNext->y) {
|
||||
return [$pointNext, $pointPrev];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
namespace PhpMyAdmin\Gis\Ds;
|
||||
|
||||
use function max;
|
||||
use function min;
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ declare(strict_types=1);
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use ErrorException;
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\Polygon;
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
@ -348,20 +350,22 @@ class GisMultiPolygon extends GisGeometry
|
||||
*/
|
||||
public function getShape(array $rowData): string
|
||||
{
|
||||
// Determines whether each line ring is an inner ring or an outer ring.
|
||||
// If it's an inner ring get a point on the surface which can be used to
|
||||
// correctly classify inner rings to their respective outer rings.
|
||||
// Buffer polygons for further use
|
||||
/** @var Polygon[] $polygons */
|
||||
$polygons = [];
|
||||
foreach ($rowData['parts'] as $i => $ring) {
|
||||
$rowData['parts'][$i]['isOuter'] = GisPolygon::isOuterRing($ring['points']);
|
||||
}
|
||||
$polygons[$i] = Polygon::fromXYArray($ring['points']);
|
||||
|
||||
// Find points on surface for inner rings
|
||||
foreach ($rowData['parts'] as $i => $ring) {
|
||||
if ($ring['isOuter']) {
|
||||
// Determines whether each line ring is an inner ring or an outer ring.
|
||||
// If it's an inner ring get a point on the surface which can be used to
|
||||
// correctly classify inner rings to their respective outer rings.
|
||||
$rowData['parts'][$i]['isOuter'] = $polygons[$i]->isOuterRing();
|
||||
if ($rowData['parts'][$i]['isOuter']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowData['parts'][$i]['pointOnSurface'] = GisPolygon::getPointOnSurface($ring['points']);
|
||||
// Find points on surface for inner rings
|
||||
$rowData['parts'][$i]['pointOnSurface'] = $polygons[$i]->getPointOnSurface();
|
||||
}
|
||||
|
||||
// Classify inner rings to their respective outer rings.
|
||||
@ -377,7 +381,7 @@ class GisMultiPolygon extends GisGeometry
|
||||
|
||||
// If the pointOnSurface of the inner ring
|
||||
// is also inside the outer ring
|
||||
if (! GisPolygon::isPointInsidePolygon($ring1['pointOnSurface'], $ring2['points'])) {
|
||||
if (! $ring1['pointOnSurface']->isInsidePolygon($polygons[$k])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
@ -15,12 +16,9 @@ use function array_slice;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function json_encode;
|
||||
use function max;
|
||||
use function mb_substr;
|
||||
use function min;
|
||||
use function round;
|
||||
use function sprintf;
|
||||
use function sqrt;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
@ -293,170 +291,6 @@ class GisPolygon extends GisGeometry
|
||||
return $wkt . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the area of a closed simple polygon.
|
||||
*
|
||||
* @param mixed[] $ring array of points forming the ring
|
||||
*
|
||||
* @return float the area of a closed simple polygon
|
||||
*/
|
||||
public static function area(array $ring): float
|
||||
{
|
||||
$noOfPoints = count($ring);
|
||||
|
||||
// If the last point is same as the first point ignore it
|
||||
$last = count($ring) - 1;
|
||||
if (($ring[0]['x'] == $ring[$last]['x']) && ($ring[0]['y'] == $ring[$last]['y'])) {
|
||||
$noOfPoints--;
|
||||
}
|
||||
|
||||
// _n-1
|
||||
// A = _1_ \ (X(i) * Y(i+1)) - (Y(i) * X(i+1))
|
||||
// 2 /__
|
||||
// i=0
|
||||
$area = 0;
|
||||
for ($i = 0; $i < $noOfPoints; $i++) {
|
||||
$j = ($i + 1) % $noOfPoints;
|
||||
$area += $ring[$i]['x'] * $ring[$j]['y'];
|
||||
$area -= $ring[$i]['y'] * $ring[$j]['x'];
|
||||
}
|
||||
|
||||
$area /= 2.0;
|
||||
|
||||
return $area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a set of points represents an outer ring.
|
||||
* If points are in clockwise orientation then, they form an outer ring.
|
||||
*
|
||||
* @param mixed[] $ring array of points forming the ring
|
||||
*/
|
||||
public static function isOuterRing(array $ring): bool
|
||||
{
|
||||
// If area is negative then it's in clockwise orientation,
|
||||
// i.e. it's an outer ring
|
||||
return self::area($ring) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given point is inside a given polygon.
|
||||
*
|
||||
* @param mixed[] $point x, y coordinates of the point
|
||||
* @param mixed[] $polygon array of points forming the ring
|
||||
*/
|
||||
public static function isPointInsidePolygon(array $point, array $polygon): bool
|
||||
{
|
||||
// If first point is repeated at the end remove it
|
||||
$last = count($polygon) - 1;
|
||||
if (($polygon[0]['x'] == $polygon[$last]['x']) && ($polygon[0]['y'] == $polygon[$last]['y'])) {
|
||||
$polygon = array_slice($polygon, 0, $last);
|
||||
}
|
||||
|
||||
$noOfPoints = count($polygon);
|
||||
$counter = 0;
|
||||
|
||||
// Use ray casting algorithm
|
||||
$p1 = $polygon[0];
|
||||
for ($i = 1; $i <= $noOfPoints; $i++) {
|
||||
$p2 = $polygon[$i % $noOfPoints];
|
||||
if ($point['y'] <= min([$p1['y'], $p2['y']])) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($point['y'] > max([$p1['y'], $p2['y']])) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($point['x'] > max([$p1['x'], $p2['x']])) {
|
||||
$p1 = $p2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($p1['y'] != $p2['y']) {
|
||||
$xinters = ($point['y'] - $p1['y'])
|
||||
* ($p2['x'] - $p1['x'])
|
||||
/ ($p2['y'] - $p1['y']) + $p1['x'];
|
||||
if ($p1['x'] == $p2['x'] || $point['x'] <= $xinters) {
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
|
||||
$p1 = $p2;
|
||||
}
|
||||
|
||||
return $counter % 2 != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a point that is guaranteed to be on the surface of the ring.
|
||||
* (for simple closed rings)
|
||||
*
|
||||
* @param mixed[] $ring array of points forming the ring
|
||||
*
|
||||
* @return mixed[]|false a point on the surface of the ring
|
||||
*/
|
||||
public static function getPointOnSurface(array $ring): array|false
|
||||
{
|
||||
$x0 = null;
|
||||
$x1 = null;
|
||||
$y0 = null;
|
||||
$y1 = null;
|
||||
// Find two consecutive distinct points.
|
||||
for ($i = 0, $nb = count($ring) - 1; $i < $nb; $i++) {
|
||||
if ($ring[$i]['y'] != $ring[$i + 1]['y']) {
|
||||
$x0 = $ring[$i]['x'];
|
||||
$x1 = $ring[$i + 1]['x'];
|
||||
$y0 = $ring[$i]['y'];
|
||||
$y1 = $ring[$i + 1]['y'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! isset($x0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the mid point
|
||||
$x2 = ($x0 + $x1) / 2;
|
||||
$y2 = ($y0 + $y1) / 2;
|
||||
|
||||
// Always keep $epsilon < 1 to go with the reduction logic down here
|
||||
$epsilon = 0.1;
|
||||
$denominator = sqrt(($y1 - $y0) ** 2 + ($x0 - $x1) ** 2);
|
||||
$pointA = [];
|
||||
$pointB = [];
|
||||
|
||||
while (true) {
|
||||
// Get the points on either sides of the line
|
||||
// with a distance of epsilon to the mid point
|
||||
$pointA['x'] = $x2 + ($epsilon * ($y1 - $y0)) / $denominator;
|
||||
$pointA['y'] = $y2 + ($pointA['x'] - $x2) * ($x0 - $x1) / ($y1 - $y0);
|
||||
|
||||
$pointB['x'] = $x2 + ($epsilon * ($y1 - $y0)) / (0 - $denominator);
|
||||
$pointB['y'] = $y2 + ($pointB['x'] - $x2) * ($x0 - $x1) / ($y1 - $y0);
|
||||
|
||||
// One of the points should be inside the polygon,
|
||||
// unless epsilon chosen is too large
|
||||
if (self::isPointInsidePolygon($pointA, $ring)) {
|
||||
return $pointA;
|
||||
}
|
||||
|
||||
if (self::isPointInsidePolygon($pointB, $ring)) {
|
||||
return $pointB;
|
||||
}
|
||||
|
||||
//If both are outside the polygon reduce the epsilon and
|
||||
//recalculate the points(reduce exponentially for faster convergence)
|
||||
$epsilon **= 2;
|
||||
if ($epsilon == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate coordinate parameters for the GIS data editor from the value of the GIS column.
|
||||
*
|
||||
|
||||
@ -8,6 +8,7 @@ declare(strict_types=1);
|
||||
namespace PhpMyAdmin\Gis;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
@ -3922,7 +3922,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
|
||||
count: 8
|
||||
count: 7
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
@ -3967,7 +3967,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'points' on mixed\\.$#"
|
||||
count: 5
|
||||
count: 3
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
@ -3997,6 +3997,11 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset mixed on mixed\\.$#"
|
||||
count: 2
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method isInsidePolygon\\(\\) on mixed\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
@ -4005,23 +4010,13 @@ parameters:
|
||||
count: 2
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$point of static method PhpMyAdmin\\\\Gis\\\\GisPolygon\\:\\:isPointInsidePolygon\\(\\) expects array, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$points of method PhpMyAdmin\\\\Image\\\\ImageWrapper\\:\\:filledPolygon\\(\\) expects array\\<int, int\\>, array\\<float\\> given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$ring of static method PhpMyAdmin\\\\Gis\\\\GisPolygon\\:\\:getPointOnSurface\\(\\) expects array, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$ring of static method PhpMyAdmin\\\\Gis\\\\GisPolygon\\:\\:isOuterRing\\(\\) expects array, mixed given\\.$#"
|
||||
message: "#^Parameter \\#1 \\$points of static method PhpMyAdmin\\\\Gis\\\\Ds\\\\Polygon\\:\\:fromXYArray\\(\\) expects non\\-empty\\-array\\<int, array\\{x\\: float, y\\: float\\}\\>, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
@ -4030,11 +4025,6 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$polygon of static method PhpMyAdmin\\\\Gis\\\\GisPolygon\\:\\:isPointInsidePolygon\\(\\) expects array, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Gis/GisMultiPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#5 \\$color of method PhpMyAdmin\\\\Image\\\\ImageWrapper\\:\\:string\\(\\) expects int, int\\|false given\\.$#"
|
||||
count: 1
|
||||
@ -4092,12 +4082,12 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'x' on mixed\\.$#"
|
||||
count: 18
|
||||
count: 3
|
||||
path: libraries/classes/Gis/GisPolygon.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'y' on mixed\\.$#"
|
||||
count: 22
|
||||
count: 3
|
||||
path: libraries/classes/Gis/GisPolygon.php
|
||||
|
||||
-
|
||||
@ -8965,6 +8955,16 @@ parameters:
|
||||
count: 1
|
||||
path: test/classes/ErrorHandlerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'no_of_points' on mixed\\.$#"
|
||||
count: 2
|
||||
path: test/classes/Gis/Ds/PolygonTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$points of static method PhpMyAdmin\\\\Gis\\\\Ds\\\\Polygon\\:\\:fromXYArray\\(\\) expects non\\-empty\\-array\\<int, array\\{x\\: float, y\\: float\\}\\>, mixed given\\.$#"
|
||||
count: 2
|
||||
path: test/classes/Gis/Ds/PolygonTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'no_of_lines' on mixed\\.$#"
|
||||
count: 1
|
||||
@ -8977,7 +8977,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'no_of_points' on mixed\\.$#"
|
||||
count: 3
|
||||
count: 1
|
||||
path: test/classes/Gis/GisPolygonTest.php
|
||||
|
||||
-
|
||||
|
||||
@ -6363,6 +6363,11 @@
|
||||
<code>mixed</code>
|
||||
</UnusedReturnValue>
|
||||
</file>
|
||||
<file src="libraries/classes/Gis/Ds/Polygon.php">
|
||||
<NullArgument>
|
||||
<code>$polygon</code>
|
||||
</NullArgument>
|
||||
</file>
|
||||
<file src="libraries/classes/Gis/GisGeometry.php">
|
||||
<MixedOperand>
|
||||
<code><![CDATA[$scaleData['height']]]></code>
|
||||
@ -6504,9 +6509,6 @@
|
||||
<code>$labelPoint[0]</code>
|
||||
<code>$labelPoint[1]</code>
|
||||
<code>$labelPoint[1]</code>
|
||||
<code><![CDATA[$ring1['pointOnSurface']]]></code>
|
||||
<code><![CDATA[$ring2['points']]]></code>
|
||||
<code><![CDATA[$ring['points']]]></code>
|
||||
<code><![CDATA[$ring['points']]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArrayAccess>
|
||||
@ -6528,11 +6530,8 @@
|
||||
<code><![CDATA[$ring1['isOuter']]]></code>
|
||||
<code><![CDATA[$ring1['pointOnSurface']]]></code>
|
||||
<code><![CDATA[$ring2['isOuter']]]></code>
|
||||
<code><![CDATA[$ring2['points']]]></code>
|
||||
<code><![CDATA[$ring['inner']]]></code>
|
||||
<code><![CDATA[$ring['isOuter']]]></code>
|
||||
<code><![CDATA[$ring['isOuter']]]></code>
|
||||
<code><![CDATA[$ring['points']]]></code>
|
||||
<code><![CDATA[$ring['points']]]></code>
|
||||
<code><![CDATA[$ring['points']]]></code>
|
||||
<code><![CDATA[$rowData['parts'][$j]]]></code>
|
||||
@ -6549,6 +6548,8 @@
|
||||
<code><![CDATA[$rowData['parts'][$k]['inner']]]></code>
|
||||
</MixedArrayAssignment>
|
||||
<MixedArrayOffset>
|
||||
<code>$polygons[$i]</code>
|
||||
<code>$polygons[$k]</code>
|
||||
<code><![CDATA[$rowData['parts'][$i]]]></code>
|
||||
<code><![CDATA[$rowData['parts'][$i]]]></code>
|
||||
<code><![CDATA[$rowData['parts'][$j]]]></code>
|
||||
@ -6558,7 +6559,6 @@
|
||||
<MixedAssignment>
|
||||
<code>$dataRow</code>
|
||||
<code>$i</code>
|
||||
<code>$i</code>
|
||||
<code>$innerPoint</code>
|
||||
<code>$j</code>
|
||||
<code>$j</code>
|
||||
@ -6569,11 +6569,13 @@
|
||||
<code>$point</code>
|
||||
<code>$ring</code>
|
||||
<code>$ring</code>
|
||||
<code>$ring</code>
|
||||
<code>$ring1</code>
|
||||
<code>$ring2</code>
|
||||
<code><![CDATA[$rowData['parts'][$k]['inner'][]]]></code>
|
||||
</MixedAssignment>
|
||||
<MixedMethodCall>
|
||||
<code>isInsidePolygon</code>
|
||||
</MixedMethodCall>
|
||||
<MixedOperand>
|
||||
<code><![CDATA[$innerPoint['x']]]></code>
|
||||
<code><![CDATA[$innerPoint['y']]]></code>
|
||||
@ -6623,110 +6625,17 @@
|
||||
<ArgumentTypeCoercion>
|
||||
<code>$pointsArr</code>
|
||||
</ArgumentTypeCoercion>
|
||||
<MixedArgument>
|
||||
<code>($y1 - $y0) ** 2 + ($x0 - $x1) ** 2</code>
|
||||
</MixedArgument>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$gisData[$index]['POLYGON']]]></code>
|
||||
<code><![CDATA[$gisData[$index]['POLYGON'][$i]]]></code>
|
||||
<code><![CDATA[$gisData[$index]['POLYGON'][$i]['no_of_points']]]></code>
|
||||
<code><![CDATA[$gisData[$index]['POLYGON']['no_of_lines']]]></code>
|
||||
<code><![CDATA[$p1['x']]]></code>
|
||||
<code><![CDATA[$p1['x']]]></code>
|
||||
<code><![CDATA[$p1['x']]]></code>
|
||||
<code><![CDATA[$p1['x']]]></code>
|
||||
<code><![CDATA[$p1['y']]]></code>
|
||||
<code><![CDATA[$p1['y']]]></code>
|
||||
<code><![CDATA[$p1['y']]]></code>
|
||||
<code><![CDATA[$p1['y']]]></code>
|
||||
<code><![CDATA[$p1['y']]]></code>
|
||||
<code><![CDATA[$p2['x']]]></code>
|
||||
<code><![CDATA[$p2['x']]]></code>
|
||||
<code><![CDATA[$p2['x']]]></code>
|
||||
<code><![CDATA[$p2['y']]]></code>
|
||||
<code><![CDATA[$p2['y']]]></code>
|
||||
<code><![CDATA[$p2['y']]]></code>
|
||||
<code><![CDATA[$p2['y']]]></code>
|
||||
<code><![CDATA[$polygon[$last]['x']]]></code>
|
||||
<code><![CDATA[$polygon[$last]['y']]]></code>
|
||||
<code><![CDATA[$polygon[0]['x']]]></code>
|
||||
<code><![CDATA[$polygon[0]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i + 1]['x']]]></code>
|
||||
<code><![CDATA[$ring[$i + 1]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i + 1]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i]['x']]]></code>
|
||||
<code><![CDATA[$ring[$i]['x']]]></code>
|
||||
<code><![CDATA[$ring[$i]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i]['y']]]></code>
|
||||
<code><![CDATA[$ring[$j]['x']]]></code>
|
||||
<code><![CDATA[$ring[$j]['y']]]></code>
|
||||
<code><![CDATA[$ring[$last]['x']]]></code>
|
||||
<code><![CDATA[$ring[$last]['y']]]></code>
|
||||
<code><![CDATA[$ring[0]['x']]]></code>
|
||||
<code><![CDATA[$ring[0]['y']]]></code>
|
||||
</MixedArrayAccess>
|
||||
<MixedAssignment>
|
||||
<code>$area</code>
|
||||
<code>$area</code>
|
||||
<code>$area</code>
|
||||
<code>$noOfLines</code>
|
||||
<code>$noOfPoints</code>
|
||||
<code>$p1</code>
|
||||
<code>$p1</code>
|
||||
<code>$p1</code>
|
||||
<code>$p1</code>
|
||||
<code>$p1</code>
|
||||
<code>$p2</code>
|
||||
<code><![CDATA[$pointA['x']]]></code>
|
||||
<code><![CDATA[$pointA['y']]]></code>
|
||||
<code><![CDATA[$pointB['x']]]></code>
|
||||
<code><![CDATA[$pointB['y']]]></code>
|
||||
<code>$x0</code>
|
||||
<code>$x1</code>
|
||||
<code>$x2</code>
|
||||
<code>$xinters</code>
|
||||
<code>$y0</code>
|
||||
<code>$y1</code>
|
||||
<code>$y2</code>
|
||||
</MixedAssignment>
|
||||
<MixedInferredReturnType>
|
||||
<code>float</code>
|
||||
</MixedInferredReturnType>
|
||||
<MixedOperand>
|
||||
<code>$area</code>
|
||||
<code>$area</code>
|
||||
<code>$epsilon * ($y1 - $y0)</code>
|
||||
<code>$epsilon * ($y1 - $y0)</code>
|
||||
<code><![CDATA[$p2['x']]]></code>
|
||||
<code><![CDATA[$p2['y']]]></code>
|
||||
<code><![CDATA[$pointA['x']]]></code>
|
||||
<code><![CDATA[$pointB['x']]]></code>
|
||||
<code><![CDATA[$point['y']]]></code>
|
||||
<code><![CDATA[$ring[$i]['x']]]></code>
|
||||
<code><![CDATA[$ring[$i]['x'] * $ring[$j]['y']]]></code>
|
||||
<code><![CDATA[$ring[$i]['y']]]></code>
|
||||
<code>$x0</code>
|
||||
<code>$x0</code>
|
||||
<code>$x0</code>
|
||||
<code>$x0</code>
|
||||
<code>$x2</code>
|
||||
<code>$x2</code>
|
||||
<code>$y0</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1 - $y0</code>
|
||||
<code>$y1 - $y0</code>
|
||||
<code>$y2</code>
|
||||
<code>$y2</code>
|
||||
<code><![CDATA[($pointA['x'] - $x2) * ($x0 - $x1)]]></code>
|
||||
<code><![CDATA[($pointB['x'] - $x2) * ($x0 - $x1)]]></code>
|
||||
<code><![CDATA[($point['y'] - $p1['y'])
|
||||
* ($p2['x'] - $p1['x'])]]></code>
|
||||
<code>($y1 - $y0) ** 2</code>
|
||||
<code><![CDATA[isset($gisData[$index]['POLYGON'][$i][$j]['x'])
|
||||
&& trim((string) $gisData[$index]['POLYGON'][$i][$j]['x']) != ''
|
||||
? $gisData[$index]['POLYGON'][$i][$j]['x'] : $empty]]></code>
|
||||
@ -6734,31 +6643,10 @@
|
||||
&& trim((string) $gisData[$index]['POLYGON'][$i][$j]['y']) != ''
|
||||
? $gisData[$index]['POLYGON'][$i][$j]['y'] : $empty]]></code>
|
||||
</MixedOperand>
|
||||
<MixedReturnStatement>
|
||||
<code>$area</code>
|
||||
</MixedReturnStatement>
|
||||
<PossiblyFalseArgument>
|
||||
<code>$black</code>
|
||||
<code>$fillColor</code>
|
||||
</PossiblyFalseArgument>
|
||||
<PossiblyNullOperand>
|
||||
<code>$x1</code>
|
||||
<code>$x1</code>
|
||||
<code>$x1</code>
|
||||
<code>$x1</code>
|
||||
<code>$y0</code>
|
||||
<code>$y0</code>
|
||||
<code>$y0</code>
|
||||
<code>$y0</code>
|
||||
<code>$y0</code>
|
||||
<code>$y0</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
<code>$y1</code>
|
||||
</PossiblyNullOperand>
|
||||
<RedundantPropertyInitializationCheck>
|
||||
<code>isset(self::$instance)</code>
|
||||
</RedundantPropertyInitializationCheck>
|
||||
@ -13910,6 +13798,19 @@
|
||||
<code>$privates</code>
|
||||
</PossiblyUnusedProperty>
|
||||
</file>
|
||||
<file src="test/classes/Gis/Ds/PolygonTest.php">
|
||||
<MixedArgument>
|
||||
<code><![CDATA[$temp['POLYGON'][0]]]></code>
|
||||
<code><![CDATA[$temp['POLYGON'][1]]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$temp['POLYGON'][0]['no_of_points']]]></code>
|
||||
<code><![CDATA[$temp['POLYGON'][1]['no_of_points']]]></code>
|
||||
</MixedArrayAccess>
|
||||
<PossiblyInvalidArgument>
|
||||
<code>testGetPointOnSurface</code>
|
||||
</PossiblyInvalidArgument>
|
||||
</file>
|
||||
<file src="test/classes/Gis/GisGeometryTest.php">
|
||||
<DeprecatedMethod>
|
||||
<code>getMockForAbstractClass</code>
|
||||
@ -13922,12 +13823,7 @@
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$temp1[0]['POLYGON'][1][3]]]></code>
|
||||
<code><![CDATA[$temp1[0]['POLYGON'][1][3]['y']]]></code>
|
||||
<code><![CDATA[$temp['POLYGON'][0]['no_of_points']]]></code>
|
||||
<code><![CDATA[$temp['POLYGON'][1]['no_of_points']]]></code>
|
||||
</MixedArrayAccess>
|
||||
<PossiblyInvalidArgument>
|
||||
<code>testGetPointOnSurface</code>
|
||||
</PossiblyInvalidArgument>
|
||||
</file>
|
||||
<file src="test/classes/Gis/GisVisualizationTest.php">
|
||||
<MixedAssignment>
|
||||
|
||||
185
test/classes/Gis/Ds/PolygonTest.php
Normal file
185
test/classes/Gis/Ds/PolygonTest.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis\Ds;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\Point;
|
||||
use PhpMyAdmin\Gis\Ds\Polygon;
|
||||
use PhpMyAdmin\Tests\AbstractTestCase;
|
||||
|
||||
/** @covers \PhpMyAdmin\Ds\Polygon */
|
||||
class PolygonTest extends AbstractTestCase
|
||||
{
|
||||
/**
|
||||
* Provide some common data to data providers
|
||||
*
|
||||
* @return mixed[][]
|
||||
*/
|
||||
private static function getData(): array
|
||||
{
|
||||
return [
|
||||
'POLYGON' => [
|
||||
'no_of_lines' => 2,
|
||||
0 => [
|
||||
'no_of_points' => 5,
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 20],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
3 => ['x' => 45, 'y' => 45],
|
||||
4 => ['x' => 35, 'y' => 10],
|
||||
],
|
||||
1 => [
|
||||
'no_of_points' => 4,
|
||||
0 => ['x' => 20, 'y' => 30],
|
||||
1 => ['x' => 35, 'y' => 32],
|
||||
2 => ['x' => 30, 'y' => 20],
|
||||
3 => ['x' => 20, 'y' => 30],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for Area
|
||||
*
|
||||
* @dataProvider providerForTestArea
|
||||
*/
|
||||
public function testArea(Polygon $ring, float $area): void
|
||||
{
|
||||
$this->assertEquals($area, $ring->area());
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testArea
|
||||
*
|
||||
* @return list<array{Polygon, float}>
|
||||
*/
|
||||
public static function providerForTestArea(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
Polygon::fromXYArray([
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
]),
|
||||
-375.00,
|
||||
],
|
||||
// first point of the ring repeated as the last point
|
||||
[
|
||||
Polygon::fromXYArray([
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
3 => ['x' => 35, 'y' => 10],
|
||||
]),
|
||||
-375.00,
|
||||
],
|
||||
// anticlockwise gives positive area
|
||||
[
|
||||
Polygon::fromXYArray([
|
||||
0 => ['x' => 15, 'y' => 40],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 35, 'y' => 10],
|
||||
]),
|
||||
375.00,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for isPointInsidePolygon
|
||||
*
|
||||
* @dataProvider providerForTestIsPointInsidePolygon
|
||||
*/
|
||||
public function testIsPointInsidePolygon(Point $point, Polygon $polygon, bool $isInside): void
|
||||
{
|
||||
$this->assertEquals($isInside, $point->isInsidePolygon($polygon));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testIsPointInsidePolygon
|
||||
*
|
||||
* @return array<array{Point, Polygon, bool}>
|
||||
*/
|
||||
public static function providerForTestIsPointInsidePolygon(): array
|
||||
{
|
||||
$ring = Polygon::fromXYArray([
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
3 => ['x' => 35, 'y' => 10],
|
||||
]);
|
||||
|
||||
return [
|
||||
// point inside the ring
|
||||
[new Point(20, 15), $ring, true],
|
||||
// point on an edge of the ring
|
||||
[new Point(20, 10), $ring, false],
|
||||
// point on a vertex of the ring
|
||||
[new Point(10, 10), $ring, false],
|
||||
// point outside the ring
|
||||
[new Point(5, 10), $ring, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for getPointOnSurface
|
||||
*
|
||||
* @param Polygon $ring array of points forming the ring
|
||||
*
|
||||
* @dataProvider providerForTestGetPointOnSurface
|
||||
*/
|
||||
public function testGetPointOnSurface(Polygon $ring): void
|
||||
{
|
||||
$point = $ring->getPointOnSurface();
|
||||
$this->assertInstanceOf(Point::class, $point);
|
||||
$this->assertTrue($point->isInsidePolygon($ring));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testGetPointOnSurface
|
||||
*
|
||||
* @return list{list{mixed}, list{mixed}}
|
||||
*/
|
||||
public static function providerForTestGetPointOnSurface(): array
|
||||
{
|
||||
$temp = self::getData();
|
||||
unset($temp['POLYGON'][0]['no_of_points']);
|
||||
unset($temp['POLYGON'][1]['no_of_points']);
|
||||
|
||||
return [[Polygon::fromXYArray($temp['POLYGON'][0])], [Polygon::fromXYArray($temp['POLYGON'][1])]];
|
||||
}
|
||||
|
||||
/**
|
||||
* test case for isOuterRing() method
|
||||
*
|
||||
* @param Polygon $ring coordinates of the points in a ring
|
||||
*
|
||||
* @dataProvider providerForIsOuterRing
|
||||
*/
|
||||
public function testIsOuterRing(Polygon $ring): void
|
||||
{
|
||||
$this->assertTrue($ring->isOuterRing());
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testIsOuterRing() test case
|
||||
*
|
||||
* @return array<array{Polygon}>
|
||||
*/
|
||||
public static function providerForIsOuterRing(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
Polygon::fromXYArray([
|
||||
['x' => 0, 'y' => 0],
|
||||
['x' => 0, 'y' => 1],
|
||||
['x' => 1, 'y' => 1],
|
||||
['x' => 1, 'y' => 0],
|
||||
]),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisGeometryCollection;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisGeometry;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Tests\AbstractTestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisLineString;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisMultiLineString;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisMultiPoint;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisMultiPolygon;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisPoint;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Gis;
|
||||
|
||||
use PhpMyAdmin\Gis\Ds\ScaleData;
|
||||
use PhpMyAdmin\Gis\GisPolygon;
|
||||
use PhpMyAdmin\Gis\ScaleData;
|
||||
use PhpMyAdmin\Image\ImageWrapper;
|
||||
use TCPDF;
|
||||
|
||||
@ -123,114 +123,6 @@ class GisPolygonTest extends GisGeomTestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for Area
|
||||
*
|
||||
* @param mixed[] $ring array of points forming the ring
|
||||
* @param float $area area of the ring
|
||||
*
|
||||
* @dataProvider providerForTestArea
|
||||
*/
|
||||
public function testArea(array $ring, float $area): void
|
||||
{
|
||||
$object = GisPolygon::singleton();
|
||||
$this->assertEquals($area, $object->area($ring));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testArea
|
||||
*
|
||||
* @return array<array{mixed[], float}>
|
||||
*/
|
||||
public static function providerForTestArea(): array
|
||||
{
|
||||
return [
|
||||
[[0 => ['x' => 35, 'y' => 10], 1 => ['x' => 10, 'y' => 10], 2 => ['x' => 15, 'y' => 40]], -375.00],
|
||||
// first point of the ring repeated as the last point
|
||||
[
|
||||
[
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
3 => ['x' => 35, 'y' => 10],
|
||||
],
|
||||
-375.00,
|
||||
],
|
||||
// anticlockwise gives positive area
|
||||
[[0 => ['x' => 15, 'y' => 40], 1 => ['x' => 10, 'y' => 10], 2 => ['x' => 35, 'y' => 10]], 375.00],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for isPointInsidePolygon
|
||||
*
|
||||
* @param mixed[] $point x, y coordinates of the point
|
||||
* @param mixed[] $polygon array of points forming the ring
|
||||
* @param bool $isInside output
|
||||
*
|
||||
* @dataProvider providerForTestIsPointInsidePolygon
|
||||
*/
|
||||
public function testIsPointInsidePolygon(array $point, array $polygon, bool $isInside): void
|
||||
{
|
||||
$object = GisPolygon::singleton();
|
||||
$this->assertEquals($isInside, $object->isPointInsidePolygon($point, $polygon));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testIsPointInsidePolygon
|
||||
*
|
||||
* @return array<array{mixed[], mixed[], bool}>
|
||||
*/
|
||||
public static function providerForTestIsPointInsidePolygon(): array
|
||||
{
|
||||
$ring = [
|
||||
0 => ['x' => 35, 'y' => 10],
|
||||
1 => ['x' => 10, 'y' => 10],
|
||||
2 => ['x' => 15, 'y' => 40],
|
||||
3 => ['x' => 35, 'y' => 10],
|
||||
];
|
||||
|
||||
return [
|
||||
// point inside the ring
|
||||
[['x' => 20, 'y' => 15], $ring, true],
|
||||
// point on an edge of the ring
|
||||
[['x' => 20, 'y' => 10], $ring, false],
|
||||
// point on a vertex of the ring
|
||||
[['x' => 10, 'y' => 10], $ring, false],
|
||||
// point outside the ring
|
||||
[['x' => 5, 'y' => 10], $ring, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test for getPointOnSurface
|
||||
*
|
||||
* @param mixed[] $ring array of points forming the ring
|
||||
*
|
||||
* @dataProvider providerForTestGetPointOnSurface
|
||||
*/
|
||||
public function testGetPointOnSurface(array $ring): void
|
||||
{
|
||||
$object = GisPolygon::singleton();
|
||||
$point = $object->getPointOnSurface($ring);
|
||||
$this->assertIsArray($point);
|
||||
$this->assertTrue($object->isPointInsidePolygon($point, $ring));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testGetPointOnSurface
|
||||
*
|
||||
* @return list{list{mixed}, list{mixed}}
|
||||
*/
|
||||
public static function providerForTestGetPointOnSurface(): array
|
||||
{
|
||||
$temp = self::getData();
|
||||
unset($temp['POLYGON'][0]['no_of_points']);
|
||||
unset($temp['POLYGON'][1]['no_of_points']);
|
||||
|
||||
return [[$temp['POLYGON'][0]], [$temp['POLYGON'][1]]];
|
||||
}
|
||||
|
||||
/**
|
||||
* test scaleRow method
|
||||
*
|
||||
@ -413,27 +305,4 @@ class GisPolygonTest extends GisGeomTestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test case for isOuterRing() method
|
||||
*
|
||||
* @param array<array<string, int>> $ring coordinates of the points in a ring
|
||||
*
|
||||
* @dataProvider providerForIsOuterRing
|
||||
*/
|
||||
public function testIsOuterRing(array $ring): void
|
||||
{
|
||||
$object = GisPolygon::singleton();
|
||||
$this->assertTrue($object->isOuterRing($ring));
|
||||
}
|
||||
|
||||
/**
|
||||
* data provider for testIsOuterRing() test case
|
||||
*
|
||||
* @return array<array{array<array<string, int>>}>
|
||||
*/
|
||||
public static function providerForIsOuterRing(): array
|
||||
{
|
||||
return [[[['x' => 0, 'y' => 0], ['x' => 0, 'y' => 1], ['x' => 1, 'y' => 1], ['x' => 1, 'y' => 0]]]];
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user