Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport release_3_8] Fix WKT geometry string provided by QGIS Server in GetFeatureInfo #5381

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 50 additions & 18 deletions lizmap/modules/lizmap/classes/lizmapWkt.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
*
* @license Mozilla Public License : http://www.mozilla.org/MPL/
*/

/**
* @phpstan-type WktMatches array{geomType: string, dim: string, str: string}
*/
class lizmapWkt
{
/** @var array<string, string> */
Expand All @@ -24,7 +28,7 @@ class lizmapWkt
*
* @param string $wkt A WKT string
*
* @return array|false The WKT string is well formed
* @return false|WktMatches The WKT string is well formed
*/
public static function check($wkt)
{
Expand All @@ -42,13 +46,55 @@ public static function check($wkt)
return false;
}

$geomType = strtolower($matches[1]);
$dim = strtolower($matches[2]);
$str = $matches[3];

if (substr($geomType, -2) === 'zm') {
$geomType = substr($geomType, 0, -2);
$dim = 'zm';
} elseif (substr($geomType, -2) === 'mz') {
$geomType = substr($geomType, 0, -2);
$dim = 'mz';
} elseif (substr($geomType, -1) === 'z') {
$geomType = substr($geomType, 0, -1);
$dim = 'z';
} elseif (substr($geomType, -1) === 'm') {
$geomType = substr($geomType, 0, -1);
$dim = 'm';
}

return array(
'geomType' => strtolower($matches[1]),
'dim' => strtolower($matches[2]),
'str' => $matches[3],
'geomType' => $geomType,
'dim' => $dim,
'str' => $str,
);
}

/**
* Return a WKT string corrected with space between geometry type and dimension as upper case.
*
* @param string $wkt A WKT string
*
* @return null|string The WKT string corrected with space between geometry type and dimension as upper case
*/
public static function fix($wkt)
{
// Checking and extracting geometry type, dimension and coordinates
$matches = self::check($wkt);
if (!$matches) {
return null;
}

$nWkt = $matches['geomType'];
if ($matches['dim'] !== '') {
$nWkt .= ' '.$matches['dim'];
}
$nWkt .= ' ('.$matches['str'].')';

return strtoupper($nWkt);
}

/**
* Return a geometry array likes it is defined in GeoJSON.
*
Expand All @@ -67,20 +113,6 @@ public static function parse($wkt)
$dim = $matches['dim'];
$str = $matches['str'];

if (substr($geomType, -2) === 'zm') {
$geomType = substr($geomType, 0, -2);
$dim = 'zm';
} elseif (substr($geomType, -2) === 'mz') {
$geomType = substr($geomType, 0, -2);
$dim = 'mz';
} elseif (substr($geomType, -1) === 'z') {
$geomType = substr($geomType, 0, -1);
$dim = 'z';
} elseif (substr($geomType, -1) === 'm') {
$geomType = substr($geomType, 0, -1);
$dim = 'm';
}

// Get coordinates
$coordinates = null;
if ($geomType === 'point') {
Expand Down
6 changes: 5 additions & 1 deletion lizmap/modules/lizmap/lib/Request/WMSRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,11 @@ protected function gfiVectorXmlToHtml($layerId, $layerName, $layerTitle, $layer,
'maxy' => 'bbox-maxy',
);
if ($feature->BoundingBox) {
$hiddenGeometry .= '<input type="hidden" value="'.$attribute['value'].'" class="lizmap-popup-layer-feature-geometry"/>'.PHP_EOL;
// Fix geometry by adding space between geometry type and Z, M or ZM
$geom = \lizmapWkt::fix($attribute['value']);
// Insert geometry as an hidden input
$hiddenGeometry .= '<input type="hidden" value="'.$geom.'" class="lizmap-popup-layer-feature-geometry"/>'.PHP_EOL;
// Insert bounding box data as hidden inputs
$bbox = $feature->BoundingBox[0];
foreach ($props as $prop => $class) {
$hiddenGeometry .= '<input type="hidden" value="'.$bbox[$prop].'" class="lizmap-popup-layer-feature-'.$class.'"/>'.PHP_EOL;
Expand Down
56 changes: 55 additions & 1 deletion tests/units/classes/lizmapWktTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,32 @@ function testChecking() {
'GEOMETRY (((30 10, 40 40, 20 40, 10 20, 30 10)))',
);
foreach($wktArray as $wkt) {
$this->assertIsArray(lizmapWkt::check($wkt), 'The '.$wkt.' has not been checked!');
$checked = lizmapWkt::check($wkt);
$this->assertIsArray($checked, 'The '.$wkt.' has not been checked!');
$this->assertArrayHasKey('geomType', $checked);
$this->assertArrayHasKey('dim', $checked);
$this->assertEquals('', $checked['dim']);
$this->assertArrayHasKey('str', $checked);
}

$zWktArray = array(
'POINT Z (30 10 0)',
'POINT Z(30 10 0)',
'POINTZ(30 10 0)',
'LINESTRING Z (30 10 0, 10 30 1, 40 40 2)',
'LINESTRING Z(30 10 0, 10 30 1, 40 40 2)',
'LINESTRINGZ(30 10 0, 10 30 1, 40 40 2)',
'POLYGON Z ((30 10 0, 40 40 2, 20 40 1, 10 20 2, 30 10 0))',
'POLYGON Z((30 10 0, 40 40 2, 20 40 1, 10 20 2, 30 10 0))',
'POLYGONZ((30 10 0, 40 40 2, 20 40 1, 10 20 2, 30 10 0))',
);
foreach($zWktArray as $wkt) {
$checked = lizmapWkt::check($wkt);
$this->assertIsArray($checked, 'The '.$wkt.' has not been checked!');
$this->assertArrayHasKey('geomType', $checked);
$this->assertArrayHasKey('dim', $checked);
$this->assertEquals('z', $checked['dim']);
$this->assertArrayHasKey('str', $checked);
}

$notWktArray = array(
Expand All @@ -41,6 +66,35 @@ function testChecking() {
}
}

function testFixing() {
// Unfixed WKT
$wkt = 'POINT (30 10)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($wkt, $nWkt);

$wkt = 'POINT Z (30 10 0)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($wkt, $nWkt);

$wkt = 'POINT M (30 10 0)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($wkt, $nWkt);

$wkt = 'POINT ZM (30 10 0 0)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($wkt, $nWkt);

// Fixed WKT
$expectedWkt = 'POINT Z (30 10 0)';
$wkt = 'POINT Z(30 10 0)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($expectedWkt, $nWkt);

$wkt = 'POINTZ(30 10 0)';
$nWkt = lizmapWkt::fix($wkt);
$this->assertEquals($expectedWkt, $nWkt);
}

function testPoint() {
$wkt = 'POINT (30 10)';
$geom = lizmapWkt::parse($wkt);
Expand Down
Loading