Merge pull request #1541 from twpayne/vector-api-gpx

[vector-api] Add ol.format.GPX
This commit is contained in:
Tom Payne
2014-01-17 07:39:56 -08:00
14 changed files with 2251 additions and 1114 deletions
+16
View File
@@ -291,6 +291,8 @@
* features will be added to this layer's source. If neither `source` nor
* `layer` are defined then the dropped features will be added as a new
* layer.
* @property {ol.feature.StyleFunction|undefined} styleFunction Style function.
* This is used to configure any new layers created.
*/
/**
@@ -554,6 +556,20 @@
* @property {Array.<string>|undefined} urls URLs.
*/
/**
* @typedef {Object} olx.source.GPXOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @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.<string>|undefined} urls URLs.
*/
/**
* @typedef {Object} olx.source.TopoJSONOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
+3
View File
@@ -0,0 +1,3 @@
@exportSymbol ol.format.GPX
@exportProperty ol.format.GPX.prototype.readFeature
@exportProperty ol.format.GPX.prototype.readFeatures
+420
View File
@@ -0,0 +1,420 @@
goog.provide('ol.format.GPX');
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.XML');
goog.require('ol.format.XSD');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.Point');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @constructor
* @extends {ol.format.XML}
*/
ol.format.GPX = function() {
goog.base(this);
};
goog.inherits(ol.format.GPX, ol.format.XML);
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.GPX.NAMESPACE_URIS_ = [
null,
'http://www.topografix.com/GPX/1/0',
'http://www.topografix.com/GPX/1/1'
];
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Node} node Node.
* @param {Object} values Values.
* @private
* @return {Array.<number>} Flat coordinates.
*/
ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
flatCoordinates.push(
parseFloat(node.getAttribute('lon')),
parseFloat(node.getAttribute('lat')));
if (goog.object.containsKey(values, 'ele')) {
flatCoordinates.push(
/** @type {number} */ (goog.object.get(values, 'ele')));
goog.object.remove(values, 'ele');
} else {
flatCoordinates.push(0);
}
if (goog.object.containsKey(values, 'time')) {
flatCoordinates.push(
/** @type {number} */ (goog.object.get(values, 'time')));
goog.object.remove(values, 'time');
} else {
flatCoordinates.push(0);
}
return flatCoordinates;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseLink_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'link');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var href = node.getAttribute('href');
if (!goog.isNull(href)) {
goog.object.set(values, 'link', href);
}
ol.xml.parse(ol.format.GPX.LINK_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseRtePt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'rtept');
var values = ol.xml.pushAndParse(
{}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack);
if (goog.isDef(values)) {
var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(goog.object.get(rteValues, 'flatCoordinates'));
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseTrkPt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trkpt');
var values = ol.xml.pushAndParse(
{}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack);
if (goog.isDef(values)) {
var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(goog.object.get(trkValues, 'flatCoordinates'));
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseTrkSeg_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trkseg');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
ol.xml.parse(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack);
var flatCoordinates = /** @type {Array.<number>} */
(goog.object.get(values, 'flatCoordinates'));
var ends = /** @type {Array.<number>} */ (goog.object.get(values, 'ends'));
ends.push(flatCoordinates.length);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.GPX.readRte_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'rte');
var values = ol.xml.pushAndParse({
'flatCoordinates': []
}, ol.format.GPX.RTE_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var flatCoordinates = /** @type {Array.<number>} */
(goog.object.get(values, 'flatCoordinates'));
goog.object.remove(values, 'flatCoordinates');
var geometry = new ol.geom.LineString(null);
geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
var feature = new ol.Feature(geometry);
feature.setValues(values);
return feature;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.GPX.readTrk_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trk');
var values = ol.xml.pushAndParse({
'flatCoordinates': [],
'ends': []
}, ol.format.GPX.TRK_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var flatCoordinates = /** @type {Array.<number>} */
(goog.object.get(values, 'flatCoordinates'));
goog.object.remove(values, 'flatCoordinates');
var ends = /** @type {Array.<number>} */ (goog.object.get(values, 'ends'));
goog.object.remove(values, 'ends');
var geometry = new ol.geom.MultiLineString(null);
geometry.setFlatCoordinates(
ol.geom.GeometryLayout.XYZM, flatCoordinates, ends);
var feature = new ol.Feature(geometry);
feature.setValues(values);
return feature;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Waypoint.
*/
ol.format.GPX.readWpt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'wpt');
var values = ol.xml.pushAndParse(
{}, ol.format.GPX.WPT_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var coordinates = ol.format.GPX.appendCoordinate_([], node, values);
var geometry = new ol.geom.Point(
coordinates, ol.geom.GeometryLayout.XYZM);
var feature = new ol.Feature(geometry);
feature.setValues(values);
return feature;
};
/**
* @const
* @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>}
* @private
*/
ol.format.GPX.FEATURE_READER_ = {
'rte': ol.format.GPX.readRte_,
'trk': ol.format.GPX.readTrk_,
'wpt': ol.format.GPX.readWpt_
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.GPX_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_),
'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_),
'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.LINK_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'text':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'),
'type':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType')
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.RTE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'number':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'rtept': ol.format.GPX.parseRtePt_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRK_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'number':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'trkseg': ol.format.GPX.parseTrkSeg_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'trkpt': ol.format.GPX.parseTrkPt_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.WPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime),
'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'sat': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'ageofdgpsdata':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'dgpsid':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger)
});
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readFeatureFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
if (goog.array.indexOf(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI) ==
-1) {
return null;
}
var featureReader = ol.format.GPX.FEATURE_READER_[node.localName];
if (!goog.isDef(featureReader)) {
return null;
}
var feature = featureReader(node, []);
if (!goog.isDef(feature)) {
return null;
}
return feature;
};
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readFeaturesFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
if (goog.array.indexOf(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI) ==
-1) {
return [];
}
if (node.localName == 'gpx') {
var features = ol.xml.pushAndParse(/** @type {Array.<ol.Feature>} */ ([]),
ol.format.GPX.GPX_PARSERS_, node, []);
if (goog.isDef(features)) {
return features;
} else {
return [];
}
}
return [];
};
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readProjectionFromDocument = function(doc) {
return ol.proj.get('EPSG:4326');
};
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readProjectionFromNode = function(node) {
return ol.proj.get('EPSG:4326');
};
+83
View File
@@ -0,0 +1,83 @@
goog.provide('ol.format.XSD');
goog.require('goog.string');
goog.require('ol.xml');
/**
* @const
* @type {string}
*/
ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';
/**
* @param {Node} node Node.
* @return {number|undefined} DateTime.
*/
ol.format.XSD.readDateTime = function(node) {
var s = ol.xml.getAllTextContent(node, false);
var re =
/^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/;
var m = re.exec(s);
if (m) {
var year = parseInt(m[1], 10);
var month = parseInt(m[2], 10) - 1;
var day = parseInt(m[3], 10);
var hour = parseInt(m[4], 10);
var minute = parseInt(m[5], 10);
var second = parseInt(m[6], 10);
var dateTime = Date.UTC(year, month, day, hour, minute, second, 0) / 1000;
if (m[7] != 'Z') {
var sign = m[8] == '-' ? -1 : 1;
dateTime += sign * 60 * parseInt(m[9], 10);
if (goog.isDef(m[10])) {
dateTime += sign * 60 * 60 * parseInt(m[10], 10);
}
}
return dateTime;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {number|undefined} Decimal.
*/
ol.format.XSD.readDecimal = function(node) {
// FIXME check spec
var s = ol.xml.getAllTextContent(node, false);
var m = /^\s*([+\-]?\d+(?:\.\d*)?)\s*$/.exec(s);
if (m) {
return parseFloat(m[1]);
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {number|undefined} Decimal.
*/
ol.format.XSD.readNonNegativeInteger = function(node) {
var s = ol.xml.getAllTextContent(node, false);
var m = /^\s*(\d+)\s*$/.exec(s);
if (m) {
return parseInt(m[1], 10);
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {string|undefined} String.
*/
ol.format.XSD.readString = function(node) {
var s = ol.xml.getAllTextContent(node, false);
return goog.string.trim(s);
};
@@ -52,6 +52,12 @@ ol.interaction.DragAndDrop = function(opt_options) {
*/
this.layer_ = goog.isDef(options.layer) ? options.layer : null;
/**
* @private
* @type {ol.feature.StyleFunction|undefined}
*/
this.styleFunction_ = options.styleFunction;
/**
* @private
* @type {goog.events.FileDropHandler}
@@ -149,6 +155,7 @@ ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) {
}
if (goog.isNull(this.layer_)) {
map.getLayers().push(new ol.layer.Vector({
styleFunction: this.styleFunction_,
source: source
}));
}
+1
View File
@@ -0,0 +1 @@
@exportSymbol ol.source.GPX
+32
View File
@@ -0,0 +1,32 @@
goog.provide('ol.source.GPX');
goog.require('ol.format.GPX');
goog.require('ol.source.VectorFile');
/**
* @constructor
* @extends {ol.source.VectorFile}
* @param {olx.source.GPXOptions=} opt_options Options.
*/
ol.source.GPX = 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.GPX(),
logo: options.logo,
node: options.node,
projection: options.projection,
reprojectTo: options.reprojectTo,
text: options.text,
url: options.url,
urls: options.urls
});
};
goog.inherits(ol.source.GPX, ol.source.VectorFile);