123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <?php
- /**
- * LineString. A collection of Points representing a line.
- * A line can have more than one segment.
- */
- class LineString extends Collection
- {
- protected $geom_type = 'LineString';
- /**
- * Constructor
- *
- * @param array $points An array of at least two points with
- * which to build the LineString
- */
- public function __construct($points = array()) {
- if (count($points) == 1) {
- throw new Exception("Cannot construct a LineString with a single point");
- }
- // Call the Collection constructor to build the LineString
- parent::__construct($points);
- }
- // The boundary of a linestring is itself
- public function boundary() {
- return $this;
- }
- public function startPoint() {
- return $this->pointN(1);
- }
- public function endPoint() {
- $last_n = $this->numPoints();
- return $this->pointN($last_n);
- }
- public function isClosed() {
- return ($this->startPoint()->equals($this->endPoint()));
- }
- public function isRing() {
- return ($this->isClosed() && $this->isSimple());
- }
- public function numPoints() {
- return $this->numGeometries();
- }
- public function pointN($n) {
- return $this->geometryN($n);
- }
- public function dimension() {
- if ($this->isEmpty()) return 0;
- return 1;
- }
- public function area() {
- return 0;
- }
- public function length() {
- if ($this->geos()) {
- return $this->geos()->length();
- }
- $length = 0;
- foreach ($this->getPoints() as $delta => $point) {
- $previous_point = $this->geometryN($delta);
- if ($previous_point) {
- $length += sqrt(pow(($previous_point->getX() - $point->getX()), 2) + pow(($previous_point->getY()- $point->getY()), 2));
- }
- }
- return $length;
- }
- public function greatCircleLength($radius = 6378137) {
- $length = 0;
- $points = $this->getPoints();
- for($i=0; $i<$this->numPoints()-1; $i++) {
- $point = $points[$i];
- $next_point = $points[$i+1];
- if (!is_object($next_point)) {continue;}
- // Great circle method
- $lat1 = deg2rad($point->getY());
- $lat2 = deg2rad($next_point->getY());
- $lon1 = deg2rad($point->getX());
- $lon2 = deg2rad($next_point->getX());
- $dlon = $lon2 - $lon1;
- $length +=
- $radius *
- atan2(
- sqrt(
- pow(cos($lat2) * sin($dlon), 2) +
- pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dlon), 2)
- )
- ,
- sin($lat1) * sin($lat2) +
- cos($lat1) * cos($lat2) * cos($dlon)
- );
- }
- // Returns length in meters.
- return $length;
- }
- public function haversineLength() {
- $degrees = 0;
- $points = $this->getPoints();
- for($i=0; $i<$this->numPoints()-1; $i++) {
- $point = $points[$i];
- $next_point = $points[$i+1];
- if (!is_object($next_point)) {continue;}
- $degree = rad2deg(
- acos(
- sin(deg2rad($point->getY())) * sin(deg2rad($next_point->getY())) +
- cos(deg2rad($point->getY())) * cos(deg2rad($next_point->getY())) *
- cos(deg2rad(abs($point->getX() - $next_point->getX())))
- )
- );
- $degrees += $degree;
- }
- // Returns degrees
- return $degrees;
- }
- public function explode() {
- $parts = array();
- $points = $this->getPoints();
- foreach ($points as $i => $point) {
- if (isset($points[$i+1])) {
- $parts[] = new LineString(array($point, $points[$i+1]));
- }
- }
- return $parts;
- }
- public function isSimple() {
- if ($this->geos()) {
- return $this->geos()->isSimple();
- }
- $segments = $this->explode();
- foreach ($segments as $i => $segment) {
- foreach ($segments as $j => $check_segment) {
- if ($i != $j) {
- if ($segment->lineSegmentIntersect($check_segment)) {
- return FALSE;
- }
- }
- }
- }
- return TRUE;
- }
- // Utility function to check if any line sigments intersect
- // Derived from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
- public function lineSegmentIntersect($segment) {
- $p0_x = $this->startPoint()->x();
- $p0_y = $this->startPoint()->y();
- $p1_x = $this->endPoint()->x();
- $p1_y = $this->endPoint()->y();
- $p2_x = $segment->startPoint()->x();
- $p2_y = $segment->startPoint()->y();
- $p3_x = $segment->endPoint()->x();
- $p3_y = $segment->endPoint()->y();
- $s1_x = $p1_x - $p0_x; $s1_y = $p1_y - $p0_y;
- $s2_x = $p3_x - $p2_x; $s2_y = $p3_y - $p2_y;
- $fps = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
- $fpt = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
- if ($fps == 0 || $fpt == 0) {
- return FALSE;
- }
- $s = (-$s1_y * ($p0_x - $p2_x) + $s1_x * ($p0_y - $p2_y)) / $fps;
- $t = ( $s2_x * ($p0_y - $p2_y) - $s2_y * ($p0_x - $p2_x)) / $fpt;
- if ($s > 0 && $s < 1 && $t > 0 && $t < 1) {
- // Collision detected
- return TRUE;
- }
- return FALSE;
- }
- }
|