From 6ab3f6e175072ac492c36085f3fd956fa60faf9e Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Mon, 20 Jan 2014 17:16:03 +0100 Subject: [PATCH] Add ol.format.OSMXML and ol.source.OSMXML --- examples/data/osm/map.osm | 2223 ++++++++++++++++++++++++++++ examples/vector-osm.html | 56 + examples/vector-osm.js | 123 ++ src/objectliterals.jsdoc | 15 + src/ol/format/osmxmlformat.js | 210 +++ src/ol/source/osmxmlsource.exports | 1 + src/ol/source/osmxmlsource.js | 31 + 7 files changed, 2659 insertions(+) create mode 100644 examples/data/osm/map.osm create mode 100644 examples/vector-osm.html create mode 100644 examples/vector-osm.js create mode 100644 src/ol/format/osmxmlformat.js create mode 100644 src/ol/source/osmxmlsource.exports create mode 100644 src/ol/source/osmxmlsource.js diff --git a/examples/data/osm/map.osm b/examples/data/osm/map.osm new file mode 100644 index 0000000000..135e798e1d --- /dev/null +++ b/examples/data/osm/map.osm @@ -0,0 +1,2223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/vector-osm.html b/examples/vector-osm.html new file mode 100644 index 0000000000..6a0e5ea7ef --- /dev/null +++ b/examples/vector-osm.html @@ -0,0 +1,56 @@ + + + + + + + + + + + OSM XML example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

OSM XML example

+

Example of using the OSM XML source.

+
+

See the vector-osm.js source to see how this is done.

