blueherongis / Heron

An add-on for Grasshopper enabling the GIS functions of GDAL in Rhino 3d
MIT License
31 stars 19 forks source link

Default anchor point #41

Closed joaoponceleao closed 2 years ago

joaoponceleao commented 2 years ago

Hi. Great job with the plugin.

I've got an issue regarding the default earth anchor point that Heron uses. This was tested by importing shapefiles in a projected coordinate system (EPSG:3763).

I have tried importing this shapefile without using the Heron earth anchor point tool, using it toggled to true but with default (empty) values, and using it with coordinates inside the shapefile study area. In the first two cases, Heron imports the geometry into the exact same location (more on that later), but badly distorted. It's as if it did not recognise the projection and read the shapefile as if it was EPSG:4326 (it did, and sourceSRS in the component shows EPSG:3763). In the final case, feeding EAP lat and lon, the shapefile gets imported seemingly correctly, without distortion, but is placed near the 0,0 origin of the Rhino world view (as it should).

My understanding is that we can pick an anchor point (which uses rhino's command) in order to keep our local geometry closer to the 0,0 origin of the Rhino world view. This should help with performance on the one hand, and allow for consistency with other plugins that also use the earth anchor point.

However, if no anchor point is chosen, what happens? In the test above it looks like the shapefile's projection system was ignored. Ignoring the earth anchor point in two other tools does not exhibit the same behavious though. See below.

In our case, we have quite a large grasshopper definition that needs to communicate with QGIS or other GIS applications. For that, we use pyshp and call it within GHPython. This is quite a popular library for GH python since it is python 2 compatible and is written in pure python (so works quite well within Rhino's ironpython limitations). The issue is that pyshp (which is not aware of any such thing as earth anchor points) imports to a different location in Rhino's axis than Heron (with the earth anchor point turned off). This means both tools can't be used in conjunction. On the other hand, BearGIS which is another GH plugin, imports to the same location as pyshp (even though it doesn't use it). The same point in the shapefile gets the following coordinates in rhino depending on the tool used:

Heron Import Vector: -906984.18,4420733.38,0.00 PyShp in GHPython: -88344.66,-105653.55,38.94 BearGIS: -88344.66,-105653.55,38.94

Naturally, I can simply use BearGIS instead of Heron (with its other limitations), or try to get rid of the pyshp dependency in our code (not feasible at the moment). I would assume however, that if we're not overriding the earth anchor point, all shapefile imports would be placed in the same rhino coordinates, regardless of the tool used. Should it not be so? Am I doing something wrong?

blueherongis commented 2 years ago

Hi @joaoponceleao ! Thanks for considering Heron in your workflow. You are not doing anything wrong. As you've noted, Heron is built to work from the EarthAnchorPoint. So, if the EAP is 0deg, 0deg, Heron will put your data very far from origin. I suspect this is what's happening with your setup. If the EAP is unset (never been set at all), since v0.3.7 (or so) the ImportVector component will automatically set the EAP to the center of the data.

I'd like to get Heron to play well with the other plugins, so could you post or otherwise link your shapefile for troubleshooting?

Also, are you using pyshp for just exporting shapefiles, or is it more embedded into the QGIS conduit? Heron has an ExportVector component you could try if you are just looking to export.

joaoponceleao commented 2 years ago

Hi. Thanks for the quick reply. Pyshp is quite embedded at the moment in this particular workflow (plugin that hides the grasshopper interface from the user). Our test with heron was for teaching purposes, and for future work in other workflows (comparing with beargis in this case).

Was not aware EAP would be set to center of the data when unset. That helps in understanding what's going on.

Still.... I set the EAP to 0,0 this time (hoping to mimic what I assume would be pyshp and beargis functionality) but it did not work. Here's the issue:

GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]

If I export that same geometry through pyshp in gphython, it will show up in the wrong location and only viewable under a 4326 projection. Setting the userSRS in heron manually to the same EPSG as the source .prj file leads to heron importing the shapefile without distortion, but again, in a different location than expected.

I believe I'm either misunderstanding the expected workflow here, or there is something going on. Here's the file I've been using for testing purposes: lisbon.zip

blueherongis commented 2 years ago

Hi @joaoponceleao , It appears the BearGIS import uses the origin of the shapefile coordinate system as the Rhino origin and then reads the point coordinates straight into GH points, not utilizing Rhino's EarthAnchorPoint. So if you set the Rhino EAP using SetEAP to the origin of the coordinate system (LAT 39.66825833333333, LON -8.133108333333334 for EPSG:3763) and use ImportVector, you will get close to the BearGIS import (grey linework in screenshot). However, the ImportVector output is based in WGS84 coordinates, which will be distorted relative to the BearGIS import given we are approx. 137km from the Rhino origin. To overcome this, you can set the userSRS to EPSG:3763 making the ImportVector component output points in the EPSG:3763 coordinate system (light blue linework). One extra step is to rotate this geometry because the ImportVector component attempts to maintain true north.

image

20220518_SRS Origin.zip

Be aware, when you go through these extra steps to match the BearGIS import, you will need to do the same with any other geometry you bring in with Heron (topography, raster imagery, etc.). Plus you will be far from origin where linework can get a little "jumpy". Also note, the red line segments you see in the screenshot are from trying to make polylines out of the BearGIS imported points. It appears it doesn't create separate branches for courtyards.

