Open dchaffin opened 4 years ago
Hi, could you please provide a sample code and expected/actual output?
Thanks! Here is a quick example ...
$test01 = '{"type":"MultiPolygon","coordinates":[[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]]]]}';
$test02 = '{"type":"MultiPolygon","coordinates":[[[[127,27],[128,27],[128,28],[127,28],[127,27]]],[[[120,20],[121,20],[121,21],[120,21],[120,20]]]]}';
$s1 = $reader->read($test01);
$s2 = $reader->read($test02);
$sOut1 = $s1->union($s2);
// This output doesn't appear to follow the right-hand rule
dpm($writer->write($sOut1));
// If I use this other library to "rewind", it works
$sOut2 = \Vicchi\GeoJson\Rewind::rewind((array)json_decode($writer->write($sOut1)), true);
$sOut2 = $reader->read(json_encode($sOut2));
dpm($writer->write($sOut2));
NOTE: The dpm() function is just a quick way to output on screen in Drupal.
The first example outputs:
{"type":"MultiPolygon","coordinates":[[[[100,0],[100,1],[101,1],[101,0],[100,0]]],[[[107,7],[107,8],[108,8],[108,7],[107,7]]],[[[120,20],[120,21],[121,21],[121,20],[120,20]]],[[[127,27],[127,28],[128,28],[128,27],[127,27]]]]}
The second outputs:
{"type":"MultiPolygon","coordinates":[[[[100,0],[101,0],[101,1],[100,1],[100,0]]],[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[120,20],[121,20],[121,21],[120,21],[120,20]]],[[[127,27],[128,27],[128,28],[127,28],[127,27]]]]}
If you put these into the validator at: http://geojsonlint.com, the first output comes up with the message: "Polygons and MultiPolygons should follow the right-hand rule"
Good point, I don't think this is enforced at the moment. I don't have this on top of my head, but I'm not even sure we enforce the clockwise/counterclockwise for polygons at all in this library.
I'm surprised though, that MySQL does not output a valid geometry following the right-hand rule, could you please check the raw output of ST_Union()
?
Sorry, I've never worked with ST_Union in MySQL like that ... took me a minute to figure out. But I think I did it right with the example info above. I ran:
SELECT ST_AsText(
ST_UNION(
ST_GeomFromText('MultiLineString((107 7,108 7,108 8,107 8,107 7),(100 0,101 0,101 1,100 1,100 0))'),
ST_GeomFromText('MultiLineString((127 27,128 27,128 28,127 28,127 27),(120 20,121 20,121 21,120 21,120 20))')
))
And it generated:
MULTILINESTRING((100 0,100 1,101 1,101 0,100 0),(107 7,107 8,108 8,108 7,107 7),(120 20,120 21,121 21,121 20,120 20),(127 27,127 28,128 28,128 27,127 27))
That looks to me to match the first output above.
I had initially that other library above to "rewind" it, but that still left me with a "MultiPolygon" object that wasn't playing well with my Google Maps.
I ended up just taking the output of the union and calling array_reverse on the first item in each array and building my own object to then re-serialize with json_encode...
\Brick\Geo\Engine\GeometryEngineRegistry::set(new \Brick\Geo\Engine\PDOEngine($pdo));
$reader = new \Brick\Geo\IO\GeoJSONReader();
$shapeOutput = null;
foreach ($shapes as $shape){
$s = $reader->read(json_encode($shape));
if(is_null($shapeOutput)){
$shapeOutput = $s;
} else {
$shapeOutput = $shapeOutput->union($s);
}
}
$output = [
'type' => 'FeatureCollection',
'features' => [],
];
foreach ($shapeOutput->toArray() as $feature) {
$feature[0] = array_reverse($feature[0]);
$output['features'][] = [
'type' => 'Feature',
'properties' => (object)[ 'name' => 'TEST' ],
'geometry' => (object)[
'type' => 'Polygon',
'coordinates' => $feature,
],
];
}
Each "shape" in that "shapes" array is a PHP object like:
Array
(
[type] => FeatureCollection
[features] => Array
(
[0] => Array
(
[type] => Feature
[properties] => stdClass Object
(
[__CLASS__] => stdClass
[name] => zip-40004
)
[geometry] => stdClass Object
(
[__CLASS__] => stdClass
[type] => Polygon
[coordinates] => Array
(
[0] => Array
(
[0] => Array(2)
........ repeat coordinates...
There's probably still some refactoring to do there, but it's working so far. In my case, I'm dealing with county and zip code shapes from the US Census which appear to consist of one or more polygons for the outside and then zero or more for any holes. Only the outermost (first one) seems to need reversed so far as I've seen.
I did find this information for MS SQL which may or may not be helpful... https://bertwagner.com/2018/01/23/inverted-polygons-how-to-troubleshoot-sql-servers-left-hand-rule/
I'm trying to use the union function to combine some shapes. The GeoJSONReader outputs each shape individually correct, but if I run union on them, the output doesn't follow the 'right-hand rule' (https://mapster.me/right-hand-rule-geojson-fixer/).
EDIT: I'm using MySQL for the GeometryEngine
Am I missing something or does this not support that yet? Thanks!