Simplify gis polygon handling (#17904)
[phpmyadmin.git] / test / classes / Gis / GisPolygonTest.php
blobe936b437014e25e6301cb90caf2a85b51d671f58
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin\Tests\Gis;
7 use PhpMyAdmin\Gis\GisPolygon;
8 use PhpMyAdmin\Image\ImageWrapper;
9 use TCPDF;
11 /**
12 * @covers \PhpMyAdmin\Gis\GisPolygon
13 * @runTestsInSeparateProcesses
14 * @preserveGlobalState disabled
16 class GisPolygonTest extends GisGeomTestCase
18 /** @var GisPolygon */
19 protected $object;
21 /**
22 * Sets up the fixture, for example, opens a network connection.
23 * This method is called before a test is executed.
25 protected function setUp(): void
27 parent::setUp();
28 $this->object = GisPolygon::singleton();
31 /**
32 * Tears down the fixture, for example, closes a network connection.
33 * This method is called after a test is executed.
35 protected function tearDown(): void
37 parent::tearDown();
38 unset($this->object);
41 /**
42 * Provide some common data to data providers
44 * @return array common data for data providers
46 private function getData(): array
48 return [
49 'POLYGON' => [
50 'no_of_lines' => 2,
51 0 => [
52 'no_of_points' => 5,
53 0 => [
54 'x' => 35,
55 'y' => 10,
57 1 => [
58 'x' => 10,
59 'y' => 20,
61 2 => [
62 'x' => 15,
63 'y' => 40,
65 3 => [
66 'x' => 45,
67 'y' => 45,
69 4 => [
70 'x' => 35,
71 'y' => 10,
74 1 => [
75 'no_of_points' => 4,
76 0 => [
77 'x' => 20,
78 'y' => 30,
80 1 => [
81 'x' => 35,
82 'y' => 32,
84 2 => [
85 'x' => 30,
86 'y' => 20,
88 3 => [
89 'x' => 20,
90 'y' => 30,
97 /**
98 * data provider for testGenerateWkt
100 * @return array data for testGenerateWkt
102 public function providerForTestGenerateWkt(): array
104 $temp = [
105 0 => $this->getData(),
108 $temp1 = $temp;
109 unset($temp1[0]['POLYGON'][1][3]['y']);
111 $temp2 = $temp;
112 $temp2[0]['POLYGON']['no_of_lines'] = 0;
114 $temp3 = $temp;
115 $temp3[0]['POLYGON'][1]['no_of_points'] = 3;
117 return [
119 $temp,
121 null,
122 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))',
124 // values at undefined index
126 $temp,
128 null,
129 'POLYGON(( , , , ))',
131 // if a coordinate is missing, default is empty string
133 $temp1,
135 null,
136 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 ))',
138 // missing coordinates are replaced with provided values (3rd parameter)
140 $temp1,
142 '0',
143 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 0))',
145 // should have at least one ring
147 $temp2,
149 '0',
150 'POLYGON((35 10,10 20,15 40,45 45,35 10))',
152 // a ring should have at least four points
154 $temp3,
156 '0',
157 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))',
163 * data provider for testGenerateParams
165 * @return array data for testGenerateParams
167 public function providerForTestGenerateParams(): array
169 $temp = $this->getData();
171 $temp1 = $temp;
172 $temp1['gis_type'] = 'POLYGON';
174 return [
176 '\'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))\',124',
177 null,
179 'srid' => 124,
180 0 => $temp,
184 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))',
186 [2 => $temp1],
192 * test for Area
194 * @param array $ring array of points forming the ring
195 * @param float $area area of the ring
197 * @dataProvider providerForTestArea
199 public function testArea(array $ring, float $area): void
201 $this->assertEquals($area, $this->object->area($ring));
205 * data provider for testArea
207 * @return array data for testArea
209 public function providerForTestArea(): array
211 return [
214 0 => [
215 'x' => 35,
216 'y' => 10,
218 1 => [
219 'x' => 10,
220 'y' => 10,
222 2 => [
223 'x' => 15,
224 'y' => 40,
227 -375.00,
229 // first point of the ring repeated as the last point
232 0 => [
233 'x' => 35,
234 'y' => 10,
236 1 => [
237 'x' => 10,
238 'y' => 10,
240 2 => [
241 'x' => 15,
242 'y' => 40,
244 3 => [
245 'x' => 35,
246 'y' => 10,
249 -375.00,
251 // anticlockwise gives positive area
254 0 => [
255 'x' => 15,
256 'y' => 40,
258 1 => [
259 'x' => 10,
260 'y' => 10,
262 2 => [
263 'x' => 35,
264 'y' => 10,
267 375.00,
273 * test for isPointInsidePolygon
275 * @param array $point x, y coordinates of the point
276 * @param array $polygon array of points forming the ring
277 * @param bool $isInside output
279 * @dataProvider providerForTestIsPointInsidePolygon
281 public function testIsPointInsidePolygon(array $point, array $polygon, bool $isInside): void
283 $this->assertEquals(
284 $isInside,
285 $this->object->isPointInsidePolygon($point, $polygon)
290 * data provider for testIsPointInsidePolygon
292 * @return array data for testIsPointInsidePolygon
294 public function providerForTestIsPointInsidePolygon(): array
296 $ring = [
297 0 => [
298 'x' => 35,
299 'y' => 10,
301 1 => [
302 'x' => 10,
303 'y' => 10,
305 2 => [
306 'x' => 15,
307 'y' => 40,
309 3 => [
310 'x' => 35,
311 'y' => 10,
315 return [
316 // point inside the ring
319 'x' => 20,
320 'y' => 15,
322 $ring,
323 true,
325 // point on an edge of the ring
328 'x' => 20,
329 'y' => 10,
331 $ring,
332 false,
334 // point on a vertex of the ring
337 'x' => 10,
338 'y' => 10,
340 $ring,
341 false,
343 // point outside the ring
346 'x' => 5,
347 'y' => 10,
349 $ring,
350 false,
356 * test for getPointOnSurface
358 * @param array $ring array of points forming the ring
360 * @dataProvider providerForTestGetPointOnSurface
362 public function testGetPointOnSurface(array $ring): void
364 $point = $this->object->getPointOnSurface($ring);
365 $this->assertIsArray($point);
366 $this->assertTrue($this->object->isPointInsidePolygon($point, $ring));
370 * data provider for testGetPointOnSurface
372 * @return array data for testGetPointOnSurface
374 public function providerForTestGetPointOnSurface(): array
376 $temp = $this->getData();
377 unset($temp['POLYGON'][0]['no_of_points']);
378 unset($temp['POLYGON'][1]['no_of_points']);
380 return [
382 $temp['POLYGON'][0],
385 $temp['POLYGON'][1],
391 * data provider for testScaleRow
393 * @return array data for testScaleRow
395 public function providerForTestScaleRow(): array
397 return [
399 'POLYGON((123 0,23 30,17 63,123 0))',
401 'minX' => 17,
402 'maxX' => 123,
403 'minY' => 0,
404 'maxY' => 63,
408 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30)))',
410 'minX' => 10,
411 'maxX' => 45,
412 'minY' => 10,
413 'maxY' => 45,
420 * @requires extension gd
422 public function testPrepareRowAsPng(): void
424 $image = ImageWrapper::create(200, 124, ['red' => 229, 'green' => 229, 'blue' => 229]);
425 $this->assertNotNull($image);
426 $return = $this->object->prepareRowAsPng(
427 'POLYGON((0 0,100 0,100 100,0 100,0 0),(10 10,10 40,40 40,40 10,10 10),(60 60,90 60,90 90,60 90,60 60))',
428 'image',
429 [176, 46, 224],
430 ['x' => -56, 'y' => -16, 'scale' => 0.94, 'height' => 124],
431 $image
433 $this->assertEquals(200, $return->width());
434 $this->assertEquals(124, $return->height());
436 $fileExpected = $this->testDir . '/polygon-expected.png';
437 $fileActual = $this->testDir . '/polygon-actual.png';
438 $this->assertTrue($image->png($fileActual));
439 $this->assertFileEquals($fileExpected, $fileActual);
443 * test case for prepareRowAsPdf() method
445 * @param string $spatial GIS POLYGON object
446 * @param string $label label for the GIS POLYGON object
447 * @param int[] $color color for the GIS POLYGON object
448 * @param array $scale_data array containing data related to scaling
449 * @param TCPDF $pdf TCPDF instance
451 * @dataProvider providerForPrepareRowAsPdf
453 public function testPrepareRowAsPdf(
454 string $spatial,
455 string $label,
456 array $color,
457 array $scale_data,
458 TCPDF $pdf
459 ): void {
460 $return = $this->object->prepareRowAsPdf($spatial, $label, $color, $scale_data, $pdf);
462 $fileExpected = $this->testDir . '/polygon-expected.pdf';
463 $fileActual = $this->testDir . '/polygon-actual.pdf';
464 $return->Output($fileActual, 'F');
465 $this->assertFileEquals($fileExpected, $fileActual);
469 * data provider for testPrepareRowAsPdf() test case
471 * @return array test data for testPrepareRowAsPdf() test case
473 public function providerForPrepareRowAsPdf(): array
475 return [
477 'POLYGON((0 0,100 0,100 100,0 100,0 0),(10 10,10 40,40 40,40 10,10 10),(60 60,90 60,90 90,60 90,60 6'
478 . '0))',
479 'pdf',
480 [176, 46, 224],
481 ['x' => -8, 'y' => -32, 'scale' => 1.80, 'height' => 297],
482 $this->createEmptyPdf('POLYGON'),
488 * test case for prepareRowAsSvg() method
490 * @param string $spatial GIS POLYGON object
491 * @param string $label label for the GIS POLYGON object
492 * @param int[] $color color for the GIS POLYGON object
493 * @param array $scaleData array containing data related to scaling
494 * @param string $output expected output
496 * @dataProvider providerForPrepareRowAsSvg
498 public function testPrepareRowAsSvg(
499 string $spatial,
500 string $label,
501 array $color,
502 array $scaleData,
503 string $output
504 ): void {
505 $svg = $this->object->prepareRowAsSvg($spatial, $label, $color, $scaleData);
506 $this->assertEquals($output, $svg);
510 * data provider for testPrepareRowAsSvg() test case
512 * @return array test data for testPrepareRowAsSvg() test case
514 public function providerForPrepareRowAsSvg(): array
516 return [
518 'POLYGON((123 0,23 30,17 63,123 0),(99 12,30 35,25 55,99 12))',
519 'svg',
520 [176, 46, 224],
522 'x' => 12,
523 'y' => 69,
524 'scale' => 2,
525 'height' => 150,
527 '<path d=" M 222, 288 L 22, 228 L 10, 162 Z M 174, 264 L 36, 218 L 26, 178 Z " name="svg" id="svg12'
528 . '34567890" class="polygon vector" stroke="black" stroke-width="0.5" fill="#b02ee0" fill-rule="evenod'
529 . 'd" fill-opacity="0.8"/>',
535 * test case for prepareRowAsOl() method
537 * @param string $spatial GIS POLYGON object
538 * @param int $srid spatial reference ID
539 * @param string $label label for the GIS POLYGON object
540 * @param int[] $color color for the GIS POLYGON object
541 * @param array $scale_data array containing data related to scaling
542 * @param string $output expected output
544 * @dataProvider providerForPrepareRowAsOl
546 public function testPrepareRowAsOl(
547 string $spatial,
548 int $srid,
549 string $label,
550 array $color,
551 array $scale_data,
552 string $output
553 ): void {
554 $ol = $this->object->prepareRowAsOl($spatial, $srid, $label, $color, $scale_data);
555 $this->assertEquals($output, $ol);
559 * data provider for testPrepareRowAsOl() test case
561 * @return array test data for testPrepareRowAsOl() test case
563 public function providerForPrepareRowAsOl(): array
565 return [
567 'POLYGON((123 0,23 30,17 63,123 0))',
568 4326,
569 'Ol',
570 [176, 46, 224],
572 'minX' => '0',
573 'minY' => '0',
574 'maxX' => '1',
575 'maxY' => '1',
577 'var style = new ol.style.Style({fill: new ol.style.Fill({"color":[176,46,224,0.8]'
578 . '}),stroke: new ol.style.Stroke({"color":[0,0,0],"width":0.5}),text: new ol.styl'
579 . 'e.Text({"text":"Ol"})});var minLoc = [0, 0];var maxLoc = [1, 1];var ext = ol.ex'
580 . 'tent.boundingExtent([minLoc, maxLoc]);ext = ol.proj.transformExtent(ext, ol.pro'
581 . 'j.get("EPSG:4326"), ol.proj.get(\'EPSG:3857\'));map.getView().fit(ext, map.getS'
582 . 'ize());var arr = [];var lineArr = [];var line = new ol.geom.LinearRing(new Arra'
583 . 'y((new ol.geom.Point([123,0]).transform(ol.proj.get("EPSG:4326"), ol.proj.get('
584 . '\'EPSG:3857\'))).getCoordinates(), (new ol.geom.Point([23,30]).transform(ol.pro'
585 . 'j.get("EPSG:4326"), ol.proj.get(\'EPSG:3857\'))).getCoordinates(), (new ol.geom'
586 . '.Point([17,63]).transform(ol.proj.get("EPSG:4326"), ol.proj.get(\'EPSG:3857\'))'
587 . ').getCoordinates(), (new ol.geom.Point([123,0]).transform(ol.proj.get("EPSG:432'
588 . '6"), ol.proj.get(\'EPSG:3857\'))).getCoordinates()));var coord = line.getCoordi'
589 . 'nates();for (var i = 0; i < coord.length; i++) lineArr.push(coord[i]);arr.push(lineArr);'
590 . 'var polygon = new ol.geom.Polygon(arr);var feature = new ol.Feature({geometry: polygon});f'
591 . 'eature.setStyle(style);vectorLayer.addFeature(feature);',
597 * test case for isOuterRing() method
599 * @param array $ring coordinates of the points in a ring
601 * @dataProvider providerForIsOuterRing
603 public function testIsOuterRing(array $ring): void
605 $this->assertTrue($this->object->isOuterRing($ring));
609 * data provider for testIsOuterRing() test case
611 * @return array test data for testIsOuterRing() test case
613 public function providerForIsOuterRing(): array
615 return [
619 'x' => 0,
620 'y' => 0,
623 'x' => 0,
624 'y' => 1,
627 'x' => 1,
628 'y' => 1,
631 'x' => 1,
632 'y' => 0,