Correctly import multipolygons from ESRI shape files
This commit is contained in:
parent
28519cf25b
commit
a58bb10e18
@ -359,7 +359,115 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
|
||||
return $wkt;
|
||||
}
|
||||
|
||||
/** Generate parameters for the GIS data editor from the value of the GIS column.
|
||||
/**
|
||||
* Generate the WKT for the data from ESRI shape files.
|
||||
*
|
||||
* @param array $row_data GIS data
|
||||
*
|
||||
* @return the WKT for the data from ESRI shape files
|
||||
*/
|
||||
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.
|
||||
require_once './libraries/gis/pma_gis_polygon.php';
|
||||
foreach ($row_data['parts'] as $i => $ring) {
|
||||
$row_data['parts'][$i]['isOuter'] = PMA_GIS_Polygon::isOuterRing($ring['points']);
|
||||
}
|
||||
|
||||
$this->getPointsOnSurface($row_data['parts']);
|
||||
|
||||
// Classify inner rings to their respective outer rings.
|
||||
foreach ($row_data['parts'] as $j => $ring1) {
|
||||
if (! $ring1['isOuter']) {
|
||||
foreach ($row_data['parts'] as $k => $ring2) {
|
||||
if ($ring2['isOuter']) {
|
||||
// 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']) {
|
||||
$wkt .= '('; // start of polygon
|
||||
|
||||
$wkt .= '('; // start of outer ring
|
||||
foreach($ring['points'] as $point) {
|
||||
$wkt .= $point['x'] . ' ' . $point['y'] . ',';
|
||||
}
|
||||
$wkt = substr($wkt, 0, 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 = substr($wkt, 0, strlen($wkt) - 1);
|
||||
$wkt .= ')'; // end of inner ring
|
||||
}
|
||||
}
|
||||
|
||||
$wkt .= '),'; // end of polygon
|
||||
}
|
||||
}
|
||||
$wkt = substr($wkt, 0, strlen($wkt) - 1);
|
||||
|
||||
$wkt .= ')'; // end of multipolygon
|
||||
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.
|
||||
*
|
||||
* @param string $value of the GIS column
|
||||
* @param index $index of the geometry
|
||||
|
||||
@ -324,6 +324,100 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
|
||||
return $wkt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the area of a closed simple polygon.
|
||||
*
|
||||
* @param array $ring array of points forming the ring
|
||||
*
|
||||
* @return the area of a closed simple polygon.
|
||||
*/
|
||||
public static function area($ring) {
|
||||
|
||||
$no_of_points = count($ring);
|
||||
|
||||
// If the last point is same as the first point ignore it
|
||||
$last = count($ring) - 1;
|
||||
if (($ring[0]['x'] == $ring[$last]['x']) && ($ring[0]['y'] == $ring[$last]['y'])) {
|
||||
$no_of_points--;
|
||||
}
|
||||
|
||||
// _n-1
|
||||
// A = _1_ \ (X(i) * Y(i+1)) - (Y(i) * X(i+1))
|
||||
// 2 /__
|
||||
// i=0
|
||||
$area = 0;
|
||||
for ($i = 0; $i < $no_of_points; $i++) {
|
||||
$j = ($i + 1) % $no_of_points;
|
||||
$area += $ring[$i]['x'] * $ring[$j]['y'];
|
||||
$area -= $ring[$i]['y'] * $ring[$j]['x'];
|
||||
}
|
||||
$area /= 2.0;
|
||||
|
||||
return $area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a set of points represents an outer ring.
|
||||
* If points are in clockwise orientation then, they form an outer ring.
|
||||
*
|
||||
* @param array $ring array of points forming the ring
|
||||
*
|
||||
* @return whether a set of points represents an outer ring.
|
||||
*/
|
||||
public static function isOuterRing($ring)
|
||||
{
|
||||
// If area is negative then it's in clockwise orientation, i.e. it's an outer ring
|
||||
if (PMA_GIS_Polygon::area($ring) < 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given point is inside a given polygon.
|
||||
*
|
||||
* @param array $point x, y coordinates of the point
|
||||
* @param array $ring array of points forming the ring
|
||||
*
|
||||
* @return whether a given point is inside a given polygon
|
||||
*/
|
||||
public static function isPointInsidePolygon($point, $polygon)
|
||||
{
|
||||
// If first point is repeated at the end remove it
|
||||
$last = count($polygon) - 1;
|
||||
if (($polygon[0]['x'] == $polygon[$last]['x']) && ($polygon[0]['y'] == $polygon[$last]['y'])) {
|
||||
$polygon = array_slice($polygon, 0, $last);
|
||||
}
|
||||
|
||||
$no_of_points = count($polygon);
|
||||
$counter = 0;
|
||||
|
||||
// Use ray casting algorithm
|
||||
$p1 = $polygon[0];
|
||||
for ($i = 1; $i <= $no_of_points; $i++) {
|
||||
$p2 = $polygon[$i % $no_of_points];
|
||||
if ($point['y'] > min(array($p1['y'], $p2['y']))) {
|
||||
if ($point['y'] <= max(array($p1['y'], $p2['y']))) {
|
||||
if ($point['x'] <= max(array($p1['x'], $p2['x']))) {
|
||||
if ($p1['y'] != $p2['y']) {
|
||||
$xinters = ($point['y'] - $p1['y']) * ($p2['x'] - $p1['x']) / ($p2['y'] - $p1['y']) + $p1['x'];
|
||||
if ($p1['x'] == $p2['x'] || $point['x'] <= $xinters) {
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$p1 = $p2;
|
||||
}
|
||||
|
||||
if ($counter % 2 == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate parameters for the GIS data editor from the value of the GIS column.
|
||||
*
|
||||
* @param string $value of the GIS column
|
||||
|
||||
@ -18,8 +18,11 @@ if (isset($plugin_list)) {
|
||||
);
|
||||
} else {
|
||||
|
||||
ini_set('memory_limit', '128M');
|
||||
set_time_limit(120);
|
||||
if ((int) ini_get('memory_limit') < 512) {
|
||||
ini_set('memory_limit', '512M');
|
||||
}
|
||||
set_time_limit(300);
|
||||
|
||||
|
||||
// Append the bfShapeFiles directory to the include path variable
|
||||
set_include_path(get_include_path() . PATH_SEPARATOR . getcwd() . '/libraries/bfShapeFiles/');
|
||||
@ -208,7 +211,7 @@ if (isset($plugin_list)) {
|
||||
}
|
||||
|
||||
$shp = new PMA_ShapeFile(1);
|
||||
// If the zip archive has more than one file, get the content to the buffer from .shp file.
|
||||
// If the zip archive has more than one file, get the correct content to the buffer from .shp file.
|
||||
if ($compression == 'application/zip' && PMA_getNoOfFilesInZip($import_file) > 1) {
|
||||
$zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i');
|
||||
$GLOBALS['import_text'] = $zip_content['data'];
|
||||
@ -227,7 +230,7 @@ if (isset($plugin_list)) {
|
||||
// Extract the .dbf file and point to it.
|
||||
$extracted = PMA_zipExtract($import_file, realpath($cfg['TempDir']), array($dbf_file_name));
|
||||
if ($extracted) {
|
||||
$dbf_file_path = realpath($cfg['TempDir']) . '/' . $dbf_file_name;
|
||||
$dbf_file_path = realpath($cfg['TempDir']) . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name;
|
||||
$temp_dbf_file = true;
|
||||
// Replace the .dbf with .*, as required by the bsShapeFiles library.
|
||||
$file_name = substr($dbf_file_path, 0, strlen($dbf_file_path) - 4) . '.*';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user