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

[GEOS-11277] Have MapML TCRS instances work as actual coordinate reference systems. #357

Closed
wants to merge 11 commits into from

Conversation

aaime
Copy link
Member

@aaime aaime commented Jan 25, 2024

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):

image

The actual changes go in the direction of better integration at the protocol level instead:

  • Make TCRS names usable as CRS references, prefixed with the MapML authority (e.g, 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).
  • Have them show up in the capabilities documents and be usable in requests (WMS/WFS).
  • Use them as primary CRSs in preview links and backlinks to GeoServer, fallback on WGS84 if no supported CRS is found (this solves the issue of some layers not displaying)
  • Use the actual EPSG code for any output that might be consumed by external tools, e.g., GML, shapefile and the like.

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

For core and extension modules:

  • New unit tests have been added covering the changes.
  • Documentation has been updated (if change is visible to end users).
  • The REST API docs have been updated (when changing configuration objects or the REST controllers).
  • There is an issue in the GeoServer Jira (except for changes that do not affect administrators or end users in any way).
  • Commit message(s) must be in the form [GEOS-XYZWV] Title of the Jira ticket.
  • Bug fixes and small new features are presented as a single commit.
  • Each commit has a single objective (if there are multiple commits, each has a separate JIRA ticket describing its goal).

…rence systems. Avoid axis order assumptions in MapML Projection class
…rence systems. Use MapML CRSs whenever possible
@prushforth
Copy link
Collaborator

can you have a look at the changes and test them with the new client?

I will start looking at this in the morning. Thanks!

@prushforth
Copy link
Collaborator

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 <layer- src="..."></layer-> url, but it doesn't, that ones ok.

image

I noticed that in the document obtained at this text/mapml url that all the <map-link rel="alternate" href="..."></map-link> href values have a bbox that is in geographic coordinates, despite that the srs parameter identifies a different CRS (e.g. MapML:OSMTILE). This doesn't affect the preview, but I believe the response to a request for a particular bbox should use the bbox provided, so the preview should generate a bbox that is appropriate to the requested layers (the union of all the bboxes of the requested layers, with the map centred on the lat/lon/zoom of the largest possible scale that "fits" the bbox at some heuristically generated screen size).

<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&amp;request=GetMap&amp;crs=MapML%3AWGS84&amp;service=WMS&amp;bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&amp;format=text%2Fmapml&amp;layers=Img_Sample&amp;width=768&amp;styles=raster&amp;version=1.3.0&amp;height=372"
            rel="self style" title="raster" />
        <map-link
            href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3AOSMTILE&amp;service=WMS&amp;bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&amp;format=text%2Fmapml&amp;layers=Img_Sample&amp;width=768&amp;version=1.3.0&amp;height=372"
            rel="alternate" projection="OSMTILE" />
        <map-link
            href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3ACBMTILE&amp;service=WMS&amp;bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&amp;format=text%2Fmapml&amp;layers=Img_Sample&amp;width=768&amp;version=1.3.0&amp;height=372"
            rel="alternate" projection="CBMTILE" />
        <map-link
            href="http://localhost:8080/geoserver/nurc/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3AAPSTILE&amp;service=WMS&amp;bbox=-130.85168%2C20.7052%2C-62.0054%2C54.1141&amp;format=text%2Fmapml&amp;layers=Img_Sample&amp;width=768&amp;version=1.3.0&amp;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&amp;crs=MapML:WGS84&amp;service=WMS&amp;bbox={xmin},{ymin},{xmax},{ymax}&amp;layers=Img_Sample&amp;format=image/png&amp;width={w}&amp;styles=&amp;language=en&amp;version=1.3.0&amp;transparent=true&amp;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&amp;query_layers=Img_Sample&amp;crs=MapML:WGS84&amp;bbox={xmin},{ymin},{xmax},{ymax}&amp;language=en&amp;version=1.3.0&amp;transparent=true&amp;service=WMS&amp;layers=Img_Sample&amp;width={w}&amp;x={i}&amp;feature_count=50&amp;y={j}&amp;styles=&amp;info_format=text/mapml&amp;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...

@prushforth
Copy link
Collaborator

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.

@aaime
Copy link
Member Author

aaime commented Jan 29, 2024

Following up on the "MapML" authority.
Authorities are a namespace for CRSs, typical rules for namespaces are that in order to use one, one must own it.
So for example EPSG is the name of the owner of the same named database, and so is IAU for the astronomical CRSs.
OGC also defined their own codes using their own name as the authority, e.g., "http://www.opengis.net/def/crs/OGC/1.3/CRS84"

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.
Using "web" or "html" may be problematic if anyone else can come up and claim the name namespace (and be just fine instead, if nobody else can).

@prushforth
Copy link
Collaborator

Thanks for your thoughts. I think "MapML" works best for now, as we do "own" the namesoace.

@aaime
Copy link
Member Author

aaime commented Jan 30, 2024

