diff --git a/workshop/content/docs/advanced/other-projections.md b/workshop/content/docs/advanced/other-projections.md new file mode 100644 index 0000000..1640661 --- /dev/null +++ b/workshop/content/docs/advanced/other-projections.md @@ -0,0 +1,281 @@ +# Working with non-EPSG Coordinate Reference Systems + +## Overview + +Most geospatial workflows use EPSG-defined coordinate reference systems. However, there are cases where we need to work with custom or non-standard projections that are not included in the EPSG registry. + +In this example we will be working with the [ESRI:53009](https://spatialreference.org/ref/esri/53009/) - a spherical [Mollweide projection](https://en.wikipedia.org/wiki/Mollweide_projection), +and using WMS, WFS, and WCS services to access data in this projection. + +
+ +
+ +`ESRI:53009` can be identified using different formats, as shown in the table below: + + +| Format | Example | +|--------|--------| +| Authority code | ESRI:53009 | +| OGC URN | urn:ogc:def:crs:ESRI::53009 | +| OGC HTTP URI | http://www.opengis.net/def/crs/ESRI/0/53009 | + +## The Mapfile + +Projections are referenced in several places in the Mapfile, listed below. + +The top-level projection of the Mapfile is set to `ESRI:53009`: + +``` scala +PROJECTION + "ESRI:53009" +END +``` + +The source data used for the "raster" and "countries" layers are in the `EPSG:4326` projection. +These need to be set explicitly in the Mapfile using the `PROJECTION` object within the `LAYER` definition, as follows: + +``` scala +LAYER + NAME "raster" + TYPE RASTER + EXTENT -180 -90 180 90 + DATA "data/naturalearth/NE2_50M_SR_SMALL.tif" + PROJECTION + "EPSG:4326" + END +END +``` + +The "cities" layer uses a GeoJSON file already in the `ESRI:53009` projection. Even though it is not strictly necessary to specify the projection for this layer, +it is good practice to do so to ensure that MapServer can correctly identify the source CRS and reproject the data as needed. + +```scala +LAYER + NAME "cities" + TYPE POINT + PROJECTION + "ESRI:53009" + END + CONNECTIONTYPE OGR + CONNECTION "data/naturalearth/worldcity_53009.geojson" +``` + +!!! note + + GeoJSON traditionally assumes EPSG:4326. Using other CRS relies on client/server + agreement and is not part of the official GeoJSON specification. + +Finally we want to make the projection available to all the WxS protocols - WMS, WFS, and WCS. This is done using the `ows_srs` metadata item in the `WEB` section of the Mapfile, as follows: + +``` scala +WEB + METADATA + "ows_srs" "ESRI:53009 EPSG:4326" + END +END +``` + +Using the `ows_` prefix makes the projection available to all OWSs (OGC Web Services), and avoids having to have duplicate entries such as `wms_srs`, `wfs_srs`, and `wcs_srs` +if we were to use the service-specific metadata items. + +!!! note + + The order of the layers in the Mapfile is important when requesting a map directly using the MapServer CGI interface + (for example ). + The raster layer must be first in the Mapfile, otherwise the raster will be drawn on top of the vector layers and obscure them. The order of the layers in the request + itself does not affect the rendering order, only the order in the Mapfile. + +## OpenLayers + +The OpenLayers client for this tutorial is set up to make requests to the WMS, WFS, and WCS services using the `ESRI:53009` projection. +The client is configured to request data in this projection and display it on the map. + +OpenLayers does not include definitions for all projections by default, so we use the [proj4js](https://proj4js.org/) library +to define the `ESRI:53009` projection and register it with OpenLayers. + +```js +proj4.defs('ESRI:53009', + '+proj=moll +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs' +); +register(proj4); + +const coverageExtent = [-18019909, -9009954, 18019909, 9009954]; + +const mollweideProjection = new Projection({ + code: 'ESRI:53009', + units: 'm', + extent: coverageExtent, + worldExtent: [-180, -90, 180, 90], + global: true, +}); + +addProjection(mollweideProjection); +``` + +We set the projection on the map object to `ESRI:53009` so that all requests sent to MapServer return data in this projection. + +```js +const map = new Map({ + target: 'map', + layers: [imageLayer, wmsLayer, graticule, wfsLayer], + view: new View({ + projection: 'ESRI:53009', + center: [0, 0], + zoom: 1, + }), +}); +``` + +To help visually confirm the reprojection is working correctly we add a [graticule layer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Graticule-Graticule.html) to the map, which shows the lines of latitude and longitude. +The graticule uses the `ESRI:53009` projection of the `map` object, and display lines representing degrees of latitude and longitude. We also enable labels to show the coordinates of the graticule lines. + +```js +const graticule = new Graticule({ + strokeStyle: new Stroke({ + color: 'rgba(50,50,50,0.5)', + width: 1, + }), + showLabels: true, + wrapX: false +}); +``` + +### WFS + +The "cities" point layer is displayed as a WFS layer in the OpenLayers client. +As w"e construct the URLs to send to MapServer ourselves we need to set the `SRSNAME` to `ESRI:53009` (MapServer interprets the `BBOX` values in the CRS specified by `SRSNAME`). + +We need to set the `dataProjection` to `ESRI:53009` in the `GeoJSON` format options to ensure the features are correctly reprojected and displayed on the map. + +```js +const wfsSource = new VectorSource({ + format: new GeoJSON({ + dataProjection: 'ESRI:53009', + }), + url: function (extent) { + const [minx, miny, maxx, maxy] = extent; + return `${url}&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature` + + `&TYPENAMES=ms:cities` + + `&OUTPUTFORMAT=geojson` + + `&SRSNAME=ESRI:53009` + + `&BBOX=${minx},${miny},${maxx},${maxy}`; + }, + strategy: bbox, +}); +``` + +### WMS + +The "countries" polygon layer is displayed as a WMS. As the OpenLayers map itself is set to use the `ESRI:53009` projection we don't need to +specify any further parameters here. + +```js +const wmsLayer = new ImageLayer({ + source: new ImageWMS({ + url: url, + params: { + LAYERS: 'countries', + FORMAT: 'image/png', + TRANSPARENT: true, + VERSION: '1.3.0', + }, + serverType: 'mapserver', + }), +}); +``` + +## WCS + +!!! note + + OpenLayers does not natively support WCS. In this example we use the same approach as in the [Web Coverage Services (WCS)](../outputs/wcs.md) tutorial for testing the WCS protocol. + Images are requested as PNGs using the [ImageWMS](https://openlayers.org/en/latest/apidoc/module-ol_source_ImageWMS-ImageWMS.html) class and a custom + [imageLoadFunction](https://openlayers.org/en/latest/apidoc/module-ol_Image.html#~LoadFunction), + as displaying GeoTIFFs directly in OpenLayers is not supported without additional libraries. + +We construct the WCS request parameters manually in the `imageLoadFunction` and ensure that the `SUBSETTINGCRS` and `OUTPUTCRS` parameters are set to `http://www.opengis.net/def/crs/ESRI/0/53009` +to ensure the data is returned in the correct projection. In this example we use the OGC HTTP URI form of the CRS identifier for the CRS requests. + + +```js +const wcsSource = new ImageWMS({ + url, + params: { + SERVICE: 'WCS', + VERSION: '2.0.1', + REQUEST: 'GetCoverage', + FORMAT: 'image/png', + COVERAGEID: 'raster', + SUBSETTINGCRS: 'http://www.opengis.net/def/crs/ESRI/0/53009', + OUTPUTCRS: 'http://www.opengis.net/def/crs/ESRI/0/53009', + }, + imageLoadFunction: (image, src) => { + const srcUrl = new URL(src); + const params = srcUrl.searchParams; + + // Get the ImageWMS params + const bbox = params.get('BBOX').split(','); + const width = params.get('WIDTH'); + const height = params.get('HEIGHT'); + + // Replace with WCS 2.0.1 equivalents + params.append('SUBSET', `x(${bbox[0]},${bbox[2]})`); + params.append('SUBSET', `y(${bbox[1]},${bbox[3]})`); + params.set('SCALESIZE', `x(${width}),y(${height})`); + ... +``` + +!!! note + + `SUBSETTINGCRS` is not strictly necessary here as MapServer assumes the `SUBSET` parameters are in the same CRS as the `OUTPUTCRS`, + but it is good practice to include it. + +## Code + +!!! example + + - MapServer request: + - OpenLayers example: + +??? JavaScript "other-projections.js" + + ``` js + --8<-- "other-projections.js" + ``` + +??? Mapfile "other-projections.map" + + ``` scala + --8<-- "other-projections.map" + ``` + +## Exercises + +1. Currently the CRS is specified using the `http://www.opengis.net/def/crs/ESRI/0/53009` format, + (OGC CRS HTTP URIs) but this can also be specified using other CRS formats. + + Update the OpenLayers WCS request parameters to use this format, and test that the requests are still working correctly. + + ```js + // OGC URN CRS identifiers + SUBSETTINGCRS: 'urn:ogc:def:crs:ESRI::53009', + OUTPUTCRS: 'urn:ogc:def:crs:ESRI::53009', + + // authority codes + SUBSETTINGCRS: 'ESRI:53009', + OUTPUTCRS: 'ESRI:53009', + ``` + +2. Update the Mapfile to use another non-EPSG projection, for example `ESRI:54030` (the [Robinson projection](https://en.wikipedia.org/wiki/Robinson_projection)). + + Test everything is configured correctly by making a direct request to the MapServer CGI interface + using . + + +## Further Reading + +- [Reproject Data with GDAL Tutorial](https://gdal.org/en/latest/tutorials/reprojecting_data.html) +- [MapServer Projections](https://mapserver.org/mapfile/projection.html) +- [Spatial Reference](https://spatialreference.org/) +- [PROJ](https://proj.org/) diff --git a/workshop/content/docs/outputs/wcs.md b/workshop/content/docs/outputs/wcs.md index b465b55..988d467 100644 --- a/workshop/content/docs/outputs/wcs.md +++ b/workshop/content/docs/outputs/wcs.md @@ -122,6 +122,26 @@ rather than to display it as a map image. However, for the purposes of this tuto WCS is not natively supported in OpenLayers, but we can use the [ImageWMS](https://openlayers.org/en/latest/apidoc/module-ol_source_ImageWMS.html) source as a workaround by overriding the request parameters to call WCS, and display the results as an image layer on the map. +Typically WCS is used to return raw raster formats such as GeoTIFFs, but viewing these in a browser requires rendering the raw +pixel values using additional JavaScript libraries such as [geotiff.js](https://geotiffjs.github.io/). + +In this tutorial we instead request a rendered image (`FORMAT: 'image/png'`) and use [CSS filters](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/filter) +to visually confirm that data is being returned correctly. + +```js +const wcsSource = new ImageWMS({ + url, + params: { + SERVICE: 'WCS', + VERSION: '2.0.1', + REQUEST: 'GetCoverage', + FORMAT: 'image/png', + COVERAGEID: 'dtm', + SUBSETTINGCRS: 'http://www.opengis.net/def/crs/EPSG/0/3857', + OUTPUTCRS: 'http://www.opengis.net/def/crs/EPSG/0/3857', + } +``` + !!! tip The `COVERAGEID` corresponds to the MapServer `LAYER` `NAME` @@ -145,11 +165,11 @@ by overriding the request parameters to call WCS, and display the results as an 1. From the command line, test the WCS 2.0.1 protocol by making a `GetCoverage` request and saving the output as a GeoTIFF using the configured `OUTPUTFORMAT` (MapServer format name, not a MIME type). Then use `gdal raster info` to check the output file. -``` -mapserv -nh "QUERY_STRING=map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=dtm&FORMAT=GEOTIFF&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326&SUBSET=x(26.6507,26.7362)&SUBSET=y(58.3414,58.3879)&SCALESIZE=x(400),y(400)" \ -> output.tif -gdal raster info output.tif -``` + ```bash + mapserv -nh "QUERY_STRING=map=/etc/mapserver/wcs.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=dtm&FORMAT=GEOTIFF&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326&SUBSET=x(26.6507,26.7362)&SUBSET=y(58.3414,58.3879)&SCALESIZE=x(400),y(400)" \ + > output.tif + gdal raster info output.tif + ``` 2. Add the COG output format to the Mapfile and make a `GetCoverage` request to download a COG-formatted output. Check the output file with `gdal raster info` to see the difference in metadata. @@ -157,17 +177,17 @@ gdal raster info output.tif for example `COVERAGEID` becomes `COVERAGE`, and the CRS parameters are different. You can also remove the entire `imageLoadFunction` as WCS 1.0.0 more closely matches the WMS protocol, using `BBOX`,`WIDTH`, and `HEIGHT` parameters to specify the area and size of the output image. -```js -params: { - SERVICE: 'WCS', - VERSION: '1.0.0', - REQUEST: 'GetCoverage', - FORMAT: 'image/png', - COVERAGE: 'dtm', - CRS: 'EPSG:3857', - RESPONSE_CRS: 'EPSG:3857', -}, -``` + ```js + params: { + SERVICE: 'WCS', + VERSION: '1.0.0', + REQUEST: 'GetCoverage', + FORMAT: 'image/png', + COVERAGE: 'dtm', + CRS: 'EPSG:3857', + RESPONSE_CRS: 'EPSG:3857', + }, + ``` ## Possible Errors diff --git a/workshop/content/mkdocs.yml b/workshop/content/mkdocs.yml index 6da3dae..1317cf8 100644 --- a/workshop/content/mkdocs.yml +++ b/workshop/content/mkdocs.yml @@ -36,7 +36,7 @@ nav: - Clusters: advanced/clusters.md - SLD: advanced/sld.md - STAC: advanced/stac.md - # - WCS and non-EPSG Projections: advanced/wcs-projections.md + - Non-EPSG CRSs: advanced/other-projections.md # - Apache: advanced/apache.md # - MapScript: advanced/mapscript.md - Summary: summary.md diff --git a/workshop/exercises/app/index.html b/workshop/exercises/app/index.html index 291c8c7..f04a9f9 100644 --- a/workshop/exercises/app/index.html +++ b/workshop/exercises/app/index.html @@ -42,7 +42,7 @@