If you think it would help, I could add a menu toggle that would strip out the coordinate transformation in ImportVector so it just outputs straight coordinates, similar to the way BearGIS works. Just let me know.

When using the ExportVector component, it only exports to EPSG:4326. If you need an export to be in another coordinate system, you can use the GDALOgr2Ogr component (let me know if you want a setup for this).

joaoponceleao commented 2 years ago

Hi. Thank you for all the support. I was able to reproduce everything according to your instructions here and it worked. Again, thanks.

A few notes:

Thanks for the thought on a menu toggle to output straight coordinates. I think it might help get more people onboard Heron. It would certainly help us by keeping things simple for students. It would allow Heron to keep all its more advanced features that other plugins don't have and that will be of use to many, while also allowing it to function as a more simple shapefile importer, producing the same results users are used to seeing in their workflow. One thing I think would help and would be a greater priority is more documentation. Not tutorials, simply short documentation in github on what each component does. I would be happy to do a PR but i doubt i'm the right person for the job. I expected, for instance, for the import vector to output with the CRS of the file in featurepoints, and a user-entered CRS in featurepointsUser. I see now that it will always output as WGS84, regardless of the file CRS. I also did not expect the EAP to be set to the center of the data if not configured. This is a great idea for a single file import, but I can see issues when importing multiple files, particularly in a team setting where not all files are imported in the same order.

Great support by the way. I think you can close the issue. I do have one final question which is not related to Heron but to importing GIS files into non-geographic programs like Rhino in general. I have been always dealing in the projected coordinate system relevant for our study area, for a number of reasons. I see a number of workflows demanding a conversion to EPSG:4326 / WGS84. I see Heron does the same by default. Is there a good reason for this?

blueherongis commented 2 years ago

Excellent feedback! Thank you for taking the time to be so detailed.
First, to respond to your notes:

One of the items on the road map is to allow a user to set a coordinate system to be used by all components, similar to the way QGIS works. This requires a "sticky" global parameter that I've just started testing, but will likely take a while to implement as it would affect most of the components. In theory, setting the coordinate system as a global parameter should allow import of imagery or topo to match the straight coordinates as produced by other plugins. It would also mean I could get rid of the userSRS inputs and outputs on individual components.

The main reason I based Heron on WGS84 was due to RhinoCommon's built-in transform EarthAnchorPoint.GetModelToEarth. Heron code for this can be found here and the opennurbs implementation can be found here. Note in the RhinoCommon documentation there is discussion of error the farther you get from origin due to transforming from a planar coordinate system to a spherical one. To minimize this error, I always recommend setting the EAP first and to try to keep geometry close to the origin.

Another minor reason for using WGS84 is that many of the web services Heron can interact with only have the ability to be queried with coordinates in WGS84.

I completely agree Heron documentation is lacking. I'd be happy to review PRs for this, but am starting to focus on it myself and am looking for the right format (notion.io like pyRevit, gitbook like Bitmap+ or just stick with github Wiki). The trouble has always been me being drawn to adding more functionality over documentation.

I will close this issue, but I do want to continue the conversation!

blueherongis commented 2 years ago

Hi @joaoponceleao , I've just released Heron v0.4.0 which introduces the global parameter HeronSRS, set with the new SetSRS component. This allows on-the-fly transformation from a data source's SRS to the custom HeronSRS--no more back/forth to WGS84. If the source SRS matches the one set for HeronSRS, no translation happens and the output of ImportVector (red meshes) will match that of BearGIS (blue outlines)--note the Rhino file needs to be in meters. This HeronSRS has been integrated into most of the other components so that RESTRaster (underlay map) and ExportVector work with the HeronSRS. Two other updates to ImportVector have been added per our discussion here:

20220731_Lisbon ImportVector with HeronSRS.zip

joaoponceleao commented 2 years ago

Wow! Thanks. This looks great. Makes everything much more consistent! Thanks for taking the time to implement this. I will be updating our website / guidelines to recommend using Heron now as soon as I have the time (http://solidvoids.fa.ulisboa.pt).

" I thought it better to have them all abide by the HeronSRS" Absolutely. If there is a component that controls everything like HeronSRS, this should be the main control.

It might be an idea (very low priority - just mentioning it for future reference) if ImportVector could read the SRS and use it automatically (HeronSRS would work as an override in this case). I realise it's not so simple - this is what we try to do with a python component, but we still recommend people to enter the SRS manually: too many issues otherwise (either the database from the python lib is incomplete, the web service it uses is down, or in some cases the .prj file uses a not so standard code). I have also noticed that most people that use shapefiles seem to exchange them without the .prj file, so we kind of push them to input the SRS manually anyway. I'm hoping to get everyone using geopackage instead, once I move the whole thing to Python 3 / Hops (when i find the time...).

Good job!

blueherongis commented 2 years ago

Thanks for the recommendation!

I like your idea of setting the SRS automatically with ImportVector, similar to the way QGIS does when you import data to an empty project. I have the HeronSRS set to WGS84 by default so that it wouldn't break old workflows. I think I'll keep this, but maybe ImportVector can check if it's the first Heron component to be placed on the canvas and, if so, could set the HeronSRS to that of the source. I can see it getting complicated if there are already other Heron components on the canvas. Would that functionality help?