Following up on another bit, the WMS preview dropdown links:

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.

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:

  • Keeping it as is, MapML is not playing 100% correctly with the WMS rules anyways (if an SRS is in the capabilities document, a format must support it... if one desires to use MapML, the declared SRS in layers should be compatible). A documentation issue.
  • Have a way to filter out MapML from the drop-down list, and leave it only as a main link. This way a user cannot easily put toghether a non-working link .
  • A More complicated option (above the initial estimates for the TCRS work), would be to have a way for specific formats to come up with their exception to the links.... maybe using HTML 5 data attributes, added to the options tag, to store the custom link. And then have an extension point in GeoServer, similar to the existing one used by MapML, to create a custom link for just that format. I'll try to socialize this idea tonight at the GeoServer PSC meeting, see what acceptance it gets.

@prushforth
Copy link
Collaborator

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

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 <map-link rel=alternate projection="..."> links for the different defined MapML TCRS, even if the document is requested and generated with srsName=EPSG:32321347 which is not defined in MapML. The output document coordinates are encoded in EPSG:32321347, even if the client doesn't understand the meaning of the code, at least there's truth in advertising, as well as the "Plan B" of loading one of the alternate links. This is an example of a WFS link that the client doesn't understand the CRS, but it can still do something useful (render) with the document, because of the alternate links.

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?

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 <map-head> element could contain a <map-meta name="projection" content="EPSG:32321347"></map-meta>, as the WFS response currently does, as well as the <map-link rel=alternate projection="MapML:..."> links that it can. Because no other CRS authority has tiles in scope, the "Use Tiles" setting for the layer would have to be ignored (in this case): such a <map-extent> would always have to contain a <map-link rel="image"...>. The <map-input> elements would be generated in the normal fashion, just using the axes that are associated to the CRS.

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).

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 <layer- src="..."> URL would link to the MapML document generated in the declared SRS, whatever it might be, but with the "Plan B" alternate links embedded.

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.

Keeping it as is, MapML is not playing 100% correctly with the WMS rules anyways (if an SRS is in the capabilities document, a format must support it... if one desires to use MapML, the declared SRS in layers should be compatible). A documentation issue.

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.

@aaime
Copy link
Member Author

aaime commented Jan 31, 2024

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.

@aaime
Copy link
Member Author

aaime commented Jan 31, 2024

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.

@prushforth
Copy link
Collaborator

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.

image

I see a console log message like this:

31 Jan 14:19:47 INFO [geoserver.gwc] - Saving GeoSeverTileLayer nurc:Img_Sample
31 Jan 14:19:50 CONFIG [platform.resource] - Notifying ENTRY_MODIFY change on /home/prushforth/geoserver-data/2.22/gwc-layers. Created: 0, removed: 0, modified: 1

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.

@prushforth
Copy link
Collaborator

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.

But it doesn't stick. The dropdown list of preview formats is unchanged. Sorry maybe I'm missing something.

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.

@prushforth
Copy link
Collaborator

the preview links should work fine. If it's working fine and there's not anything else, I'll update the docs.

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

@prushforth
Copy link
Collaborator

prushforth commented Jan 31, 2024

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&amp;request=GetMap&amp;crs=EPSG:26713&amp;service=WMS&amp;bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;styles=burg&amp;version=1.3.0&amp;height=330"
            rel="style" title="burg" />
        <map-link
            href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=EPSG:26713&amp;service=WMS&amp;bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;styles=point&amp;version=1.3.0&amp;height=330"
            rel="style" title="point" />
        <map-link
            href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=EPSG:26713&amp;service=WMS&amp;bbox=590223.4382724703%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;styles=capitals&amp;version=1.3.0&amp;height=330"
            rel="self style" title="capitals" />
        <map-link
            href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3AOSMTILE&amp;service=WMS&amp;bbox=-180.0%2C4914107.882513998%2C608462.4604629107%2C4920523.89081033&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;version=1.3.0&amp;height=330"
            rel="alternate" projection="OSMTILE" />
        <map-link
            href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3ACBMTILE&amp;service=WMS&amp;bbox=-8079209.971443829%2C-3626624.322362231%2C8281691.192343056%2C1.233598344760506E7&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;version=1.3.0&amp;height=330"
            rel="alternate" projection="CBMTILE" />
        <map-link
            href="http://localhost:8080/geoserver/sf/wms?format_options=mapml-wms-format%3Aimage%2Fpng&amp;request=GetMap&amp;crs=MapML%3AAPSTILE&amp;service=WMS&amp;bbox=-1.06373184982574E7%2C-1.06373184982574E7%2C1.46373184982574E7%2C1.46373184982574E7&amp;format=text%2Fmapml&amp;layers=bugsites&amp;width=768&amp;version=1.3.0&amp;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&amp;crs=EPSG:26713&amp;service=WMS&amp;bbox={xmin},{ymin},{xmax},{ymax}&amp;layers=bugsites&amp;format=image/png&amp;width={w}&amp;styles=&amp;language=en&amp;version=1.3.0&amp;transparent=true&amp;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&amp;query_layers=bugsites&amp;crs=EPSG:26713&amp;bbox={xmin},{ymin},{xmax},{ymax}&amp;language=en&amp;version=1.3.0&amp;transparent=true&amp;service=WMS&amp;layers=bugsites&amp;width={w}&amp;x={i}&amp;feature_count=50&amp;y={j}&amp;styles=&amp;info_format=text/mapml&amp;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!

