Ejemplo n.º 1
0
 /**
  * test for getPointOnSurface
  *
  * @param array $ring array of points forming the ring
  *
  * @dataProvider providerForTestGetPointOnSurface
  * @return void
  */
 public function testGetPointOnSurface($ring)
 {
     $this->assertEquals(
         $this->object->isPointInsidePolygon(
             $this->object->getPointOnSurface($ring),
             $ring
         ),
         true
     );
 }
Ejemplo n.º 2
0
 /**
  * Returns a point that is guaranteed to be on the surface of the ring.
  * (for simple closed rings)
  *
  * @param array $ring array of points forming the ring
  *
  * @return array|void a point on the surface of the ring
  * @access public
  * @static
  */
 public static function getPointOnSurface($ring)
 {
     // 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(PMA_Util::pow($y1 - $y0, 2) + PMA_Util::pow($x0 - $x1, 2));
     $pointA = array();
     $pointB = array();
     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 (PMA_GIS_Polygon::isPointInsidePolygon($pointA, $ring)) {
             return $pointA;
         }
         if (PMA_GIS_Polygon::isPointInsidePolygon($pointB, $ring)) {
             return $pointB;
         }
         //If both are outside the polygon reduce the epsilon and
         //recalculate the points(reduce exponentially for faster convergence)
         $epsilon = PMA_Util::pow($epsilon, 2);
         if ($epsilon == 0) {
             return false;
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * Generate the WKT for the data from ESRI shape files.
  *
  * @param array $row_data GIS data
  *
  * @return string the WKT for the data from ESRI shape files
  * @access public
  */
 public function getShape($row_data)
 {
     // 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.
     include_once './libraries/gis/GIS_Polygon.class.php';
     foreach ($row_data['parts'] as $i => $ring) {
         $row_data['parts'][$i]['isOuter'] = PMA_GIS_Polygon::isOuterRing($ring['points']);
     }
     // Find points on surface for inner rings
     foreach ($row_data['parts'] as $i => $ring) {
         if (!$ring['isOuter']) {
             $row_data['parts'][$i]['pointOnSurface'] = PMA_GIS_Polygon::getPointOnSurface($ring['points']);
         }
     }
     // Classify inner rings to their respective outer rings.
     foreach ($row_data['parts'] as $j => $ring1) {
         if ($ring1['isOuter']) {
             continue;
         }
         foreach ($row_data['parts'] as $k => $ring2) {
             if (!$ring2['isOuter']) {
                 continue;
             }
             // If the pointOnSurface of the inner ring
             // is also inside the outer ring
             if (PMA_GIS_Polygon::isPointInsidePolygon($ring1['pointOnSurface'], $ring2['points'])) {
                 if (!isset($ring2['inner'])) {
                     $row_data['parts'][$k]['inner'] = array();
                 }
                 $row_data['parts'][$k]['inner'][] = $j;
             }
         }
     }
     $wkt = 'MULTIPOLYGON(';
     // for each polygon
     foreach ($row_data['parts'] as $ring) {
         if (!$ring['isOuter']) {
             continue;
         }
         $wkt .= '(';
         // start of polygon
         $wkt .= '(';
         // start of outer ring
         foreach ($ring['points'] as $point) {
             $wkt .= $point['x'] . ' ' . $point['y'] . ',';
         }
         $wkt = mb_substr($wkt, 0, mb_strlen($wkt) - 1);
         $wkt .= ')';
         // end of outer ring
         // inner rings if any
         if (isset($ring['inner'])) {
             foreach ($ring['inner'] as $j) {
                 $wkt .= ',(';
                 // start of inner ring
                 foreach ($row_data['parts'][$j]['points'] as $innerPoint) {
                     $wkt .= $innerPoint['x'] . ' ' . $innerPoint['y'] . ',';
                 }
                 $wkt = mb_substr($wkt, 0, mb_strlen($wkt) - 1);
                 $wkt .= ')';
                 // end of inner ring
             }
         }
         $wkt .= '),';
         // end of polygon
     }
     $wkt = mb_substr($wkt, 0, mb_strlen($wkt) - 1);
     $wkt .= ')';
     // end of multipolygon
     return $wkt;
 }