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(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 epsilon chosen is too large
if (GISPolygon::isPointInsidePolygon($pointA, $ring)) {
return $pointA;
}
if (GISPolygon::isPointInsidePolygon($pointB, $ring)) {
return $pointB;
}
//If both are outside the polygon reduce the epsilon and
//recalculate the points(reduce exponentially for faster convergence)
$epsilon = pow($epsilon, 2);
if ($epsilon == 0) {
return false;
}
}
}