+
+
vector, osm, xml
+
+
+
+   +
+
+ +
+ +
+ + + + + + + diff --git a/examples/vector-osm.js b/examples/vector-osm.js new file mode 100644 index 0000000000..25f757bae4 --- /dev/null +++ b/examples/vector-osm.js @@ -0,0 +1,123 @@ +goog.require('ol.Map'); +goog.require('ol.View2D'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.BingMaps'); +goog.require('ol.source.OSMXML'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + +var styles = { + 'amenity': { + 'parking': [ + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(170, 170, 170, 1.0)', + width: 1 + }), + fill: new ol.style.Fill({ + color: 'rgba(170, 170, 170, 0.3)' + }) + }) + ] + }, + 'building': { + '.*': [ + new ol.style.Style({ + zIndex: 100, + stroke: new ol.style.Stroke({ + color: 'rgba(246, 99, 79, 1.0)', + width: 1 + }), + fill: new ol.style.Fill({ + color: 'rgba(246, 99, 79, 0.3)' + }) + }) + ] + }, + 'highway': { + 'service': [ + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(255, 255, 255, 1.0)', + width: 2 + }) + }) + ], + '.*': [ + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(255, 255, 255, 1.0)', + width: 3 + }) + }) + ] + }, + 'landuse': { + 'forest|grass|allotments': [ + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(140, 208, 95, 1.0)', + width: 1 + }), + fill: new ol.style.Fill({ + color: 'rgba(140, 208, 95, 0.3)' + }) + }) + ] + }, + 'natural': { + 'tree': [ + new ol.style.Style({ + image: new ol.style.Circle({ + radius: 2, + fill: new ol.style.Fill({ + color: 'rgba(140, 208, 95, 1.0)' + }), + stroke: null + }) + }) + ] + } +}; + +var vectorSource = new ol.source.OSMXML({ + projection: 'EPSG:3857', + url: 'data/osm/map.osm' +}); + +var vector = new ol.layer.Vector({ + source: vectorSource, + style: function(feature, resolution) { + for (var key in styles) { + var value = feature.get(key); + if (value !== undefined) { + for (var regexp in styles[key]) { + if (new RegExp(regexp).test(value)) { + return styles[key][regexp]; + } + } + } + } + return null; + } +}); + +var raster = new ol.layer.Tile({ + source: new ol.source.BingMaps({ + imagerySet: 'Aerial', + key: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3' + }) +}); + +var map = new ol.Map({ + layers: [raster, vector], + renderer: 'canvas', + target: document.getElementById('map'), + view: new ol.View2D({ + center: [739218, 5906096], + zoom: 17 + }) +}); diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 74622c6b14..55fbe40143 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -700,6 +700,21 @@ * @todo stability experimental */ +/** + * @typedef {Object} olx.source.OSMXMLOptions + * @property {Array.|undefined} attributions Attributions. + * @property {Array.|undefined} defaultStyle Default style. + * @property {Document|undefined} doc Document. + * @property {ol.Extent|undefined} extent Extent. + * @property {string|undefined} logo Logo. + * @property {Node|undefined| node Node. + * @property {ol.proj.ProjectionLike} projection Projection. + * @property {ol.proj.ProjectionLike} reprojectTo Re-project to. + * @property {string|undefined} text Text. + * @property {string|undefined} url URL. + * @property {Array.|undefined} urls URLs. + */ + /** * @typedef {Object} olx.source.ImageCanvasOptions * @property {Array.|undefined} attributions Attributions. diff --git a/src/ol/format/osmxmlformat.js b/src/ol/format/osmxmlformat.js new file mode 100644 index 0000000000..65f8f2badb --- /dev/null +++ b/src/ol/format/osmxmlformat.js @@ -0,0 +1,210 @@ +// FIXME add typedef for stack state objects +goog.provide('ol.format.OSMXML'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @constructor + * @extends {ol.format.XMLFeature} + */ +ol.format.OSMXML = function() { + goog.base(this); +}; +goog.inherits(ol.format.OSMXML, ol.format.XMLFeature); + + +/** + * @const + * @type {Array.} + * @private + */ +ol.format.OSMXML.EXTENSIONS_ = ['.osm']; + + +/** + * @inheritDoc + */ +ol.format.OSMXML.prototype.getExtensions = function() { + return ol.format.OSMXML.EXTENSIONS_; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.OSMXML.readNode_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'node'); + var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var id = node.getAttribute('id'); + var coordinates = /** @type {Array.} */ ([ + parseFloat(node.getAttribute('lon')), + parseFloat(node.getAttribute('lat')) + ]); + goog.object.set(state.nodes, id, coordinates); + + var values = ol.xml.pushParseAndPop({ + tags: {} + }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack); + if (!goog.object.isEmpty(values.tags)) { + var geometry = new ol.geom.Point(coordinates); + var feature = new ol.Feature(geometry); + feature.setId(id); + feature.setValues(values.tags); + state.features.push(feature); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.OSMXML.readWay_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'way'); + var values = ol.xml.pushParseAndPop({ + ndrefs: [], + tags: {} + }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack); + var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.} */ ([]); + for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { + var point = goog.object.get(state.nodes, values.ndrefs[i]); + goog.array.extend(flatCoordinates, point); + } + if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { + // closed way + var geometry = new ol.geom.Polygon(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, + [flatCoordinates.length]); + } else { + var geometry = new ol.geom.LineString(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); + } + var feature = new ol.Feature(geometry); + feature.setValues(values.tags); + state.features.push(feature); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.OSMXML.readNd_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'nd'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + values.ndrefs.push(node.getAttribute('ref')); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.OSMXML.readTag_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'tag'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + goog.object.set(values.tags, node.getAttribute('k'), node.getAttribute('v')); +}; + + +/** + * @const + * @private + * @type {Array.} + */ +ol.format.OSMXML.NAMESPACE_URIS_ = [ + null +]; + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeParsersNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'nd': ol.format.OSMXML.readNd_, + 'tag': ol.format.OSMXML.readTag_ + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.OSMXML.PARSERS_ = ol.xml.makeParsersNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'node': ol.format.OSMXML.readNode_, + 'way': ol.format.OSMXML.readWay_ + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeParsersNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'tag': ol.format.OSMXML.readTag_ + }); + + +/** + * @inheritDoc + */ +ol.format.OSMXML.prototype.readFeaturesFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + if (node.localName == 'osm') { + var state = ol.xml.pushParseAndPop({ + nodes: {}, + features: [] + }, ol.format.OSMXML.PARSERS_, node, []); + if (goog.isDef(state.features)) { + return state.features; + } + } + return []; +}; + + +/** + * @inheritDoc + */ +ol.format.OSMXML.prototype.readProjectionFromDocument = function(doc) { + return ol.proj.get('EPSG:4326'); +}; + + +/** + * @inheritDoc + */ +ol.format.OSMXML.prototype.readProjectionFromNode = function(node) { + return ol.proj.get('EPSG:4326'); +}; diff --git a/src/ol/source/osmxmlsource.exports b/src/ol/source/osmxmlsource.exports new file mode 100644 index 0000000000..880127d254 --- /dev/null +++ b/src/ol/source/osmxmlsource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.OSMXML diff --git a/src/ol/source/osmxmlsource.js b/src/ol/source/osmxmlsource.js new file mode 100644 index 0000000000..48353beda5 --- /dev/null +++ b/src/ol/source/osmxmlsource.js @@ -0,0 +1,31 @@ +goog.provide('ol.source.OSMXML'); + +goog.require('ol.format.OSMXML'); +goog.require('ol.source.VectorFile'); + + + +/** + * @constructor + * @extends {ol.source.VectorFile} + * @param {olx.source.OSMXMLOptions=} opt_options Options. + */ +ol.source.OSMXML = function(opt_options) { + + var options = goog.isDef(opt_options) ? opt_options : {}; + + goog.base(this, { + attributions: options.attributions, + doc: options.doc, + extent: options.extent, + format: new ol.format.OSMXML(), + logo: options.logo, + node: options.node, + projection: options.projection, + reprojectTo: options.reprojectTo, + text: options.text, + url: options.url + }); + +}; +goog.inherits(ol.source.OSMXML, ol.source.VectorFile);