Advanced

  • Contours
  • SLD - Styled Layer Descriptor
  • STAC
  • - +
  • Working with non-EPSG Coordinate Reference Systems (CRS)
  • Miscellaneous

      diff --git a/workshop/exercises/app/js/other-projections.js b/workshop/exercises/app/js/other-projections.js new file mode 100644 index 0000000..a7cc0cf --- /dev/null +++ b/workshop/exercises/app/js/other-projections.js @@ -0,0 +1,137 @@ +import '../css/style.css'; +import Map from 'ol/Map'; +import View from 'ol/View'; +import ImageLayer from 'ol/layer/Image'; +import proj4 from 'proj4'; +import { register } from 'ol/proj/proj4'; +import { addProjection } from 'ol/proj'; +import Projection from 'ol/proj/Projection'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; +import GeoJSON from 'ol/format/GeoJSON'; +import { bbox } from 'ol/loadingstrategy'; +import { Style, Stroke, Fill } from 'ol/style'; +import ImageWMS from 'ol/source/ImageWMS'; +import { Circle as CircleStyle } from 'ol/style'; +import ImageCanvas from 'ol/source/ImageCanvas'; +import Graticule from 'ol/layer/Graticule'; + +const mapserverUrl = import.meta.env.VITE_MAPSERVER_BASE_URL; +const mapfilesPath = import.meta.env.VITE_MAPFILES_PATH; +const url = mapserverUrl + mapfilesPath + 'other-projections.map'; + +proj4.defs('ESRI:53009', + '+proj=moll +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs' +); +register(proj4); + +const coverageExtent = [-18019909, -9009954, 18019909, 9009954]; + +const mollweideProjection = new Projection({ + code: 'ESRI:53009', + units: 'm', + extent: coverageExtent, + worldExtent: [-180, -90, 180, 90], + global: true, +}); + +addProjection(mollweideProjection); + +const wcsSource = new ImageWMS({ + url, + params: { + SERVICE: 'WCS', + VERSION: '2.0.1', + REQUEST: 'GetCoverage', + FORMAT: 'image/png', + COVERAGEID: 'raster', + SUBSETTINGCRS: 'http://www.opengis.net/def/crs/ESRI/0/53009', + OUTPUTCRS: 'http://www.opengis.net/def/crs/ESRI/0/53009', + }, + imageLoadFunction: (image, src) => { + const srcUrl = new URL(src); + const params = srcUrl.searchParams; + + // Get the ImageWMS params + const bbox = params.get('BBOX').split(','); + const width = params.get('WIDTH'); + const height = params.get('HEIGHT'); + + // Replace with WCS 2.0.1 equivalents + params.append('SUBSET', `x(${bbox[0]},${bbox[2]})`); + params.append('SUBSET', `y(${bbox[1]},${bbox[3]})`); + params.set('SCALESIZE', `x(${width}),y(${height})`); + + // Remove the WMS params + params.delete('BBOX'); + params.delete('WIDTH'); + params.delete('HEIGHT'); + params.delete('CRS'); + + image.getImage().src = srcUrl.toString(); + }, + ratio: 1, +}); + +const imageLayer = new ImageLayer({ + source: wcsSource +}); + +const wmsLayer = new ImageLayer({ + source: new ImageWMS({ + url: url, + params: { + LAYERS: 'countries', + FORMAT: 'image/png', + TRANSPARENT: true, + VERSION: '1.3.0', + }, + serverType: 'mapserver', + }), +}); + +// https://openlayers.org/en/latest/examples/graticule.html +const graticule = new Graticule({ + strokeStyle: new Stroke({ + color: 'rgba(50,50,50,0.5)', + width: 1, + }), + showLabels: true, + wrapX: false +}); + +const wfsSource = new VectorSource({ + format: new GeoJSON({ + dataProjection: 'ESRI:53009', + }), + url: function (extent) { + const [minx, miny, maxx, maxy] = extent; + return `${url}&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature` + + `&TYPENAMES=ms:cities` + + `&OUTPUTFORMAT=geojson` + + `&SRSNAME=ESRI:53009` + + `&BBOX=${minx},${miny},${maxx},${maxy}`; + }, + strategy: bbox, +}); + +const wfsLayer = new VectorLayer({ + source: wfsSource, + style: new Style({ + image: new CircleStyle({ + radius: 5, + fill: new Fill({ color: '#ff6600' }), + stroke: new Stroke({ color: '#ffffff', width: 1 }), + }), + }), +}); + +const map = new Map({ + target: 'map', + layers: [imageLayer, wmsLayer, graticule, wfsLayer], + view: new View({ + projection: 'ESRI:53009', + center: [0, 0], + zoom: 1, + }), +}); diff --git a/workshop/exercises/app/other-projections.html b/workshop/exercises/app/other-projections.html new file mode 100644 index 0000000..a1e456d --- /dev/null +++ b/workshop/exercises/app/other-projections.html @@ -0,0 +1,14 @@ + + + + + + + + Non-EPSG Coordinate Reference Systems + + +
      + + + diff --git a/workshop/exercises/mapfiles/data/naturalearth/NE2_50M_SR_SMALL.tif b/workshop/exercises/mapfiles/data/naturalearth/NE2_50M_SR_SMALL.tif new file mode 100644 index 0000000..8dc17f5 Binary files /dev/null and b/workshop/exercises/mapfiles/data/naturalearth/NE2_50M_SR_SMALL.tif differ diff --git a/workshop/exercises/mapfiles/data/naturalearth/worldcity_53009.geojson b/workshop/exercises/mapfiles/data/naturalearth/worldcity_53009.geojson new file mode 100644 index 0000000..c244e10 --- /dev/null +++ b/workshop/exercises/mapfiles/data/naturalearth/worldcity_53009.geojson @@ -0,0 +1,70 @@ +{ +"type": "FeatureCollection", +"name": "ne_110m_populated_places_simple", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:ESRI::53009" } }, +"features": [ +{"type":"Feature","properties":{"name":"Vatican City"},"geometry":{"type":"Point","coordinates":[1037552.719364791875705,4995413.579319069162011]}}, +{"type":"Feature","properties":{"name":"Budapest"},"geometry":{"type":"Point","coordinates":[1495933.804218924371526,5603142.5508894296363]}}, +{"type":"Feature","properties":{"name":"Bucharest"},"geometry":{"type":"Point","coordinates":[2118527.645560233388096,5272965.834304659627378]}}, +{"type":"Feature","properties":{"name":"Lisbon"},"geometry":{"type":"Point","coordinates":[-784860.067850206978619,4641156.7258315756917]}}, +{"type":"Feature","properties":{"name":"Oslo"},"geometry":{"type":"Point","coordinates":[697390.064990402664989,6861296.239448919892311]}}, +{"type":"Feature","properties":{"name":"Warsaw"},"geometry":{"type":"Point","coordinates":[1547993.720128267304972,6098220.7082295473665]}}, +{"type":"Feature","properties":{"name":"Dublin"},"geometry":{"type":"Point","coordinates":[-453686.141369078250136,6212351.292395958676934]}}, +{"type":"Feature","properties":{"name":"Kuala Lumpur"},"geometry":{"type":"Point","coordinates":[10170687.746244855225086,387710.993413620977663]}}, +{"type":"Feature","properties":{"name":"Prague"},"geometry":{"type":"Point","coordinates":[1094576.988673577550799,5875993.677478404715657]}}, +{"type":"Feature","properties":{"name":"Helsinki"},"geometry":{"type":"Point","coordinates":[1610108.879478025948629,6884681.395433887839317]}}, +{"type":"Feature","properties":{"name":"København"},"geometry":{"type":"Point","coordinates":[878412.250307670910843,6447486.831736894324422]}}, +{"type":"Feature","properties":{"name":"Brussels"},"geometry":{"type":"Point","coordinates":[325446.858399160497356,5953989.420989045873284]}}, +{"type":"Feature","properties":{"name":"San Francisco"},"geometry":{"type":"Point","coordinates":[-10588018.920884869992733,4535180.73420294560492]}}, +{"type":"Feature","properties":{"name":"Miami"},"geometry":{"type":"Point","coordinates":[-7526733.331177597865462,3143714.640458142384887]}}, +{"type":"Feature","properties":{"name":"Atlanta"},"geometry":{"type":"Point","coordinates":[-7533471.350165877491236,4073757.361970468889922]}}, +{"type":"Feature","properties":{"name":"Chicago"},"geometry":{"type":"Point","coordinates":[-7305282.39120152965188,4989302.199833580292761]}}, +{"type":"Feature","properties":{"name":"Caracas"},"geometry":{"type":"Point","coordinates":[-6629806.084162600338459,1294395.757789062336087]}}, +{"type":"Feature","properties":{"name":"Dubai"},"geometry":{"type":"Point","coordinates":[5202387.133027506060898,3075463.649416013155133]}}, +{"type":"Feature","properties":{"name":"Madrid"},"geometry":{"type":"Point","coordinates":[-311475.64815323241055,4828870.697995505295694]}}, +{"type":"Feature","properties":{"name":"Geneva"},"geometry":{"type":"Point","coordinates":[488706.06598955928348,5464871.507189967669547]}}, +{"type":"Feature","properties":{"name":"Stockholm"},"geometry":{"type":"Point","coordinates":[1185542.922234875382856,6804330.052005169913173]}}, +{"type":"Feature","properties":{"name":"Bangkok"},"geometry":{"type":"Point","coordinates":[9883519.761892898008227,1692195.988805206259713]}}, +{"type":"Feature","properties":{"name":"Johannesburg"},"geometry":{"type":"Point","coordinates":[2624319.372078420128673,-3188606.051926610525697]}}, +{"type":"Feature","properties":{"name":"Amsterdam"},"geometry":{"type":"Point","coordinates":[361564.125423857884016,6110652.777624643407762]}}, +{"type":"Feature","properties":{"name":"Casablanca"},"geometry":{"type":"Point","coordinates":[-680942.978250139160082,4057915.898041976615787]}}, +{"type":"Feature","properties":{"name":"Seoul"},"geometry":{"type":"Point","coordinates":[11005771.733470009639859,4510770.816743222996593]}}, +{"type":"Feature","properties":{"name":"Manila"},"geometry":{"type":"Point","coordinates":[11868226.576458109542727,1796448.4557392206043]}}, +{"type":"Feature","properties":{"name":"Berlin"},"geometry":{"type":"Point","coordinates":[983352.886643143487163,6128281.703058420680463]}}, +{"type":"Feature","properties":{"name":"Ōsaka"},"geometry":{"type":"Point","coordinates":[12014715.843578070402145,4183103.609326903242618]}}, +{"type":"Feature","properties":{"name":"New Delhi"},"geometry":{"type":"Point","coordinates":[7130350.979256927035749,3475654.066116550937295]}}, +{"type":"Feature","properties":{"name":"Athens"},"geometry":{"type":"Point","coordinates":[2049354.152333360398188,4557875.952059769071639]}}, +{"type":"Feature","properties":{"name":"Toronto"},"geometry":{"type":"Point","coordinates":[-6497357.940769017674029,5188943.718588505871594]}}, +{"type":"Feature","properties":{"name":"Buenos Aires"},"geometry":{"type":"Point","coordinates":[-5184170.305463442578912,-4173885.682055139914155]}}, +{"type":"Feature","properties":{"name":"Vienna"},"geometry":{"type":"Point","coordinates":[1272092.629400584613904,5677539.881549976766109]}}, +{"type":"Feature","properties":{"name":"Melbourne"},"geometry":{"type":"Point","coordinates":[12537120.888618104159832,-4539001.169993371702731]}}, +{"type":"Feature","properties":{"name":"Taipei"},"geometry":{"type":"Point","coordinates":[11449733.200224874541163,3054169.173176701180637]}}, +{"type":"Feature","properties":{"name":"Auckland"},"geometry":{"type":"Point","coordinates":[15235697.901915574446321,-4429173.90740457829088]}}, +{"type":"Feature","properties":{"name":"Los Angeles"},"geometry":{"type":"Point","coordinates":[-10533466.085333880037069,4109400.99212686996907]}}, +{"type":"Feature","properties":{"name":"Washington, D.C."},"geometry":{"type":"Point","coordinates":[-6597862.922394437715411,4661025.784095732495189]}}, +{"type":"Feature","properties":{"name":"New York"},"geometry":{"type":"Point","coordinates":[-6235341.425805664621294,4864442.273222120478749]}}, +{"type":"Feature","properties":{"name":"London"},"geometry":{"type":"Point","coordinates":[-8835.297689725268356,6023091.202004038728774]}}, +{"type":"Feature","properties":{"name":"Istanbul"},"geometry":{"type":"Point","coordinates":[2434728.769358589313924,4897335.755556998774409]}}, +{"type":"Feature","properties":{"name":"Riyadh"},"geometry":{"type":"Point","coordinates":[4409155.316829094663262,3006403.033424642402679]}}, +{"type":"Feature","properties":{"name":"Cape Town"},"geometry":{"type":"Point","coordinates":[1643807.389327770797536,-4094315.328538609668612]}}, +{"type":"Feature","properties":{"name":"Moscow"},"geometry":{"type":"Point","coordinates":[2627124.88481078715995,6454821.379650089889765]}}, +{"type":"Feature","properties":{"name":"Mexico City"},"geometry":{"type":"Point","coordinates":[-9570615.304541144520044,2383785.732128122355789]}}, +{"type":"Feature","properties":{"name":"Lagos"},"geometry":{"type":"Point","coordinates":[338008.628437079722062,795381.612640018691309]}}, +{"type":"Feature","properties":{"name":"Rome"},"geometry":{"type":"Point","coordinates":[1039934.284756312845275,4994819.252561574801803]}}, +{"type":"Feature","properties":{"name":"Beijing"},"geometry":{"type":"Point","coordinates":[9882905.236769715324044,4773063.975052023306489]}}, +{"type":"Feature","properties":{"name":"Nairobi"},"geometry":{"type":"Point","coordinates":[3684974.487679351586848,-158256.298814349254826]}}, +{"type":"Feature","properties":{"name":"Jakarta"},"geometry":{"type":"Point","coordinates":[10656271.976234402507544,-761775.27536864974536]}}, +{"type":"Feature","properties":{"name":"Bogota"},"geometry":{"type":"Point","coordinates":[-7401986.668913644738495,567694.915078696329147]}}, +{"type":"Feature","properties":{"name":"Cairo"},"geometry":{"type":"Point","coordinates":[2860708.793664662633091,3645844.710800523869693]}}, +{"type":"Feature","properties":{"name":"Shanghai"},"geometry":{"type":"Point","coordinates":[11034090.843851678073406,3781902.011816143523902]}}, +{"type":"Feature","properties":{"name":"Tokyo"},"geometry":{"type":"Point","coordinates":[12296820.395886525511742,4297025.881025522947311]}}, +{"type":"Feature","properties":{"name":"Mumbai"},"geometry":{"type":"Point","coordinates":[7045658.088834062218666,2338360.349103276152164]}}, +{"type":"Feature","properties":{"name":"Paris"},"geometry":{"type":"Point","coordinates":[181420.087808243028121,5746933.251617749221623]}}, +{"type":"Feature","properties":{"name":"Santiago"},"geometry":{"type":"Point","coordinates":[-6322269.785750271752477,-4039276.955194445326924]}}, +{"type":"Feature","properties":{"name":"Rio de Janeiro"},"geometry":{"type":"Point","coordinates":[-4111765.363695851061493,-2800183.43590296106413]}}, +{"type":"Feature","properties":{"name":"São Paulo"},"geometry":{"type":"Point","coordinates":[-4423340.326991133391857,-2877844.013207453303039]}}, +{"type":"Feature","properties":{"name":"Sydney"},"geometry":{"type":"Point","coordinates":[13489315.116818597540259,-4088942.622344262432307]}}, +{"type":"Feature","properties":{"name":"Singapore"},"geometry":{"type":"Point","coordinates":[10395236.323647962883115,159933.157210316188866]}}, +{"type":"Feature","properties":{"name":"Hong Kong"},"geometry":{"type":"Point","coordinates":[10894281.329592548310757,2728261.696384030859917]}} +] +} diff --git a/workshop/exercises/mapfiles/other-projections.map b/workshop/exercises/mapfiles/other-projections.map new file mode 100644 index 0000000..7a6b96e --- /dev/null +++ b/workshop/exercises/mapfiles/other-projections.map @@ -0,0 +1,84 @@ +MAP + NAME "OTHER_PROJECTIONS" + SIZE 1200 1200 + EXTENT -18019909.21 -9009954.61 18019909.21 9009954.61 + + PROJECTION + "ESRI:53009" + END + + IMAGETYPE "png" + + MAXSIZE 8096 + + SYMBOL + NAME "circlef" + TYPE ELLIPSE + FILLED TRUE + POINTS + 10 10 + END + END + + WEB + METADATA + "ows_enable_request" "*" + "ows_onlineresource" "http://localhost/path/to/other-projections?" + "ows_srs" "ESRI:53009 EPSG:4326" + "wfs_getfeature_formatlist" "geojson" + END + END + + OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/geo+json" + FORMATOPTION "FORM=SIMPLE" + END + + LAYER + NAME "raster" + TYPE RASTER + EXTENT -180 -90 180 90 + DATA "data/naturalearth/NE2_50M_SR_SMALL.tif" + PROJECTION + "EPSG:4326" + END + END + + LAYER + NAME "countries" + TYPE POLYGON + CONNECTIONTYPE OGR + CONNECTION "data/naturalearth/ne_110m_admin_0_countries.fgb" + PROJECTION + "EPSG:4326" + END + CLASS + STYLE + OUTLINECOLOR 50 50 50 + OUTLINEWIDTH 0.4 # the width of the polygon outline + END + END + END + + LAYER + NAME "cities" + TYPE POINT + PROJECTION + "ESRI:53009" + END + METADATA + "gml_include_items" "all" + END + CONNECTIONTYPE OGR + CONNECTION "data/naturalearth/worldcity_53009.geojson" + CLASS + STYLE + SYMBOL "circlef" + COLOR "#ff6600" + SIZE 6 + END + END + END +END \ No newline at end of file