@prushforth
Copy link
Collaborator

I find that the preview link really wants to go back to WGS84 often, even if you've set the declared SRS to MapML:OSMTILE or other.

example sf:streams:

image

and the preview URL:

image

@aaime
Copy link
Member Author

aaime commented Feb 1, 2024

Tested the SRS not sticking in the configuration, but I cannot reproduce it:

setMapMLAuthority.mp4

If 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.:

http://localhost:8080/geoserver/topp/wms?service=WMS&version=1.1.0&request=GetMap&layers=topp%3Astates&bbox=-1.3885038382960921E7%2C2870337.130793682%2C-7455049.489182421%2C6338174.0557576185&width=768&height=414&srs=MAPML%3AOSMTILE&styles=&format=application/openlayers

http://localhost:8080/geoserver/topp/wms?service=WMS&version=1.1.0&request=GetMap&layers=topp%3Astates&bbox=-1.3885038382960921E7%2C2870337.130793682%2C-7455049.489182421%2C6338174.0557576185&width=768&height=414&srs=MAPML%3AOSMTILE&styles=&format=text%2Fmapml

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.

@aaime
Copy link
Member Author

aaime commented Feb 1, 2024

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 (MapMLDocumentBuilder#getMapMLHTMLDocument).

Do you have an example of what a valid HTML document for that situation would be?

@prushforth
Copy link
Collaborator

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 document, like so:

  <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 <map-link rel="alternate" projection="WGS84" ...> link that the client will select to match the <mapml-viewer>'s projection.

Or it could leave off the <mapml-viewwer projection="..."> attribute in which case it defaults to OSMTILE and the client would select the OSMTILE link, but there might be situations at the poles that could not be covered by our OSMTILE friend.

I'm wondering if you're taking just the MapML module from this branch, or the entire GeoServer.

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.

@prushforth
Copy link
Collaborator

I confirm that I'm able to save the "MapML:" CRSs, for example for spearfish streams below:

image

However the preview link still wants to use WGS84:

image

The dropdown does indeed use the saved CRS:

image

@prushforth
Copy link
Collaborator

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.

@aaime
Copy link
Member Author

aaime commented Feb 1, 2024

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:

  1. Right now, document the existing behavior and improve the error messages
  2. Collect all the requirements needed to have a working client with non-supported CRS in a new ticket, to be worked later as time allows. I also have the impression that allowing customization of CRSs will add to the pile of changes needed here... interoperability requires a shared projection database, and the client would not know how to handle one that's freshly minted (and no, we cannot create a proj string, they are not supported by GeoTools/GeoServer, but hopefully a WKT version 1 will do as well).

@aaime
Copy link
Member Author

aaime commented Feb 1, 2024

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?

@prushforth
Copy link
Collaborator

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.

About the behavior regarding non-supported CRSs, I would work it out in steps:

Right now, document the existing behavior and improve the error messages

+1

Collect all the requirements needed to have a working client with non-supported CRS in a new ticket, to be worked later as time allows. I also have the impression that allowing customization of CRSs will add to the pile of changes needed here...

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.

interoperability requires a shared projection database, and the client would not know how to handle one that's freshly minted (and no, we cannot create a proj string, they are not supported by GeoTools/GeoServer, but hopefully a WKT version 1 will do as well).

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.

@prushforth
Copy link
Collaborator

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.

@aaime
Copy link
Member Author

aaime commented Feb 1, 2024

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.
Going back to the urn notation will solve those logs, but will also go back to not being able to match OSMTILE TiledCRS object, because as defined, it's working with lat/lon base, while the TiledCRSFactory must work with the (expected) lon/lat order... testing for equality then fails.

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.

@prushforth
Copy link
Collaborator

Having something like LatLng, where there is an axis order assumption that is contrary to GeoServer own defaults, is causing these problems.

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.

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.

+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...

@aaime
Copy link
Member Author

aaime commented Feb 2, 2024

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.

@prushforth
Copy link
Collaborator

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?

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.

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.

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.

@prushforth
Copy link
Collaborator

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.

@aaime
Copy link
Member Author

aaime commented Feb 5, 2024

Confirmed the issue with layer groups, should be fixed now (I've set OSMTILE in spearfish, which would otherwise use an unsupported CRS):

image

Copy link
Collaborator

@prushforth prushforth left a 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.

@aaime aaime closed this Feb 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants