' . __('Select two different columns')
/* For tbl_change.js */
$js_messages['strIgnore'] = __('Ignore');
+$js_messages['strCopy'] = __('Copy');
+$js_messages['strX'] = __('X');
+$js_messages['strY'] = __('Y');
+$js_messages['strPoint'] = __('Point');
+$js_messages['strLineString'] = __('Linestring');
+$js_messages['strPolygon'] = __('Polygon');
+$js_messages['strGeometry'] = __('Geometry');
+$js_messages['strInnerRing'] = __('Inner Ring');
+$js_messages['strOuterRing'] = __('Outer Ring');
+$js_messages['strAddPoint'] = __('Add a point');
+$js_messages['strAddInnerRing'] = __('Add an inner ring');
+$js_messages['strAddPolygon'] = __('Add a polygon');
/* For tbl_structure.js */
$js_messages['strAddColumns'] = __('Add columns');
diff --git a/js/sql.js b/js/sql.js
index f4a7475152..99fd93c703 100644
--- a/js/sql.js
+++ b/js/sql.js
@@ -334,10 +334,10 @@ $(document).ready(function() {
*/
var button_options = {};
// in the following function we need to use $(this)
- button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
+ button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
var button_options_error = {};
- button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
+ button_options_error[PMA_messages['strOK']] = function() {$(this).dialog('close').remove();}
var $form = $("#resultsForm");
var $msgbox = PMA_ajaxShowMessage();
@@ -351,6 +351,9 @@ $(document).ready(function() {
height: 230,
width: 900,
open: PMA_verifyTypeOfAllColumns,
+ close: function(event, ui) {
+ $('#change_row_dialog').remove();
+ },
buttons : button_options_error
})// end dialog options
} else {
@@ -361,6 +364,9 @@ $(document).ready(function() {
height: 600,
width: 900,
open: PMA_verifyTypeOfAllColumns,
+ close: function(event, ui) {
+ $('#change_row_dialog').remove();
+ },
buttons : button_options
})
//Remove the top menu container from the dialog
diff --git a/js/tbl_change.js b/js/tbl_change.js
index 17677b97ee..25bc120349 100644
--- a/js/tbl_change.js
+++ b/js/tbl_change.js
@@ -218,11 +218,38 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
* Ajax handlers for Change Table page
*
* Actions Ajaxified here:
- * Submit Data to be inserted into the table
+ * Submit Data to be inserted into the table.
* Restart insertion with 'N' rows.
*/
$(document).ready(function() {
+ $('.open_gis_editor').live('click', function(event) {
+ event.preventDefault();
+
+ var $span = $(this);
+ // Current value
+ var value = $span.parent('td').children("input[type='text']").val();
+ // Field name
+ var field = $span.parents('tr').children('td:first').find("input[type='hidden']").val();
+ // Column type
+ var type = $span.parents('tr').find('span.column_type').text();
+ // Names of input field and null checkbox
+ var input_name = $span.parent('td').children("input[type='text']").attr('name');
+ //Token
+ var token = $("input[name='token']").val();
+
+ openGISEditor(value, field, type, input_name, token);
+ });
+
+ /**
+ * Uncheck the null checkbox as geometry data is placed on the input field
+ */
+ $("input[name='gis_data[save]']").live('click', function(event) {
+ var input_name = $('form#gis_data_editor_form').find("input[name='input_name']").val();
+ var $null_checkbox = $("input[name='" + input_name + "']").parents('tr').find('.checkbox_null');
+ $null_checkbox.attr('checked', false);
+ });
+
// these were hidden via the "hide" class
$('.foreign_values_anchor').show();
diff --git a/js/tbl_gis_visualization.js b/js/tbl_gis_visualization.js
index 978cd69308..0a84189c49 100644
--- a/js/tbl_gis_visualization.js
+++ b/js/tbl_gis_visualization.js
@@ -8,7 +8,9 @@
*/
var x = 0;
+var default_x = 0;
var y = 0;
+var default_y = 0;
var scale = 1;
var svg;
@@ -51,56 +53,52 @@ function zoomAndPan()
}
/**
- * Ajax handlers for GIS visualization page
- *
- * Actions Ajaxified here:
- *
- * Zooming in and zooming out on mousewheel movement.
- * Panning the visualization on dragging.
- * Zooming in on double clicking.
- * Zooming out on clicking the zoom out button.
- * Panning on clicking the arrow buttons.
- * Displaying tooltips for GIS objects.
+ * Initially loads either SVG or OSM visualization based on the choice.
*/
-$(document).ready(function() {
- var $placeholder = $('#placeholder');
- var $openlayersmap = $('#openlayersmap');
-
- if ($('#choice').prop('checked') != true) {
- $openlayersmap.hide();
+function selectVisualization() {
+ if ($('#choice').prop('checked') != true) {
+ $('#openlayersmap').hide();
} else {
- $placeholder.hide();
+ $('#placeholder').hide();
}
+ $('.choice').show();
+}
+/**
+ * Adds necessary styles to the div that coontains the openStreetMap.
+ */
+function styleOSM() {
+ var $placeholder = $('#placeholder');
var cssObj = {
'border' : '1px solid #aaa',
'width' : $placeholder.width(),
'height' : $placeholder.height(),
'float' : 'right'
};
- $openlayersmap.css(cssObj);
- drawOpenLayers();
+ $('#openlayersmap').css(cssObj);
+}
- $('.choice').show();
- $('#choice').bind('click', function() {
- if ($(this).prop('checked') == false) {
- $placeholder.show();
- $openlayersmap.hide();
- } else {
- $placeholder.hide();
- $openlayersmap.show();
- }
- });
+/**
+ * Loads the SVG element and make a reference to it.
+ */
+function loadSVG() {
+ var $placeholder = $('#placeholder');
- $('#placeholder').svg({
+ $placeholder.svg({
onLoad: function(svg_ref) {
svg = svg_ref;
}
});
- // Removes the second SVG element unnecessarily added due to the above command.
- $('#placeholder').find('svg:nth-child(2)').remove();
+ // Removes the second SVG element unnecessarily added due to the above command
+ $placeholder.find('svg:nth-child(2)').remove();
+}
+/**
+ * Adds controllers for zooming and panning.
+ */
+function addZoomPanControllers() {
+ var $placeholder = $('#placeholder');
if ($("#placeholder svg").length > 0) {
var pmaThemeImage = $('#pmaThemeImage').attr('value');
// add panning arrows
@@ -113,7 +111,81 @@ $(document).ready(function() {
$(' ').appendTo($placeholder);
$(' ').appendTo($placeholder);
}
+}
+/**
+ * Resizes the GIS visualization to fit into the space available.
+ */
+function resizeGISVisualization() {
+ var $placeholder = $('#placeholder');
+
+ // Hide inputs for width and height
+ $("input[name='visualizationSettings[width]']").parents('tr').remove();
+ $("input[name='visualizationSettings[height]']").parents('tr').remove();
+
+ var old_width = $placeholder.width();
+ var extraPadding = 100;
+ var leftWidth = $('.gis_table').width();
+ var windowWidth = document.documentElement.clientWidth;
+ var visWidth = windowWidth - extraPadding - leftWidth;
+
+ // Assign new value for width
+ $placeholder.width(visWidth);
+ $('svg').attr('width', visWidth);
+
+ // Assign the offset created due to resizing to default_x and center the svg.
+ default_x = (visWidth - old_width) / 2;
+ x = default_x;
+}
+
+/**
+ * Initialize the GIS visualization.
+ */
+function initGISVisualization() {
+ // Loads either SVG or OSM visualization based on the choice
+ selectVisualization();
+ // Resizes the GIS visualization to fit into the space available
+ resizeGISVisualization();
+ // Adds necessary styles to the div that coontains the openStreetMap
+ styleOSM();
+ // Draws openStreetMap with openLayers
+ drawOpenLayers();
+ // Loads the SVG element and make a reference to it
+ loadSVG();
+ // Adds controllers for zooming and panning
+ addZoomPanControllers();
+ zoomAndPan();
+}
+
+/**
+ * Ajax handlers for GIS visualization page
+ *
+ * Actions Ajaxified here:
+ *
+ * Zooming in and zooming out on mousewheel movement.
+ * Panning the visualization on dragging.
+ * Zooming in on double clicking.
+ * Zooming out on clicking the zoom out button.
+ * Panning on clicking the arrow buttons.
+ * Displaying tooltips for GIS objects.
+ */
+$(document).ready(function() {
+
+ // If we are in GIS visualization, initialize it
+ if ($('.gis_table').length > 0) {
+ initGISVisualization();
+ }
+
+ $('#choice').live('click', function() {
+ if ($(this).prop('checked') == false) {
+ $('#placeholder').show();
+ $('#openlayersmap').hide();
+ } else {
+ $('#placeholder').hide();
+ $('#openlayersmap').show();
+ }
+ });
+
$('#placeholder').live('mousewheel', function(event, delta) {
if (delta > 0) {
//zoom in
@@ -135,13 +207,13 @@ $(document).ready(function() {
var dragX = 0; var dragY = 0;
$('svg').live('dragstart', function(event, dd) {
- $placeholder.addClass('placeholderDrag');
+ $('#placeholder').addClass('placeholderDrag');
dragX = Math.round(dd.offsetX);
dragY = Math.round(dd.offsetY);
});
$('svg').live('mouseup', function(event) {
- $placeholder.removeClass('placeholderDrag');
+ $('#placeholder').removeClass('placeholderDrag');
});
$('svg').live('drag', function(event, dd) {
@@ -178,8 +250,8 @@ $(document).ready(function() {
$('#zoom_world').live('click', function(e) {
e.preventDefault();
scale = 1;
- x = 0;
- y = 0;
+ x = default_x;
+ y = default_y;
zoomAndPan();
});
@@ -225,7 +297,7 @@ $(document).ready(function() {
*/
$('.polygon, .multipolygon, .point, .multipoint, .linestring, .multilinestring, '
+ '.geometrycollection').live('mousemove', function(event) {
- contents = $(this).attr('name');
+ contents = $.trim($(this).attr('name'));
$("#tooltip").remove();
if (contents != '') {
$('' + contents + '
').css({
diff --git a/js/tbl_select.js b/js/tbl_select.js
index af2242ad5e..4f6ddf0883 100644
--- a/js/tbl_select.js
+++ b/js/tbl_select.js
@@ -68,7 +68,7 @@ $(document).ready(function() {
$("#sqlqueryresults").html(response);
$("#sqlqueryresults").trigger('appendAnchor');
$('#tbl_search_form')
- // work around for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
+ // workaround for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
.slideToggle()
.hide();
$('#togglesearchformlink')
@@ -87,4 +87,91 @@ $(document).ready(function() {
});
}) // end $.post()
})
+
+ // Following section is related to the 'function based search' for geometry data types.
+ // Initialy hide all the open_gis_editor spans
+ $('.open_search_gis_editor').hide();
+
+ $('.geom_func').bind('change', function() {
+ var $geomFuncSelector = $(this);
+
+ var binaryFunctions = [
+ 'Contains',
+ 'Crosses',
+ 'Disjoint',
+ 'Equals',
+ 'Intersects',
+ 'Overlaps',
+ 'Touches',
+ 'Within',
+ 'MBRContains',
+ 'MBRDisjoint',
+ 'MBREquals',
+ 'MBRIntersects',
+ 'MBROverlaps',
+ 'MBRTouches',
+ 'MBRWithin',
+ 'ST_Contains',
+ 'ST_Crosses',
+ 'ST_Disjoint',
+ 'ST_Equals',
+ 'ST_Intersects',
+ 'ST_Overlaps',
+ 'ST_Touches',
+ 'ST_Within',
+ ];
+
+ var tempArray = [
+ 'Envelope',
+ 'EndPoint',
+ 'StartPoint',
+ 'ExteriorRing',
+ 'Centroid',
+ 'PointOnSurface'
+ ];
+ var outputGeomFunctions = binaryFunctions.concat(tempArray);
+
+ // If the chosen function takes two geomerty objects as parameters
+ var $operator = $geomFuncSelector.parents('tr').find('td:nth-child(5)').find('select');
+ if ($.inArray($geomFuncSelector.val(), binaryFunctions) >= 0){
+ $operator.attr('readonly', true);
+ } else {
+ $operator.attr('readonly', false);
+ }
+
+ // if the chosen function's output is a geometry, enable GIS editor
+ var $editorSpan = $geomFuncSelector.parents('tr').find('.open_search_gis_editor');
+ if ($.inArray($geomFuncSelector.val(), outputGeomFunctions) >= 0){
+ $editorSpan.show();
+ } else {
+ $editorSpan.hide();
+ }
+
+ });
+
+ $('.open_search_gis_editor').live('click', function(event) {
+ event.preventDefault();
+
+ var $span = $(this);
+ // Current value
+ var value = $span.parent('td').children("input[type='text']").val();
+ // Field name
+ var field = 'Parameter';
+ // Column type
+ var geom_func = $span.parents('tr').find('.geom_func').val();
+ if (geom_func == 'Envelope') {
+ var type = 'polygon';
+ } else if (geom_func == 'ExteriorRing') {
+ var type = 'linestring';
+ } else {
+ var type = 'point';
+ }
+ // Names of input field and null checkbox
+ var input_name = $span.parent('td').children("input[type='text']").attr('name');
+ //Token
+ var token = $("input[name='token']").val();
+
+ openGISEditor(value, field, type, input_name, token);
+ });
+
}, 'top.frame_content'); // end $(document).ready()
diff --git a/libraries/bfShapeFiles/ShapeFile.lib.php b/libraries/bfShapeFiles/ShapeFile.lib.php
new file mode 100644
index 0000000000..0680708c05
--- /dev/null
+++ b/libraries/bfShapeFiles/ShapeFile.lib.php
@@ -0,0 +1,649 @@
+= 0 ; $i--) {
+ $result .= $binValue{$i};
+ }
+
+ return $result;
+ }
+
+ function packDouble($value, $mode = 'LE') {
+ $value = (double)$value;
+ $bin = pack("d", $value);
+
+ //We test if the conversion of an integer (1) is done as LE or BE by default
+ switch (pack ('L', 1)) {
+ case pack ('V', 1): //Little Endian
+ $result = ($mode == 'LE') ? $bin : swap($bin);
+ break;
+ case pack ('N', 1): //Big Endian
+ $result = ($mode == 'BE') ? $bin : swap($bin);
+ break;
+ default: //Some other thing, we just return false
+ $result = FALSE;
+ }
+
+ return $result;
+ }
+
+ class ShapeFile {
+ var $FileName;
+
+ var $SHPFile;
+ var $SHXFile;
+ var $DBFFile;
+
+ var $DBFHeader;
+
+ var $lastError = "";
+
+ var $boundingBox = array("xmin" => 0.0, "ymin" => 0.0, "xmax" => 0.0, "ymax" => 0.0);
+ var $fileLength = 0;
+ var $shapeType = 0;
+
+ var $records;
+
+ function ShapeFile($shapeType, $boundingBox = array("xmin" => 0.0, "ymin" => 0.0, "xmax" => 0.0, "ymax" => 0.0), $FileName = NULL) {
+ $this->shapeType = $shapeType;
+ $this->boundingBox = $boundingBox;
+ $this->FileName = $FileName;
+ $this->fileLength = 50;
+ }
+
+ function loadFromFile($FileName) {
+ $this->FileName = $FileName;
+
+ if (($this->_openSHPFile()) && ($this->_openDBFFile())) {
+ $this->_loadHeaders();
+ $this->_loadRecords();
+ $this->_closeSHPFile();
+ $this->_closeDBFFile();
+ } else {
+ return false;
+ }
+ }
+
+ function saveToFile($FileName = NULL) {
+ if ($FileName != NULL) $this->FileName = $FileName;
+
+ if (($this->_openSHPFile(TRUE)) && ($this->_openSHXFile(TRUE)) && ($this->_openDBFFile(TRUE))) {
+ $this->_saveHeaders();
+ $this->_saveRecords();
+ $this->_closeSHPFile();
+ $this->_closeSHXFile();
+ $this->_closeDBFFile();
+ } else {
+ return false;
+ }
+ }
+
+ function addRecord($record) {
+ if ((isset($this->DBFHeader)) && (is_array($this->DBFHeader))) {
+ $record->updateDBFInfo($this->DBFHeader);
+ }
+
+ $this->fileLength += ($record->getContentLength() + 4);
+ $this->records[] = $record;
+ $this->records[count($this->records) - 1]->recordNumber = count($this->records);
+
+ return (count($this->records) - 1);
+ }
+
+ function deleteRecord($index) {
+ if (isset($this->records[$index])) {
+ $this->fileLength -= ($this->records[$index]->getContentLength() + 4);
+ for ($i = $index; $i < (count($this->records) - 1); $i++) {
+ $this->records[$i] = $this->records[$i + 1];
+ }
+ unset($this->records[count($this->records) - 1]);
+ $this->_deleteRecordFromDBF($index);
+ }
+ }
+
+ function getDBFHeader() {
+ return $this->DBFHeader;
+ }
+
+ function setDBFHeader($header) {
+ $this->DBFHeader = $header;
+
+ for ($i = 0; $i < count($this->records); $i++) {
+ $this->records[$i]->updateDBFInfo($header);
+ }
+ }
+
+ function getIndexFromDBFData($field, $value) {
+ $result = -1;
+ for ($i = 0; $i < (count($this->records) - 1); $i++) {
+ if (isset($this->records[$i]->DBFData[$field]) && (strtoupper($this->records[$i]->DBFData[$field]) == strtoupper($value))) {
+ $result = $i;
+ }
+ }
+
+ return $result;
+ }
+
+ function _loadDBFHeader() {
+ $DBFFile = fopen(str_replace('.*', '.dbf', $this->FileName), 'r');
+
+ $result = array();
+ $buff32 = array();
+ $i = 1;
+ $inHeader = true;
+
+ while ($inHeader) {
+ if (!feof($DBFFile)) {
+ $buff32 = fread($DBFFile, 32);
+ if ($i > 1) {
+ if (substr($buff32, 0, 1) == chr(13)) {
+ $inHeader = false;
+ } else {
+ $pos = strpos(substr($buff32, 0, 10), chr(0));
+ $pos = ($pos == 0 ? 10 : $pos);
+
+ $fieldName = substr($buff32, 0, $pos);
+ $fieldType = substr($buff32, 11, 1);
+ $fieldLen = ord(substr($buff32, 16, 1));
+ $fieldDec = ord(substr($buff32, 17, 1));
+
+ array_push($result, array($fieldName, $fieldType, $fieldLen, $fieldDec));
+ }
+ }
+ $i++;
+ } else {
+ $inHeader = false;
+ }
+ }
+
+ fclose($DBFFile);
+ return($result);
+ }
+
+ function _deleteRecordFromDBF($index) {
+ if (@dbase_delete_record($this->DBFFile, $index)) {
+ @dbase_pack($this->DBFFile);
+ }
+ }
+
+ function _loadHeaders() {
+ fseek($this->SHPFile, 24, SEEK_SET);
+ $this->fileLength = loadData("N", fread($this->SHPFile, 4));
+
+ fseek($this->SHPFile, 32, SEEK_SET);
+ $this->shapeType = loadData("V", fread($this->SHPFile, 4));
+
+ $this->boundingBox = array();
+ $this->boundingBox["xmin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->boundingBox["ymin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->boundingBox["xmax"] = loadData("d", fread($this->SHPFile, 8));
+ $this->boundingBox["ymax"] = loadData("d", fread($this->SHPFile, 8));
+
+ $this->DBFHeader = $this->_loadDBFHeader();
+ }
+
+ function _saveHeaders() {
+ fwrite($this->SHPFile, pack("NNNNNN", 9994, 0, 0, 0, 0, 0));
+ fwrite($this->SHPFile, pack("N", $this->fileLength));
+ fwrite($this->SHPFile, pack("V", 1000));
+ fwrite($this->SHPFile, pack("V", $this->shapeType));
+ fwrite($this->SHPFile, packDouble($this->boundingBox['xmin']));
+ fwrite($this->SHPFile, packDouble($this->boundingBox['ymin']));
+ fwrite($this->SHPFile, packDouble($this->boundingBox['xmax']));
+ fwrite($this->SHPFile, packDouble($this->boundingBox['ymax']));
+ fwrite($this->SHPFile, pack("dddd", 0, 0, 0, 0));
+
+ fwrite($this->SHXFile, pack("NNNNNN", 9994, 0, 0, 0, 0, 0));
+ fwrite($this->SHXFile, pack("N", 50 + 4*count($this->records)));
+ fwrite($this->SHXFile, pack("V", 1000));
+ fwrite($this->SHXFile, pack("V", $this->shapeType));
+ fwrite($this->SHXFile, packDouble($this->boundingBox['xmin']));
+ fwrite($this->SHXFile, packDouble($this->boundingBox['ymin']));
+ fwrite($this->SHXFile, packDouble($this->boundingBox['xmax']));
+ fwrite($this->SHXFile, packDouble($this->boundingBox['ymax']));
+ fwrite($this->SHXFile, pack("dddd", 0, 0, 0, 0));
+ }
+
+ function _loadRecords() {
+ fseek($this->SHPFile, 100);
+ while (!feof($this->SHPFile)) {
+ $bByte = ftell($this->SHPFile);
+ $record = new ShapeRecord(-1);
+ $record->loadFromFile($this->SHPFile, $this->DBFFile);
+ $eByte = ftell($this->SHPFile);
+ if (($eByte <= $bByte) || ($record->lastError != "")) {
+ return false;
+ }
+
+ $this->records[] = $record;
+ }
+ }
+
+ function _saveRecords() {
+ if (file_exists(str_replace('.*', '.dbf', $this->FileName))) {
+ @unlink(str_replace('.*', '.dbf', $this->FileName));
+ }
+ if (!($this->DBFFile = @dbase_create(str_replace('.*', '.dbf', $this->FileName), $this->DBFHeader))) {
+ return $this->setError(sprintf("It wasn't possible to create the DBase file '%s'", str_replace('.*', '.dbf', $this->FileName)));
+ }
+
+ $offset = 50;
+ if (is_array($this->records) && (count($this->records) > 0)) {
+ reset($this->records);
+ while (list($index, $record) = each($this->records)) {
+ //Save the record to the .shp file
+ $record->saveToFile($this->SHPFile, $this->DBFFile, $index + 1);
+
+ //Save the record to the .shx file
+ fwrite($this->SHXFile, pack("N", $offset));
+ fwrite($this->SHXFile, pack("N", $record->getContentLength()));
+ $offset += (4 + $record->getContentLength());
+ }
+ }
+ @dbase_pack($this->DBFFile);
+ }
+
+ function _openSHPFile($toWrite = false) {
+ $this->SHPFile = @fopen(str_replace('.*', '.shp', $this->FileName), ($toWrite ? "wb+" : "rb"));
+ if (!$this->SHPFile) {
+ return $this->setError(sprintf("It wasn't possible to open the Shape file '%s'", str_replace('.*', '.shp', $this->FileName)));
+ }
+
+ return TRUE;
+ }
+
+ function _closeSHPFile() {
+ if ($this->SHPFile) {
+ fclose($this->SHPFile);
+ $this->SHPFile = NULL;
+ }
+ }
+
+ function _openSHXFile($toWrite = false) {
+ $this->SHXFile = @fopen(str_replace('.*', '.shx', $this->FileName), ($toWrite ? "wb+" : "rb"));
+ if (!$this->SHXFile) {
+ return $this->setError(sprintf("It wasn't possible to open the Index file '%s'", str_replace('.*', '.shx', $this->FileName)));
+ }
+
+ return TRUE;
+ }
+
+ function _closeSHXFile() {
+ if ($this->SHXFile) {
+ fclose($this->SHXFile);
+ $this->SHXFile = NULL;
+ }
+ }
+
+ function _openDBFFile($toWrite = false) {
+ $checkFunction = $toWrite ? "is_writable" : "is_readable";
+ if (($toWrite) && (!file_exists(str_replace('.*', '.dbf', $this->FileName)))) {
+ if (!@dbase_create(str_replace('.*', '.dbf', $this->FileName), $this->DBFHeader)) {
+ return $this->setError(sprintf("It wasn't possible to create the DBase file '%s'", str_replace('.*', '.dbf', $this->FileName)));
+ }
+ }
+ if ($checkFunction(str_replace('.*', '.dbf', $this->FileName))) {
+ $this->DBFFile = dbase_open(str_replace('.*', '.dbf', $this->FileName), ($toWrite ? 2 : 0));
+ if (!$this->DBFFile) {
+ return $this->setError(sprintf("It wasn't possible to open the DBase file '%s'", str_replace('.*', '.dbf', $this->FileName)));
+ }
+ } else {
+ return $this->setError(sprintf("It wasn't possible to find the DBase file '%s'", str_replace('.*', '.dbf', $this->FileName)));
+ }
+ return TRUE;
+ }
+
+ function _closeDBFFile() {
+ if ($this->DBFFile) {
+ dbase_close($this->DBFFile);
+ $this->DBFFile = NULL;
+ }
+ }
+
+ function setError($error) {
+ $this->lastError = $error;
+ return false;
+ }
+ }
+
+ class ShapeRecord {
+ var $SHPFile = NULL;
+ var $DBFFile = NULL;
+
+ var $recordNumber = NULL;
+ var $shapeType = NULL;
+
+ var $lastError = "";
+
+ var $SHPData = array();
+ var $DBFData = array();
+
+ function ShapeRecord($shapeType) {
+ $this->shapeType = $shapeType;
+ }
+
+ function loadFromFile(&$SHPFile, &$DBFFile) {
+ $this->SHPFile = $SHPFile;
+ $this->DBFFile = $DBFFile;
+ $this->_loadHeaders();
+
+ switch ($this->shapeType) {
+ case 0:
+ $this->_loadNullRecord();
+ break;
+ case 1:
+ $this->_loadPointRecord();
+ break;
+ case 3:
+ $this->_loadPolyLineRecord();
+ break;
+ case 5:
+ $this->_loadPolygonRecord();
+ break;
+ case 8:
+ $this->_loadMultiPointRecord();
+ break;
+ default:
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ $this->_loadDBFData();
+ }
+
+ function saveToFile(&$SHPFile, &$DBFFile, $recordNumber) {
+ $this->SHPFile = $SHPFile;
+ $this->DBFFile = $DBFFile;
+ $this->recordNumber = $recordNumber;
+ $this->_saveHeaders();
+
+ switch ($this->shapeType) {
+ case 0:
+ $this->_saveNullRecord();
+ break;
+ case 1:
+ $this->_savePointRecord();
+ break;
+ case 3:
+ $this->_savePolyLineRecord();
+ break;
+ case 5:
+ $this->_savePolygonRecord();
+ break;
+ case 8:
+ $this->_saveMultiPointRecord();
+ break;
+ default:
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ $this->_saveDBFData();
+ }
+
+ function updateDBFInfo($header) {
+ $tmp = $this->DBFData;
+ unset($this->DBFData);
+ $this->DBFData = array();
+ reset($header);
+ while (list($key, $value) = each($header)) {
+ $this->DBFData[$value[0]] = (isset($tmp[$value[0]])) ? $tmp[$value[0]] : "";
+ }
+ }
+
+ function _loadHeaders() {
+ $this->recordNumber = loadData("N", fread($this->SHPFile, 4));
+ $tmp = loadData("N", fread($this->SHPFile, 4)); //We read the length of the record
+ $this->shapeType = loadData("V", fread($this->SHPFile, 4));
+ }
+
+ function _saveHeaders() {
+ fwrite($this->SHPFile, pack("N", $this->recordNumber));
+ fwrite($this->SHPFile, pack("N", $this->getContentLength()));
+ fwrite($this->SHPFile, pack("V", $this->shapeType));
+ }
+
+ function _loadPoint() {
+ $data = array();
+
+ $data["x"] = loadData("d", fread($this->SHPFile, 8));
+ $data["y"] = loadData("d", fread($this->SHPFile, 8));
+
+ return $data;
+ }
+
+ function _savePoint($data) {
+ fwrite($this->SHPFile, packDouble($data["x"]));
+ fwrite($this->SHPFile, packDouble($data["y"]));
+ }
+
+ function _loadNullRecord() {
+ $this->SHPData = array();
+ }
+
+ function _saveNullRecord() {
+ //Don't save anything
+ }
+
+ function _loadPointRecord() {
+ $this->SHPData = $this->_loadPoint();
+ }
+
+ function _savePointRecord() {
+ $this->_savePoint($this->SHPData);
+ }
+
+ function _loadMultiPointRecord() {
+ $this->SHPData = array();
+ $this->SHPData["xmin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["ymin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["xmax"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["ymax"] = loadData("d", fread($this->SHPFile, 8));
+
+ $this->SHPData["numpoints"] = loadData("V", fread($this->SHPFile, 4));
+
+ for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) {
+ $this->SHPData["points"][] = $this->_loadPoint();
+ }
+ }
+
+ function _saveMultiPointRecord() {
+ fwrite($this->SHPFile, pack("dddd", $this->SHPData["xmin"], $this->SHPData["ymin"], $this->SHPData["xmax"], $this->SHPData["ymax"]));
+
+ fwrite($this->SHPFile, pack("V", $this->SHPData["numpoints"]));
+
+ for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) {
+ $this->_savePoint($this->SHPData["points"][$i]);
+ }
+ }
+
+ function _loadPolyLineRecord() {
+ $this->SHPData = array();
+ $this->SHPData["xmin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["ymin"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["xmax"] = loadData("d", fread($this->SHPFile, 8));
+ $this->SHPData["ymax"] = loadData("d", fread($this->SHPFile, 8));
+
+ $this->SHPData["numparts"] = loadData("V", fread($this->SHPFile, 4));
+ $this->SHPData["numpoints"] = loadData("V", fread($this->SHPFile, 4));
+
+ for ($i = 0; $i < $this->SHPData["numparts"]; $i++) {
+ $this->SHPData["parts"][$i] = loadData("V", fread($this->SHPFile, 4));
+ }
+
+ $firstIndex = ftell($this->SHPFile);
+ $readPoints = 0;
+ reset($this->SHPData["parts"]);
+ while (list($partIndex, $partData) = each($this->SHPData["parts"])) {
+ if (!isset($this->SHPData["parts"][$partIndex]["points"]) || !is_array($this->SHPData["parts"][$partIndex]["points"])) {
+ $this->SHPData["parts"][$partIndex] = array();
+ $this->SHPData["parts"][$partIndex]["points"] = array();
+ }
+ while (!in_array($readPoints, $this->SHPData["parts"]) && ($readPoints < ($this->SHPData["numpoints"])) && !feof($this->SHPFile)) {
+ $this->SHPData["parts"][$partIndex]["points"][] = $this->_loadPoint();
+ $readPoints++;
+ }
+ }
+
+ fseek($this->SHPFile, $firstIndex + ($readPoints*16));
+ }
+
+ function _savePolyLineRecord() {
+ fwrite($this->SHPFile, pack("dddd", $this->SHPData["xmin"], $this->SHPData["ymin"], $this->SHPData["xmax"], $this->SHPData["ymax"]));
+
+ fwrite($this->SHPFile, pack("VV", $this->SHPData["numparts"], $this->SHPData["numpoints"]));
+
+ for ($i = 0; $i < $this->SHPData["numparts"]; $i++) {
+ fwrite($this->SHPFile, pack("V", count($this->SHPData["parts"][$i])));
+ }
+
+ reset($this->SHPData["parts"]);
+ foreach ($this->SHPData["parts"] as $partData){
+ reset($partData["points"]);
+ while (list($pointIndex, $pointData) = each($partData["points"])) {
+ $this->_savePoint($pointData);
+ }
+ }
+ }
+
+ function _loadPolygonRecord() {
+ $this->_loadPolyLineRecord();
+ }
+
+ function _savePolygonRecord() {
+ $this->_savePolyLineRecord();
+ }
+
+ function addPoint($point, $partIndex = 0) {
+ switch ($this->shapeType) {
+ case 0:
+ //Don't add anything
+ break;
+ case 1:
+ //Substitutes the value of the current point
+ $this->SHPData = $point;
+ break;
+ case 3:
+ case 5:
+ //Adds a new point to the selected part
+ if (!isset($this->SHPData["xmin"]) || ($this->SHPData["xmin"] > $point["x"])) $this->SHPData["xmin"] = $point["x"];
+ if (!isset($this->SHPData["ymin"]) || ($this->SHPData["ymin"] > $point["y"])) $this->SHPData["ymin"] = $point["y"];
+ if (!isset($this->SHPData["xmax"]) || ($this->SHPData["xmax"] < $point["x"])) $this->SHPData["xmax"] = $point["x"];
+ if (!isset($this->SHPData["ymax"]) || ($this->SHPData["ymax"] < $point["y"])) $this->SHPData["ymax"] = $point["y"];
+
+ $this->SHPData["parts"][$partIndex]["points"][] = $point;
+
+ $this->SHPData["numparts"] = count($this->SHPData["parts"]);
+ $this->SHPData["numpoints"]++;
+ break;
+ case 8:
+ //Adds a new point
+ if (!isset($this->SHPData["xmin"]) || ($this->SHPData["xmin"] > $point["x"])) $this->SHPData["xmin"] = $point["x"];
+ if (!isset($this->SHPData["ymin"]) || ($this->SHPData["ymin"] > $point["y"])) $this->SHPData["ymin"] = $point["y"];
+ if (!isset($this->SHPData["xmax"]) || ($this->SHPData["xmax"] < $point["x"])) $this->SHPData["xmax"] = $point["x"];
+ if (!isset($this->SHPData["ymax"]) || ($this->SHPData["ymax"] < $point["y"])) $this->SHPData["ymax"] = $point["y"];
+
+ $this->SHPData["points"][] = $point;
+ $this->SHPData["numpoints"]++;
+ break;
+ default:
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ }
+
+ function deletePoint($pointIndex = 0, $partIndex = 0) {
+ switch ($this->shapeType) {
+ case 0:
+ //Don't delete anything
+ break;
+ case 1:
+ //Sets the value of the point to zero
+ $this->SHPData["x"] = 0.0;
+ $this->SHPData["y"] = 0.0;
+ break;
+ case 3:
+ case 5:
+ //Deletes the point from the selected part, if exists
+ if (isset($this->SHPData["parts"][$partIndex]) && isset($this->SHPData["parts"][$partIndex]["points"][$pointIndex])) {
+ for ($i = $pointIndex; $i < (count($this->SHPData["parts"][$partIndex]["points"]) - 1); $i++) {
+ $this->SHPData["parts"][$partIndex]["points"][$i] = $this->SHPData["parts"][$partIndex]["points"][$i + 1];
+ }
+ unset($this->SHPData["parts"][$partIndex]["points"][count($this->SHPData["parts"][$partIndex]["points"]) - 1]);
+
+ $this->SHPData["numparts"] = count($this->SHPData["parts"]);
+ $this->SHPData["numpoints"]--;
+ }
+ break;
+ case 8:
+ //Deletes the point, if exists
+ if (isset($this->SHPData["points"][$pointIndex])) {
+ for ($i = $pointIndex; $i < (count($this->SHPData["points"]) - 1); $i++) {
+ $this->SHPData["points"][$i] = $this->SHPData["points"][$i + 1];
+ }
+ unset($this->SHPData["points"][count($this->SHPData["points"]) - 1]);
+
+ $this->SHPData["numpoints"]--;
+ }
+ break;
+ default:
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ }
+
+ function getContentLength() {
+ switch ($this->shapeType) {
+ case 0:
+ $result = 0;
+ break;
+ case 1:
+ $result = 10;
+ break;
+ case 3:
+ case 5:
+ $result = 22 + 2*count($this->SHPData["parts"]);
+ for ($i = 0; $i < count($this->SHPData["parts"]); $i++) {
+ $result += 8*count($this->SHPData["parts"][$i]["points"]);
+ }
+ break;
+ case 8:
+ $result = 20 + 8*count($this->SHPData["points"]);
+ break;
+ default:
+ $result = false;
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ return $result;
+ }
+
+ function _loadDBFData() {
+ $this->DBFData = @dbase_get_record_with_names($this->DBFFile, $this->recordNumber);
+ unset($this->DBFData["deleted"]);
+ }
+
+ function _saveDBFData() {
+ unset($this->DBFData["deleted"]);
+ if ($this->recordNumber <= dbase_numrecords($this->DBFFile)) {
+ if (!dbase_replace_record($this->DBFFile, array_values($this->DBFData), $this->recordNumber)) {
+ $this->setError("I wasn't possible to update the information in the DBF file.");
+ }
+ } else {
+ if (!dbase_add_record($this->DBFFile, array_values($this->DBFData))) {
+ $this->setError("I wasn't possible to add the information to the DBF file.");
+ }
+ }
+ }
+
+ function setError($error) {
+ $this->lastError = $error;
+ return false;
+ }
+ }
+
+?>
diff --git a/libraries/common.lib.php b/libraries/common.lib.php
index 0b89345629..f232b985cb 100644
--- a/libraries/common.lib.php
+++ b/libraries/common.lib.php
@@ -2073,6 +2073,13 @@ function PMA_getUniqueCondition($handle, $fields_cnt, $fields_meta, $row, $force
// this blob won't be part of the final condition
$con_val = null;
}
+ } elseif (in_array($meta->type, PMA_getGISDatatypes()) && ! empty($row[$i])) {
+ // do not build a too big condition
+ if (strlen($row[$i]) < 5000) {
+ $condition .= '=0x' . bin2hex($row[$i]) . ' AND';
+ } else {
+ $condition = '';
+ }
} elseif ($meta->type == 'bit') {
$con_val = "= b'" . PMA_printable_bit_value($row[$i], $meta->length) . "'";
} else {
@@ -2854,6 +2861,31 @@ function PMA_replace_binary_contents($content)
return $result;
}
+/**
+ * Converts GIS data to Well Known Text format
+ *
+ * @param $data GIS data
+ * @param $includeSRID Add SRID to the WKT
+ * @return GIS data in Well Know Text format
+ */
+function PMA_asWKT($data, $includeSRID = false) {
+ // Convert to WKT format
+ $hex = bin2hex($data);
+ $wktsql = "SELECT ASTEXT(x'" . $hex . "')";
+ if ($includeSRID) {
+ $wktsql .= ", SRID(x'" . $hex . "')";
+ }
+ $wktresult = PMA_DBI_try_query($wktsql, null, PMA_DBI_QUERY_STORE);
+ $wktarr = PMA_DBI_fetch_row($wktresult, 0);
+ $wktval = $wktarr[0];
+ if ($includeSRID) {
+ $srid = $wktarr[1];
+ $wktval = "'" . $wktval . "'," . $srid;
+ }
+ @PMA_DBI_free_result($wktresult);
+ return $wktval;
+}
+
/**
* If the string starts with a \r\n pair (0x0d0a) add an extra \n
*
@@ -3166,22 +3198,157 @@ function PMA_getSupportedDatatypes($html = false, $selected = '')
* @return array list of datatypes
*/
-function PMA_unsupportedDatatypes()
-{
- // These GIS data types are not yet supported.
- $no_support_types = array('geometry',
- 'point',
- 'linestring',
- 'polygon',
- 'multipoint',
- 'multilinestring',
- 'multipolygon',
- 'geometrycollection'
- );
-
+function PMA_unsupportedDatatypes() {
+ $no_support_types = array();
return $no_support_types;
}
+function PMA_getGISDatatypes($upper_case = false) {
+ $gis_data_types = array('geometry',
+ 'point',
+ 'linestring',
+ 'polygon',
+ 'multipoint',
+ 'multilinestring',
+ 'multipolygon',
+ 'geometrycollection'
+ );
+ if ($upper_case) {
+ for ($i = 0; $i < count($gis_data_types); $i++) {
+ $gis_data_types[$i] = strtoupper($gis_data_types[$i]);
+ }
+ }
+
+ return $gis_data_types;
+}
+
+/**
+ * Generates GIS data based on the string passed.
+ *
+ * @param string $gis_string GIS string
+ */
+function PMA_createGISData($gis_string) {
+ $gis_string = trim($gis_string);
+ $geom_types = '(POINT|MULTIPOINT|LINESTRING|MULTILINESTRING|POLYGON|MULTIPOLYGON|GEOMETRYCOLLECTION)';
+ if (preg_match("/^'" . $geom_types . "\(.*\)',[0-9]*$/i", $gis_string)) {
+ return 'GeomFromText(' . $gis_string . ')';
+ } elseif (preg_match("/^" . $geom_types . "\(.*\)$/i", $gis_string)) {
+ return "GeomFromText('" . $gis_string . "')";
+ } else {
+ return $gis_string;
+ }
+}
+
+/**
+ * Returns the names and details of the functions
+ * that can be applied on geometry data typess.
+ *
+ * @param string $geom_type if provided the output is limited to the functions
+ * that are applicable to the provided geometry type.
+ * @param bool $binary if set to false functions that take two geometries
+ * as arguments will not be included.
+ * @param bool $display if set to true seperators will be added to the
+ * output array.
+ *
+ * @return array names and details of the functions that can be applied on
+ * geometry data typess.
+ */
+function PMA_getGISFunctions($geom_type = null, $binary = true, $display = false) {
+
+ $funcs = array();
+ if ($display) {
+ $funcs[] = array('display' => ' ');
+ }
+
+ // Unary functions common to all geomety types
+ $funcs['Dimension'] = array('params' => 1, 'type' => 'int');
+ $funcs['Envelope'] = array('params' => 1, 'type' => 'Polygon');
+ $funcs['GeometryType'] = array('params' => 1, 'type' => 'text');
+ $funcs['SRID'] = array('params' => 1, 'type' => 'int');
+ $funcs['IsEmpty'] = array('params' => 1, 'type' => 'int');
+ $funcs['IsSimple'] = array('params' => 1, 'type' => 'int');
+
+ $geom_type = trim(strtolower($geom_type));
+ if ($display && $geom_type != 'geometry' && $geom_type != 'multipoint') {
+ $funcs[] = array('display' => '--------');
+ }
+
+ // Unary functions that are specific to each geomety type
+ if ($geom_type == 'point') {
+ $funcs['X'] = array('params' => 1, 'type' => 'float');
+ $funcs['Y'] = array('params' => 1, 'type' => 'float');
+
+ } elseif ($geom_type == 'multipoint') {
+ // no fucntions here
+ } elseif ($geom_type == 'linestring') {
+ $funcs['EndPoint'] = array('params' => 1, 'type' => 'point');
+ $funcs['GLength'] = array('params' => 1, 'type' => 'float');
+ $funcs['NumPoints'] = array('params' => 1, 'type' => 'int');
+ $funcs['StartPoint'] = array('params' => 1, 'type' => 'point');
+ $funcs['IsRing'] = array('params' => 1, 'type' => 'int');
+
+ } elseif ($geom_type == 'multilinestring') {
+ $funcs['GLength'] = array('params' => 1, 'type' => 'float');
+ $funcs['IsClosed'] = array('params' => 1, 'type' => 'int');
+
+ } elseif ($geom_type == 'polygon') {
+ $funcs['Area'] = array('params' => 1, 'type' => 'float');
+ $funcs['ExteriorRing'] = array('params' => 1, 'type' => 'linestring');
+ $funcs['NumInteriorRings'] = array('params' => 1, 'type' => 'int');
+
+ } elseif ($geom_type == 'multipolygon') {
+ $funcs['Area'] = array('params' => 1, 'type' => 'float');
+ $funcs['Centroid'] = array('params' => 1, 'type' => 'point');
+ // Not yet implemented in MySQL
+ //$funcs['PointOnSurface'] = array('params' => 1, 'type' => 'point');
+
+ } elseif ($geom_type == 'geometrycollection') {
+ $funcs['NumGeometries'] = array('params' => 1, 'type' => 'int');
+ }
+
+ // If we are asked for binary functions as well
+ if ($binary) {
+ // section seperator
+ if ($display) {
+ $funcs[] = array('display' => '--------');
+ }
+ if (PMA_MYSQL_INT_VERSION < 50601) {
+ $funcs['Crosses'] = array('params' => 2, 'type' => 'int');
+ $funcs['Contains'] = array('params' => 2, 'type' => 'int');
+ $funcs['Disjoint'] = array('params' => 2, 'type' => 'int');
+ $funcs['Equals'] = array('params' => 2, 'type' => 'int');
+ $funcs['Intersects'] = array('params' => 2, 'type' => 'int');
+ $funcs['Overlaps'] = array('params' => 2, 'type' => 'int');
+ $funcs['Touches'] = array('params' => 2, 'type' => 'int');
+ $funcs['Within'] = array('params' => 2, 'type' => 'int');
+ } else {
+ // If MySQl version is greaeter than or equal 5.6.1, use the ST_ prefix.
+ $funcs['ST_Crosses'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Contains'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Disjoint'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Equals'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Intersects'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Overlaps'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Touches'] = array('params' => 2, 'type' => 'int');
+ $funcs['ST_Within'] = array('params' => 2, 'type' => 'int');
+
+ }
+
+ if ($display) {
+ $funcs[] = array('display' => '--------');
+ }
+ // Minimum bounding rectangle functions
+ $funcs['MBRContains'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBRDisjoint'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBREquals'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBRIntersects'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBROverlaps'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBRTouches'] = array('params' => 2, 'type' => 'int');
+ $funcs['MBRWithin'] = array('params' => 2, 'type' => 'int');
+ }
+ return $funcs;
+}
+
/**
* Creates a dropdown box with MySQL functions for a particular column.
*
diff --git a/libraries/config.default.php b/libraries/config.default.php
index c40e784f83..9dea34af1e 100644
--- a/libraries/config.default.php
+++ b/libraries/config.default.php
@@ -2806,6 +2806,7 @@ if ($cfg['ShowFunctionFields']) {
'FUNC_CHAR' => '',
'FUNC_DATE' => '',
'FUNC_NUMBER' => '',
+ 'FUNC_SPATIAL' => 'GeomFromText',
'first_timestamp' => 'NOW',
'pk_char36' => 'UUID',
);
diff --git a/libraries/display_tbl.lib.php b/libraries/display_tbl.lib.php
index 4baa65fbd0..ddcfb7a175 100644
--- a/libraries/display_tbl.lib.php
+++ b/libraries/display_tbl.lib.php
@@ -1555,65 +1555,67 @@ function PMA_displayTableBody(&$dt_result, &$is_display, $map, $analyzed_sql)
// Remove 'grid_edit' from $class as we do not allow to inline-edit geometry data.
$class = str_replace('grid_edit', '', $class);
- // Display as [GEOMETRY - (size)]
- if ('GEOM' == $_SESSION['tmp_user_values']['geometry_display']) {
- $geometry_text = PMA_handle_non_printable_contents(
- 'GEOMETRY', (isset($row[$i]) ? $row[$i] : ''), $transform_function,
- $transform_options, $default_function, $meta
- );
- $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay(
- $class, $condition_field, $geometry_text
- );
+ if (! isset($row[$i]) || is_null($row[$i])) {
+ $vertical_display['data'][$row_no][$i] = PMA_buildNullDisplay($class, $condition_field);
+ } elseif ($row[$i] != '') {
+ // Display as [GEOMETRY - (size)]
+ if ('GEOM' == $_SESSION['tmp_user_values']['geometry_display']) {
+ $geometry_text = PMA_handle_non_printable_contents(
+ 'GEOMETRY', (isset($row[$i]) ? $row[$i] : ''), $transform_function,
+ $transform_options, $default_function, $meta
+ );
+ $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay(
+ $class, $condition_field, $geometry_text
+ );
- // Display in Well Known Text(WKT) format.
- } elseif ('WKT' == $_SESSION['tmp_user_values']['geometry_display']) {
- // Convert to WKT format
- $wktsql = "SELECT ASTEXT (GeomFromWKB(x'" . PMA_substr(bin2hex($row[$i]), 8) . "'))";
- $wktresult = PMA_DBI_try_query($wktsql, null, PMA_DBI_QUERY_STORE);
- $wktarr = PMA_DBI_fetch_row($wktresult, 0);
- $wktval = $wktarr[0];
- @PMA_DBI_free_result($wktresult);
+ // Display in Well Known Text(WKT) format.
+ } elseif ('WKT' == $_SESSION['tmp_user_values']['geometry_display']) {
+ // Convert to WKT format
+ $wktval = PMA_asWKT($row[$i]);
- if (PMA_strlen($wktval) > $GLOBALS['cfg']['LimitChars']
- && $_SESSION['tmp_user_values']['display_text'] == 'P'
- ) {
- $wktval = PMA_substr($wktval, 0, $GLOBALS['cfg']['LimitChars']) . '...';
- $is_field_truncated = true;
- }
-
- $vertical_display['data'][$row_no][$i] = ' $GLOBALS['cfg']['LimitChars']
+ if (PMA_strlen($wktval) > $GLOBALS['cfg']['LimitChars']
&& $_SESSION['tmp_user_values']['display_text'] == 'P'
) {
- $wkbval = PMA_substr($wkbval, 0, $GLOBALS['cfg']['LimitChars']) . '...';
+ $wktval = PMA_substr($wktval, 0, $GLOBALS['cfg']['LimitChars']) . '...';
$is_field_truncated = true;
}
$vertical_display['data'][$row_no][$i] = ' $GLOBALS['cfg']['LimitChars']
+ && $_SESSION['tmp_user_values']['display_text'] == 'P'
+ ) {
+ $wkbval = PMA_substr($wkbval, 0, $GLOBALS['cfg']['LimitChars']) . '...';
+ $is_field_truncated = true;
+ }
+
+ $vertical_display['data'][$row_no][$i] = ' $srid, 'wkt' => $wkt);
+ }
+
/**
* Extracts points, scales and returns them as an array.
*
@@ -141,14 +176,22 @@ abstract class PMA_GIS_Geometry
// Extract cordinates of the point
$cordinates = explode(" ", $point);
- if ($scale_data != null) {
- $x = ($cordinates[0] - $scale_data['x']) * $scale_data['scale'];
- $y = $scale_data['height'] - ($cordinates[1] - $scale_data['y']) * $scale_data['scale'];
+ if (isset($cordinates[0]) && trim($cordinates[0]) != ''
+ && isset($cordinates[1]) && trim($cordinates[1]) != ''
+ ) {
+ if ($scale_data != null) {
+ $x = ($cordinates[0] - $scale_data['x']) * $scale_data['scale'];
+ $y = $scale_data['height'] - ($cordinates[1] - $scale_data['y']) * $scale_data['scale'];
+ } else {
+ $x = trim($cordinates[0]);
+ $y = trim($cordinates[1]);
+ }
} else {
- $x = $cordinates[0];
- $y = $cordinates[1];
+ $x = '';
+ $y = '';
}
+
if (! $linear) {
$points_arr[] = array($x, $y);
} else {
diff --git a/libraries/gis/pma_gis_geometrycollection.php b/libraries/gis/pma_gis_geometrycollection.php
index a3da6bf3ad..96074d5767 100644
--- a/libraries/gis/pma_gis_geometrycollection.php
+++ b/libraries/gis/pma_gis_geometrycollection.php
@@ -53,6 +53,9 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
$type = substr($sub_part, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$scale_data = $gis_obj->scaleRow($sub_part);
// Upadate minimum/maximum values for x and y cordinates.
@@ -102,6 +105,9 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
$type = substr($sub_part, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$image = $gis_obj->prepareRowAsPng($sub_part, $label, $color, $scale_data, $image);
}
return $image;
@@ -130,6 +136,9 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
$type = substr($sub_part, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$pdf = $gis_obj->prepareRowAsPdf($sub_part, $label, $color, $scale_data, $pdf);
}
return $pdf;
@@ -159,6 +168,9 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
$type = substr($sub_part, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$row .= $gis_obj->prepareRowAsSvg($sub_part, $label, $color, $scale_data);
}
return $row;
@@ -190,6 +202,9 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
$type = substr($sub_part, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$row .= $gis_obj->prepareRowAsOl($sub_part, $srid, $label, $color, $scale_data);
}
return $row;
@@ -222,5 +237,71 @@ class PMA_GIS_Geometrycollection extends PMA_GIS_Geometry
}
return $sub_parts;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Value for empty points
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $geom_count = (isset($gis_data['GEOMETRYCOLLECTION']['geom_count']))
+ ? $gis_data['GEOMETRYCOLLECTION']['geom_count'] : 1;
+ $wkt = 'GEOMETRYCOLLECTION(';
+ for ($i = 0; $i < $geom_count; $i++) {
+ if (isset($gis_data[$i]['gis_type'])) {
+ $type = $gis_data[$i]['gis_type'];
+ $gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
+ $wkt .= $gis_obj->generateWkt($gis_data, $i, $empty) . ',';
+ }
+ }
+ if (isset($gis_data[0]['gis_type'])) {
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ }
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /** 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value)
+ {
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+
+ // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
+ $goem_col = substr($wkt, 19, (strlen($wkt) - 20));
+ // Split the geometry collection object to get its constituents.
+ $sub_parts = $this->_explodeGeomCol($goem_col);
+ $params['GEOMETRYCOLLECTION']['geom_count'] = count($sub_parts);
+
+ $i = 0;
+ foreach ($sub_parts as $sub_part) {
+ $type_pos = stripos($sub_part, '(');
+ $type = substr($sub_part, 0, $type_pos);
+
+ $gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
+ $params = array_merge($params, $gis_obj->generateParams($sub_part, $i));
+ $i++;
+ }
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_linestring.php b/libraries/gis/pma_gis_linestring.php
index 97113b7d8d..fc36b220ab 100644
--- a/libraries/gis/pma_gis_linestring.php
+++ b/libraries/gis/pma_gis_linestring.php
@@ -59,6 +59,7 @@ class PMA_GIS_Linestring extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $line_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($line_color, 1, 2));
$green = hexdec(substr($line_color, 3, 2));
$blue = hexdec(substr($line_color, 4, 2));
@@ -77,6 +78,10 @@ class PMA_GIS_Linestring extends PMA_GIS_Geometry
$temp_point = $point;
}
}
+ // print label if applicable
+ if (isset($label) && trim($label) != '') {
+ imagestring($image, 1, $points_arr[1][0], $points_arr[1][1], trim($label), $black);
+ }
return $image;
}
@@ -112,6 +117,12 @@ class PMA_GIS_Linestring extends PMA_GIS_Geometry
$temp_point = $point;
}
}
+ // print label
+ if (isset($label) && trim($label) != '') {
+ $pdf->SetXY($points_arr[1][0], $points_arr[1][1]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
+ }
return $pdf;
}
@@ -196,5 +207,70 @@ class PMA_GIS_Linestring extends PMA_GIS_Geometry
. json_encode($style_options) . '));';
return $result;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Value for empty points
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $no_of_points = isset($gis_data[$index]['LINESTRING']['no_of_points'])
+ ? $gis_data[$index]['LINESTRING']['no_of_points'] : 2;
+ if ($no_of_points < 2) {
+ $no_of_points = 2;
+ }
+ $wkt = 'LINESTRING(';
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $wkt .= ((isset($gis_data[$index]['LINESTRING'][$i]['x'])
+ && trim($gis_data[$index]['LINESTRING'][$i]['x']) != '')
+ ? $gis_data[$index]['LINESTRING'][$i]['x'] : $empty)
+ . ' ' . ((isset($gis_data[$index]['LINESTRING'][$i]['y'])
+ && trim($gis_data[$index]['LINESTRING'][$i]['y']) != '')
+ ? $gis_data[$index]['LINESTRING'][$i]['y'] : $empty) .',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'LINESTRING';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'LINESTRING(' and trailing ')'
+ $linestring = substr($wkt, 11, (strlen($wkt) - 12));
+ $points_arr = $this->extractPoints($linestring, null);
+
+ $no_of_points = count($points_arr);
+ $params[$index]['LINESTRING']['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['LINESTRING'][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['LINESTRING'][$i]['y'] = $points_arr[$i][1];
+ }
+
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_multilinestring.php b/libraries/gis/pma_gis_multilinestring.php
index 733cc84ff3..f5aa31f3ef 100644
--- a/libraries/gis/pma_gis_multilinestring.php
+++ b/libraries/gis/pma_gis_multilinestring.php
@@ -68,6 +68,7 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $line_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($line_color, 1, 2));
$green = hexdec(substr($line_color, 3, 2));
$blue = hexdec(substr($line_color, 4, 2));
@@ -78,6 +79,7 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
// Seperate each linestring
$linestirngs = explode("),(", $multilinestirng);
+ $first_line = true;
foreach ($linestirngs as $linestring) {
$points_arr = $this->extractPoints($linestring, $scale_data);
foreach ($points_arr as $point) {
@@ -90,6 +92,11 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
}
}
unset($temp_point);
+ // print label if applicable
+ if (isset($label) && trim($label) != '' && $first_line) {
+ imagestring($image, 1, $points_arr[1][0], $points_arr[1][1], trim($label), $black);
+ }
+ $first_line = false;
}
return $image;
}
@@ -118,6 +125,7 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
// Seperate each linestring
$linestirngs = explode("),(", $multilinestirng);
+ $first_line = true;
foreach ($linestirngs as $linestring) {
$points_arr = $this->extractPoints($linestring, $scale_data);
foreach ($points_arr as $point) {
@@ -130,6 +138,13 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
}
}
unset($temp_point);
+ // print label
+ if (isset($label) && trim($label) != '' && $first_line) {
+ $pdf->SetXY($points_arr[1][0], $points_arr[1][1]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
+ }
+ $first_line = false;
}
return $pdf;
}
@@ -225,5 +240,109 @@ class PMA_GIS_Multilinestring extends PMA_GIS_Geometry
$row .= ')), null, ' . json_encode($style_options) . '));';
return $row;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Value for empty points
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $no_of_lines = isset($gis_data[$index]['MULTILINESTRING']['no_of_lines'])
+ ? $gis_data[$index]['MULTILINESTRING']['no_of_lines'] : 1;
+ if ($no_of_lines < 1) {
+ $no_of_lines = 1;
+ }
+ $wkt = 'MULTILINESTRING(';
+ for ($i = 0; $i < $no_of_lines; $i++) {
+ $no_of_points = isset($gis_data[$index]['MULTILINESTRING'][$i]['no_of_points'])
+ ? $gis_data[$index]['MULTILINESTRING'][$i]['no_of_points'] : 2;
+ if ($no_of_points < 2) {
+ $no_of_points = 2;
+ }
+ $wkt .= '(';
+ for ($j = 0; $j < $no_of_points; $j++) {
+ $wkt .= ((isset($gis_data[$index]['MULTILINESTRING'][$i][$j]['x'])
+ && trim($gis_data[$index]['MULTILINESTRING'][$i][$j]['x']) != '')
+ ? $gis_data[$index]['MULTILINESTRING'][$i][$j]['x'] : $empty)
+ . ' ' . ((isset($gis_data[$index]['MULTILINESTRING'][$i][$j]['y'])
+ && trim($gis_data[$index]['MULTILINESTRING'][$i][$j]['y']) != '')
+ ? $gis_data[$index]['MULTILINESTRING'][$i][$j]['y'] : $empty) . ',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= '),';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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)
+ {
+ $wkt = 'MULTILINESTRING(';
+ for ($i = 0; $i < $row_data['numparts']; $i++) {
+ $wkt .= '(';
+ foreach ($row_data['parts'][$i]['points'] as $point) {
+ $wkt .= $point['x'] . ' ' . $point['y'] . ',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= '),';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'MULTILINESTRING';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
+ $multilinestirng = substr($wkt, 17, (strlen($wkt) - 19));
+ // Seperate each linestring
+ $linestirngs = explode("),(", $multilinestirng);
+ $params[$index]['MULTILINESTRING']['no_of_lines'] = count($linestirngs);
+
+ $j = 0;
+ foreach ($linestirngs as $linestring) {
+ $points_arr = $this->extractPoints($linestring, null);
+ $no_of_points = count($points_arr);
+ $params[$index]['MULTILINESTRING'][$j]['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['MULTILINESTRING'][$j][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['MULTILINESTRING'][$j][$i]['y'] = $points_arr[$i][1];
+ }
+ $j++;
+ }
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_multipoint.php b/libraries/gis/pma_gis_multipoint.php
index ce20f9248f..b557465b17 100644
--- a/libraries/gis/pma_gis_multipoint.php
+++ b/libraries/gis/pma_gis_multipoint.php
@@ -59,6 +59,7 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $point_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($point_color, 1, 2));
$green = hexdec(substr($point_color, 3, 2));
$blue = hexdec(substr($point_color, 4, 2));
@@ -70,7 +71,15 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
foreach ($points_arr as $point) {
// draw a small circle to mark the point
- imagearc($image, $point[0], $point[1], 7, 7, 0, 360, $color);
+ if ($point[0] != '' && $point[1] != '') {
+ imagearc($image, $point[0], $point[1], 7, 7, 0, 360, $color);
+ }
+ }
+ // print label for each point
+ if ((isset($label) && trim($label) != '')
+ && ($points_arr[0][0] != '' && $points_arr[0][1] != '')
+ ) {
+ imagestring($image, 1, $points_arr[0][0], $points_arr[0][1], trim($label), $black);
}
return $image;
}
@@ -100,7 +109,17 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
foreach ($points_arr as $point) {
// draw a small circle to mark the point
- $pdf->Circle($point[0], $point[1], 2, 0, 360, 'D', $line);
+ if ($point[0] != '' && $point[1] != '') {
+ $pdf->Circle($point[0], $point[1], 2, 0, 360, 'D', $line);
+ }
+ }
+ // print label for each point
+ if ((isset($label) && trim($label) != '')
+ && ($points_arr[0][0] != '' && $points_arr[0][1] != '')
+ ) {
+ $pdf->SetXY($points_arr[0][0], $points_arr[0][1]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
}
return $pdf;
}
@@ -131,12 +150,14 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
$row = '';
foreach ($points_arr as $point) {
- $row .= ' $val) {
- $row .= ' ' . $option . '="' . trim($val) . '"';
+ if ($point[0] != '' && $point[1] != '') {
+ $row .= ' $val) {
+ $row .= ' ' . $option . '="' . trim($val) . '"';
+ }
+ $row .= '/>';
}
- $row .= '/>';
}
return $row;
@@ -176,11 +197,15 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
$row = 'new Array(';
foreach ($points_arr as $point) {
- $row .= '(new OpenLayers.Geometry.Point(' . $point[0] . ', ' . $point[1]
- . ')).transform(new OpenLayers.Projection("EPSG:' . $srid
- . '"), map.getProjectionObject()), ';
+ if ($point[0] != '' && $point[1] != '') {
+ $row .= '(new OpenLayers.Geometry.Point(' . $point[0] . ', ' . $point[1]
+ . ')).transform(new OpenLayers.Projection("EPSG:' . $srid
+ . '"), map.getProjectionObject()), ';
+ }
+ }
+ if (substr($row, strlen($row) - 2) == ', ') {
+ $row = substr($row, 0, strlen($row) - 2);
}
- $row = substr($row, 0, strlen($row) - 2);
$row .= ')';
$result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector('
@@ -188,5 +213,88 @@ class PMA_GIS_Multipoint extends PMA_GIS_Geometry
. json_encode($style_options) . '));';
return $result;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Multipoint does not adhere to this
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $no_of_points = isset($gis_data[$index]['MULTIPOINT']['no_of_points'])
+ ? $gis_data[$index]['MULTIPOINT']['no_of_points'] : 1;
+ if ($no_of_points < 1) {
+ $no_of_points = 1;
+ }
+ $wkt = 'MULTIPOINT(';
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $wkt .= ((isset($gis_data[$index]['MULTIPOINT'][$i]['x'])
+ && trim($gis_data[$index]['MULTIPOINT'][$i]['x']) != '')
+ ? $gis_data[$index]['MULTIPOINT'][$i]['x'] : '')
+ . ' ' . ((isset($gis_data[$index]['MULTIPOINT'][$i]['y'])
+ && trim($gis_data[$index]['MULTIPOINT'][$i]['y']) != '')
+ ? $gis_data[$index]['MULTIPOINT'][$i]['y'] : '') . ',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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)
+ {
+ $wkt = 'MULTIPOINT(';
+ for ($i = 0; $i < $row_data['numpoints']; $i++) {
+ $wkt .= $row_data['points'][$i]['x'] . ' ' . $row_data['points'][$i]['y'] . ',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'MULTIPOINT';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'MULTIPOINT(' and trailing ')'
+ $points = substr($wkt, 11, (strlen($wkt) - 12));
+ $points_arr = $this->extractPoints($points, null);
+
+ $no_of_points = count($points_arr);
+ $params[$index]['MULTIPOINT']['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['MULTIPOINT'][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['MULTIPOINT'][$i]['y'] = $points_arr[$i][1];
+ }
+
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_multipolygon.php b/libraries/gis/pma_gis_multipolygon.php
index 431fc88cb8..b5765efb2e 100644
--- a/libraries/gis/pma_gis_multipolygon.php
+++ b/libraries/gis/pma_gis_multipolygon.php
@@ -82,6 +82,7 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $fill_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($fill_color, 1, 2));
$green = hexdec(substr($fill_color, 3, 2));
$blue = hexdec(substr($fill_color, 4, 2));
@@ -92,6 +93,7 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
// Seperate each polygon
$polygons = explode(")),((", $multipolygon);
+ $first_poly = true;
foreach ($polygons as $polygon) {
// If the polygon doesnt have an inner polygon
if (strpos($polygon, "),(") === false) {
@@ -112,6 +114,15 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
}
// draw polygon
imagefilledpolygon($image, $points_arr, sizeof($points_arr) / 2, $color);
+ // mark label point if applicable
+ if (isset($label) && trim($label) != '' && $first_poly) {
+ $label_point = array($points_arr[2], $points_arr[3]);
+ }
+ $first_poly = false;
+ }
+ // print label if applicable
+ if (isset($label_point)) {
+ imagestring($image, 1, $points_arr[2], $points_arr[3], trim($label), $black);
}
return $image;
}
@@ -140,6 +151,7 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
// Seperate each polygon
$polygons = explode(")),((", $multipolygon);
+ $first_poly = true;
foreach ($polygons as $polygon) {
// If the polygon doesnt have an inner polygon
if (strpos($polygon, "),(") === false) {
@@ -161,6 +173,18 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
}
// draw polygon
$pdf->Polygon($points_arr, 'F*', array(), $color, true);
+ // mark label point if applicable
+ if (isset($label) && trim($label) != '' && $first_poly) {
+ $label_point = array($points_arr[2], $points_arr[3]);
+ }
+ $first_poly = false;
+ }
+
+ // print label if applicable
+ if (isset($label_point)) {
+ $pdf->SetXY($label_point[0], $label_point[1]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
}
return $pdf;
}
@@ -287,5 +311,190 @@ class PMA_GIS_Multipolygon extends PMA_GIS_Geometry
return $row;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Value for empty points
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $no_of_polygons = isset($gis_data[$index]['MULTIPOLYGON']['no_of_polygons'])
+ ? $gis_data[$index]['MULTIPOLYGON']['no_of_polygons'] : 1;
+ if ($no_of_polygons < 1) {
+ $no_of_polygons = 1;
+ }
+ $wkt = 'MULTIPOLYGON(';
+ for ($k = 0; $k < $no_of_polygons; $k++) {
+ $no_of_lines = isset($gis_data[$index]['MULTIPOLYGON'][$k]['no_of_lines'])
+ ? $gis_data[$index]['MULTIPOLYGON'][$k]['no_of_lines'] : 1;
+ if ($no_of_lines < 1) {
+ $no_of_lines = 1;
+ }
+ $wkt .= '(';
+ for ($i = 0; $i < $no_of_lines; $i++) {
+ $no_of_points = isset($gis_data[$index]['MULTIPOLYGON'][$k][$i]['no_of_points'])
+ ? $gis_data[$index]['MULTIPOLYGON'][$k][$i]['no_of_points'] : 4;
+ if ($no_of_points < 4) {
+ $no_of_points = 4;
+ }
+ $wkt .= '(';
+ for ($j = 0; $j < $no_of_points; $j++) {
+ $wkt .= ((isset($gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['x'])
+ && trim($gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['x']) != '')
+ ? $gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['x'] : $empty)
+ . ' ' . ((isset($gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['y'])
+ && trim($gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['y']) != '')
+ ? $gis_data[$index]['MULTIPOLYGON'][$k][$i][$j]['y'] : $empty) .',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= '),';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= '),';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ return $wkt;
+ }
+
+ /**
+ * 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']);
+ }
+
+ // 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']) {
+ 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;
+ }
+
+ /**
+ * 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'MULTIPOLYGON';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'MULTIPOLYGON(((' and trailing ')))'
+ $multipolygon = substr($wkt, 15, (strlen($wkt) - 18));
+ // Seperate each polygon
+ $polygons = explode(")),((", $multipolygon);
+ $params[$index]['MULTIPOLYGON']['no_of_polygons'] = count($polygons);
+
+ $k = 0;
+ foreach ($polygons as $polygon) {
+ // If the polygon doesnt have an inner polygon
+ if (strpos($polygon, "),(") === false) {
+ $params[$index]['MULTIPOLYGON'][$k]['no_of_lines'] = 1;
+ $points_arr = $this->extractPoints($polygon, null);
+ $no_of_points = count($points_arr);
+ $params[$index]['MULTIPOLYGON'][$k][0]['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['MULTIPOLYGON'][$k][0][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['MULTIPOLYGON'][$k][0][$i]['y'] = $points_arr[$i][1];
+ }
+ } else {
+ // Seperate outer and inner polygons
+ $parts = explode("),(", $polygon);
+ $params[$index]['MULTIPOLYGON'][$k]['no_of_lines'] = count($parts);
+ $j = 0;
+ foreach ($parts as $ring) {
+ $points_arr = $this->extractPoints($ring, null);
+ $no_of_points = count($points_arr);
+ $params[$index]['MULTIPOLYGON'][$k][$j]['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['MULTIPOLYGON'][$k][$j][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['MULTIPOLYGON'][$k][$j][$i]['y'] = $points_arr[$i][1];
+ }
+ $j++;
+ }
+ }
+ $k++;
+ }
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_point.php b/libraries/gis/pma_gis_point.php
index 31531f31b0..82fb00c4ce 100644
--- a/libraries/gis/pma_gis_point.php
+++ b/libraries/gis/pma_gis_point.php
@@ -59,6 +59,7 @@ class PMA_GIS_Point extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $point_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($point_color, 1, 2));
$green = hexdec(substr($point_color, 3, 2));
$blue = hexdec(substr($point_color, 4, 2));
@@ -69,7 +70,13 @@ class PMA_GIS_Point extends PMA_GIS_Geometry
$points_arr = $this->extractPoints($point, $scale_data);
// draw a small circle to mark the point
- imagearc($image, $points_arr[0][0], $points_arr[0][1], 7, 7, 0, 360, $color);
+ if ($points_arr[0][0] != '' && $points_arr[0][1] != '') {
+ imagearc($image, $points_arr[0][0], $points_arr[0][1], 7, 7, 0, 360, $color);
+ // print label if applicable
+ if (isset($label) && trim($label) != '') {
+ imagestring($image, 1, $points_arr[0][0], $points_arr[0][1], trim($label), $black);
+ }
+ }
return $image;
}
@@ -97,7 +104,15 @@ class PMA_GIS_Point extends PMA_GIS_Geometry
$points_arr = $this->extractPoints($point, $scale_data);
// draw a small circle to mark the point
- $pdf->Circle($points_arr[0][0], $points_arr[0][1], 2, 0, 360, 'D', $line);
+ if ($points_arr[0][0] != '' && $points_arr[0][1] != '') {
+ $pdf->Circle($points_arr[0][0], $points_arr[0][1], 2, 0, 360, 'D', $line);
+ // print label if applicable
+ if (isset($label) && trim($label) != '') {
+ $pdf->SetXY($points_arr[0][0], $points_arr[0][1]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
+ }
+ }
return $pdf;
}
@@ -126,11 +141,14 @@ class PMA_GIS_Point extends PMA_GIS_Geometry
$point = substr($spatial, 6, (strlen($spatial) - 7));
$points_arr = $this->extractPoints($point, $scale_data);
- $row = ' $val) {
- $row .= ' ' . $option . '="' . trim($val) . '"';
+ $row = '';
+ if ($points_arr[0][0] != '' && $points_arr[0][1] != '') {
+ $row .= ' $val) {
+ $row .= ' ' . $option . '="' . trim($val) . '"';
+ }
+ $row .= '/>';
}
- $row .= '/>';
return $row;
}
@@ -167,12 +185,76 @@ class PMA_GIS_Point extends PMA_GIS_Geometry
$point = substr($spatial, 6, (strlen($spatial) - 7));
$points_arr = $this->extractPoints($point, null);
- $result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(('
- . 'new OpenLayers.Geometry.Point(' . $points_arr[0][0] . ', '
- . $points_arr[0][1] . ').transform(new OpenLayers.Projection("EPSG:'
- . $srid . '"), map.getProjectionObject())), null, '
- . json_encode($style_options) . '));';
+ if ($points_arr[0][0] != '' && $points_arr[0][1] != '') {
+ $result .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector(('
+ . 'new OpenLayers.Geometry.Point(' . $points_arr[0][0] . ', '
+ . $points_arr[0][1] . ').transform(new OpenLayers.Projection("EPSG:'
+ . $srid . '"), map.getProjectionObject())), null, '
+ . json_encode($style_options) . '));';
+ }
return $result;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Point deos not adhere to this parameter
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ return 'POINT('
+ . ((isset($gis_data[$index]['POINT']['x']) && trim($gis_data[$index]['POINT']['x']) != '')
+ ? $gis_data[$index]['POINT']['x'] : '') . ' '
+ . ((isset($gis_data[$index]['POINT']['y']) && trim($gis_data[$index]['POINT']['y']) != '')
+ ? $gis_data[$index]['POINT']['y'] : '') . ')';
+ }
+
+ /**
+ * 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)
+ {
+ return 'POINT(' . (isset($row_data['x']) ? $row_data['x'] : '')
+ . ' ' . (isset($row_data['y']) ? $row_data['y'] : '') . ')';
+ }
+
+ /**
+ * 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'POINT';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'POINT(' and trailing ')'
+ $point = substr($wkt, 6, (strlen($wkt) - 7));
+ $points_arr = $this->extractPoints($point, null);
+
+ $params[$index]['POINT']['x'] = $points_arr[0][0];
+ $params[$index]['POINT']['y'] = $points_arr[0][1];
+
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_polygon.php b/libraries/gis/pma_gis_polygon.php
index 02f01738cb..8f461ad73e 100644
--- a/libraries/gis/pma_gis_polygon.php
+++ b/libraries/gis/pma_gis_polygon.php
@@ -77,6 +77,7 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
public function prepareRowAsPng($spatial, $label, $fill_color, $scale_data, $image)
{
// allocate colors
+ $black = imagecolorallocate($image, 0, 0, 0);
$red = hexdec(substr($fill_color, 1, 2));
$green = hexdec(substr($fill_color, 3, 2));
$blue = hexdec(substr($fill_color, 4, 2));
@@ -105,6 +106,10 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
// draw polygon
imagefilledpolygon($image, $points_arr, sizeof($points_arr) / 2, $color);
+ // print label if applicable
+ if (isset($label) && trim($label) != '') {
+ imagestring($image, 1, $points_arr[2], $points_arr[3], trim($label), $black);
+ }
return $image;
}
@@ -150,6 +155,12 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
// draw polygon
$pdf->Polygon($points_arr, 'F*', array(), $color, true);
+ // print label if applicable
+ if (isset($label) && trim($label) != '') {
+ $pdf->SetXY($points_arr[2], $points_arr[3]);
+ $pdf->SetFontSize(5);
+ $pdf->Cell(0, 0, trim($label));
+ }
return $pdf;
}
@@ -262,5 +273,248 @@ class PMA_GIS_Polygon extends PMA_GIS_Geometry
return $row;
}
+
+ /**
+ * Generate the WKT with the set of parameters passed by the GIS editor.
+ *
+ * @param array $gis_data GIS data
+ * @param int $index Index into the parameter object
+ * @param string $empty Value for empty points
+ *
+ * @return WKT with the set of parameters passed by the GIS editor
+ */
+ public function generateWkt($gis_data, $index, $empty = '')
+ {
+ $no_of_lines = isset($gis_data[$index]['POLYGON']['no_of_lines'])
+ ? $gis_data[$index]['POLYGON']['no_of_lines'] : 1;
+ if ($no_of_lines < 1) {
+ $no_of_lines = 1;
+ }
+ $wkt = 'POLYGON(';
+ for ($i = 0; $i < $no_of_lines; $i++) {
+ $no_of_points = isset($gis_data[$index]['POLYGON'][$i]['no_of_points'])
+ ? $gis_data[$index]['POLYGON'][$i]['no_of_points'] : 4;
+ if ($no_of_points < 4) {
+ $no_of_points = 4;
+ }
+ $wkt .= '(';
+ for ($j = 0; $j < $no_of_points; $j++) {
+ $wkt .= ((isset($gis_data[$index]['POLYGON'][$i][$j]['x'])
+ && trim($gis_data[$index]['POLYGON'][$i][$j]['x']) != '')
+ ? $gis_data[$index]['POLYGON'][$i][$j]['x'] : $empty)
+ . ' ' . ((isset($gis_data[$index]['POLYGON'][$i][$j]['y'])
+ && trim($gis_data[$index]['POLYGON'][$i][$j]['y']) != '')
+ ? $gis_data[$index]['POLYGON'][$i][$j]['y'] : $empty) .',';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= '),';
+ }
+ $wkt = substr($wkt, 0, strlen($wkt) - 1);
+ $wkt .= ')';
+ 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 $polygon 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;
+ }
+ }
+
+ /**
+ * 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 a point on the surface of the ring
+ */
+ public static function getPointOnSurface($ring)
+ {
+ // Find two consecutive distinct points.
+ for ($i = 0; $i < count($ring) - 1; $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 epcilon chosen is too large
+ if (PMA_GIS_Polygon::isPointInsidePolygon($pointA, $ring)) {
+ return $pointA;
+ } elseif (PMA_GIS_Polygon::isPointInsidePolygon($pointB, $ring)) {
+ return $pointB;
+ } else {
+ //If both are outside the polygon reduce the epsilon and
+ //recalculate the points(reduce exponentially for faster convergance)
+ $epsilon = pow($epsilon, 2);
+ if ($epsilon == 0) {
+ return false;
+ }
+ }
+
+ }
+ }
+
+ /** 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
+ *
+ * @return parameters for the GIS data editor from the value of the GIS column
+ */
+ public function generateParams($value, $index = -1)
+ {
+ if ($index == -1) {
+ $index = 0;
+ $params = array();
+ $data = PMA_GIS_Geometry::generateParams($value);
+ $params['srid'] = $data['srid'];
+ $wkt = $data['wkt'];
+ } else {
+ $params[$index]['gis_type'] = 'POLYGON';
+ $wkt = $value;
+ }
+
+ // Trim to remove leading 'POLYGON((' and trailing '))'
+ $polygon = substr($wkt, 9, (strlen($wkt) - 11));
+ // Seperate each linestring
+ $linerings = explode("),(", $polygon);
+ $params[$index]['POLYGON']['no_of_lines'] = count($linerings);
+
+ $j = 0;
+ foreach ($linerings as $linering) {
+ $points_arr = $this->extractPoints($linering, null);
+ $no_of_points = count($points_arr);
+ $params[$index]['POLYGON'][$j]['no_of_points'] = $no_of_points;
+ for ($i = 0; $i < $no_of_points; $i++) {
+ $params[$index]['POLYGON'][$j][$i]['x'] = $points_arr[$i][0];
+ $params[$index]['POLYGON'][$j][$i]['y'] = $points_arr[$i][1];
+ }
+ $j++;
+ }
+ return $params;
+ }
}
?>
diff --git a/libraries/gis/pma_gis_visualization.php b/libraries/gis/pma_gis_visualization.php
index 2817a23c4f..29f2e1c11c 100644
--- a/libraries/gis/pma_gis_visualization.php
+++ b/libraries/gis/pma_gis_visualization.php
@@ -18,15 +18,14 @@ class PMA_GIS_Visualization
// Array of colors to be used for GIS visualizations.
'colors' => array(
- '#BCE02E',
+ '#B02EE0',
'#E0642E',
'#E0D62E',
'#2E97E0',
- '#B02EE0',
+ '#BCE02E',
'#E02E75',
'#5CE02E',
'#E0B02E',
- '#000000',
'#0022E0',
'#726CB1',
'#481A36',
@@ -153,7 +152,7 @@ class PMA_GIS_Visualization
$output .= '';
$scale_data = $this->_scaleDataSet($this->_data);
- $output .= $this->_prepareDataSet($this->_data, 0, $scale_data, 'svg', '');
+ $output .= $this->_prepareDataSet($this->_data, $scale_data, 'svg', '');
$output .= ' ';
$output .= '';
@@ -206,7 +205,7 @@ class PMA_GIS_Visualization
);
$scale_data = $this->_scaleDataSet($this->_data);
- $image = $this->_prepareDataSet($this->_data, 0, $scale_data, 'png', $image);
+ $image = $this->_prepareDataSet($this->_data, $scale_data, 'png', $image);
return $image;
}
@@ -256,7 +255,33 @@ class PMA_GIS_Visualization
{
$this->init();
$scale_data = $this->_scaleDataSet($this->_data);
- $output = $this->_prepareDataSet($this->_data, 0, $scale_data, 'ol', '');
+ $output =
+ 'var options = {'
+ . 'projection: new OpenLayers.Projection("EPSG:900913"),'
+ . 'displayProjection: new OpenLayers.Projection("EPSG:4326"),'
+ . 'units: "m",'
+ . 'numZoomLevels: 18,'
+ . 'maxResolution: 156543.0339,'
+ . 'maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508),'
+ . 'restrictedExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508)'
+ . '};'
+ . 'var map = new OpenLayers.Map("openlayersmap", options);'
+ . 'var layerNone = new OpenLayers.Layer.Boxes("None", {isBaseLayer: true});'
+ . 'var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");'
+ . 'var layerOsmarender = new OpenLayers.Layer.OSM.Osmarender("Osmarender");'
+ . 'var layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");'
+ . 'map.addLayers([layerMapnik, layerOsmarender, layerCycleMap, layerNone]);'
+ . 'var vectorLayer = new OpenLayers.Layer.Vector("Data");'
+ . 'var bound;';
+ $output .= $this->_prepareDataSet($this->_data, $scale_data, 'ol', '');
+ $output .=
+ 'map.addLayer(vectorLayer);'
+ . 'map.zoomToExtent(bound);'
+ . 'if (map.getZoom() < 2) {'
+ . 'map.zoomTo(2);'
+ . '}'
+ . 'map.addControl(new OpenLayers.Control.LayerSwitcher());'
+ . 'map.addControl(new OpenLayers.Control.MousePosition());';
return $output;
}
@@ -274,7 +299,7 @@ class PMA_GIS_Visualization
include_once './libraries/tcpdf/tcpdf.php';
// create pdf
- $pdf = new TCPDF('', 'pt', 'A4', true, 'UTF-8', false);
+ $pdf = new TCPDF('', 'pt', $GLOBALS['cfg']['PDFDefaultPageSize'], true, 'UTF-8', false);
// disable header and footer
$pdf->setPrintHeader(false);
@@ -287,7 +312,7 @@ class PMA_GIS_Visualization
$pdf->AddPage();
$scale_data = $this->_scaleDataSet($this->_data);
- $pdf = $this->_prepareDataSet($this->_data, 0, $scale_data, 'pdf', $pdf);
+ $pdf = $this->_prepareDataSet($this->_data, $scale_data, 'pdf', $pdf);
// sanitize file name
$file_name = $this->_sanitizeName($file_name, 'pdf');
@@ -319,6 +344,9 @@ class PMA_GIS_Visualization
$type = substr($ref_data, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$scale_data = $gis_obj->scaleRow($row[$this->_settings['spatialColumn']]);
// Upadate minimum/maximum values for x and y cordinates.
@@ -377,19 +405,19 @@ class PMA_GIS_Visualization
/**
* Prepares and return the dataset as needed by the visualization.
*
- * @param array $data Raw data
- * @param int $color_number Start index to the color array
- * @param array $scale_data Data related to scaling
- * @param string $format Format of the visulaization
- * @param image $results Image object in the case of png
+ * @param array $data Raw data
+ * @param array $scale_data Data related to scaling
+ * @param string $format Format of the visulaization
+ * @param image $results Image object in the case of png
*
* @return the formatted array of data.
*/
- private function _prepareDataSet($data, $color_number, $scale_data, $format, $results)
+ private function _prepareDataSet($data, $scale_data, $format, $results)
{
+ $color_number = 0;
+
// loop through the rows
foreach ($data as $row) {
-
$index = $color_number % sizeof($this->_settings['colors']);
// Figure out the data type
@@ -398,6 +426,9 @@ class PMA_GIS_Visualization
$type = substr($ref_data, 0, $type_pos);
$gis_obj = PMA_GIS_Factory::factory($type);
+ if (! $gis_obj) {
+ continue;
+ }
$label = '';
if (isset($this->_settings['labelColumn'])
&& isset($row[$this->_settings['labelColumn']])
@@ -432,4 +463,3 @@ class PMA_GIS_Visualization
}
}
?>
-
diff --git a/libraries/gis_visualization.lib.php b/libraries/gis_visualization.lib.php
index cc15dc984a..a35af807ef 100644
--- a/libraries/gis_visualization.lib.php
+++ b/libraries/gis_visualization.lib.php
@@ -16,7 +16,7 @@
*
* @return the modified sql query.
*/
-function PMA_GIS_modify_query($sql_query, $visualizationSettings)
+function PMA_GIS_modifyQuery($sql_query, $visualizationSettings)
{
$modified_query = 'SELECT ';
@@ -75,7 +75,9 @@ function PMA_GIS_modify_query($sql_query, $visualizationSettings)
// If select cluase is *
} else {
// If label column is chosen add it to the query
- if ($visualizationSettings['labelColumn'] != '') {
+ if (isset($visualizationSettings['labelColumn'])
+ && $visualizationSettings['labelColumn'] != ''
+ ) {
$modified_query .= '`' . $visualizationSettings['labelColumn'] .'`, ';
}
@@ -84,7 +86,8 @@ function PMA_GIS_modify_query($sql_query, $visualizationSettings)
. '`) AS `' . $visualizationSettings['spatialColumn'] . '`, ';
// Get the SRID
- $modified_query .= 'SRID(`' . $visualizationSettings['spatialColumn'] . '`) AS `srid` ';
+ $modified_query .= 'SRID(`' . $visualizationSettings['spatialColumn']
+ . '`) AS `srid` ';
}
// Append the rest of the query
@@ -98,14 +101,16 @@ function PMA_GIS_modify_query($sql_query, $visualizationSettings)
function sanitize($select)
{
$table_col = $select['table_name'] . "." . $select['column'];
- $db_table_col = $select['db'] . "." . $select['table_name'] . "." . $select['column'];
+ $db_table_col = $select['db'] . "." . $select['table_name']
+ . "." . $select['column'];
if ($select['expr'] == $select['column']) {
return "`" . $select['column'] . "`";
} elseif ($select['expr'] == $table_col) {
return "`" . $select['table_name'] . "`.`" . $select['column'] . "`";
} elseif ($select['expr'] == $db_table_col) {
- return "`" . $select['db'] . "`.`" . $select['table_name'] . "`.`" . $select['column'] . "`";
+ return "`" . $select['db'] . "`.`" . $select['table_name']
+ . "`.`" . $select['column'] . "`";
}
return $select['expr'];
}
@@ -119,7 +124,7 @@ function sanitize($select)
*
* @return string HTML and JS code for the GIS visualization
*/
-function PMA_GIS_visualization_results($data, &$visualizationSettings, $format)
+function PMA_GIS_visualizationResults($data, &$visualizationSettings, $format)
{
include_once './libraries/gis/pma_gis_visualization.php';
include_once './libraries/gis/pma_gis_factory.php';
@@ -156,7 +161,7 @@ function PMA_GIS_visualization_results($data, &$visualizationSettings, $format)
*
* @return file File containing the visualization
*/
-function PMA_GIS_save_to_file($data, $visualizationSettings, $format, $fileName)
+function PMA_GIS_saveToFile($data, $visualizationSettings, $format, $fileName)
{
include_once './libraries/gis/pma_gis_visualization.php';
include_once './libraries/gis/pma_gis_factory.php';
diff --git a/libraries/import.lib.php b/libraries/import.lib.php
index 0d0239c33f..df4290eb0d 100644
--- a/libraries/import.lib.php
+++ b/libraries/import.lib.php
@@ -425,6 +425,7 @@ define("VARCHAR", 1);
define("INT", 2);
define("DECIMAL", 3);
define("BIGINT", 4);
+define("GEOMETRY", 5);
/* Decimal size defs */
define("M", 0);
@@ -437,8 +438,9 @@ define("COL_NAMES", 1);
define("ROWS", 2);
/* Analysis array defs */
-define("TYPES", 0);
-define("SIZES", 1);
+define("TYPES", 0);
+define("SIZES", 1);
+define("FORMATTEDSQL", 2);
/**
* Obtains the precision (total # of digits) from a size of type decimal
@@ -916,7 +918,7 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = null, &$additional_sql =
}
if ($analyses != null) {
- $type_array = array(NONE => "NULL", VARCHAR => "varchar", INT => "int", DECIMAL => "decimal", BIGINT => "bigint");
+ $type_array = array(NONE => "NULL", VARCHAR => "varchar", INT => "int", DECIMAL => "decimal", BIGINT => "bigint", GEOMETRY => 'geometry');
/* TODO: Do more checking here to make sure they really are matched */
if (count($tables) != count($analyses)) {
@@ -935,7 +937,10 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = null, &$additional_sql =
$size = 10;
}
- $tempSQLStr .= PMA_backquote($tables[$i][COL_NAMES][$j]) . " " . $type_array[$analyses[$i][TYPES][$j]] . "(" . $size . ")";
+ $tempSQLStr .= PMA_backquote($tables[$i][COL_NAMES][$j]) . " " . $type_array[$analyses[$i][TYPES][$j]];
+ if ($analyses[$i][TYPES][$j] != GEOMETRY) {
+ $tempSQLStr .= "(" . $size . ")";
+ }
if ($j != (count($tables[$i][COL_NAMES]) - 1)) {
$tempSQLStr .= ", ";
@@ -980,20 +985,28 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = null, &$additional_sql =
$tempSQLStr .= "(";
for ($k = 0; $k < $num_cols; ++$k) {
- if ($analyses != null) {
- $is_varchar = ($analyses[$i][TYPES][$col_count] === VARCHAR);
+ // If fully formatted SQL, no need to enclose with aphostrophes, add shalshes etc.
+ if ($analyses != null
+ && isset($analyses[$i][FORMATTEDSQL][$col_count])
+ && $analyses[$i][FORMATTEDSQL][$col_count] == true
+ ) {
+ $tempSQLStr .= (string) $tables[$i][ROWS][$j][$k];
} else {
- $is_varchar = !is_numeric($tables[$i][ROWS][$j][$k]);
- }
+ if ($analyses != null) {
+ $is_varchar = ($analyses[$i][TYPES][$col_count] === VARCHAR);
+ } else {
+ $is_varchar = !is_numeric($tables[$i][ROWS][$j][$k]);
+ }
- /* Don't put quotes around NULL fields */
- if (! strcmp($tables[$i][ROWS][$j][$k], 'NULL')) {
- $is_varchar = false;
- }
+ /* Don't put quotes around NULL fields */
+ if (! strcmp($tables[$i][ROWS][$j][$k], 'NULL')) {
+ $is_varchar = false;
+ }
- $tempSQLStr .= (($is_varchar) ? "'" : "");
- $tempSQLStr .= PMA_sqlAddSlashes((string)$tables[$i][ROWS][$j][$k]);
- $tempSQLStr .= (($is_varchar) ? "'" : "");
+ $tempSQLStr .= (($is_varchar) ? "'" : "");
+ $tempSQLStr .= PMA_sqlAddSlashes((string)$tables[$i][ROWS][$j][$k]);
+ $tempSQLStr .= (($is_varchar) ? "'" : "");
+ }
if ($k != ($num_cols - 1)) {
$tempSQLStr .= ", ";
diff --git a/libraries/import/shp.php b/libraries/import/shp.php
new file mode 100644
index 0000000000..7ee62fdce3
--- /dev/null
+++ b/libraries/import/shp.php
@@ -0,0 +1,399 @@
+ __('ESRI Shape File'),
+ 'extension' => 'shp',
+ 'options' => array(),
+ 'options_text' => __('Options'),
+ );
+} else {
+
+ 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/');
+ require_once './libraries/bfShapeFiles/ShapeFile.lib.php';
+
+ $GLOBALS['finished'] = false;
+ $buffer = '';
+ $eof = false;
+
+ // Returns specified number of bytes from the buffer.
+ // Buffer automatically fetches next chunk of data when the buffer falls short.
+ // Sets $eof when $GLOBALS['finished'] is set and the buffer falls short.
+ function readFromBuffer($length){
+ global $buffer, $eof;
+
+ if (strlen($buffer) < $length) {
+ if ($GLOBALS['finished']) {
+ $eof = true;
+ } else {
+ $buffer .= PMA_importGetNextChunk();
+ }
+ }
+ $result = substr($buffer, 0, $length);
+ $buffer = substr($buffer, $length);
+ return $result;
+ }
+
+ /**
+ * This class extends ShapeFile class to cater following phpMyAdmin specific requirements.
+ * 1) To load data from .dbf file only when the dBase extension is available.
+ * 2) To use PMA_importGetNextChunk() functionality to read data, rather than reading directly from a file.
+ * Using readFromBuffer() in place of fread(). This makes it possible to use compressions.
+ */
+ class PMA_ShapeFile extends ShapeFile {
+
+ function _isDbaseLoaded()
+ {
+ return extension_loaded('dbase');
+ }
+
+ function loadFromFile($FileName)
+ {
+ $this->_loadHeaders();
+ $this->_loadRecords();
+ if ($this->_isDbaseLoaded()) {
+ $this->_closeDBFFile();
+ }
+ }
+
+ function _loadHeaders()
+ {
+ readFromBuffer(24);
+ $this->fileLength = loadData("N", readFromBuffer(4));
+
+ readFromBuffer(4);
+ $this->shapeType = loadData("V", readFromBuffer(4));
+
+ $this->boundingBox = array();
+ $this->boundingBox["xmin"] = loadData("d", readFromBuffer(8));
+ $this->boundingBox["ymin"] = loadData("d", readFromBuffer(8));
+ $this->boundingBox["xmax"] = loadData("d", readFromBuffer(8));
+ $this->boundingBox["ymax"] = loadData("d", readFromBuffer(8));
+
+ if ($this->_isDbaseLoaded() && $this->_openDBFFile()) {
+ $this->DBFHeader = $this->_loadDBFHeader();
+ }
+ }
+
+ function _loadRecords()
+ {
+ global $eof;
+ readFromBuffer(32);
+ while (true) {
+ $record = new PMA_ShapeRecord(-1);
+ $record->loadFromFile($this->SHPFile, $this->DBFFile);
+ if ($record->lastError != "") {
+ return false;
+ }
+ if ($eof) {
+ break;
+ }
+
+ $this->records[] = $record;
+ }
+ }
+ }
+
+ /**
+ * This class extends ShapeRecord class to cater following phpMyAdmin specific requirements.
+ * 1) To load data from .dbf file only when the dBase extension is available.
+ * 2) To use PMA_importGetNextChunk() functionality to read data, rather than reading directly from a file.
+ * Using readFromBuffer() in place of fread(). This makes it possible to use compressions.
+ */
+ class PMA_ShapeRecord extends ShapeRecord {
+
+ function loadFromFile(&$SHPFile, &$DBFFile)
+ {
+ $this->DBFFile = $DBFFile;
+ $this->_loadHeaders();
+
+ switch ($this->shapeType) {
+ case 0:
+ $this->_loadNullRecord();
+ break;
+ case 1:
+ $this->_loadPointRecord();
+ break;
+ case 3:
+ $this->_loadPolyLineRecord();
+ break;
+ case 5:
+ $this->_loadPolygonRecord();
+ break;
+ case 8:
+ $this->_loadMultiPointRecord();
+ break;
+ default:
+ $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
+ break;
+ }
+ if (extension_loaded('dbase') && isset($this->DBFFile)) {
+ $this->_loadDBFData();
+ }
+ }
+
+ function _loadHeaders()
+ {
+ $this->recordNumber = loadData("N", readFromBuffer(4));
+ $tmp = loadData("N", readFromBuffer(4)); //We read the length of the record
+ $this->shapeType = loadData("V", readFromBuffer(4));
+ }
+
+ function _loadPoint()
+ {
+ $data = array();
+
+ $data["x"] = loadData("d", readFromBuffer(8));
+ $data["y"] = loadData("d", readFromBuffer(8));
+
+ return $data;
+ }
+
+ function _loadMultiPointRecord()
+ {
+ $this->SHPData = array();
+ $this->SHPData["xmin"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["ymin"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["xmax"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["ymax"] = loadData("d", readFromBuffer(8));
+
+ $this->SHPData["numpoints"] = loadData("V", readFromBuffer(4));
+
+ for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) {
+ $this->SHPData["points"][] = $this->_loadPoint();
+ }
+ }
+
+ function _loadPolyLineRecord()
+ {
+ $this->SHPData = array();
+ $this->SHPData["xmin"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["ymin"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["xmax"] = loadData("d", readFromBuffer(8));
+ $this->SHPData["ymax"] = loadData("d", readFromBuffer(8));
+
+ $this->SHPData["numparts"] = loadData("V", readFromBuffer(4));
+ $this->SHPData["numpoints"] = loadData("V", readFromBuffer(4));
+
+ for ($i = 0; $i < $this->SHPData["numparts"]; $i++) {
+ $this->SHPData["parts"][$i] = loadData("V", readFromBuffer(4));
+ }
+
+ $readPoints = 0;
+ reset($this->SHPData["parts"]);
+ while (list($partIndex, $partData) = each($this->SHPData["parts"])) {
+ if (!isset($this->SHPData["parts"][$partIndex]["points"]) || !is_array($this->SHPData["parts"][$partIndex]["points"])) {
+ $this->SHPData["parts"][$partIndex] = array();
+ $this->SHPData["parts"][$partIndex]["points"] = array();
+ }
+ while (!in_array($readPoints, $this->SHPData["parts"]) && ($readPoints < ($this->SHPData["numpoints"]))) {
+ $this->SHPData["parts"][$partIndex]["points"][] = $this->_loadPoint();
+ $readPoints++;
+ }
+ }
+ }
+ }
+
+ $shp = new PMA_ShapeFile(1);
+ // 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'];
+ }
+
+ $temp_dbf_file = false;
+ // We need dbase extension to handle .dbf file
+ if (extension_loaded('dbase')) {
+ // If we can extract the zip archive to 'TempDir' and use the files in it for import
+ if ($compression == 'application/zip'
+ && ! empty($cfg['TempDir'])
+ && is_writable($cfg['TempDir'])
+ ) {
+ $dbf_file_name = PMA_findFileFromZipArchive('/^.*\.dbf$/i', $import_file);
+ // If the corresponding .dbf file is in the zip archive
+ if ($dbf_file_name) {
+ // 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']) . (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) . '.*';
+ $shp->FileName = $file_name;
+ }
+ }
+ }
+ // If file is in UploadDir, use .dbf file in the same UploadDir to load extra data.
+ elseif (! empty($local_import_file) && ! empty($cfg['UploadDir']) && $compression == 'none') {
+ // Replace the .shp with .*, so the bsShapeFiles library correctly locates .dbf file.
+ $file_name = substr($import_file, 0, strlen($import_file) - 4) . '.*';
+ $shp->FileName = $file_name;
+ }
+ }
+
+ // Load data
+ $shp->loadFromFile('');
+ if ($shp->lastError != "") {
+ $error = true;
+ $message = PMA_Message::error(__('There was an error importing the ESRI shape file: "%s".'));
+ $message->addParam($shp->lastError);
+ return;
+ }
+
+ // Delete the .dbf file extracted to 'TempDir'
+ if ($temp_dbf_file) {
+ unlink($dbf_file_path);
+ }
+
+ $esri_types = array(
+ 0 => 'Null Shape',
+ 1 => 'Point',
+ 3 => 'PolyLine',
+ 5 => 'Polygon',
+ 8 => 'MultiPoint',
+ 11 => 'PointZ',
+ 13 => 'PolyLineZ',
+ 15 => 'PolygonZ',
+ 18 => 'MultiPointZ',
+ 21 => 'PointM',
+ 23 => 'PolyLineM',
+ 25 => 'PolygonM',
+ 28 => 'MultiPointM',
+ 31 => 'MultiPatch',
+ );
+
+ require_once './libraries/gis/pma_gis_geometry.php';
+ switch ($shp->shapeType) {
+ // ESRI Null Shape
+ case 0:
+ $gis_obj = null;
+ break;
+ // ESRI Point
+ case 1:
+ require_once './libraries/gis/pma_gis_point.php';
+ $gis_obj = PMA_GIS_Point::singleton();
+ break;
+ // ESRI PolyLine
+ case 3:
+ require_once './libraries/gis/pma_gis_multilinestring.php';
+ $gis_obj = PMA_GIS_Multilinestring::singleton();
+ break;
+ // ESRI Polygon
+ case 5:
+ require_once './libraries/gis/pma_gis_multipolygon.php';
+ $gis_obj = PMA_GIS_Multipolygon::singleton();
+ break;
+ // ESRI MultiPoint
+ case 8:
+ require_once './libraries/gis/pma_gis_multipoint.php';
+ $gis_obj = PMA_GIS_Multipoint::singleton();
+ break;
+ default:
+ $error = true;
+ if (! isset($esri_types[$shp->shapeType])) {
+ $message = PMA_Message::error(__('You tried to import an invalid file or the imported file contains invalid data'));
+ } else {
+ $message = PMA_Message::error(__('MySQL Spatial Extension does not support ESRI type "%s".'));
+ $message->addParam($param);
+ }
+ return;
+ }
+
+ $num_rows = count($shp->records);
+ // If .dbf file is loaded, the number of extra data columns
+ $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0;
+
+ $rows = array();
+ $col_names = array();
+ if ($num_rows != 0) {
+ foreach($shp->records as $record){
+ $tempRow = array();
+ if ($gis_obj == null) {
+ $tempRow[] = null;
+ } else {
+ $tempRow[] = "GeomFromText('" . $gis_obj->getShape($record->SHPData) . "')";
+ }
+
+ if (isset($shp->DBFHeader)) {
+ foreach ($shp->DBFHeader as $c) {
+ $cell = trim($record->DBFData[$c[0]]);
+
+ if (! strcmp($cell, '')) {
+ $cell = 'NULL';
+ }
+
+ $tempRow[] = $cell;
+ }
+ }
+ $rows[] = $tempRow;
+ }
+ }
+
+ if(count($rows) == 0) {
+ $error = true;
+ $message = PMA_Message::error(__('The imported file does not contain any data'));
+ return;
+ }
+
+ // Column names for spatial column and the rest of the columns, if they are available
+ $col_names[] = 'SPATIAL';
+ for ($n = 0; $n < $num_data_cols; $n++) {
+ $col_names[] = $shp->DBFHeader[$n][0];
+ }
+
+ // Set table name based on the number of tables
+ if (strlen($db)) {
+ $result = PMA_DBI_fetch_result('SHOW TABLES');
+ $table_name = 'TABLE '.(count($result) + 1);
+ } else {
+ $table_name = 'TBL_NAME';
+ }
+ $tables = array(array($table_name, $col_names, $rows));
+
+ // Use data from shape file to chose best-fit MySQL types for each column
+ $analyses = array();
+ $analyses[] = PMA_analyzeTable($tables[0]);
+
+ $table_no = 0; $spatial_col = 0;
+ $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY;
+ $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true;
+
+ // Set database name to the currently selected one, if applicable
+ if (strlen($db)) {
+ $db_name = $db;
+ $options = array('create_db' => false);
+ } else {
+ $db_name = 'SHP_DB';
+ $options = null;
+ }
+
+ // Created and execute necessary SQL statements from data
+ $null_param = null;
+ PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options);
+
+ unset($tables);
+ unset($analyses);
+
+ $finished = true;
+ $error = false;
+
+ // Commit any possible data in buffers
+ PMA_importRunQuery();
+}
+?>
diff --git a/libraries/tbl_select.lib.php b/libraries/tbl_select.lib.php
index 6384f60b16..af97aa434e 100644
--- a/libraries/tbl_select.lib.php
+++ b/libraries/tbl_select.lib.php
@@ -3,8 +3,8 @@
/**
* Functions for the table-search page and zoom-search page
*
- * Funtion PMA_tbl_getFields : Returns the fields of a table
- * Funtion PMA_tbl_search_getWhereClause : Returns the where clause for query generation
+ * Funtion PMA_tbl_getFields : Returns the fields of a table
+ * Funtion PMA_tbl_search_getWhereClause : Returns the where clause for query generation
*
* @package phpMyAdmin
*/
@@ -13,7 +13,7 @@ require_once 'url_generating.lib.php';
/**
* PMA_tbl_setTitle() sets the title for foreign keys display link
- *
+ *
* @param $propertiesIconic Type of icon property
* @param $themeImage Icon Image
* @return string $str Value of the Title
@@ -51,20 +51,26 @@ function PMA_tbl_setTitle($propertiesIconic,$pmaThemeImage){
* @param $db Selected database
* @param $table Selected table
*
- * @return array($fields_list,$fields_type,$fields_collation,$fields_null) Array containing the field list, field types, collations and null constatint
+ * @return array($fields_list,$fields_type,$fields_collation,$fields_null) Array containing the field list, field types, collations and null constatint
*
*/
function PMA_tbl_getFields($table,$db) {
-
+
// Gets the list and number of fields
$result = PMA_DBI_query('SHOW FULL FIELDS FROM ' . PMA_backquote($table) . ' FROM ' . PMA_backquote($db) . ';', null, PMA_DBI_QUERY_STORE);
$fields_cnt = PMA_DBI_num_rows($result);
$fields_list = $fields_null = $fields_type = $fields_collation = array();
+ $geom_column_present = false;
+ $geom_types = PMA_getGISDatatypes();
while ($row = PMA_DBI_fetch_assoc($result)) {
$fields_list[] = $row['Field'];
$type = $row['Type'];
+ // check whether table contains geometric columns
+ if (in_array($type, $geom_types)) {
+ $geom_column_present = true;
+ }
// reformat mysql query output
if (strncasecmp($type, 'set', 3) == 0
|| strncasecmp($type, 'enum', 4) == 0) {
@@ -93,20 +99,26 @@ function PMA_tbl_getFields($table,$db) {
PMA_DBI_free_result($result);
unset($result, $type);
- return array($fields_list,$fields_type,$fields_collation,$fields_null);
-
+ return array($fields_list,$fields_type,$fields_collation,$fields_null, $geom_column_present);
+
}
/* PMA_tbl_setTableHeader() sets the table header for displaying a table in query-by-example format
*
- * @return HTML content, the tags and content for table header
+ * @return HTML content, the tags and content for table header
*
*/
-function PMA_tbl_setTableHeader(){
+function PMA_tbl_setTableHeader($geom_column_present = false){
+
+ // Display the Function column only if there is alteast one geomety colum
+ $func = '';
+ if ($geom_column_present) {
+ $func = '' . __('Function') . ' ';
+ }
return '
- ' . __('Column') . '
+ ' . $func . '' . __('Column') . '
' . __('Type') . '
' . __('Collation') . '
' . __('Operator') . '
@@ -117,9 +129,9 @@ return '
}
-/* PMA_tbl_getSubTabs() returns an array with necessary configrations to create sub-tabs(Table Search and Zoom Search) in the table_select page
+/* PMA_tbl_getSubTabs() returns an array with necessary configrations to create sub-tabs(Table Search and Zoom Search) in the table_select page
*
- * @return array $subtabs Array containing configuration (icon,text,link,id,args) of sub-tabs for Table Search and Zoom search
+ * @return array $subtabs Array containing configuration (icon,text,link,id,args) of sub-tabs for Table Search and Zoom search
*
*/
@@ -137,7 +149,7 @@ function PMA_tbl_getSubTabs(){
$subtabs['zoom']['link'] = 'tbl_zoom_select.php';
$subtabs['zoom']['text'] = __('Zoom Search');
$subtabs['zoom']['id'] = 'zoom_search_id';
-
+
return $subtabs;
}
@@ -164,12 +176,13 @@ function PMA_tbl_getSubTabs(){
* @param $titles Selected title
* @param $foreignMaxLimit Max limit of displaying foreign elements
* @param $fields Array of search criteria inputs
+ * @param $in_fbs In function based search
*
- * @return string $str HTML content for viewing foreing data and elements for search criteria input.
+ * @return string $str HTML content for viewing foreing data and elements for search criteria input.
*
*/
-function PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fields_type, $i, $db, $table,$titles,$foreignMaxLimit, $fields){
+function PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fields_type, $i, $db, $table, $titles, $foreignMaxLimit, $fields, $in_fbs = false){
$str = '';
@@ -185,29 +198,40 @@ function PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fie
$foreignData['foreign_display'],
'', $foreignMaxLimit);
$str .= ' ' . "\n";
- }
+ }
elseif ($foreignData['foreign_link'] == true) {
if(isset($fields[$i]) && is_string($fields[$i])){
$str .= ' ' ;
+ 'id="field_' . md5($field) . '[' . $i .']"
+ class="textfield"/>' ;
}
else{
$str .= ' ' ;
+ 'id="field_' . md5($field) . '[' . $i .']"
+ class="textfield" />' ;
}
?>
';
// ' . str_replace("'", "\'", $titles['Browse']) . '';
// ]]
$str .= '';
- }
- elseif (strncasecmp($tbl_fields_type[$i], 'enum', 4) == 0) {
+ } elseif (in_array($tbl_fields_type[$i], PMA_getGISDatatypes())) {
+ // g e o m e t r y
+ $str .= ' ' . "\n";
+
+ if ($in_fbs) {
+ $edit_url = 'gis_data_editor.php?' . PMA_generate_common_url();
+ $edit_str = PMA_getIcon('b_edit.png', __('Edit/Insert'), true);
+ $str .= '';
+ $str .= PMA_linkOrButton($edit_url, $edit_str, array(), false, false, '_blank');
+ $str .= ' ';
+ }
+ } elseif (strncasecmp($tbl_fields_type[$i], 'enum', 4) == 0) {
// e n u m s
$enum_value=explode(', ', str_replace("'", '', substr($tbl_fields_type[$i], 5, -1)));
$cnt_enum_value = count($enum_value);
@@ -224,7 +248,7 @@ EOT;
}
} // end for
$str .= ' ' . "\n";
- }
+ }
else {
// o t h e r c a s e s
$the_class = 'textfield';
@@ -267,17 +291,61 @@ EOT;
* @param $func_type Search fucntion/operator
* @param $unaryFlag Whether operator unary or not
*
- * @return string $str HTML content for viewing foreing data and elements for search criteria input.
+ * @return string $str HTML content for viewing foreing data and elements for search criteria input.
*
*/
-function PMA_tbl_search_getWhereClause($fields, $names, $types, $collations, $func_type, $unaryFlag){
-
+function PMA_tbl_search_getWhereClause($fields, $names, $types, $collations, $func_type, $unaryFlag, $geom_func = null){
+
+ /**
+ * @todo move this to a more apropriate place
+ */
+ $geom_unary_functions = array(
+ 'IsEmpty' => 1,
+ 'IsSimple' => 1,
+ 'IsRing' => 1,
+ 'IsClosed' => 1,
+ );
+
+ $w = '';
+
+ // If geometry function is set apply it to the field name
+ if ($geom_func != null && trim($geom_func) != '') {
+ // Get details about the geometry fucntions
+ $geom_funcs = PMA_getGISFunctions($types, true, false);
+
+ // If the function takes a single parameter
+ if ($geom_funcs[$geom_func]['params'] == 1) {
+ $backquoted_name = $geom_func . '(' . PMA_backquote($names) . ')';
+ // If the function takes two parameters
+ } else {
+ // create gis data from the string
+ $gis_data = PMA_createGISData($fields);
+
+ $w = $geom_func . '(' . PMA_backquote($names) . ',' . $gis_data . ')';
+ return $w;
+ }
+
+ // New output type is the output type of the function being applied
+ $types = $geom_funcs[$geom_func]['type'];
+
+ // If the intended where clause is something like 'IsEmpty(`spatial_col_name`)'
+ if (isset($geom_unary_functions[$geom_func]) && trim($fields) == '') {
+ $w = $backquoted_name;
+ return $w;
+ }
+ } else {
+ $backquoted_name = PMA_backquote($names);
+ }
- $w = '';
if($unaryFlag){
$fields = '';
- $w = PMA_backquote($names) . ' ' . $func_type;
+ $w = $backquoted_name . ' ' . $func_type;
+
+ } elseif (in_array($types, PMA_getGISDatatypes())) {
+ // create gis data from the string
+ $gis_data = PMA_createGISData($fields);
+ $w = $backquoted_name . ' ' . $func_type . ' ' . $gis_data;
} elseif (strncasecmp($types, 'enum', 4) == 0) {
if (!empty($fields)) {
@@ -304,7 +372,7 @@ function PMA_tbl_search_getWhereClause($fields, $names, $types, $collations, $fu
$enum_where .= ', \'' . PMA_sqlAddslashes($fields[$e]) . '\'';
}
- $w = PMA_backquote($names) . ' ' . $func_type . ' ' . $parens_open . $enum_where . $parens_close;
+ $w = $backquoted_name . ' ' . $func_type . ' ' . $parens_open . $enum_where . $parens_close;
}
} elseif ($fields != '') {
@@ -336,12 +404,12 @@ function PMA_tbl_search_getWhereClause($fields, $names, $types, $collations, $fu
$value = $quot . PMA_sqlAddslashes(trim($value)) . $quot;
if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN')
- $w = PMA_backquote($names) . ' ' . $func_type . ' ' . (isset($values[0]) ? $values[0] : '') . ' AND ' . (isset($values[1]) ? $values[1] : '');
+ $w = $backquoted_name . ' ' . $func_type . ' ' . (isset($values[0]) ? $values[0] : '') . ' AND ' . (isset($values[1]) ? $values[1] : '');
else
- $w = PMA_backquote($names) . ' ' . $func_type . ' (' . implode(',', $values) . ')';
+ $w = $backquoted_name . ' ' . $func_type . ' (' . implode(',', $values) . ')';
}
else {
- $w = PMA_backquote($names) . ' ' . $func_type . ' ' . $quot . PMA_sqlAddslashes($fields) . $quot;;
+ $w = $backquoted_name . ' ' . $func_type . ' ' . $quot . PMA_sqlAddslashes($fields) . $quot;;
}
} // end if
diff --git a/libraries/zip_extension.lib.php b/libraries/zip_extension.lib.php
index b665b74e5b..7bfa84875f 100644
--- a/libraries/zip_extension.lib.php
+++ b/libraries/zip_extension.lib.php
@@ -9,12 +9,12 @@
/**
* Gets zip file contents
*
- * @param string $file
+ * @param string $specific_entry regular expression to match a file
* @return array ($error_message, $file_data); $error_message
* is empty if no error
*/
-function PMA_getZipContents($file)
+function PMA_getZipContents($file, $specific_entry = null)
{
$error_message = '';
$file_data = '';
@@ -28,11 +28,15 @@ function PMA_getZipContents($file)
$read = zip_entry_read($first_zip_entry);
$ods_mime = 'application/vnd.oasis.opendocument.spreadsheet';
if (!strcmp($ods_mime, $read)) {
+ $specific_entry = '/^content\.xml$/';
+ }
+
+ if (isset($specific_entry)) {
/* Return the correct contents, not just the first entry */
for ( ; ; ) {
$entry = zip_read($zip_handle);
if (is_resource($entry)) {
- if (!strcmp('content.xml', zip_entry_name($entry))) {
+ if (preg_match($specific_entry, zip_entry_name($entry))) {
zip_entry_open($zip_handle, $entry, 'r');
$file_data = zip_entry_read($entry, zip_entry_filesize($entry));
zip_entry_close($entry);
@@ -41,15 +45,15 @@ function PMA_getZipContents($file)
} else {
/**
* Either we have reached the end of the zip and still
- * haven't found 'content.xml' or there was a parsing
+ * haven't found $specific_entry or there was a parsing
* error that we must display
*/
if ($entry === false) {
- $error_message = __('Error in ZIP archive:') . ' Could not find "content.xml"';
+ $error_message = __('Error in ZIP archive:') . ' Could not find "' . $specific_entry . '"';
} else {
$error_message = __('Error in ZIP archive:') . ' ' . PMA_getZipError($zip_handle);
}
-
+
break;
}
}
@@ -68,6 +72,69 @@ function PMA_getZipContents($file)
return (array('error' => $error_message, 'data' => $file_data));
}
+/**
+ * Returns the file name of the first file that matches the given $file_regexp.
+ *
+ * @param string $file_regexp regular expression for the file name to match
+ * @param string $file zip archive
+ */
+function PMA_findFileFromZipArchive ($file_regexp, $file)
+{
+ $zip_handle = zip_open($file);
+ $found = false;
+ if (is_resource($zip_handle)) {
+ $entry = zip_read($zip_handle);
+ while (is_resource($entry)) {
+ if (preg_match($file_regexp, zip_entry_name($entry))) {
+ $file_name = zip_entry_name($entry);
+ zip_close($zip_handle);
+ return $file_name;
+ }
+ $entry = zip_read($zip_handle);
+ }
+ }
+ zip_close($zip_handle);
+ return false;
+}
+
+/**
+ * Returns the number of files in the zip archive.
+ *
+ * @param string $file
+ */
+function PMA_getNoOfFilesInZip($file)
+{
+ $count = 0;
+ $zip_handle = zip_open($file);
+ $found = false;
+ if (is_resource($zip_handle)) {
+ $entry = zip_read($zip_handle);
+ while (is_resource($entry)) {
+ $count++;
+ $entry = zip_read($zip_handle);
+ }
+ }
+ zip_close($zip_handle);
+ return $count;
+}
+
+/**
+ * Extracts a set of files from the given zip archive to a given destinations.
+ *
+ * @param string $zip_path
+ * @param string $destination
+ * @param array $entries
+ */
+function PMA_zipExtract($zip_path, $destination, $entries) {
+ $zip = new ZipArchive;
+ if ($zip->open($zip_path) === true) {
+ $zip->extractTo($destination, $entries);
+ $zip->close();
+ return true;
+ }
+ return false;
+}
+
/**
* Gets zip error message
*
diff --git a/sql.php b/sql.php
index 6e5a05d82f..e2d956d0a1 100644
--- a/sql.php
+++ b/sql.php
@@ -18,6 +18,15 @@ $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
$GLOBALS['js_include'][] = 'tbl_change.js';
+// required for GIS editor loaded via AJAX
+$GLOBALS['js_include'][] = 'gis_data_editor.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.svg.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.mousewheel.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.event.drag-2.0.min.js';
+$GLOBALS['js_include'][] = 'tbl_gis_visualization.js';
+$GLOBALS['js_include'][] = 'openlayers/OpenLayers.js';
+$GLOBALS['js_include'][] = 'OpenStreetMap.js';
+
if (isset($_SESSION['profiling'])) {
$GLOBALS['js_include'][] = 'highcharts/highcharts.js';
/* Files required for chart exporting */
diff --git a/tbl_change.php b/tbl_change.php
index 9148ef32f3..5329f159a1 100644
--- a/tbl_change.php
+++ b/tbl_change.php
@@ -118,6 +118,16 @@ $GLOBALS['js_include'][] = 'functions.js';
$GLOBALS['js_include'][] = 'tbl_change.js';
$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
+
+// required for GIS editor
+$GLOBALS['js_include'][] = 'gis_data_editor.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.svg.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.mousewheel.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.event.drag-2.0.min.js';
+$GLOBALS['js_include'][] = 'tbl_gis_visualization.js';
+$GLOBALS['js_include'][] = 'openlayers/OpenLayers.js';
+$GLOBALS['js_include'][] = 'OpenStreetMap.js';
+
/**
* HTTP and HTML headers
*/
@@ -472,6 +482,9 @@ foreach ($rows as $row_id => $vrow) {
$vrow) {
$data = $vrow[$field['Field']];
} elseif ($field['True_Type'] == 'bit') {
$special_chars = PMA_printable_bit_value($vrow[$field['Field']], $extracted_fieldspec['spec_in_brackets']);
+ } elseif (in_array($field['True_Type'], $gis_data_types)) {
+ // Convert gis data to Well Know Text format
+ $vrow[$field['Field']] = PMA_asWKT($vrow[$field['Field']], true);
+ $special_chars = htmlspecialchars($vrow[$field['Field']]);
} else {
// special binary "characters"
if ($field['is_binary'] || ($field['is_blob'] && ! $cfg['ProtectBinary'])) {
@@ -897,7 +914,6 @@ foreach ($rows as $row_id => $vrow) {
}
} // end if (web-server upload directory)
} // end elseif (binary or blob)
-
elseif (in_array($field['pma_type'], $no_support_types)) {
// ignore this column to avoid changing it
} else {
@@ -965,6 +981,21 @@ foreach ($rows as $row_id => $vrow) {
}
}
}
+ if (in_array($field['pma_type'], $gis_data_types)) {
+ $data_val = isset($vrow[$field['Field']]) ? $vrow[$field['Field']] : '';
+ $_url_params = array(
+ 'field' => $field['Field_title'],
+ 'value' => $data_val,
+ );
+ if ($field['pma_type'] != 'geometry') {
+ $_url_params = $_url_params + array('gis_data[gis_type]' => strtoupper($field['pma_type']));
+ }
+ $edit_url = 'gis_data_editor.php' . PMA_generate_common_url($_url_params);
+ $edit_str = PMA_getIcon('b_edit.png', __('Edit/Insert'), true);
+ echo('');
+ echo(PMA_linkOrButton($edit_url, $edit_str, array(), false, false, '_blank'));
+ echo(' ');
+ }
?>
@@ -975,8 +1006,8 @@ foreach ($rows as $row_id => $vrow) {
echo ' ';
} // end foreach on multi-edit
?>
+
-
diff --git a/tbl_gis_visualization.php b/tbl_gis_visualization.php
index 5c54b2f984..31bcd81e4f 100644
--- a/tbl_gis_visualization.php
+++ b/tbl_gis_visualization.php
@@ -20,6 +20,7 @@ $GLOBALS['js_include'][] = 'jquery/jquery.svg.js';
$GLOBALS['js_include'][] = 'jquery/jquery.mousewheel.js';
$GLOBALS['js_include'][] = 'jquery/jquery.event.drag-2.0.min.js';
$GLOBALS['js_include'][] = 'tbl_gis_visualization.js';
+$GLOBALS['js_include'][] = 'OpenStreetMap.js';
// Allows for resending headers even after sending some data
ob_start();
@@ -63,7 +64,7 @@ if (! isset($visualizationSettings['spatialColumn'])) {
}
// Convert geometric columns from bytes to text.
-$modified_query = PMA_GIS_modify_query($sql_query, $visualizationSettings);
+$modified_query = PMA_GIS_modifyQuery($sql_query, $visualizationSettings);
$modified_result = PMA_DBI_try_query($modified_query);
$data = array();
@@ -89,7 +90,7 @@ if (isset($_REQUEST['saveToFile'])) {
}
$save_format = $_REQUEST['fileFormat'];
- PMA_GIS_save_to_file($data, $visualizationSettings, $save_format, $file_name);
+ PMA_GIS_saveToFile($data, $visualizationSettings, $save_format, $file_name);
exit();
}
@@ -97,7 +98,7 @@ $svg_support = (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER <= 8) ? fal
$format = $svg_support ? 'svg' : 'png';
// get the chart and settings after chart generation
-$visualization = PMA_GIS_visualization_results($data, $visualizationSettings, $format);
+$visualization = PMA_GIS_visualizationResults($data, $visualizationSettings, $format);
/**
* Displays the page
@@ -115,39 +116,9 @@ $visualization = PMA_GIS_visualization_results($data, $visualizationSettings, $f
-
diff --git a/tbl_replace.php b/tbl_replace.php
index a14574a879..460908e350 100644
--- a/tbl_replace.php
+++ b/tbl_replace.php
@@ -153,6 +153,28 @@ $func_optional_param = array(
'UNIX_TIMESTAMP',
);
+$gis_from_text_functions = array(
+ 'GeomFromText',
+ 'GeomCollFromText',
+ 'LineFromText',
+ 'MLineFromText',
+ 'PointFromText',
+ 'MPointFromText',
+ 'PolyFromText',
+ 'MPolyFromText',
+);
+
+$gis_from_wkb_functions = array(
+ 'GeomFromWKB',
+ 'GeomCollFromWKB',
+ 'LineFromWKB',
+ 'MLineFromWKB',
+ 'PointFromWKB',
+ 'MPointFromWKB',
+ 'PolyFromWKB',
+ 'MPolyFromWKB',
+);
+
foreach ($loop_array as $rownumber => $where_clause) {
// skip fields to be ignored
if (! $using_key && isset($_REQUEST['insert_ignore_' . $where_clause])) {
@@ -238,10 +260,19 @@ foreach ($loop_array as $rownumber => $where_clause) {
/* This way user will know what UUID new row has */
$uuid = PMA_DBI_fetch_value('SELECT UUID()');
$cur_value = "'" . $uuid . "'";
- } elseif (!in_array($me_funcs[$key], $func_no_param)
+ } elseif ((in_array($me_funcs[$key], $gis_from_text_functions)
+ && substr($val, 0, 3) == "'''")
+ || in_array($me_funcs[$key], $gis_from_wkb_functions)
+ ) {
+ // Remove enclosing apostrophes
+ $val = substr($val, 1, strlen($val) - 2);
+ // Remove escaping apostrophes
+ $val = str_replace("''", "'", $val);
+ $cur_value = $me_funcs[$key] . '(' . $val . ')';
+ } elseif (! in_array($me_funcs[$key], $func_no_param)
|| ($val != "''" && in_array($me_funcs[$key], $func_optional_param))) {
$cur_value = $me_funcs[$key] . '(' . $val . ')';
- } else {
+ } else {
$cur_value = $me_funcs[$key] . '()';
}
diff --git a/tbl_select.php b/tbl_select.php
index e9b1eaec11..1191c3a09f 100644
--- a/tbl_select.php
+++ b/tbl_select.php
@@ -24,8 +24,18 @@ $GLOBALS['js_include'][] = 'tbl_change.js';
$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
+// required for GIS editor loaded via AJAX
+$GLOBALS['js_include'][] = 'gis_data_editor.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.svg.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.mousewheel.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.event.drag-2.0.min.js';
+$GLOBALS['js_include'][] = 'tbl_gis_visualization.js';
+$GLOBALS['js_include'][] = 'openlayers/OpenLayers.js';
+$GLOBALS['js_include'][] = 'OpenStreetMap.js';
+
$titles['Browse'] = PMA_tbl_setTitle($GLOBALS['cfg']['PropertiesIconic'], $pmaThemeImage);
+$geom_types = PMA_getGISDatatypes();
/**
* Not selection yet required -> displays the selection form
*/
@@ -52,8 +62,7 @@ if (! isset($param) || $param[0] == '') {
$err_url = $goto . '?' . PMA_generate_common_url($db, $table);
// Gets the list and number of fields
-
- list($fields_list, $fields_type, $fields_collation, $fields_null) = PMA_tbl_getFields($table,$db);
+ list($fields_list, $fields_type, $fields_collation, $fields_null, $geom_column_present) = PMA_tbl_getFields($table,$db);
$fields_cnt = count($fields_list);
// retrieve keys into foreign fields, if any
@@ -82,7 +91,7 @@ echo PMA_generate_html_tabs(PMA_tbl_getSubTabs(), $url_params);
-
+
+ ');
+ // if a geometry column
+ if (in_array($fields_type[$i], $geom_types)) {
+ echo('');
+ // get the relevant list of functions
+ $funcs = PMA_getGISFunctions($fields_type[$i], true, true);
+ foreach ($funcs as $func_name => $func) {
+ $name = isset($func['display']) ? $func['display'] : $func_name;
+ echo(''
+ . htmlspecialchars($name) . ' ');
+ }
+ echo(' ');
+ } else {
+ echo(' ');
+ }
+ echo('');
+ }
+ ?>
@@ -131,8 +161,8 @@ echo PMA_generate_html_tabs(PMA_tbl_getSubTabs(), $url_params);
$foreignData = PMA_getForeignData($foreigners, $field, false, '', '');
- echo PMA_getForeignFields_Values($foreigners, $foreignData, $field, $fields_type, $i, $db, $table, $titles,$GLOBALS['cfg']['ForeignKeyMaxLimit'], '' );
-
+ echo PMA_getForeignFields_Values($foreigners, $foreignData, $field, $fields_type, $i, $db, $table, $titles,$GLOBALS['cfg']['ForeignKeyMaxLimit'], '', true);
+
?>
@@ -147,6 +177,7 @@ echo PMA_generate_html_tabs(PMA_tbl_getSubTabs(), $url_params);
?>
+
do the work
*/
else {
- echo "ZZ";
// Builds the query
$sql_query = 'SELECT ' . (isset($distinct) ? 'DISTINCT ' : '');
@@ -258,14 +288,16 @@ else {
$cnt_func = count($func);
reset($func);
while (list($i, $func_type) = each($func)) {
-
- list($charsets[$i]) = explode('_', $collations[$i]);
+
+ list($charsets[$i]) = explode('_', $collations[$i]);
$unaryFlag = (isset($GLOBALS['cfg']['UnaryOperators'][$func_type]) && $GLOBALS['cfg']['UnaryOperators'][$func_type] == 1) ? true : false;
- $whereClause = PMA_tbl_search_getWhereClause($fields[$i],$names[$i], $types[$i], $collations[$i], $func_type, $unaryFlag);
- if($whereClause)
- $w[] = $whereClause;
-
- } // end for
+
+ $tmp_geom_func = isset($geom_func[$i]) ? $geom_func[$i] : null;
+ $whereClause = PMA_tbl_search_getWhereClause($fields[$i],$names[$i], $types[$i], $collations[$i], $func_type, $unaryFlag, $tmp_geom_func);
+
+ if($whereClause)
+ $w[] = $whereClause;
+ } // end for
//print_r($w);
if ($w) {
$sql_query .= ' WHERE ' . implode(' AND ', $w);
@@ -278,4 +310,4 @@ else {
require './sql.php';
}
-?>
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Factory_test.php b/test/classes/gis/PMA_GIS_Factory_test.php
new file mode 100644
index 0000000000..6d778ab799
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Factory_test.php
@@ -0,0 +1,80 @@
+assertInstanceOf($geom, PMA_GIS_Factory::factory($type));
+ }
+
+ /**
+ * data provider for testFactory
+ *
+ * @return data for testFactory
+ */
+ public function providerForTestFactory()
+ {
+ return array(
+ array(
+ 'MULTIPOLYGON',
+ 'PMA_GIS_Multipolygon'
+ ),
+ array(
+ 'POLYGON',
+ 'PMA_GIS_Polygon'
+ ),
+ array(
+ 'MULTILINESTRING',
+ 'PMA_GIS_Multilinestring'
+ ),
+ array(
+ 'LINESTRING',
+ 'PMA_GIS_Linestring'
+ ),
+ array(
+ 'MULTIPOINT',
+ 'PMA_GIS_Multipoint'
+ ),
+ array(
+ 'POINT',
+ 'PMA_GIS_Point'
+ ),
+ array(
+ 'GEOMETRYCOLLECTION',
+ 'PMA_GIS_Geometrycollection'
+ ),
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Geometry_test.php b/test/classes/gis/PMA_GIS_Geometry_test.php
new file mode 100644
index 0000000000..37d4c423c5
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Geometry_test.php
@@ -0,0 +1,60 @@
+ test classes
+ *
+ * @package phpMyAdmin-test
+ */
+
+require_once 'libraries/gis/pma_gis_geometry.php';
+
+/**
+ * Abstract parent class for all PMA_GIS_ test classes
+ */
+abstract class PMA_GIS_GeometryTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * test generateWkt method
+ *
+ * @param array $gis_data array of GIS data
+ * @param int $index index
+ * @param string $empty string to be insterted in place of missing values
+ * @param string $wkt expected WKT
+ *
+ * @return nothing
+ * @dataProvider providerForTestGenerateWkt
+ */
+ public function testGenerateWkt($gis_data, $index, $empty, $wkt)
+ {
+ if ($empty == null) {
+ $this->assertEquals($this->object->generateWkt($gis_data, $index), $wkt);
+ } else {
+ $this->assertEquals(
+ $this->object->generateWkt($gis_data, $index, $empty),
+ $wkt
+ );
+ }
+ }
+
+ /**
+ * test generateParams method
+ *
+ * @param string $wkt point in WKT form
+ * @param index $index index
+ * @param array $params expected output array
+ *
+ * @dataProvider providerForTestGenerateParams
+ * @return nothing
+ */
+ public function testGenerateParams($wkt, $index, $params)
+ {
+ if ($index == null) {
+ $this->assertEquals($this->object->generateParams($wkt), $params);
+ } else {
+ $this->assertEquals(
+ $this->object->generateParams($wkt, $index),
+ $params
+ );
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Linestring_test.php b/test/classes/gis/PMA_GIS_Linestring_test.php
new file mode 100644
index 0000000000..4bef75c3d9
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Linestring_test.php
@@ -0,0 +1,142 @@
+object = PMA_GIS_Linestring::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ $temp1 = array(
+ 0 => array(
+ 'LINESTRING' => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => 5.02, 'y' => 8.45),
+ 1 => array('x' => 6.14, 'y' => 0.15)
+ )
+ )
+ );
+
+ $temp2 = $temp1;
+ $temp2[0]['LINESTRING']['no_of_points'] = 3;
+ $temp2[0]['LINESTRING'][2] = array('x' => 1.56);
+
+ $temp3 = $temp2;
+ $temp3[0]['LINESTRING']['no_of_points'] = -1;
+
+ $temp4 = $temp3;
+ $temp4[0]['LINESTRING']['no_of_points'] = 3;
+ unset($temp4[0]['LINESTRING'][2]['x']);
+
+ return array(
+ array(
+ $temp1,
+ 0,
+ null,
+ 'LINESTRING(5.02 8.45,6.14 0.15)'
+ ),
+ // if a coordinate is missing, default is empty string
+ array(
+ $temp2,
+ 0,
+ null,
+ 'LINESTRING(5.02 8.45,6.14 0.15,1.56 )'
+ ),
+ // if no_of_points is not valid, it is considered as 2
+ array(
+ $temp3,
+ 0,
+ null,
+ 'LINESTRING(5.02 8.45,6.14 0.15)'
+ ),
+ // missing coordinates are replaced with provided values (3rd parameter)
+ array(
+ $temp4,
+ 0,
+ '0',
+ 'LINESTRING(5.02 8.45,6.14 0.15,0 0)'
+ )
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ $temp = array(
+ 'LINESTRING' => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => '5.02', 'y' => '8.45'),
+ 1 => array('x' => '6.14', 'y' => '0.15')
+ )
+ );
+ $temp1 = $temp;
+ $temp1['gis_type'] = 'LINESTRING';
+
+ return array(
+ array(
+ "'LINESTRING(5.02 8.45,6.14 0.15)',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => $temp
+ )
+ ),
+ array(
+ 'LINESTRING(5.02 8.45,6.14 0.15)',
+ 2,
+ array(
+ 2 => $temp1
+ )
+ )
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Multilinestring_test.php b/test/classes/gis/PMA_GIS_Multilinestring_test.php
new file mode 100644
index 0000000000..cef0cefbbc
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Multilinestring_test.php
@@ -0,0 +1,182 @@
+object = PMA_GIS_Multilinestring::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ $temp = array(
+ 0 => array(
+ 'MULTILINESTRING' => array(
+ 'no_of_lines' => 2,
+ 0 => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => 5.02, 'y' => 8.45),
+ 1 => array('x' => 6.14, 'y' => 0.15)
+ ),
+ 1 => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => 1.23, 'y' => 4.25),
+ 1 => array('x' => 9.15, 'y' => 0.47)
+ )
+ )
+ )
+ );
+
+ $temp1 = $temp;
+ unset($temp1[0]['MULTILINESTRING'][1][1]['y']);
+
+ return array(
+ array(
+ $temp,
+ 0,
+ null,
+ 'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 0.47))'
+ ),
+ // values at undefined index
+ array(
+ $temp,
+ 1,
+ null,
+ 'MULTILINESTRING(( , ))'
+ ),
+ // if a coordinate is missing, default is empty string
+ array(
+ $temp1,
+ 0,
+ null,
+ 'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 ))'
+ ),
+ // missing coordinates are replaced with provided values (3rd parameter)
+ array(
+ $temp1,
+ 0,
+ '0',
+ 'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 0))'
+ )
+ );
+ }
+
+ /**
+ * test getShape method
+ *
+ * @return nothing
+ */
+ public function testGetShape()
+ {
+ $row_data = array(
+ 'numparts' => 2,
+ 'parts' => array(
+ 0 => array(
+ 'points' => array(
+ 0 => array('x' => 5.02, 'y' => 8.45),
+ 1 => array('x' => 6.14, 'y' => 0.15),
+ ),
+ ),
+ 1 => array(
+ 'points' => array(
+ 0 => array('x' => 1.23, 'y' => 4.25),
+ 1 => array('x' => 9.15, 'y' => 0.47),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals(
+ $this->object->getShape($row_data),
+ 'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 0.47))'
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ $temp = array(
+ 'MULTILINESTRING' => array(
+ 'no_of_lines' => 2,
+ 0 => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => 5.02, 'y' => 8.45),
+ 1 => array('x' => 6.14, 'y' => 0.15),
+ ),
+ 1 => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => 1.23, 'y' => 4.25),
+ 1 => array('x' => 9.15, 'y' => 0.47),
+ )
+ )
+ );
+
+ $temp1 = $temp;
+ $temp1['gis_type'] = 'MULTILINESTRING';
+
+ return array(
+ array(
+ "'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 0.47))',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => $temp
+ )
+ ),
+ array(
+ 'MULTILINESTRING((5.02 8.45,6.14 0.15),(1.23 4.25,9.15 0.47))',
+ 2,
+ array(
+ 2 => $temp1
+ )
+ )
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Multipoint_test.php b/test/classes/gis/PMA_GIS_Multipoint_test.php
new file mode 100644
index 0000000000..8ab0aef928
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Multipoint_test.php
@@ -0,0 +1,146 @@
+object = PMA_GIS_Multipoint::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ $gis_data1 = array(
+ 0 => array(
+ 'MULTIPOINT' => array(
+ 'no_of_points' => 2,
+ 0 => array(
+ 'x' => 5.02,
+ 'y' => 8.45
+ ),
+ 1 => array(
+ 'x' => 1.56,
+ 'y' => 4.36
+ )
+ )
+ )
+ );
+
+ $gis_data2 = $gis_data1;
+ $gis_data2[0]['MULTIPOINT']['no_of_points'] = -1;
+
+ return array(
+ array(
+ $gis_data1,
+ 0,
+ null,
+ 'MULTIPOINT(5.02 8.45,1.56 4.36)'
+ ),
+ array(
+ $gis_data2,
+ 0,
+ null,
+ 'MULTIPOINT(5.02 8.45)'
+ )
+ );
+ }
+
+ /**
+ * test getShape method
+ *
+ * @return nothing
+ */
+ public function testGetShape()
+ {
+ $gis_data = array(
+ 'numpoints' => 2,
+ 'points' => array(
+ 0 => array('x' => 5.02, 'y' => 8.45),
+ 1 => array('x' => 6.14, 'y' => 0.15)
+ )
+ );
+
+ $this->assertEquals(
+ $this->object->getShape($gis_data),
+ 'MULTIPOINT(5.02 8.45,6.14 0.15)'
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ $temp1 = array(
+ 'MULTIPOINT' => array(
+ 'no_of_points' => 2,
+ 0 => array('x' => '5.02', 'y' => '8.45'),
+ 1 => array('x' => '6.14', 'y' => '0.15')
+ )
+ );
+ $temp2 = $temp1;
+ $temp2['gis_type'] = 'MULTIPOINT';
+
+ return array(
+ array(
+ "'MULTIPOINT(5.02 8.45,6.14 0.15)',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => $temp1
+ )
+ ),
+ array(
+ 'MULTIPOINT(5.02 8.45,6.14 0.15)',
+ 2,
+ array(
+ 2 => $temp2
+ )
+ )
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Multipolygon_test.php b/test/classes/gis/PMA_GIS_Multipolygon_test.php
new file mode 100644
index 0000000000..1a43555b56
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Multipolygon_test.php
@@ -0,0 +1,139 @@
+object = PMA_GIS_Multipolygon::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ private function _getData()
+ {
+ return array(
+ 'MULTIPOLYGON' => array(
+ 'no_of_polygons' => 2,
+ 0 => array(
+ 'no_of_lines' => 2,
+ 0 => array(
+ 'no_of_points' => 5,
+ 0 => array('x' => 35, 'y' => 10),
+ 1 => array('x' => 10, 'y' => 20),
+ 2 => array('x' => 15, 'y' => 40),
+ 3 => array('x' => 45, 'y' => 45),
+ 4 => array('x' => 35, 'y' => 10),
+ ),
+ 1 => array(
+ 'no_of_points' => 4,
+ 0 => array('x' => 20, 'y' => 30),
+ 1 => array('x' => 35, 'y' => 32),
+ 2 => array('x' => 30, 'y' => 20),
+ 3 => array('x' => 20, 'y' => 30),
+ )
+ ),
+ 1 => array(
+ 'no_of_lines' => 1,
+ 0 => array(
+ 'no_of_points' => 4,
+ 0 => array('x' => 123, 'y' => 0),
+ 1 => array('x' => 23, 'y' => 30),
+ 2 => array('x' => 17, 'y' => 63),
+ 3 => array('x' => 123, 'y' => 0),
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ $temp = array(
+ 0 => $this->_getData()
+ );
+
+ return array(
+ array(
+ $temp,
+ 0,
+ null,
+ 'MULTIPOLYGON(((35 10,10 20,15 40,45 45,35 10)'
+ . ',(20 30,35 32,30 20,20 30)),((123 0,23 30,17 63,123 0)))'
+ ),
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ $temp = $this->_getData();
+
+ $temp1 = $this->_getData();
+ $temp1['gis_type'] = 'MULTIPOLYGON';
+
+ return array(
+ array(
+ "'MULTIPOLYGON(((35 10,10 20,15 40,45 45,35 10),"
+ . "(20 30,35 32,30 20,20 30)),((123 0,23 30,17 63,123 0)))',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => $temp
+ )
+ ),
+ array(
+ 'MULTIPOLYGON(((35 10,10 20,15 40,45 45,35 10)'
+ . ',(20 30,35 32,30 20,20 30)),((123 0,23 30,17 63,123 0)))',
+ 2,
+ array(
+ 2 => $temp1
+ )
+ )
+ );
+ }
+}
+?>
diff --git a/test/classes/gis/PMA_GIS_Point_test.php b/test/classes/gis/PMA_GIS_Point_test.php
new file mode 100644
index 0000000000..a25a66ab95
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Point_test.php
@@ -0,0 +1,148 @@
+object = PMA_GIS_Point::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ return array(
+ array(
+ array(0 => array('POINT' => array('x' => 5.02, 'y' => 8.45))),
+ 0,
+ null,
+ 'POINT(5.02 8.45)'
+ ),
+ array(
+ array(0 => array('POINT' => array('x' => 5.02, 'y' => 8.45))),
+ 1,
+ null,
+ 'POINT( )'
+ ),
+ array(
+ array(0 => array('POINT' => array('x' => 5.02))),
+ 0,
+ null,
+ 'POINT(5.02 )'
+ ),
+ array(
+ array(0 => array('POINT' => array('y' => 8.45))),
+ 0,
+ null,
+ 'POINT( 8.45)'
+ ),
+ array(
+ array(0 => array('POINT' => array())),
+ 0,
+ null,
+ 'POINT( )'
+ ),
+ );
+ }
+
+ /**
+ * test getShape method
+ *
+ * @param array $row_data array of GIS data
+ * @param string $shape expected shape in WKT
+ *
+ * @dataProvider providerForTestGetShape
+ * @return nothing
+ */
+ public function testGetShape($row_data, $shape)
+ {
+ $this->assertEquals($this->object->getShape($row_data), $shape);
+ }
+
+ /**
+ * data provider for testGetShape
+ *
+ * @return data for testGetShape
+ */
+ public function providerForTestGetShape()
+ {
+ return array(
+ array(
+ array('x' => 5.02, 'y' => 8.45),
+ 'POINT(5.02 8.45)'
+ )
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ return array(
+ array(
+ "'POINT(5.02 8.45)',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => array(
+ 'POINT' => array('x' => '5.02', 'y' => '8.45')
+ ),
+ )
+ ),
+ array(
+ 'POINT(5.02 8.45)',
+ 2,
+ array(
+ 2 => array(
+ 'gis_type' => 'POINT',
+ 'POINT' => array('x' => '5.02', 'y' => '8.45')
+ ),
+ )
+ )
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/classes/gis/PMA_GIS_Polygon_test.php b/test/classes/gis/PMA_GIS_Polygon_test.php
new file mode 100644
index 0000000000..b504acc12e
--- /dev/null
+++ b/test/classes/gis/PMA_GIS_Polygon_test.php
@@ -0,0 +1,299 @@
+object = PMA_GIS_Polygon::singleton();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @access protected
+ * @return nothing
+ */
+ protected function tearDown()
+ {
+ unset($this->object);
+ }
+
+ private function _getData()
+ {
+ return array(
+ 'POLYGON' => array(
+ 'no_of_lines' => 2,
+ 0 => array(
+ 'no_of_points' => 5,
+ 0 => array('x' => 35, 'y' => 10),
+ 1 => array('x' => 10, 'y' => 20),
+ 2 => array('x' => 15, 'y' => 40),
+ 3 => array('x' => 45, 'y' => 45),
+ 4 => array('x' => 35, 'y' => 10),
+ ),
+ 1 => array(
+ 'no_of_points' => 4,
+ 0 => array('x' => 20, 'y' => 30),
+ 1 => array('x' => 35, 'y' => 32),
+ 2 => array('x' => 30, 'y' => 20),
+ 3 => array('x' => 20, 'y' => 30),
+ )
+ )
+ );
+ }
+
+ /**
+ * data provider for testGenerateWkt
+ *
+ * @return data for testGenerateWkt
+ */
+ public function providerForTestGenerateWkt()
+ {
+ $temp = array(
+ 0 => $this->_getData()
+ );
+
+ $temp1 = $temp;
+ unset($temp1[0]['POLYGON'][1][3]['y']);
+
+ return array(
+ array(
+ $temp,
+ 0,
+ null,
+ 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))'
+ ),
+ // values at undefined index
+ array(
+ $temp,
+ 1,
+ null,
+ 'POLYGON(( , , , ))'
+ ),
+ // if a coordinate is missing, default is empty string
+ array(
+ $temp1,
+ 0,
+ null,
+ 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 ))'
+ ),
+ // missing coordinates are replaced with provided values (3rd parameter)
+ array(
+ $temp1,
+ 0,
+ '0',
+ 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 0))'
+ )
+ );
+ }
+
+ /**
+ * data provider for testGenerateParams
+ *
+ * @return data for testGenerateParams
+ */
+ public function providerForTestGenerateParams()
+ {
+ $temp = $this->_getData();
+
+ $temp1 = $temp;
+ $temp1['gis_type'] = 'POLYGON';
+
+ return array(
+ array(
+ "'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))',124",
+ null,
+ array(
+ 'srid' => '124',
+ 0 => $temp
+ )
+ ),
+ array(
+ 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 32,30 20,20 30))',
+ 2,
+ array(
+ 2 => $temp1
+ )
+ )
+ );
+ }
+
+ /**
+ * test for Area
+ *
+ * @param array $ring array of points forming the ring
+ * @param fload $area area of the ring
+ *
+ * @dataProvider providerForTestArea
+ * @return nothing
+ */
+ public function testArea($ring, $area)
+ {
+ $this->assertEquals($this->object->area($ring), $area);
+ }
+
+ /**
+ * data provider for testArea
+ *
+ * @return data for testArea
+ */
+ public function providerForTestArea()
+ {
+ return array(
+ array(
+ array(
+ 0 => array('x' => 35, 'y' => 10),
+ 1 => array('x' => 10, 'y' => 10),
+ 2 => array('x' => 15, 'y' => 40)
+ ),
+ -375.00
+ ),
+ // first point of the ring repeated as the last point
+ array(
+ array(
+ 0 => array('x' => 35, 'y' => 10),
+ 1 => array('x' => 10, 'y' => 10),
+ 2 => array('x' => 15, 'y' => 40),
+ 3 => array('x' => 35, 'y' => 10)
+ ),
+ -375.00
+ ),
+ // anticlockwise gives positive area
+ array(
+ array(
+ 0 => array('x' => 15, 'y' => 40),
+ 1 => array('x' => 10, 'y' => 10),
+ 2 => array('x' => 35, 'y' => 10)
+ ),
+ 375.00
+ )
+ );
+ }
+
+ /**
+ * test for isPointInsidePolygon
+ *
+ * @param array $point x, y coordinates of the point
+ * @param array $polygon array of points forming the ring
+ * @param bool $isInside output
+ *
+ * @dataProvider providerForTestIsPointInsidePolygon
+ * @return nothing
+ */
+ public function testIsPointInsidePolygon($point, $polygon, $isInside)
+ {
+ $this->assertEquals(
+ $this->object->isPointInsidePolygon($point, $polygon),
+ $isInside
+ );
+ }
+
+ /**
+ * data provider for testIsPointInsidePolygon
+ *
+ * @return data for testIsPointInsidePolygon
+ */
+ public function providerForTestIsPointInsidePolygon()
+ {
+ $ring = array(
+ 0 => array('x' => 35, 'y' => 10),
+ 1 => array('x' => 10, 'y' => 10),
+ 2 => array('x' => 15, 'y' => 40),
+ 3 => array('x' => 35, 'y' => 10)
+ );
+
+ return array(
+ // point inside the ring
+ array(
+ array('x' => 20, 'y' => 15),
+ $ring,
+ true
+ ),
+ // point on an edge of the ring
+ array(
+ array('x' => 20, 'y' => 10),
+ $ring,
+ false
+ ),
+ // point on a vertex of the ring
+ array(
+ array('x' => 10, 'y' => 10),
+ $ring,
+ false
+ ),
+ // point outside the ring
+ array(
+ array('x' => 5, 'y' => 10),
+ $ring,
+ false
+ ),
+ );
+ }
+
+ /**
+ * test for getPointOnSurface
+ *
+ * @param array $ring array of points forming the ring
+ *
+ * @dataProvider providerForTestGetPointOnSurface
+ * @return nothing
+ */
+ public function testGetPointOnSurface($ring)
+ {
+ $this->assertEquals(
+ $this->object->isPointInsidePolygon(
+ $this->object->getPointOnSurface($ring),
+ $ring
+ ),
+ true
+ );
+ }
+
+ /**
+ * data provider for testGetPointOnSurface
+ *
+ * @return data for testGetPointOnSurface
+ */
+ public function providerForTestGetPointOnSurface()
+ {
+ $temp = $this->_getData();
+ unset($temp['POLYGON'][0]['no_of_points']);
+ unset($temp['POLYGON'][1]['no_of_points']);
+
+ return array(
+ array(
+ $temp['POLYGON'][0]
+ ),
+ array(
+ $temp['POLYGON'][1]
+ )
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/test/libraries/PMA_GIS_modifyQuery_test.php b/test/libraries/PMA_GIS_modifyQuery_test.php
new file mode 100644
index 0000000000..04e9e1adad
--- /dev/null
+++ b/test/libraries/PMA_GIS_modifyQuery_test.php
@@ -0,0 +1,94 @@
+assertEquals(
+ PMA_GIS_modifyQuery($sql_query, $settings),
+ $modified_query
+ );
+ }
+
+ /**
+ * data provider for testModifyQuery
+ *
+ * @return data for testModifyQuery
+ */
+ public function provider()
+ {
+ return array(
+ // select *
+ array(
+ 'SELECT * FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `noo`, ASTEXT(`moo`) AS `moo`, SRID(`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // select * with no label column
+ array(
+ 'SELECT * FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo'),
+ 'SELECT ASTEXT(`moo`) AS `moo`, SRID(`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // more columns
+ array(
+ 'SELECT `aaa`, `moo`, `bbb`, `noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `noo`, ASTEXT(`moo`) AS `moo`, SRID(`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // no labelColumn defined
+ array(
+ 'SELECT `moo`, `noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo'),
+ 'SELECT ASTEXT(`moo`) AS `moo`, SRID(`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // alias for spatialColumn
+ array(
+ 'SELECT `aaa` AS `moo`, `noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `noo`, ASTEXT(`aaa`) AS `moo`, SRID(`aaa`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // alias for labelColumn
+ array(
+ 'SELECT `moo`, `bbb` AS `noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `bbb` AS `noo`, ASTEXT(`moo`) AS `moo`, SRID(`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // with database names
+ array(
+ 'SELECT `db`.`moo`, `db`.`noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `db`.`noo`, ASTEXT(`db`.`moo`) AS `moo`, SRID(`db`.`moo`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ // database names plus alias
+ array(
+ 'SELECT `db`.`aaa` AS `moo`, `noo` FROM `foo` WHERE `bar` = `zoo`',
+ array('spatialColumn' => 'moo', 'labelColumn' => 'noo'),
+ 'SELECT `noo`, ASTEXT(`db`.`aaa`) AS `moo`, SRID(`db`.`aaa`) AS `srid` FROM `foo` WHERE `bar` = `zoo`'
+ ),
+ );
+ }
+}
+?>
\ No newline at end of file
diff --git a/themes/original/css/theme_right.css.php b/themes/original/css/theme_right.css.php
index 64e64e49a7..6cb423363f 100644
--- a/themes/original/css/theme_right.css.php
+++ b/themes/original/css/theme_right.css.php
@@ -1739,6 +1739,44 @@ input#input_import_file {
margin: 5px 0px 5px 0px;
}
+/**
+ * GIS data editor styles
+ */
+a.close_gis_editor {
+ float: right;
+}
+
+#gis_editor {
+ display: none;
+ position: fixed;
+ _position: absolute; /* hack for IE */
+ z-index: 101;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+#gis_data {
+ min-height: 230px;
+}
+
+#gis_data_textarea {
+ height: 6em;
+}
+
+#gis_data_editor {
+ background: #D0DCE0;
+ padding: 15px;
+ min-height: 500px;
+}
+
+#gis_data_editor .choice {
+ display: none;
+}
+
+#gis_data_editor input[type="text"] {
+ width: 75px;
+}
+
/**
* ENUM/SET editor styles
*/
diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php
index 982e744a7d..1103bfa770 100644
--- a/themes/pmahomme/css/theme_right.css.php
+++ b/themes/pmahomme/css/theme_right.css.php
@@ -2134,6 +2134,44 @@ input#input_import_file {
margin: 5px 0px 5px 0px;
}
+/**
+ * GIS data editor styles
+ */
+a.close_gis_editor {
+ float: right;
+}
+
+#gis_editor {
+ display: none;
+ position: fixed;
+ _position: absolute; /* hack for IE */
+ z-index: 101;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+#gis_data {
+ min-height: 230px;
+}
+
+#gis_data_textarea {
+ height: 6em;
+}
+
+#gis_data_editor {
+ background: #D0DCE0;
+ padding: 15px;
+ min-height: 500px;
+}
+
+#gis_data_editor .choice {
+ display: none;
+}
+
+#gis_data_editor input[type="text"] {
+ width: 75px;
+}
+
/**
* ENUM/SET editor styles
*/