diff --git a/doc/en/user/source/extensions/mapml/images/mapml_tcrs_menu.png b/doc/en/user/source/extensions/mapml/images/mapml_tcrs_menu.png new file mode 100644 index 00000000000..2e0fdaf49b2 Binary files /dev/null and b/doc/en/user/source/extensions/mapml/images/mapml_tcrs_menu.png differ diff --git a/doc/en/user/source/extensions/mapml/images/mapml_tcrs_selector.png b/doc/en/user/source/extensions/mapml/images/mapml_tcrs_selector.png new file mode 100644 index 00000000000..5dc71756f83 Binary files /dev/null and b/doc/en/user/source/extensions/mapml/images/mapml_tcrs_selector.png differ diff --git a/doc/en/user/source/extensions/mapml/installation.rst b/doc/en/user/source/extensions/mapml/installation.rst index 1272d9405ac..c4b4fa45ba3 100644 --- a/doc/en/user/source/extensions/mapml/installation.rst +++ b/doc/en/user/source/extensions/mapml/installation.rst @@ -47,6 +47,33 @@ If the ``Represent multi-layer requests as multiple elements`` is checked (and t .. figure:: images/mapml_wms_multi_extent.png +TiledCRS +-------- +MapML supports 4 built-in TiledCRS: + +- MapML:WGS84 (or EPSG:4326) +- MapML:OSMTILE (or EPSG:3857) +- MapML:CBMTILE (or EPSG:3978) +- MapML:APSTILE (or EPSG:5936) + +In addition, is it possible to configure custom TiledCRS based on the available WMTS GridSets. +A new MapML TCRS Settings menu is available in the GeoServer UI on the Settings section: + +.. figure:: images/mapml_tcrs_menu.png + + +It provides a selector containing available GridSets. Administrator can select GridSets from the left list that will be converted to TiledCRSs. + + +.. figure:: images/mapml_tcrs_selector.png + + +Notes: + +- Gridsets containing ":" character in the name won't be listed +- Gridsets with not-numeric levels or without a common prefix won't be listed + + Styles ------ @@ -262,7 +289,7 @@ MapML resources will be available for any published WMS layers by making a GetMa **SRS/CRS** -Note that the WMS SRS or CRS must be one of the projections supported by MapML: +Note that the WMS SRS or CRS must be one of the built-in projections supported by MapML or one of the TCRS configured through the dedicated section. Built-in MapML CRS are: - MapML:WGS84 (or EPSG:4326) - MapML:OSMTILE (or EPSG:3857) diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLDocumentBuilder.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLDocumentBuilder.java index 51c40cd7f0a..684c96dc3b9 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLDocumentBuilder.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLDocumentBuilder.java @@ -13,7 +13,6 @@ import static org.geoserver.mapml.MapMLConstants.MAPML_USE_FEATURES; import static org.geoserver.mapml.MapMLConstants.MAPML_USE_REMOTE; import static org.geoserver.mapml.MapMLConstants.MAPML_USE_TILES; -import static org.geoserver.mapml.MapMLHTMLOutput.PREVIEW_TCRS_MAP; import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_PREVIEW_HEAD_FTL; import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_XML_HEAD_FTL; import static org.geoserver.wms.capabilities.DimensionHelper.getDataType; @@ -66,6 +65,7 @@ import org.geoserver.gwc.layer.GeoServerTileLayer; import org.geoserver.mapml.tcrs.Bounds; import org.geoserver.mapml.tcrs.TiledCRS; +import org.geoserver.mapml.tcrs.WrappingProjType; import org.geoserver.mapml.template.MapMLMapTemplate; import org.geoserver.mapml.xml.AxisType; import org.geoserver.mapml.xml.Base; @@ -157,7 +157,7 @@ public class MapMLDocumentBuilder { private String imageFormat = DEFAULT_MIME_TYPE; private String baseUrl; private String baseUrlPattern; - private ProjType projType; + private WrappingProjType projType; private MetadataMap layerMeta; private int height; private int width; @@ -408,7 +408,7 @@ private MapMLLayerMetadata layersToOneMapMLLayerMetadata(List layers) mapMLLayerMetadata.setTimeEnabled(false); mapMLLayerMetadata.setElevationEnabled(false); mapMLLayerMetadata.setTransparent(transparent.orElse(false)); - ProjType projType = parseProjType(); + WrappingProjType projType = parseProjType(); mapMLLayerMetadata.setBbbox(layersToBBBox(layers, projType)); mapMLLayerMetadata.setQueryable(layersToQueryable(layers)); mapMLLayerMetadata.setLayerLabel(layersToLabel(layers)); @@ -422,9 +422,9 @@ private MapMLLayerMetadata layersToOneMapMLLayerMetadata(List layers) * Parses the projection into a ProjType, or throws a proper service exception indicating the * unsupported CRS */ - private ProjType parseProjType() { + private WrappingProjType parseProjType() { try { - return ProjType.fromValue(proj.toUpperCase()); + return new WrappingProjType(proj.toUpperCase()); } catch (IllegalArgumentException | FactoryException iae) { // figure out the parameter name (version dependent) and the actual original // string value for the srs/crs parameter @@ -488,10 +488,9 @@ private String layersToLabel(List layers) { * @param projType ProjType object * @return ReferencedEnvelope object */ - private ReferencedEnvelope layersToBBBox(List layers, ProjType projType) { - + private ReferencedEnvelope layersToBBBox(List layers, WrappingProjType projType) { ReferencedEnvelope bbbox; - bbbox = new ReferencedEnvelope(PREVIEW_TCRS_MAP.get(projType.value()).getCRS()); + bbbox = new ReferencedEnvelope(projType.getCRS()); for (int i = 0; i < layers.size(); i++) { RawLayer layer = layers.get(i); try { @@ -502,26 +501,20 @@ private ReferencedEnvelope layersToBBBox(List layers, ProjType projTyp .getResource() .boundingBox(); if (i == 0) { - bbbox = - layerBbbox.transform( - PREVIEW_TCRS_MAP.get(projType.value()).getCRS(), true); + bbbox = layerBbbox.transform(projType.getCRS(), true); } else { - bbbox.expandToInclude( - layerBbbox.transform( - PREVIEW_TCRS_MAP.get(projType.value()).getCRS(), true)); + bbbox.expandToInclude(layerBbbox.transform(projType.getCRS(), true)); } } catch (Exception e) { // get the default max/min of the pcrs from the TCRS - Bounds defaultBounds = PREVIEW_TCRS_MAP.get(projType.value()).getBounds(); + Bounds defaultBounds = projType.getTiledCRS().getBounds(); double x1, x2, y1, y2; x1 = defaultBounds.getMin().x; x2 = defaultBounds.getMax().x; y1 = defaultBounds.getMin().y; y2 = defaultBounds.getMax().y; // use the bounds of the TCRS as the default bounds for this layer - bbbox = - new ReferencedEnvelope( - x1, x2, y1, y2, PREVIEW_TCRS_MAP.get(projType.value()).getCRS()); + bbbox = new ReferencedEnvelope(x1, x2, y1, y2, projType.getCRS()); } } @@ -595,7 +588,7 @@ private MapMLLayerMetadata layerToMapMLLayerMetadata(RawLayer layer, String styl .orElse(DEFAULT_MIME_TYPE) .toString(); } - ProjType projType = parseProjType(); + WrappingProjType projType = parseProjType(); cqlFilter = cql != null ? cql : ""; tileLayerExists = gwc.hasTileLayer(isLayerGroup ? layerGroupInfo : layerInfo) @@ -843,15 +836,18 @@ private HeadContent prepareHead() throws IOException { selfStyleLink.setHref(selfStyleURL); links.add(selfStyleLink); // alternate projection links + ProjType builtInProj = projType.unwrap(); for (ProjType pt : ProjType.values()) { // skip the current proj - if (pt.equals(projType)) continue; + + if (pt.equals(builtInProj)) continue; try { Link projectionLink = new Link(); projectionLink.setRel(RelType.ALTERNATE); - projectionLink.setProjection(pt); + projectionLink.setProjection(pt.value()); // reproject the bounds - ReferencedEnvelope reprojectedBounds = reproject(projectedBox, pt); + ReferencedEnvelope reprojectedBounds = + reproject(projectedBox, new WrappingProjType(pt)); // Copy the base params to create one for self style Map projParams = new HashMap<>(wmsParams); projParams.put("crs", pt.getCRSCode()); @@ -972,9 +968,9 @@ private String buildStyles() throws IOException { * @throws FactoryException In the event of a factory error. * @throws TransformException In the event of a transform error. */ - private ReferencedEnvelope reproject(ReferencedEnvelope bounds, ProjType pt) + private ReferencedEnvelope reproject(ReferencedEnvelope bounds, WrappingProjType pt) throws FactoryException, TransformException { - CoordinateReferenceSystem targetCRS = PREVIEW_TCRS_MAP.get(pt.value()).getCRS(); + CoordinateReferenceSystem targetCRS = pt.getCRS(); // leverage the rendering ProjectionHandlers to build a set of envelopes // inside the valid area of the target CRS, and fuse them ProjectionHandler ph = ProjectionHandlerFinder.getHandler(bounds, targetCRS, true); @@ -1019,7 +1015,8 @@ private List prepareExtents() throws IOException { List extents = new ArrayList<>(); for (MapMLLayerMetadata mapMLLayerMetadata : mapMLLayerMetadataList) { Extent extent = new Extent(); - extent.setUnits(projType); + TiledCRS tiledCRS = projType.getTiledCRS(); + extent.setUnits(tiledCRS.getName()); extentList = extent.getInputOrDatalistOrLink(); // zoom @@ -1036,7 +1033,6 @@ private List prepareExtents() throws IOException { } Input extentZoomInput = new Input(); - TiledCRS tiledCRS = PREVIEW_TCRS_MAP.get(projType.value()); extentZoomInput.setName("z"); extentZoomInput.setType(InputType.ZOOM); // passing in max sld denominator to get min zoom @@ -1046,7 +1042,7 @@ private List prepareExtents() throws IOException { tiledCRS.getMinZoomForDenominator( scaleDenominators.getMaxValue().intValue())) : "0"); - int mxz = PREVIEW_TCRS_MAP.get(projType.value()).getScales().length - 1; + int mxz = tiledCRS.getScales().length - 1; // passing in min sld denominator to get max zoom String maxZoom = scaleDenominators != null @@ -1362,7 +1358,7 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) // of WGS84 is a cartesian cs per the table on this page: // https://docs.geotools.org/stable/javadocs/org/opengis/referencing/cs/package-summary.html#AxisNames // input.setAxis(previewTcrsMap.get(projType.value()).getCRS(UnitType.PCRS).getAxisByDirection(AxisDirection.DISPLAY_RIGHT)); - bbbox = new ReferencedEnvelope(PREVIEW_TCRS_MAP.get(projType.value()).getCRS()); + bbbox = new ReferencedEnvelope(projType.getCRS()); LayerInfo layerInfo = mapMLLayerMetadata.getLayerInfo(); try { @@ -1370,12 +1366,12 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) mapMLLayerMetadata.isLayerGroup() ? mapMLLayerMetadata.getLayerGroupInfo().getBounds() : layerInfo.getResource().boundingBox(); - bbbox = bbbox.transform(PREVIEW_TCRS_MAP.get(projType.value()).getCRS(), true); + bbbox = bbbox.transform(projType.getCRS(), true); } catch (Exception e) { // sometimes, when the geographicBox is right to 90N or 90S, in epsg:3857, // the transform method will throw. In that case, use the // bounds of the TCRS to define the geographicBox for the layer - TiledCRS t = PREVIEW_TCRS_MAP.get(projType.value()); + TiledCRS t = projType.getTiledCRS(); double x1 = t.getBounds().getMax().x; double y1 = t.getBounds().getMax().y; double x2 = t.getBounds().getMin().x; @@ -1392,7 +1388,7 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) input.setUnits(UnitType.TILEMATRIX); input.setPosition(PositionType.TOP_LEFT); input.setRel(InputRelType.TILE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LONGITUDE : AxisType.EASTING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LONGITUDE : AxisType.EASTING); input.setMin(Double.toString(bbbox.getMinX())); input.setMax(Double.toString(bbbox.getMaxX())); extentList.add(input); @@ -1404,7 +1400,7 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) input.setUnits(UnitType.TILEMATRIX); input.setPosition(PositionType.BOTTOM_LEFT); input.setRel(InputRelType.TILE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LATITUDE : AxisType.NORTHING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LATITUDE : AxisType.NORTHING); input.setMin(Double.toString(bbbox.getMinY())); input.setMax(Double.toString(bbbox.getMaxY())); extentList.add(input); @@ -1416,7 +1412,7 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) input.setUnits(UnitType.TILEMATRIX); input.setPosition(PositionType.TOP_RIGHT); input.setRel(InputRelType.TILE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LONGITUDE : AxisType.EASTING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LONGITUDE : AxisType.EASTING); input.setMin(Double.toString(bbbox.getMinX())); input.setMax(Double.toString(bbbox.getMaxX())); extentList.add(input); @@ -1428,7 +1424,7 @@ private void generateTiledWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) input.setUnits(UnitType.TILEMATRIX); input.setPosition(PositionType.TOP_LEFT); input.setRel(InputRelType.TILE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LATITUDE : AxisType.NORTHING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LATITUDE : AxisType.NORTHING); input.setMin(Double.toString(bbbox.getMinY())); input.setMax(Double.toString(bbbox.getMaxY())); extentList.add(input); @@ -1490,7 +1486,7 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { try { // initialization is necessary so as to set the PCRS to which // the resource's geographicBox will be transformed, below. - bbbox = new ReferencedEnvelope(PREVIEW_TCRS_MAP.get(projType.value()).getCRS()); + bbbox = new ReferencedEnvelope(projType.getCRS()); bbbox = mapMLLayerMetadata.isLayerGroup ? mapMLLayerMetadata.getLayerGroupInfo().getBounds() @@ -1503,19 +1499,17 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { // the projectedBox.transform will leave the CRS set to that of whatever // was returned by layerInfo.getResource().boundingBox() or // layerGroupInfo.getBounds(), above. - bbbox = bbbox.transform(PREVIEW_TCRS_MAP.get(projType.value()).getCRS(), true); + bbbox = bbbox.transform(projType.getCRS(), true); } catch (Exception e) { // get the default max/min of the pcrs from the TCRS - Bounds defaultBounds = PREVIEW_TCRS_MAP.get(projType.value()).getBounds(); + Bounds defaultBounds = projType.getTiledCRS().getBounds(); double x1, x2, y1, y2; x1 = defaultBounds.getMin().x; x2 = defaultBounds.getMax().x; y1 = defaultBounds.getMin().y; y2 = defaultBounds.getMax().y; // use the bounds of the TCRS as the default bounds for this layer - bbbox = - new ReferencedEnvelope( - x1, x2, y1, y2, PREVIEW_TCRS_MAP.get(projType.value()).getCRS()); + bbbox = new ReferencedEnvelope(x1, x2, y1, y2, projType.getCRS()); } } @@ -1524,10 +1518,10 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { Input input = new Input(); input.setName("xmin"); input.setType(InputType.LOCATION); - input.setUnits(projType == projType.WGS_84 ? UnitType.GCRS : UnitType.PCRS); + input.setUnits(ProjType.WGS_84 == projType.unwrap() ? UnitType.GCRS : UnitType.PCRS); input.setPosition(PositionType.TOP_LEFT); input.setRel(InputRelType.IMAGE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LONGITUDE : AxisType.EASTING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LONGITUDE : AxisType.EASTING); input.setMin(Double.toString(bbbox.getMinX())); input.setMax(Double.toString(bbbox.getMaxX())); extentList.add(input); @@ -1536,10 +1530,10 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { input = new Input(); input.setName("ymin"); input.setType(InputType.LOCATION); - input.setUnits(projType == projType.WGS_84 ? UnitType.GCRS : UnitType.PCRS); + input.setUnits(ProjType.WGS_84 == projType.unwrap() ? UnitType.GCRS : UnitType.PCRS); input.setPosition(PositionType.BOTTOM_LEFT); input.setRel(InputRelType.IMAGE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LATITUDE : AxisType.NORTHING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LATITUDE : AxisType.NORTHING); input.setMin(Double.toString(bbbox.getMinY())); input.setMax(Double.toString(bbbox.getMaxY())); extentList.add(input); @@ -1548,10 +1542,10 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { input = new Input(); input.setName("xmax"); input.setType(InputType.LOCATION); - input.setUnits(projType == projType.WGS_84 ? UnitType.GCRS : UnitType.PCRS); + input.setUnits(ProjType.WGS_84 == projType.unwrap() ? UnitType.GCRS : UnitType.PCRS); input.setPosition(PositionType.TOP_RIGHT); input.setRel(InputRelType.IMAGE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LONGITUDE : AxisType.EASTING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LONGITUDE : AxisType.EASTING); input.setMin(Double.toString(bbbox.getMinX())); input.setMax(Double.toString(bbbox.getMaxX())); extentList.add(input); @@ -1560,10 +1554,10 @@ public void generateWMSClientLinks(MapMLLayerMetadata mapMLLayerMetadata) { input = new Input(); input.setName("ymax"); input.setType(InputType.LOCATION); - input.setUnits(projType == projType.WGS_84 ? UnitType.GCRS : UnitType.PCRS); + input.setUnits(ProjType.WGS_84 == projType.unwrap() ? UnitType.GCRS : UnitType.PCRS); input.setPosition(PositionType.TOP_LEFT); input.setRel(InputRelType.IMAGE); - input.setAxis(projType == projType.WGS_84 ? AxisType.LATITUDE : AxisType.NORTHING); + input.setAxis(ProjType.WGS_84 == projType.unwrap() ? AxisType.LATITUDE : AxisType.NORTHING); input.setMin(Double.toString(bbbox.getMinY())); input.setMax(Double.toString(bbbox.getMaxY())); extentList.add(input); @@ -2314,7 +2308,7 @@ static class MapMLLayerMetadata { private boolean isTransparent; private String layerName; private String layerTitle; - private ProjType projType; + private WrappingProjType projType; private String styleName; private boolean tileLayerExists; @@ -2361,7 +2355,7 @@ public void setUseFeatures(boolean useFeatures) { * @param isTransparent boolean * @param layerName String * @param layerTitle String - * @param projType ProjType object + * @param projType ProjType * @param styleName String * @param tileLayerExists boolean * @param useTiles boolean @@ -2378,7 +2372,7 @@ public MapMLLayerMetadata( boolean isTransparent, String layerName, String layerTitle, - ProjType projType, + WrappingProjType projType, String styleName, boolean tileLayerExists, boolean useTiles, @@ -2678,7 +2672,7 @@ public void setLayerTitle(String layerTitle) { * * @return ProjType */ - public ProjType getProjType() { + public WrappingProjType getProjType() { return projType; } @@ -2687,7 +2681,7 @@ public ProjType getProjType() { * * @param projType ProjType */ - public void setProjType(ProjType projType) { + public void setProjType(WrappingProjType projType) { this.projType = projType; } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java index 5fe33a7dec8..ef32200af18 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java @@ -37,7 +37,6 @@ import org.geoserver.mapml.xml.Link; import org.geoserver.mapml.xml.Mapml; import org.geoserver.mapml.xml.Meta; -import org.geoserver.mapml.xml.ProjType; import org.geoserver.mapml.xml.RelType; import org.geoserver.ows.Request; import org.geoserver.ows.URLMangler; @@ -45,7 +44,6 @@ import org.geoserver.platform.ServiceException; import org.geoserver.wms.featureinfo.FeatureTemplate; import org.geotools.api.feature.simple.SimpleFeature; -import org.geotools.api.referencing.FactoryException; import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import org.geotools.api.referencing.crs.GeodeticCRS; import org.geotools.api.style.Style; @@ -409,7 +407,7 @@ private static Set deduceProjectionAndExtent( if (requestCRS != null) { responseCRS = requestCRS; responseCRSCode = CRS.toSRS(requestCRS); - tcrs = TiledCRSConstants.lookupTCRS(responseCRSCode); + tcrs = TiledCRSConstants.lookupTCRSParams(responseCRSCode); if (tcrs != null) { projection.setContent(tcrs.getName()); crs = (responseCRS instanceof GeodeticCRS) ? "gcrs" : "pcrs"; @@ -453,7 +451,7 @@ private static String getExtent( "top-left-easting=%1$.2f,top-left-northing=%2$.2f,bottom-right-easting=%3$.2f,bottom-right-northing=%4$.2f"; double minLong, minLat, maxLong, maxLat; double minEasting, minNorthing, maxEasting, maxNorthing; - TiledCRSParams tcrs = TiledCRSConstants.lookupTCRS(responseCRSCode); + TiledCRSParams tcrs = TiledCRSConstants.lookupTCRSParams(responseCRSCode); try { if (responseCRS instanceof GeodeticCRS) { re = r.getLatLonBoundingBox(); @@ -506,30 +504,27 @@ public static List alternateProjections( String base, String path, Map query) { ArrayList links = new ArrayList<>(); Set projections = TiledCRSConstants.tiledCRSBySrsName.keySet(); - projections.forEach( - (String p) -> { - Link l = new Link(); - TiledCRSParams projection = TiledCRSConstants.lookupTCRS(p); - try { - l.setProjection(ProjType.fromValue(projection.getName())); - } catch (FactoryException e) { - throw new ServiceException("Invalid TCRS name"); - } - l.setRel(RelType.ALTERNATE); - query.put("srsName", "MapML:" + projection.getName()); - HashMap kvp = new HashMap<>(query.size()); - query.keySet() - .forEach( - key -> { - kvp.put(key, query.getOrDefault(key, "").toString()); - }); - l.setHref( - ResponseUtils.urlDecode( - ResponseUtils.buildURL( - base, path, kvp, URLMangler.URLType.SERVICE))); - links.add(l); - }); - + for (String proj : projections) { + Link l = new Link(); + TiledCRSParams projection = TiledCRSConstants.lookupTCRSParams(proj); + boolean addMe = false; + l.setProjection(projection.getName()); + addMe = true; + + if (!addMe) continue; + l.setRel(RelType.ALTERNATE); + query.put("srsName", "MapML:" + projection.getName()); + HashMap kvp = new HashMap<>(query.size()); + query.keySet() + .forEach( + key -> { + kvp.put(key, query.getOrDefault(key, "").toString()); + }); + l.setHref( + ResponseUtils.urlDecode( + ResponseUtils.buildURL(base, path, kvp, URLMangler.URLType.SERVICE))); + links.add(l); + } return links; } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLGetFeatureOutputFormat.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLGetFeatureOutputFormat.java index d7cfd22d05a..609ef30943c 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLGetFeatureOutputFormat.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLGetFeatureOutputFormat.java @@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletRequest; import org.geoserver.catalog.LayerInfo; import org.geoserver.config.GeoServer; -import org.geoserver.mapml.xml.ProjType; +import org.geoserver.mapml.tcrs.WrappingProjType; import org.geoserver.ows.Dispatcher; import org.geoserver.ows.Request; import org.geoserver.ows.URLMangler; @@ -83,7 +83,7 @@ protected void write( ReferencedEnvelope projectedBbox = extractBbox(fc); LayerInfo layerInfo = gs.getCatalog().getLayerByName(fc.getSchema().getTypeName()); CoordinateReferenceSystem crs = projectedBbox.getCoordinateReferenceSystem(); - ProjType projType = parseProjType(request); + WrappingProjType projType = parseProjType(request); double longitude; double latitude; ReferencedEnvelope geographicBox; @@ -116,7 +116,7 @@ protected void write( osw.flush(); } - private ProjType parseProjType(Request request) throws ServiceException { + private WrappingProjType parseProjType(Request request) throws ServiceException { try { Map rawKvp = request.getRawKvp(); String srs; @@ -127,7 +127,7 @@ private ProjType parseProjType(Request request) throws ServiceException { } else { srs = "EPSG:4326"; } - return ProjType.fromValue(srs.toUpperCase()); + return new WrappingProjType(srs.toUpperCase()); } catch (IllegalArgumentException | FactoryException iae) { // figure out the parameter name (version dependent) and the actual original // string value for the srs/crs parameter diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLOutput.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLOutput.java index 4c45c3c817e..ba3de8dba85 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLOutput.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLHTMLOutput.java @@ -6,32 +6,26 @@ import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; -import java.util.HashMap; +import java.util.Locale; import javax.servlet.http.HttpServletRequest; import org.geoserver.mapml.tcrs.Bounds; import org.geoserver.mapml.tcrs.Point; import org.geoserver.mapml.tcrs.TiledCRS; -import org.geoserver.mapml.xml.ProjType; +import org.geoserver.mapml.tcrs.TiledCRSParams; +import org.geoserver.mapml.tcrs.WrappingProjType; import org.geoserver.ows.URLMangler; import org.geoserver.ows.util.ResponseUtils; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; +import org.geotools.referencing.proj.PROJFormatter; /** Class delegated to build an HTML Document embedding a MapML Viewer. */ public class MapMLHTMLOutput { - public static final HashMap PREVIEW_TCRS_MAP = new HashMap<>(); - - static { - PREVIEW_TCRS_MAP.put("OSMTILE", new TiledCRS("OSMTILE")); - PREVIEW_TCRS_MAP.put("CBMTILE", new TiledCRS("CBMTILE")); - PREVIEW_TCRS_MAP.put("APSTILE", new TiledCRS("APSTILE")); - PREVIEW_TCRS_MAP.put("WGS84", new TiledCRS("WGS84")); - } - private String layerLabel; private HttpServletRequest request; - private ProjType projType; + private WrappingProjType projType; private String sourceUrL; private int zoom = 0; private Double latitude = 0.0; @@ -54,7 +48,7 @@ private MapMLHTMLOutput(HTMLOutputBuilder builder) { public static class HTMLOutputBuilder { private String layerLabel; private HttpServletRequest request; - private ProjType projType; + private WrappingProjType projType; private String sourceUrL; private ReferencedEnvelope projectedBbox; private int zoom = 0; @@ -72,7 +66,7 @@ public HTMLOutputBuilder setRequest(HttpServletRequest request) { return this; } - public HTMLOutputBuilder setProjType(ProjType projType) { + public HTMLOutputBuilder setProjType(WrappingProjType projType) { this.projType = projType; return this; } @@ -127,6 +121,7 @@ public String toHTML() { .append("mapml-viewer:not(:defined) > * { display: none; } n") .append("map-layer { display: none; }\n") .append("\n") + .append(buildProjectionScript(projType)) .append("