Maps4HTML / geoserver

Maps for HTML MapML Extension / plug-in development fork of GeoServer
https://docs.geoserver.org/latest/en/user/extensions/mapml/index.html
Other
4 stars 1 forks source link

In response to GetMap, GetFeatureInfo with the `format_options=mapmlfeatures:true` parameter, add ability to recursively 'de-layer' a layergroup into a text/mapml document composed of its composite layers as features and tiles #74

Open prushforth opened 7 months ago

prushforth commented 7 months ago

Background

A LayerGroup in GeoServer is composed of one or more Layer or LayerGroup objects, ordered from bottom to top of the rendering stack i.e. in painter's model order. Because a LayerGroup is a composition of layers, per the previous statement, it's possible that there are many levels of nesting within a LayerGroup's definition. Despite this nesting, at the end of processing a WMS GetMap or GetFeatureInfo for such a layer, it must be de-nested into a linear set of layers to be rendered, each one on top of all the previous layers, in the painter's model.

A MapML document that requests the above result as a bitmapped image doesn't have to concern itself with the recursive rendering of the component layers, it only has to render the bitmapped image. On the other hand, if the de-nested layers were rendered as ordered sets of \ vectors and \ elements, it would be possible to render that content on the \ client or in the MapML preview.

Currently in GeoServer, a GetMap for format=text/mapml can indeed support a request for one or more layer groups among the layers that are requested via the layers=layer1,layer2,layer3 parameter i.e. any one or all of layer1 , layer2 or layer3 can be a LayerGroup. When this occurs (that is, any multi-layer request where the global "Use Tiles" setting is set to use a single map-extent), GeoServer MapML extension "falls back" to processing the request via a GetMap-style client for images (\<map-link rel="image"...>). Processing a single-layer request in which the layer is a LayerGroup is a similar process to processing a multi-layer request in general. This issue, together with issues #73 and #72 will enable vector-based +/- tile MapML responses for a layer group or multi-layer GetMap / GetFeatureInfo requests, i.e. true "vector tiles" potentially containing data from more than a single layer. This issue focuses on LayerGroup processing.

Aside: The MapML language has a \ element that is like a "square feature", in which the network source of the tile image is pointed to by the src attribute, and the placement of the tile is specified by its row, col and zoom attributes. We need to use the \ element in this requirement to support the processing of non-vector-capable layers in GeoServer in the context of GetMap / GetFeature requests for layer groups that contain such layers.

The requirement outlined in this issue is to enable a request for a single LayerGroup to be serialized according to the passed mapmlusefeatures, mapmlusetiles, mapmlmultiextent token values for the format_options GeoServer WMS parameter, regardless of its inclusion of non-vector-capable layers.

The implementation of this requirement will make it possible to render the component layers of any LayerGroup as though it was a simple vector-capable GeoServer Layer, as MapML \ +/- \ elements for each of the nested layers, rendered as sets of adjacent elements, in painter's model order in the response document.

The first requirement would be to add a "Use Features" checkbox to the LayerGroup Publishing tab's MapML section, right below the currently implemented "Use Tiles" checkbox:

This interface:

image

should be updated to become this:

image

(just as that panel has for the Layer Publishing tab currently).

Building upon previous requirements

To summarize #73, the user interface checkbox settings are used to dictate the URLs used (with the associated mapmlusetiles,mapmlusefeatures,mapmlmultiextent format_options values) in the GeoServer preview, but they may be set (dynamically) at runtime by a client in the format_options value that is passed via the GetMap / GetFeatureInfo parameter. In other words, the user interface checkboxes affect the preview that is generated, but do not diminish or affect the client's ability to select a different option at runtime. Put another way, the geoserver user interface settings are ignored when processing requests dynamically, relying instead on the format_options vendor parameter.

In sum:

mapmlmultiextent tells GeoServer if individual layers referenced in the layers parameter list should be represented as individual elements, or if they may all be piled into a single (pair of) \GetMap and GetFeatureInfo URL template(s) (depending on the queryable nature of the layers).

