-
Notifications
You must be signed in to change notification settings - Fork 7
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
[GEOS-11277] Have MapML TCRS instances work as actual coordinate reference systems. #357
Conversation
…erce systems. CRS factory.
…rence systems. Avoid axis order assumptions in MapML Projection class
…rence systems. Use MapML CRSs whenever possible
I will start looking at this in the morning. Thanks! |
Good start! I will add a few comments here, and if I can identify where in the code the comment might fit better, I'll insert them there too. I think the use of "MapML" as a CRS authority/prefix is good and appropriate. I thought about using "web" or "html", but I guess that would be premature, and perhaps grandiose as well. But, using "web" or "html" does / would highlight the fact that these TCRS were invented because of / for Web architecture: fetching and caching of resources is central to the stateless requirement of designing for the web and it's why tiles exist in the first place, and it is also imho why the geospatial community should consider adding the ability to record resolutions / grids inside a CRS definition: For the Web! It (the web) is not the only way to manage information, but it is central to our society. So, we should as a community make some concessions in the design of CRS for the Web specifically. I noticed that the format=text/mapml url generated by the WMS Formats MapML selection, the srs parameter does not use the MapML:WGS84 value that was used by the preview link, but instead uses the (hopefully) obsolete hard-coded EPSG:4326 value. I thought that might also apply to the I noticed that in the document obtained at this text/mapml url that all the <mapml- xmlns="http://www.w3.org/1999/xhtml">
<map-head>
<map-title>North America sample imagery</map-title>
<map-base href="http://localhost:8080/geoserver/wms" />
<map-meta charset="utf-8" />
<map-meta content="text/mapml;projection=WGS84" http-equiv="Content-Type" />
<map-link
href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3AWGS84&service=WMS&bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&format=text%2Fmapml&layers=Img_Sample&width=768&styles=raster&version=1.3.0&height=372"
rel="self style" title="raster" />
<map-link
href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3AOSMTILE&service=WMS&bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&format=text%2Fmapml&layers=Img_Sample&width=768&version=1.3.0&height=372"
rel="alternate" projection="OSMTILE" />
<map-link
href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3ACBMTILE&service=WMS&bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&format=text%2Fmapml&layers=Img_Sample&width=768&version=1.3.0&height=372"
rel="alternate" projection="CBMTILE" />
<map-link
href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3AAPSTILE&service=WMS&bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&format=text%2Fmapml&layers=Img_Sample&width=768&version=1.3.0&height=372"
rel="alternate" projection="APSTILE" />
</map-head>
<map-body>
<map-extent units="WGS84" checked="checked" hidden="hidden">
<map-input name="z" type="zoom" value="21" min="0" max="21" />
<map-input name="xmin" type="location" rel="map" position="top-left" axis="longitude"
units="gcrs" min="-130.85168" max="-62.0054" />
<map-input name="ymin" type="location" rel="map" position="bottom-left" axis="latitude"
units="gcrs" min="20.7052" max="54.1141" />
<map-input name="xmax" type="location" rel="map" position="top-right" axis="longitude"
units="gcrs" min="-130.85168" max="-62.0054" />
<map-input name="ymax" type="location" rel="map" position="top-left" axis="latitude"
units="gcrs" min="20.7052" max="54.1141" />
<map-input name="w" type="width" min="1" max="10000" />
<map-input name="h" type="height" min="1" max="10000" />
<map-link
tref="http://localhost:8080/geoserver/nurc/wms?request=GetMap&crs=MapML:WGS84&service=WMS&bbox={xmin},{ymin},{xmax},{ymax}&layers=Img_Sample&format=image/png&width={w}&styles=&language=en&version=1.3.0&transparent=true&height={h}"
rel="image" />
<map-input name="i" type="location" axis="i" units="map" />
<map-input name="j" type="location" axis="j" units="map" />
<map-link
tref="http://localhost:8080/geoserver/nurc/wms?request=GetFeatureInfo&query_layers=Img_Sample&crs=MapML:WGS84&bbox={xmin},{ymin},{xmax},{ymax}&language=en&version=1.3.0&transparent=true&service=WMS&layers=Img_Sample&width={w}&x={i}&feature_count=50&y={j}&styles=&info_format=text/mapml&height={h}"
rel="query" />
</map-extent>
</map-body>
</mapml->```
I wonder if the WMTS Capabilities should use the "MapML:CBMTILE" etc. values for the `<ows:SupportedCRS>` value? It would be consistent with the other capabilities documents, which look good. I can try to update the grid files to see what breaks... |
I was looking at the problem of ensuring that a preview for a layer is available despite that the layer's published CRS is not a MapML: value. I believe you've already sort of tackled this by extending the MapMLPreviewLink class, so perhaps that is the path to creating a WGS84 preview link where no MapML:tcrs is available? Btw, if we could map other planets using CRSs available to GeoServer that would be very cool. I wonder if the proj4js library is capable, though, it might be getting a little out of date tbd. And making it work with Leaflet is also a barrier. But it would be very cool. |
Following up on the "MapML" authority. Historically, OGC slipped a bit on that, for example, the "AUTO" codes for WMS, and the "CRS" authority, but at least those are baked in the standard that use them. So long story short, we can use whatever prefix you think it's best, as long as you or the MapML developers "own" such prefix. Thinking out loud, it could be W3C, if W3C authorized you such usage. |
Thanks for your thoughts. I think "MapML" works best for now, as we do "own" the namesoace. |
Following up on another bit, the WMS preview dropdown links:
That list, HTML wise, is just a list of format names, which has a javascript action taking the selected format, and appending it to a base WMS URL that is using the layer native SRS, opening the resulting link in a new window. That puts the MapML case in a tight spot, we cannot have its own unique link. At the same time, it would be odd to have each format build its own link for the sake of just one variant (it would be 20+ long links for the sake of customizing one, times 25 layers in the preview page, in other words, text for 500 new links in the preview page). The same happens for the WFS links by the way. An observation, MapML is generated in the native SRS without issues, but would that result work anywhere? Also, using the EPSG code rather than MapML native codes is not the worse issue per se IMHO, it's that using the native SRS, can result in an error, because MapML would not support it (the WMS link of "sf:roads" leads to an exception, for example). What to do... thinking out loud:
|
I think it's using the declared SRS. I tried setting the declared SRS to MapML:CBMTILE, and it seems to work but it can't be saved. If it could be saved, I guess it would generate the correct URL. That URL is quite valuable, because it's the actual MapML format that's returned, not just a preview document. In the previous version (with the old REST controller), we could only get access to MapML documents through content negotiation (the Content-Type: header). With that URL generator the user can do mashups quite easily, as I documented in the previous pull request. In generating the WFS url to a MapML document, the system generates several
Yes! I think that something similar could be done with the WMS link (if we could save the MapML: authority as declared SRS): the declared SRS, regardless of what authority it's from, could be appended. Inside the generated MapML document, the
Currently we have (yet) to document to the user to make the declared SRS one of EPSG:3978, EPSG:4326, EPSG:3857 or EPSG:5936 else they'll hit that exception. Ideally, if a non MapML: authority CRS is declared as declared SRS, the preview layer would generate a preview HTML document that referenced, say MapML:WGS84, while the In a future milestone, we're going to talk about generating responses in "custom projections" which might mean that instead of WGS84 above, the user could generate and register a "custom projection" definition associated with for example EPSG:32321347, including a grid and a proj4js file for it. The preview could check to see if there is a custom projection definition associated to the particular CRS code, and generate the preview in that projection. I guess such custom projections could be "MapML:something", so long as they don't conflict with other existing or predefined values.
This would be my preference, and I think it falls into the scenario that we've discussed as an extension of how the WFS urls work, where the document is generated (truth in advertising), but the client only loads the CRS that it understands. Later, if there's a custom projection CRS for the declared CRS, the preview gets generated with that preview (in a later milestone). Sorry for the long reply. |
Bounds for alternate projections are now in the target CRS, taking into account the area of validity of the target CRS when possible (e.g., cutting to -85/85 degrees latitude when going towards 3857). If that does not work for any reason, or the area of the data is just outside of the area of validity of the alternate projection, then that link will be skipped. Trying to get the MapML CRS stay in the configuration when entered manually. |
Ok, you can try again, this time the MapML CRSs should be working as a layer own CRS, and the preview links should work fine. If it's working fine and there's not anything else, I'll update the docs. |
I can select the MapML: CRSs and save them, but when I go back and look at the layer the MapML: CRS has gone. I see a console log message like this: 31 Jan 14:19:47 INFO [geoserver.gwc] - Saving GeoSeverTileLayer nurc:Img_Sample But it doesn't stick. The dropdown list of preview formats is unchanged. Sorry maybe I'm missing something. I see that the WFS GetFeature output format has the correct SRSNAME parameters, thank you. |
The thing that I was missing is that it does save the value of the EPSG: CRS associated to the MapML: CRS, and it does use that value if you calculate the bounds using the "Compute the bounds from the data" link. I can also see that the bounding boxes on the alternate links in the text/mapml response are correctly transformed. |
Dang I just realized that you've generated the preview link in the MapML:WGS84 if the saved declared CRS isn't understood, so that's a good step forward, I think, thanks! Sorry, for the multiple comments |
So the only thing that isn't ideal is that the WMS Formats dropdown still generates the service exception when the declared SRS is not known to the MapML: authority. I guess it would be a lot of work to fix that, but I'll drop this annotated example of what could be done and maybe it can go on a backlog. FWIW this is how the WFS link from the same dropdown works, I think. <mapml- xmlns="http://www.w3.org/1999/xhtml">
<map-head>
<map-title>Spearfish bug locations</map-title>
<map-base href="http://localhost:8080/geoserver/wms" />
<map-meta charset="utf-8" />
<map-meta name="projection" content="EPSG:26713"></map-meta><!-- client can use this to tell if it is capable of rendering this document. If not, it looks through the rel=alternate projection=... links below for one it recognizes -->
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=EPSG:26713&service=WMS&bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&format=text%2Fmapml&layers=bugsites&width=768&styles=burg&version=1.3.0&height=330"
rel="style" title="burg" />
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=EPSG:26713&service=WMS&bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&format=text%2Fmapml&layers=bugsites&width=768&styles=point&version=1.3.0&height=330"
rel="style" title="point" />
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=EPSG:26713&service=WMS&bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&format=text%2Fmapml&layers=bugsites&width=768&styles=capitals&version=1.3.0&height=330"
rel="self style" title="capitals" />
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3AOSMTILE&service=WMS&bbox=-180.0%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&format=text%2Fmapml&layers=bugsites&width=768&version=1.3.0&height=330"
rel="alternate" projection="OSMTILE" />
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3ACBMTILE&service=WMS&bbox=-8079209.971443829%2C-3626624.322362231%2C8281691.192343056%2C1.233598344760506E7&format=text%2Fmapml&layers=bugsites&width=768&version=1.3.0&height=330"
rel="alternate" projection="CBMTILE" />
<map-link
href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&request=GetMap&crs=MapML%3AAPSTILE&service=WMS&bbox=-1.06373184982574E7%2C-1.06373184982574E7%2C1.46373184982574E7%2C1.46373184982574E7&format=text%2Fmapml&layers=bugsites&width=768&version=1.3.0&height=330"
rel="alternate" projection="APSTILE" />
</map-head>
<map-body>
<!-- this coordinate system is not 'understood' by any client, but it's truth in advertising -->
<map-extent units="EPSG:26713" checked="checked" hidden="hidden">
<map-input name="z" type="zoom" value="21" min="0" max="21" /><!-- this can be omitted -->
<map-input name="xmin" type="location" rel="map" position="top-left" axis="easting"
units="pcrs" min="..." max="..." /><!-- min / max values according to the CRS area of use?? Or, omit altogether. -->
<map-input name="ymin" type="location" rel="map" position="bottom-left" axis="northing"
units="pcrs" min="..." max="..." /><!-- actual axis names from the CRS metadata-->
<map-input name="xmax" type="location" rel="map" position="top-right" axis="easting"
units="pcrs" min="..." max="..." />
<map-input name="ymax" type="location" rel="map" position="top-left" axis="northing"
units="pcrs" min="..." max="..." />
<map-input name="w" type="width" min="1" max="10000" />
<map-input name="h" type="height" min="1" max="10000" />
<map-link
tref="http://localhost:8080/geoserver/sf/wms?request=GetMap&crs=EPSG:26713&service=WMS&bbox={xmin},{ymin},{xmax},{ymax}&layers=bugsites&format=image/png&width={w}&styles=&language=en&version=1.3.0&transparent=true&height={h}"
rel="image" />
<map-input name="i" type="location" axis="i" units="map" />
<map-input name="j" type="location" axis="j" units="map" />
<map-link
tref="http://localhost:8080/geoserver/sf/wms?request=GetFeatureInfo&query_layers=bugsites&crs=EPSG:26713&bbox={xmin},{ymin},{xmax},{ymax}&language=en&version=1.3.0&transparent=true&service=WMS&layers=bugsites&width={w}&x={i}&feature_count=50&y={j}&styles=&info_format=text/mapml&height={h}"
rel="query" />
</map-extent>
</map-body>
</mapml-> Thank you for all your good work. Sorry it took me a minute to understand what had been done! |
Tested the SRS not sticking in the configuration, but I cannot reproduce it: setMapMLAuthority.mp4If I had to guess why there is a difference... I'm wondering if you're taking just the MapML module from this branch, or the entire GeoServer. For MapML authority to stick, I had to make a change in gs-main. Before the change, GeoServer would have looked into the possible identifiers for a given CRS, and would have preferred an EPSG one, if it was available: given the MapML ones are just aliases to existing EPSG codes (same structure), it would have always found an equivalent CRS under the EPSG authority. I changed it to try and prefer the first identifier found instead, even if not from EPSG. But for this to work, you need to use a full GeoServer built from this branch, or at least, pick and replace the gs-main jar. Also, once I set the MapML code, both the main preview link and the in the dropdown are using the MapML authority, e.g.:
Finally, yes, you're indeed right that it will fall back on WGS84 when the native CRS is not a match for a MapML supported TCRS code. |
I have checked about fixing the output for the case where the CRS is not supported... looks indeed quite a bit of work. The assumption that a valid TCRS is provided appears to be endemic in the code, and does not affect only the MapML generation, but also the client HTML code itself ( Do you have an example of what a valid HTML document for that situation would be? |
A viewer could be coded to use WGS84 as its projection value, and have the link to the non-MapML: authority encoded <mapml-viewer projection="WGS84" zoom="11" lat="40.37767410279042" lon="5.385360717746465" controls controlslist="geolocation">
<layer- label="Spearfish streams"
src="/geoserver/wms?&LAYERS=streams&BBOX= <bbox in projected coordinates for EPSG:26713> &HEIGHT=540&WIDTH=768&SRS=EPSG:26713
&STYLES=&FORMAT=text/mapml&format_options=mapml-wms-format:image/png&SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0" checked></layer->
</mapml-viewer> in which case the text/mapml document returned will have the Or it could leave off the
You're right! It's been a while since I built GeoServer as a whole. I will try it out. I should have noticed that. |
Seems to be a particular issue with OSMTILE. For example I can get a preview of the states shapefile in CBMTILE, but it won't do OSMTILE, it goes back to WGS84. |
Found out why the OSMTILE was not working in the preview link, a couple of "urn" CRS syntaxes managed to escape when I cleaned them in the previous rounds. Now it should work. About the behavior regarding non-supported CRSs, I would work it out in steps:
|
I just realized that perhaps we are working too hard. If we steal a page from the KML output format, one can make a GetMap request in whatever CRS they desire... but the KML output format will only ever return data in WGS84, because that's what KML is designed for, and no client would understand a KML in projected coordinates systems anyways. Rather than trying to fill in a fake HTML/MapML document with alternate links, can't we simply recognize the CRS is not supported, and directly return WGS84, along with maybe a warning, as a comment or HTML element, that WGS84 was used because the original CRS in the request is not MapML compatible? |
Yes, that is essentially what is suggested above, except for the WGS84 link to the text/mapml document.
+1
I agree that we should put off a bit of this until the custom projections work, because we'll want to be able to preview a layer in a configured custom projection if possible, and that might involve changes / rework and if we can avoid that I'm all for it. My intentions are : we want to honour requests for valid CRS documents, even if we can't render them. We intend to make it so that we can render them in the future custom projections work.
Not sure what the shared projection db is, but we use proj4.js and proj4leaflet libraries so I'll have to look into if wkt is supported. There will undoubtedly be some bumps in the road. Recall that our definition of a "custom projection" includes zoom level resolutions, bounds, and grid origin, which would rule out WKT. |
Seeing a lot of problems in the logs with the latest commit. Might be worth going back a step. I recall fussing over those URN codes previously. |
Humm... ah... it's the LatLng class. In GeoServer, internally, CRSs are normally east/north oriented, and at most, a point should have a CRS attached allowing the projection machinery to decide about the axis order. Having something like LatLng, where there is an axis order assumption that is contrary to GeoServer own defaults, is causing these problems. I'll see about restoring URN and performing the match in the preview link in some other way, but long term, LatLng LatLngBounds should really go, they are at odds with how GeoServer works. |
I do NOT want to be the one holding the axis order smoking gun ;-) However, I copied that code from an older system, and I was not aware of the GeoServer machinery for managing envelopes and geometries.
+1 I searched and there are 168 case-insensitive occurrences of "LatLng" in java files in the module. What would be appropriate replacements for LatLng and LatLngBounds in GeoServer now? I can look into the job of refactoring... |
I have updated the preview link CRS matching so that it's not influenced by axis order, made the code throw WMS exceptions with code, locator and a clear message, and updated the docs. Are we good to go? Regarding Point/LatLng and Bounds/LatLongBounds, the code should be using the existing classes to represent the same information: Position2D and ReferencedEnvelope. They both are a location with a CRS on the side. There is no difference in GT/GS between projected and geographic, we have more options in terms of CRS, like geocentric, 3D, composite and so on, and support to transform across the various types. The MapML code ideally should be just using what GeoTools already provides. However, mind, that refactor would cause a lot of conflicts with ongoing work, so I'd recommend performing the refactor while the other activity is no longer in progress, ideally, after we have delivered milestone 2 tasks. |
I apologize I am at work today and I'm unable to build anything with mvn due to proxy ssl certificate problems with accessing remote artifacts. I will check when I get home this evening. I tried out the latest stuff late last night and saw some issues, so I will hunt those down tonight if I can.
OK it can wait. Would be good to do things in the GeoServer way; I will look into replacing Point/LatLng and Bounds/LatLngBounds with the Position2D and ReferenceEnvelope. |
I can't get layer groups to be able to not use MapML:WGS84 in their preview link. Also, the URL from the WMS formats dropdown, for layer groups always reverts back to the aliased EPSG: code, despite that the MapML: code was successfully saved, but at least the projection is correct. Layers seem to be behaving well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. Eventually I want to balance how the WMS and WFS links are handled; the exception message seems to single out MapML for not supporting the CRS, but in the future I want to produce the text/mapml
document in that exact CRS, the user having defined a "custom projection" for that CRS code, so no exception will be thrown, the text/mapml
document will be generated in that CRS per this comment.
Making TCRS play as first-class CRSs.
As anticipated, it's not possible to have TCRS extend CoordinateReferenceSystem, as that is just the root of an inheritance hierarchy, of which, right now, we'd need the two highlighted interfaces be implemented by different TCRS subclasses (and with the need to support them all, in case we make TCRS configurable):
The actual changes go in the direction of better integration at the protocol level instead:
MapML:WGS84
), by acting as aliases for EPSG codes (or codes from other authorities too, in case we want to go there, e.g., support MapML for planetary objects with CRSs from the IAU authority).In the process, I've also removed one assumption that is going to cause problems if the MapML CRSs become user configurable (e.g., to support the mandatory European CRSs for example): that geographic CRSs all use lat/lon order (which is not the case in general, at least inside GeoServer). Also removed the URN notation for CRSs, as nothing in GeoServer uses it internally, it's something used only for external representations.
I would have loved to have GWC gridsets also use the MapML SRS, e.g., jave the OSMTILE grid be based on "MapML:OSMTILE", but GWC still mandates the usage of numeric codes for SRS representation.
@prushforth can you have a look at the changes and test them with the new client?
Checklist
main
branch (backports managed later; ignore for branch specific issues).For core and extension modules:
[GEOS-XYZWV] Title of the Jira ticket
.