1<?php 2 3namespace geoPHP\Geometry; 4 5use geoPHP\Exception\UnsupportedMethodException; 6use geoPHP\geoPHP; 7 8/** 9 * Geometry is the root class of the hierarchy. Geometry is an abstract (non-instantiable) class. 10 * 11 * OGC 06-103r4 6.1.2 specification: 12 * The instantiable subclasses of Geometry defined in this Standard are restricted to 13 * 0, 1 and 2-dimensional geometric objects that exist in 2, 3 or 4-dimensional coordinate space. 14 * 15 * Geometry values in R^2 have points with coordinate values for x and y. 16 * Geometry values in R^3 have points with coordinate values for x, y and z or for x, y and m. 17 * Geometry values in R^4 have points with coordinate values for x, y, z and m. 18 * The interpretation of the coordinates is subject to the coordinate reference systems associated to the point. 19 * All coordinates within a geometry object should be in the same coordinate reference systems. 20 * Each coordinate shall be unambiguously associated to a coordinate reference system 21 * either directly or through its containing geometry. 22 * 23 * The z coordinate of a point is typically, but not necessarily, represents altitude or elevation. 24 * The m coordinate represents a measurement. 25 */ 26abstract class Geometry 27{ 28 29 /** 30 * Type constants 31 */ 32 const POINT = 'Point'; 33 const LINE_STRING = 'LineString'; 34 const POLYGON = 'Polygon'; 35 const MULTI_POINT = 'MultiPoint'; 36 const MULTI_LINE_STRING = 'MultiLineString'; 37 const MULTI_POLYGON = 'MultiPolygon'; 38 const GEOMETRY_COLLECTION = 'GeometryCollection'; 39 40 const CIRCULAR_STRING = 'CircularString'; 41 const COMPOUND_CURVE = 'CompoundCurve'; 42 const CURVE_POLYGON = 'CurvePolygon'; 43 const MULTI_CURVE = 'MultiCurve'; // Abstract 44 const MULTI_SURFACE = 'MultiSurface'; // Abstract 45 const CURVE = 'Curve'; // Abstract 46 const SURFACE = 'Surface'; // Abstract 47 const POLYHEDRAL_SURFACE = 'PolyhedralSurface'; 48 const TIN = 'TIN'; 49 const TRIANGLE = 'Triangle'; 50 51 /** 52 * @var bool True if Geometry has Z (altitude) value 53 */ 54 protected $hasZ = false; 55 56 /** 57 * @var bool True if Geometry has M (measure) value 58 */ 59 protected $isMeasured = false; 60 61 /** @var int|null $srid Spatial Reference System Identifier (http://en.wikipedia.org/wiki/SRID) */ 62 protected $srid = null; 63 64 /** 65 * @var mixed|null Custom (meta)data 66 */ 67 protected $data; 68 69 /** 70 * @var \GEOSGeometry|null|false 71 */ 72 private $geos = null; 73 74 75 76 77 /**************************************** 78 * Basic methods on geometric objects * 79 ****************************************/ 80 81 /** 82 * The inherent dimension of the geometric object, which must be less than or equal to the coordinate dimension. 83 * In non-homogeneous collections, this will return the largest topological dimension of the contained objects. 84 * 85 * @return int 86 */ 87 abstract public function dimension(); 88 89 /** 90 * Returns the name of the instantiable subtype of Geometry of which the geometric object is an instantiable member. 91 * 92 * @return string 93 */ 94 abstract public function geometryType(); 95 96 /** 97 * Returns true if the geometric object is the empty Geometry. 98 * If true, then the geometric object represents the empty point set ∅ for the coordinate space. 99 * 100 * @return bool 101 */ 102 abstract public function isEmpty(); 103 104 /** 105 * Returns true if the geometric object has no anomalous geometric points, 106 * such as self intersection or self tangency. 107 * The description of each instantiable geometric class will include the specific conditions 108 * that cause an instance of that class to be classified as not simple 109 * 110 * @return bool 111 */ 112 abstract public function isSimple(); 113 114 /** 115 * Returns the closure of the combinatorial boundary of the geometric object 116 * 117 * @return Geometry 118 */ 119 abstract public function boundary(); 120 121 /** 122 * @return Geometry[] 123 */ 124 abstract public function getComponents(); 125 126 127 /************************************************* 128 * Methods applicable on certain geometry types * 129 *************************************************/ 130 131 abstract public function area(); 132 133 /** 134 * @return Point 135 */ 136 abstract public function centroid(); 137 138 abstract public function length(); 139 140 abstract public function length3D(); 141 142 /** 143 * @return float|null 144 */ 145 abstract public function x(); 146 147 /** 148 * @return float|null 149 */ 150 abstract public function y(); 151 152 /** 153 * @return float|null 154 */ 155 abstract public function z(); 156 157 /** 158 * @return float|null 159 */ 160 abstract public function m(); 161 162 /** 163 * @return int|null 164 */ 165 abstract public function numGeometries(); 166 167 /** 168 * @param int $n One-based index. 169 * @return Geometry|null The geometry, or null if not found. 170 */ 171 abstract public function geometryN($n); 172 173 /** 174 * @return Point|null 175 */ 176 abstract public function startPoint(); 177 178 /** 179 * @return Point|null 180 */ 181 abstract public function endPoint(); 182 183 abstract public function isRing(); // Missing dependency 184 185 abstract public function isClosed(); // Missing dependency 186 187 abstract public function numPoints(); 188 189 /** 190 * @param int $n Nth point 191 * @return Point|null 192 */ 193 abstract public function pointN($n); 194 195 abstract public function exteriorRing(); 196 197 abstract public function numInteriorRings(); 198 199 abstract public function interiorRingN($n); 200 201 abstract public function distance($geom); 202 203 abstract public function equals($geom); 204 205 206 // Abstract: Non-Standard 207 // ---------------------------------------------------------- 208 209 abstract public function getBBox(); 210 211 abstract public function asArray(); 212 213 /** 214 * @return Point[] 215 */ 216 abstract public function getPoints(); 217 218 abstract public function invertXY(); 219 220 /** 221 * Get all line segments 222 * @param bool $toArray return segments as LineString or array of start and end points. Explode(true) is faster 223 * 224 * @return LineString[] | Point[][] | null 225 */ 226 abstract public function explode($toArray = false); 227 228 abstract public function greatCircleLength($radius = null); //meters 229 230 abstract public function haversineLength(); //degrees 231 232 abstract public function flatten(); // 3D to 2D 233 234 // Elevations statistics 235 236 abstract public function minimumZ(); 237 238 abstract public function maximumZ(); 239 240 abstract public function minimumM(); 241 242 abstract public function maximumM(); 243 244 abstract public function zDifference(); 245 246 abstract public function elevationGain($verticalTolerance = 0); 247 248 abstract public function elevationLoss($verticalTolerance = 0); 249 250 251 // Public: Standard -- Common to all geometries 252 // ---------------------------------------------------------- 253 254 /** 255 * Check if Geometry has Z (altitude) coordinate 256 * 257 * @return bool True if collection has Z value 258 */ 259 public function is3D() 260 { 261 return $this->hasZ; 262 } 263 264 /** 265 * Check if Geometry has a measure value 266 * 267 * @return bool True if collection has measure value 268 */ 269 public function isMeasured() 270 { 271 return $this->isMeasured; 272 } 273 274 public function SRID() 275 { 276 return $this->srid; 277 } 278 279 /** 280 * @param int $srid Spatial Reference System Identifier 281 */ 282 public function setSRID($srid) 283 { 284 if ($this->getGeos()) { 285 // @codeCoverageIgnoreStart 286 /** @noinspection PhpUndefinedMethodInspection */ 287 $this->getGeos()->setSRID((int) $srid); 288 // @codeCoverageIgnoreEnd 289 } 290 $this->srid = $srid; 291 } 292 293 /** 294 * Adds custom data to the geometry 295 * 296 * @param string|array $property The name of the data or an associative array 297 * @param mixed|null $value The data. Can be any type (string, integer, array, etc.) 298 */ 299 public function setData($property, $value = null) 300 { 301 if (is_array($property)) { 302 $this->data = $property; 303 } else { 304 $this->data[$property] = $value; 305 } 306 } 307 308 /** 309 * Returns the requested data by property name, or all data of the geometry 310 * 311 * @param string|null $property The name of the data. If omitted, all data will be returned 312 * @return mixed|null The data or null if not exists 313 */ 314 public function getData($property = null) 315 { 316 if ($property) { 317 return $this->hasDataProperty($property) ? $this->data[$property] : null; 318 } else { 319 return $this->data; 320 } 321 } 322 323 /** 324 * Tells whether the geometry has data with the specified name 325 * @param string $property The name of the property 326 * @return bool True if the geometry has data with the specified name 327 */ 328 public function hasDataProperty($property) 329 { 330 return array_key_exists($property, $this->data ?: []); 331 } 332 333 public function envelope() 334 { 335 if ($this->isEmpty()) { 336 $type = geoPHP::CLASS_NAMESPACE . 'Geometry\\' . $this->geometryType(); 337 return new $type(); 338 } 339 if ($this->geometryType() === Geometry::POINT) { 340 return $this; 341 } 342 343 if ($this->getGeos()) { 344 // @codeCoverageIgnoreStart 345 /** @noinspection PhpUndefinedMethodInspection */ 346 return geoPHP::geosToGeometry($this->getGeos()->envelope()); 347 // @codeCoverageIgnoreEnd 348 } 349 350 $boundingBox = $this->getBBox(); 351 $points = [ 352 new Point($boundingBox['maxx'], $boundingBox['miny']), 353 new Point($boundingBox['maxx'], $boundingBox['maxy']), 354 new Point($boundingBox['minx'], $boundingBox['maxy']), 355 new Point($boundingBox['minx'], $boundingBox['miny']), 356 new Point($boundingBox['maxx'], $boundingBox['miny']), 357 ]; 358 return new Polygon([new LineString($points)]); 359 } 360 361 // Public: Non-Standard -- Common to all geometries 362 // ------------------------------------------------ 363 364 // $this->out($format, $other_args); 365 public function out() 366 { 367 $args = func_get_args(); 368 369 $format = strtolower(array_shift($args)); 370 if (strstr($format, 'xdr')) { //Big Endian WKB 371 $args[] = true; 372 $format = str_replace('xdr', '', $format); 373 } 374 375 $processorType = geoPHP::CLASS_NAMESPACE . 'Adapter\\' . geoPHP::getAdapterMap()[$format]; 376 $processor = new $processorType(); 377 array_unshift($args, $this); 378 379 380 $result = call_user_func_array([$processor, 'write'], $args); 381 382 return $result; 383 } 384 385 public function coordinateDimension() 386 { 387 return 2 + ($this->hasZ() ? 1 : 0) + ($this->isMeasured() ? 1 : 0); 388 } 389 390 /** 391 * Utility function to check if any line segments intersect 392 * Derived from @source http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect 393 * @param Point $segment1Start 394 * @param Point $segment1End 395 * @param Point $segment2Start 396 * @param Point $segment2End 397 * @return bool 398 */ 399 public static function segmentIntersects($segment1Start, $segment1End, $segment2Start, $segment2End) 400 { 401 $p0x = $segment1Start->x(); 402 $p0y = $segment1Start->y(); 403 $p1x = $segment1End->x(); 404 $p1y = $segment1End->y(); 405 $p2x = $segment2Start->x(); 406 $p2y = $segment2Start->y(); 407 $p3x = $segment2End->x(); 408 $p3y = $segment2End->y(); 409 410 $s1x = $p1x - $p0x; 411 $s1y = $p1y - $p0y; 412 $s2x = $p3x - $p2x; 413 $s2y = $p3y - $p2y; 414 415 $fps = (-$s2x * $s1y) + ($s1x * $s2y); 416 $fpt = (-$s2x * $s1y) + ($s1x * $s2y); 417 418 if ($fps == 0 || $fpt == 0) { 419 return false; 420 } 421 422 $s = (-$s1y * ($p0x - $p2x) + $s1x * ($p0y - $p2y)) / $fps; 423 $t = ($s2x * ($p0y - $p2y) - $s2y * ($p0x - $p2x)) / $fpt; 424 425 // Return true if collision is detected 426 return ($s > 0 && $s < 1 && $t > 0 && $t < 1); 427 } 428 429 430 // Public: Aliases 431 // ------------------------------------------------ 432 433 public function hasZ() 434 { 435 return $this->is3D(); 436 } 437 public function getX() 438 { 439 return $this->x(); 440 } 441 public function getY() 442 { 443 return $this->y(); 444 } 445 public function getZ() 446 { 447 return $this->z(); 448 } 449 public function getM() 450 { 451 return $this->m(); 452 } 453 public function getBoundingBox() 454 { 455 return $this->getBBox(); 456 } 457 public function dump() 458 { 459 return $this->getComponents(); 460 } 461 public function getCentroid() 462 { 463 return $this->centroid(); 464 } 465 public function getArea() 466 { 467 return $this->area(); 468 } 469 public function geos() 470 { 471 return $this->getGeos(); 472 } 473 public function getGeomType() 474 { 475 return $this->geometryType(); 476 } 477 public function getSRID() 478 { 479 return $this->SRID(); 480 } 481 public function asText() 482 { 483 return $this->out('wkt'); 484 } 485 public function asBinary() 486 { 487 return $this->out('wkb'); 488 } 489 490 // Public: GEOS Only Functions 491 // ------------------------------------------------ 492 493 /** 494 * Returns the GEOS representation of Geometry if GEOS is installed 495 * 496 * @return \GEOSGeometry|false 497 * @codeCoverageIgnore 498 */ 499 public function getGeos() 500 { 501 // If it's already been set, just return it 502 if ($this->geos && geoPHP::geosInstalled()) { 503 return $this->geos; 504 } 505 // It hasn't been set yet, generate it 506 if (geoPHP::geosInstalled()) { 507 /** @noinspection PhpUndefinedClassInspection */ 508 $reader = new \GEOSWKBReader(); 509 /** @noinspection PhpUndefinedMethodInspection */ 510 $this->geos = $reader->read($this->out('wkb')); 511 } else { 512 $this->geos = false; 513 } 514 return $this->geos; 515 } 516 517 public function setGeos($geos) 518 { 519 $this->geos = $geos; 520 } 521 522 /** 523 * @return Geometry|Point|null 524 * @throws UnsupportedMethodException 525 * @codeCoverageIgnore 526 */ 527 public function pointOnSurface() 528 { 529 if ($this->isEmpty()) { 530 return new Point(); 531 } 532 if ($this->getGeos()) { 533 /** @noinspection PhpUndefinedMethodInspection */ 534 return geoPHP::geosToGeometry($this->getGeos()->pointOnSurface()); 535 } 536 // help for implementation: http://gis.stackexchange.com/questions/76498/how-is-st-pointonsurface-calculated 537 throw UnsupportedMethodException::geos(__METHOD__); 538 } 539 540 /** 541 * @param Geometry $geometry 542 * @return bool 543 * @throws UnsupportedMethodException 544 * @codeCoverageIgnore 545 */ 546 public function equalsExact(Geometry $geometry) 547 { 548 if ($this->getGeos()) { 549 /** @noinspection PhpUndefinedMethodInspection */ 550 return $this->getGeos()->equalsExact($geometry->getGeos()); 551 } 552 throw UnsupportedMethodException::geos(__METHOD__); 553 } 554 555 /** 556 * @param Geometry $geometry 557 * @param string|null $pattern 558 * @return string|null 559 * @throws UnsupportedMethodException 560 * @codeCoverageIgnore 561 */ 562 public function relate(Geometry $geometry, $pattern = null) 563 { 564 if ($this->getGeos()) { 565 if ($pattern) { 566 /** @noinspection PhpUndefinedMethodInspection */ 567 return $this->getGeos()->relate($geometry->getGeos(), $pattern); 568 } else { 569 /** @noinspection PhpUndefinedMethodInspection */ 570 return $this->getGeos()->relate($geometry->getGeos()); 571 } 572 } 573 throw UnsupportedMethodException::geos(__METHOD__); 574 } 575 576 /** 577 * @return array 578 * @throws UnsupportedMethodException 579 * @codeCoverageIgnore 580 */ 581 public function checkValidity() 582 { 583 if ($this->getGeos()) { 584 /** @noinspection PhpUndefinedMethodInspection */ 585 return $this->getGeos()->checkValidity(); 586 } 587 throw UnsupportedMethodException::geos(__METHOD__); 588 } 589 590 /** 591 * @param float|int $distance 592 * @return Geometry|null 593 * @throws UnsupportedMethodException 594 * @codeCoverageIgnore 595 */ 596 public function buffer($distance) 597 { 598 if ($this->getGeos()) { 599 /** @noinspection PhpUndefinedMethodInspection */ 600 return geoPHP::geosToGeometry($this->getGeos()->buffer($distance)); 601 } 602 throw UnsupportedMethodException::geos(__METHOD__); 603 } 604 605 /** 606 * @param Geometry $geometry 607 * @return Geometry|null 608 * @throws UnsupportedMethodException 609 * @codeCoverageIgnore 610 */ 611 public function intersection(Geometry $geometry) 612 { 613 if ($this->getGeos()) { 614 /** @noinspection PhpUndefinedMethodInspection */ 615 return geoPHP::geosToGeometry($this->getGeos()->intersection($geometry->getGeos())); 616 } 617 throw UnsupportedMethodException::geos(__METHOD__); 618 } 619 620 /** 621 * @return Geometry|null 622 * @throws UnsupportedMethodException 623 * @codeCoverageIgnore 624 */ 625 public function convexHull() 626 { 627 if ($this->getGeos()) { 628 /** @noinspection PhpUndefinedMethodInspection */ 629 return geoPHP::geosToGeometry($this->getGeos()->convexHull()); 630 } 631 throw UnsupportedMethodException::geos(__METHOD__); 632 } 633 634 /** 635 * @param Geometry $geometry 636 * @return Geometry|null 637 * @throws UnsupportedMethodException 638 * @codeCoverageIgnore 639 */ 640 public function difference(Geometry $geometry) 641 { 642 if ($this->getGeos()) { 643 /** @noinspection PhpUndefinedMethodInspection */ 644 return geoPHP::geosToGeometry($this->getGeos()->difference($geometry->getGeos())); 645 } 646 throw UnsupportedMethodException::geos(__METHOD__); 647 } 648 649 /** 650 * @param Geometry $geometry 651 * @return Geometry|null 652 * @throws UnsupportedMethodException 653 * @codeCoverageIgnore 654 */ 655 public function symDifference(Geometry $geometry) 656 { 657 if ($this->getGeos()) { 658 /** @noinspection PhpUndefinedMethodInspection */ 659 return geoPHP::geosToGeometry($this->getGeos()->symDifference($geometry->getGeos())); 660 } 661 throw UnsupportedMethodException::geos(__METHOD__); 662 } 663 664 /** 665 * Can pass in a geometry or an array of geometries 666 * 667 * @param Geometry $geometry 668 * @return bool|mixed|null|GeometryCollection 669 * @throws UnsupportedMethodException 670 * @codeCoverageIgnore 671 */ 672 public function union(Geometry $geometry) 673 { 674 if ($this->getGeos()) { 675 if (is_array($geometry)) { 676 $geom = $this->getGeos(); 677 foreach ($geometry as $item) { 678 /** @noinspection PhpUndefinedMethodInspection */ 679 $geom = $geom->union($item->geos()); 680 } 681 return geoPHP::geosToGeometry($geom); 682 } else { 683 /** @noinspection PhpUndefinedMethodInspection */ 684 return geoPHP::geosToGeometry($this->getGeos()->union($geometry->getGeos())); 685 } 686 } 687 throw UnsupportedMethodException::geos(__METHOD__); 688 } 689 690 /** 691 * @param float $tolerance 692 * @param bool|false $preserveTopology 693 * @return Geometry|null 694 * @throws UnsupportedMethodException 695 * @codeCoverageIgnore 696 */ 697 public function simplify($tolerance, $preserveTopology = false) 698 { 699 if ($this->getGeos()) { 700 /** @noinspection PhpUndefinedMethodInspection */ 701 return geoPHP::geosToGeometry($this->getGeos()->simplify($tolerance, $preserveTopology)); 702 } 703 throw UnsupportedMethodException::geos(__METHOD__); 704 } 705 706 /** 707 * @return Geometry|null 708 * @throws UnsupportedMethodException 709 * @codeCoverageIgnore 710 */ 711 public function makeValid() 712 { 713 if ($this->getGeos()) { 714 /** @noinspection PhpUndefinedMethodInspection */ 715 return geoPHP::geosToGeometry($this->getGeos()->makeValid()); 716 } 717 throw UnsupportedMethodException::geos(__METHOD__); 718 } 719 720 /** 721 * @return Geometry|null 722 * @throws UnsupportedMethodException 723 * @codeCoverageIgnore 724 */ 725 public function buildArea() 726 { 727 if ($this->getGeos()) { 728 /** @noinspection PhpUndefinedMethodInspection */ 729 return geoPHP::geosToGeometry($this->getGeos()->buildArea()); 730 } 731 throw UnsupportedMethodException::geos(__METHOD__); 732 } 733 734 /** 735 * @param Geometry $geometry 736 * @return bool 737 * @throws UnsupportedMethodException 738 * @codeCoverageIgnore 739 */ 740 public function disjoint(Geometry $geometry) 741 { 742 if ($this->getGeos()) { 743 /** @noinspection PhpUndefinedMethodInspection */ 744 return $this->getGeos()->disjoint($geometry->getGeos()); 745 } 746 throw UnsupportedMethodException::geos(__METHOD__); 747 } 748 749 /** 750 * @param Geometry $geometry 751 * @return bool 752 * @throws UnsupportedMethodException 753 * @codeCoverageIgnore 754 */ 755 public function touches(Geometry $geometry) 756 { 757 if ($this->getGeos()) { 758 /** @noinspection PhpUndefinedMethodInspection */ 759 return $this->getGeos()->touches($geometry->getGeos()); 760 } 761 throw UnsupportedMethodException::geos(__METHOD__); 762 } 763 764 /** 765 * @param Geometry $geometry 766 * @return bool 767 * @throws UnsupportedMethodException 768 * @codeCoverageIgnore 769 */ 770 public function intersects(Geometry $geometry) 771 { 772 if ($this->getGeos()) { 773 /** @noinspection PhpUndefinedMethodInspection */ 774 return $this->getGeos()->intersects($geometry->getGeos()); 775 } 776 throw UnsupportedMethodException::geos(__METHOD__); 777 } 778 779 /** 780 * @param Geometry $geometry 781 * @return bool 782 * @throws UnsupportedMethodException 783 * @codeCoverageIgnore 784 */ 785 public function crosses(Geometry $geometry) 786 { 787 if ($this->getGeos()) { 788 /** @noinspection PhpUndefinedMethodInspection */ 789 return $this->getGeos()->crosses($geometry->getGeos()); 790 } 791 throw UnsupportedMethodException::geos(__METHOD__); 792 } 793 794 /** 795 * @param Geometry $geometry 796 * @return bool 797 * @throws UnsupportedMethodException 798 * @codeCoverageIgnore 799 */ 800 public function within(Geometry $geometry) 801 { 802 if ($this->getGeos()) { 803 /** @noinspection PhpUndefinedMethodInspection */ 804 return $this->getGeos()->within($geometry->getGeos()); 805 } 806 throw UnsupportedMethodException::geos(__METHOD__); 807 } 808 809 /** 810 * @param Geometry $geometry 811 * @return bool 812 * @throws UnsupportedMethodException 813 * @codeCoverageIgnore 814 */ 815 public function contains(Geometry $geometry) 816 { 817 if ($this->getGeos()) { 818 /** @noinspection PhpUndefinedMethodInspection */ 819 return $this->getGeos()->contains($geometry->getGeos()); 820 } 821 throw UnsupportedMethodException::geos(__METHOD__); 822 } 823 824 /** 825 * @param Geometry $geometry 826 * @return bool 827 * @throws UnsupportedMethodException 828 * @codeCoverageIgnore 829 */ 830 public function overlaps(Geometry $geometry) 831 { 832 if ($this->getGeos()) { 833 /** @noinspection PhpUndefinedMethodInspection */ 834 return $this->getGeos()->overlaps($geometry->getGeos()); 835 } 836 throw UnsupportedMethodException::geos(__METHOD__); 837 } 838 839 /** 840 * @param Geometry $geometry 841 * @return bool 842 * @throws UnsupportedMethodException 843 * @codeCoverageIgnore 844 */ 845 public function covers(Geometry $geometry) 846 { 847 if ($this->getGeos()) { 848 /** @noinspection PhpUndefinedMethodInspection */ 849 return $this->getGeos()->covers($geometry->getGeos()); 850 } 851 throw UnsupportedMethodException::geos(__METHOD__); 852 } 853 854 /** 855 * @param Geometry $geometry 856 * @return bool 857 * @throws UnsupportedMethodException 858 * @codeCoverageIgnore 859 */ 860 public function coveredBy(Geometry $geometry) 861 { 862 if ($this->getGeos()) { 863 /** @noinspection PhpUndefinedMethodInspection */ 864 return $this->getGeos()->coveredBy($geometry->getGeos()); 865 } 866 throw UnsupportedMethodException::geos(__METHOD__); 867 } 868 869 /** 870 * @param Geometry $geometry 871 * @return float 872 * @throws UnsupportedMethodException 873 * @codeCoverageIgnore 874 */ 875 public function hausdorffDistance(Geometry $geometry) 876 { 877 if ($this->getGeos()) { 878 /** @noinspection PhpUndefinedMethodInspection */ 879 return $this->getGeos()->hausdorffDistance($geometry->getGeos()); 880 } 881 throw UnsupportedMethodException::geos(__METHOD__); 882 } 883 884 /** 885 * @param Geometry $point 886 * @param null $normalized 887 * @return \GEOSGeometry 888 * @throws UnsupportedMethodException 889 * @codeCoverageIgnore 890 */ 891 public function project(Geometry $point, $normalized = null) 892 { 893 if ($this->getGeos()) { 894 /** @noinspection PhpUndefinedMethodInspection */ 895 return $this->getGeos()->project($point->getGeos(), $normalized); 896 } 897 throw UnsupportedMethodException::geos(__METHOD__); 898 } 899} 900