mapmlusetiles tells the extension what the configuration of the \s in the \(s) should be: true means that the inputs should be created to support \ GetMap and GetFeatureInfo URL templates.

mapmlusefeatures tells GeoServer to generate a \ for which the \(s) is/are configured to make GetMap / GetFeatureInfo requests for feature data. When mapmlusetiles:true is also set, the generated \ will also contain the type="text/mapml" attribute, which tells the client to expect a "leaf-node" MapML document (i.e. a "leaf-node" document does not reference other text/mapml documents in a tree-like structure -- it is the deepest such node in the tree).

Statement of Requirement on LayerGroup processing

For this requirement on GeoServer LayerGroup processing, when a GetMap or GetFeatureInfo request is received that includes this layer group in which the format_options=mapmlfeatures:true (note it's mapmlfeatures:true here, not mapmlusefeatures:true) request parameter is found, GeoServer MapML extension should render the response "leaf-node" document as (painter's) ordered grouped-by-layer sets of \s and/or \ elements.

Below is an example of a MapML document generated in response to a traditional whole-map WMS GetMap request(for a layer group) like GetMap&format=text/mapml&format_options=mapmlusefeatures:true - note that the GetMap template below contains the mapmlfeatures:true format option, because the received request contained the mapml**use**features:true parameter value:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
    <map-head>
        <map-title>Layer Group ZZZ</map-title>
        <map-style>.bbox {display:none} .population-r1-s1{fill:#4DFF4D; fill-opacity:0.7}
            .population-r2-s1{fill:#FF4D4D; fill-opacity:0.7} .population-r3-s1{fill:#4D4DFF;
            fill-opacity:0.7} .population-r4-s1{stroke-opacity:1.0; stroke-dashoffset:0;
            stroke-width:0.2; stroke:#000000; stroke-linecap:butt}</map-style>
    </map-head>
        <map-extent units="CBMTILE" checked="checked" hidden="hidden">
            <map-input name="z" type="zoom" min="0" max="25" />
            <map-input name="xmin" type="location" rel="map" position="top-left" axis="easting" units="pcrs" min="-3385113" max="3204541" />
            <map-input name="ymin" type="location" rel="map" position="bottom-left" axis="northing" units="pcrs" min="-2857720" max="536137" />
            <map-input name="xmax" type="location" rel="map" position="top-right" axis="easting" units="pcrs" min="-3385114" max="3204541" />
            <map-input name="ymax" type="location" rel="map" position="top-left" axis="northing" units="pcrs" min="-2857720" max="536137" />
            <map-input name="w" type="width" min="1" max="4079" />
            <map-input name="h" type="height" min="1" max="4079" />
            <map-link
                tref="format_options=mapmlfeatures:true&request=GetMap&crs=MapML:CBMTILE&bbox={xmin},{ymin},{xmax},{ymax}&format=text/mapml&language=en&version=1.3.0&transparent=true&service=WMS&layers=layergroupZZZ&width={w}&styles=&height={h}"
                rel="features" />
        </map-extent>
    </map-body>
</mapml->

If a given layer encountered in the recursive expansion of the layergroup's set of layers can NOT be represented as \ data i.e. is backed by a raster data set, it should be represented as a set of one or more \ elements within the stack of serialized layer data, ordered by distance of the tile center point from the request envelope/bbox center point.

So long as the non-templated GetMap request used in the \<map-tile src="GetMap or GetTile> returns transparent imagery, it may still be useful mixed into the feature information as such, TBD by experimentation with actual data, and it will be up to the GeoServer admin to validate that their layer groups are useful as configured.

e.g. the tref URL template above, when variable references were resolved to a WMS GetMap URL, the response might look like the following text/mapml document:

<mapml- xmlns="...">
  <map-head>
   <map-title>Layer Group ZZZ Example of interleaved features and tiles</map-title>
  </map-head>
  <map-body>
    <map-feature>
      <map-featurecaption>A feature from Layer A</map-featurecaption>
      <map-geometry><map-point><map-coordinates>-72 43.5</map-coordinates></map-point></map-geometry>
    </map-feature>
   <!-- Layer B is imagery must be represented by the tiles that cover the bbox of the GetMap -->
    <map-tile row="12" col="14" zoom="3" src="tile-shaped non-templated GetMap resource URL"></map-tile>
    <map-tile row="12" col="13" zoom="3" src="tile-shaped non-templated GetMap resource URL"></map-tile>
    <map-tile row="13" col="14" zoom="3" src="tile-shaped non-templated GetMap resource URL"></map-tile>
    <map-tile row="13" col="13" zoom="3" src="tile-shaped non-templated GetMap resource URL"></map-tile>
   <map-feature>
      <map-featurecaption>A feature from Layer C</map-featurecaption>
      <map-geometry><map-linestring><map-coordinates>...</map-coordinates></map-linestring></map-geometry>
   </map-feature
  </map-body>
</mapml->

Similarly, a layer group may be requested as tiled data, via the mapmlusetiles:true format option. In this case the \ elements generated to represent requests for tiled data for the layer group are configured to either make "tile-shaped" WMS GetMap requests, or if the layer group has previously defined a tile cache and associated gridset, the \ will be configured to generate WMTS GetTile requests via the embedded \ element. This is possible today, although the configuration is not passed as a format_option until #73 is resolved.

Once #73 is working, it should now be possible, in response to a GetMap involving a layer group, to generate \s and associated child \\ which will generate requests for the layer group's content to be serialized as "tile shaped" text/mapml documents, with the appropriately clipped / spanned+styled and layer-ordered groups of \ elements to represent the layer group's constituent layers, with non-vector capable layers in the group represented by non-templated \ elements coded to the calculated zoom level (calculated based on the scale which is calculated from either the bbox of the GetMap, or the tile matrix level from the GetTile.

<mapml- xmlns="...">
  <map-head>
   <map-title>Layer Group ZZZ Example of interleaved features and tiles</map-title>
  </map-head>
  <map-body>
    <map-feature>
      <map-featurecaption>A feature from Layer A</map-featurecaption>
      <map-geometry><map-point><map-coordinates>-72 43.5</map-coordinates></map-point></map-geometry>
    </map-feature>
   <!-- Layer B is imagery must be represented by the tile that covers the bbox of the GetMap -->
    <map-tile row="13" col="13" zoom="3" src="tile-shaped non-templated GetMap resource URL"></map-tile>
   <map-feature>
      <map-featurecaption>A feature from Layer C</map-featurecaption>
      <map-geometry><map-linestring><map-coordinates>...</map-coordinates></map-linestring></map-geometry>
   </map-feature
  </map-body>
</mapml->
aaime commented 5 months ago

When mixing rasters and vectors in the same output, we need a TiledCRS to locate where the tiles are. If we don't have a TiledCRS, then we need to skip the imagery layer. If we have a TiledCRS and the request is not tiled anyways, we'll have to generate enough map-tiles references to cover the entire area.

aaime commented 4 months ago

It's going to be quite likely to have a mapmlfeatures and mapmlusefeatures be used by mistake in each other place. How about a mapmlbody option with two possible values: layers and flat instead?

prushforth commented 4 months ago

How about a mapmlbody option with two possible values: layers and flat instead?

mapmlfeatures already exists, so I was / am hesitant about changing anything in how it works. Are you suggesting that mapmlbody would have the same meaning as mapmlusefeatures, OR would it replace both mapmlusefeatures and mapmlfeatures , or something else? I'm unsure how that would work, need to think about it more. Currently, mapmlfeatures only appears in templated URLs generated in the tref attribute. mapmlusefeatures is a flag controlling the 'inner node' document. If mapmlbody does something related to mapmlusefeatures, I will have to re-write the table in the first details over here