Manually implemented PointOnSurface() function as it is not yet implemented in MySQL
This commit is contained in:
parent
faced3027a
commit
c81db372d7
@ -376,7 +376,12 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
|
||||
$row_data['parts'][$i]['isOuter'] = PMA_GIS_Polygon::isOuterRing($ring['points']);
|
||||
}
|
||||
|
||||
$this->getPointsOnSurface($row_data['parts']);
|
||||
// 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) {
|
||||
@ -429,43 +434,6 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
|
||||
return $wkt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to each ring a point on its surface.
|
||||
*
|
||||
* @param array $rings
|
||||
*/
|
||||
private function getPointsOnSurface(&$rings)
|
||||
{
|
||||
$sql = 'SELECT ';
|
||||
$inner_rings = false;
|
||||
|
||||
foreach ($rings as $i => $ring) {
|
||||
if (! $ring['isOuter']) {
|
||||
$inner_rings = true;
|
||||
// gis_data[0]['MULTIPOLYGON'][0][0] will have $ring
|
||||
$gis_data = array(array('MULTIPOLYGON' => array(array($ring['points']))));
|
||||
$gis_data[0]['MULTIPOLYGON'][0][0]['no_of_points'] = count($ring['points']);
|
||||
$geom = $this->generateWkt($gis_data, 0);
|
||||
$sql .= 'AsText(PointOnSurface(GeomFromText("' . $geom . '"))) as `P' . $i . '`, ';
|
||||
}
|
||||
}
|
||||
if (! $inner_rings) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = substr($sql, 0, strlen($sql) - 2);
|
||||
$result = PMA_DBI_fetch_result($sql);
|
||||
|
||||
require_once './libraries/gis/pma_gis_point.php';
|
||||
$point = PMA_GIS_Point::singleton();
|
||||
foreach ($rings as $i => $ring) {
|
||||
if (! $ring['isOuter']) {
|
||||
$param = $point->generateParams($result[0]['P' . $i], 0);
|
||||
$rings[$i]['pointOnSurface'] = $param[0]['POINT'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate parameters for the GIS data editor from the value of the GIS column.
|
||||
*
|
||||
|
||||
@ -418,6 +418,63 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static function getPointOnSurface($ring)
|
||||
{
|
||||
// Find two consecutive distinct points.
|
||||
for ($i = 0; $i < count($ring) - 1; $i++) {
|
||||
if (($ring[$i]['x'] != $ring[$i + 1]['x'])
|
||||
|| ($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'];
|
||||
}
|
||||
}
|
||||
|
||||
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 found later in this method
|
||||
$epsilon = 0.1;
|
||||
$denominator = sqrt(pow(($y1 - $y0), 2) + 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 epcilon chosen is too large
|
||||
if (PMA_GIS_Polygon::isPointInsidePolygon($pointA, $ring)) {
|
||||
return $pointA;
|
||||
} else 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 convergance)
|
||||
else {
|
||||
$epsilon = pow($epsilon, 2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate parameters for the GIS data editor from the value of the GIS column.
|
||||
*
|
||||
* @param string $value of the GIS column
|
||||
|
||||
Loading…
Reference in New Issue
Block a user