Merge pull request #6155 from romanzoller/gpx-geometry-layout

Set GeometryLayout correctly when reading GPX
This commit is contained in:
Bart van den Eijnden
2016-11-23 08:52:26 +01:00
committed by GitHub
3 changed files with 90 additions and 27 deletions

View File

@@ -66,12 +66,13 @@ ol.format.GPX.SCHEMA_LOCATION_ = 'http://www.topografix.com/GPX/1/1 ' +
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {ol.LayoutOptions} layoutOptions Layout options.
* @param {Node} node Node.
* @param {Object} values Values.
* @private
* @return {Array.<number>} Flat coordinates.
*/
ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
ol.format.GPX.appendCoordinate_ = function(flatCoordinates, layoutOptions, node, values) {
ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,
'node.nodeType should be ELEMENT');
flatCoordinates.push(
@@ -80,12 +81,14 @@ ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
if ('ele' in values) {
flatCoordinates.push(/** @type {number} */ (values['ele']));
delete values['ele'];
layoutOptions.hasZ = true;
} else {
flatCoordinates.push(0);
}
if ('time' in values) {
flatCoordinates.push(/** @type {number} */ (values['time']));
delete values['time'];
layoutOptions.hasM = true;
} else {
flatCoordinates.push(0);
}
@@ -93,6 +96,51 @@ ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
};
/**
* Choose GeometryLayout based on flags in layoutOptions and adjust flatCoordinates
* and ends arrays by shrinking them accordingly (removing unused zero entries).
*
* @param {ol.LayoutOptions} layoutOptions Layout options.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Array.<number>=} ends Ends.
* @return {ol.geom.GeometryLayout} Layout.
*/
ol.format.GPX.applyLayoutOptions_ = function(layoutOptions, flatCoordinates, ends) {
var layout = ol.geom.GeometryLayout.XY;
var stride = 2;
if (layoutOptions.hasZ && layoutOptions.hasM) {
layout = ol.geom.GeometryLayout.XYZM;
stride = 4;
} else if (layoutOptions.hasZ) {
layout = ol.geom.GeometryLayout.XYZ;
stride = 3;
} else if (layoutOptions.hasM) {
layout = ol.geom.GeometryLayout.XYM;
stride = 3;
}
if (stride !== 4) {
var i, ii;
for (i = 0, ii = flatCoordinates.length / 4; i < ii; i++) {
flatCoordinates[i * stride] = flatCoordinates[i * 4];
flatCoordinates[i * stride + 1] = flatCoordinates[i * 4 + 1];
if (layoutOptions.hasZ) {
flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 2];
}
if (layoutOptions.hasM) {
flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 3];
}
}
flatCoordinates.length = flatCoordinates.length / 4 * stride;
if (ends) {
for (i = 0, ii = ends.length; i < ii; i++) {
ends[i] = ends[i] / 4 * stride;
}
}
}
return layout;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
@@ -141,7 +189,9 @@ ol.format.GPX.parseRtePt_ = function(node, objectStack) {
var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(rteValues['flatCoordinates']);
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
var layoutOptions = /** @type {ol.LayoutOptions} */
(rteValues['layoutOptions']);
ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);
}
};
@@ -161,7 +211,9 @@ ol.format.GPX.parseTrkPt_ = function(node, objectStack) {
var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(trkValues['flatCoordinates']);
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
var layoutOptions = /** @type {ol.LayoutOptions} */
(trkValues['layoutOptions']);
ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);
}
};
@@ -197,7 +249,8 @@ ol.format.GPX.readRte_ = function(node, objectStack) {
ol.DEBUG && console.assert(node.localName == 'rte', 'localName should be rte');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({
'flatCoordinates': []
'flatCoordinates': [],
'layoutOptions': {}
}, ol.format.GPX.RTE_PARSERS_, node, objectStack);
if (!values) {
return undefined;
@@ -205,8 +258,11 @@ ol.format.GPX.readRte_ = function(node, objectStack) {
var flatCoordinates = /** @type {Array.<number>} */
(values['flatCoordinates']);
delete values['flatCoordinates'];
var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);
delete values['layoutOptions'];
var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates);
var geometry = new ol.geom.LineString(null);
geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
geometry.setFlatCoordinates(layout, flatCoordinates);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);
@@ -227,7 +283,8 @@ ol.format.GPX.readTrk_ = function(node, objectStack) {
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({
'flatCoordinates': [],
'ends': []
'ends': [],
'layoutOptions': {}
}, ol.format.GPX.TRK_PARSERS_, node, objectStack);
if (!values) {
return undefined;
@@ -237,9 +294,11 @@ ol.format.GPX.readTrk_ = function(node, objectStack) {
delete values['flatCoordinates'];
var ends = /** @type {Array.<number>} */ (values['ends']);
delete values['ends'];
var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);
delete values['layoutOptions'];
var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates, ends);
var geometry = new ol.geom.MultiLineString(null);
geometry.setFlatCoordinates(
ol.geom.GeometryLayout.XYZM, flatCoordinates, ends);
geometry.setFlatCoordinates(layout, flatCoordinates, ends);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);
@@ -263,9 +322,10 @@ ol.format.GPX.readWpt_ = function(node, objectStack) {
if (!values) {
return undefined;
}
var coordinates = ol.format.GPX.appendCoordinate_([], node, values);
var geometry = new ol.geom.Point(
coordinates, ol.geom.GeometryLayout.XYZM);
var layoutOptions = /** @type {ol.LayoutOptions} */ ({});
var coordinates = ol.format.GPX.appendCoordinate_([], layoutOptions, node, values);
var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, coordinates);
var geometry = new ol.geom.Point(coordinates, layout);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);

View File

@@ -311,6 +311,12 @@ ol.KMLGxTrackObject_;
ol.LayerState;
/**
* @typedef {{hasZ: (boolean|undefined), hasM: (boolean|undefined)}}
*/
ol.LayoutOptions;
/**
* A function that takes an {@link ol.Extent} and a resolution as arguments, and
* returns an array of {@link ol.Extent} with the extents to load. Usually this

View File

@@ -42,7 +42,7 @@ describe('ol.format.GPX', function() {
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.LineString);
expect(g.getCoordinates()).to.eql([]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getLayout()).to.be('XY');
});
it('can read and write various rte attributes', function() {
@@ -98,8 +98,8 @@ describe('ol.format.GPX', function() {
expect(f).to.be.an(ol.Feature);
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.LineString);
expect(g.getCoordinates()).to.eql([[2, 1, 0, 0], [4, 3, 0, 0]]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getCoordinates()).to.eql([[2, 1], [4, 3]]);
expect(g.getLayout()).to.be('XY');
var serialized = format.writeFeaturesNode(fs);
expect(serialized).to.xmleql(ol.xml.parse(text));
});
@@ -124,11 +124,9 @@ describe('ol.format.GPX', function() {
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.LineString);
var p1 = ol.proj.transform([2, 1], 'EPSG:4326', 'EPSG:3857');
p1.push(0, 0);
var p2 = ol.proj.transform([6, 5], 'EPSG:4326', 'EPSG:3857');
p2.push(0, 0);
expect(g.getCoordinates()).to.eql([p1, p2]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getLayout()).to.be('XY');
var serialized = format.writeFeaturesNode(fs, {
featureProjection: 'EPSG:3857'
});
@@ -168,7 +166,7 @@ describe('ol.format.GPX', function() {
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.MultiLineString);
expect(g.getCoordinates()).to.eql([]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getLayout()).to.be('XY');
});
it('can read and write various trk attributes', function() {
@@ -224,7 +222,7 @@ describe('ol.format.GPX', function() {
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.MultiLineString);
expect(g.getCoordinates()).to.eql([[]]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getLayout()).to.be('XY');
var serialized = format.writeFeaturesNode(fs);
expect(serialized).to.xmleql(ol.xml.parse(text));
});
@@ -398,8 +396,8 @@ describe('ol.format.GPX', function() {
expect(f).to.be.an(ol.Feature);
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.Point);
expect(g.getCoordinates()).to.eql([2, 1, 0, 0]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getCoordinates()).to.eql([2, 1]);
expect(g.getLayout()).to.be('XY');
var serialized = format.writeFeaturesNode(fs);
expect(serialized).to.xmleql(ol.xml.parse(text));
});
@@ -421,9 +419,8 @@ describe('ol.format.GPX', function() {
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.Point);
var expectedPoint = ol.proj.transform([2, 1], 'EPSG:4326', 'EPSG:3857');
expectedPoint.push(0, 0);
expect(g.getCoordinates()).to.eql(expectedPoint);
expect(g.getLayout()).to.be('XYZM');
expect(g.getLayout()).to.be('XY');
var serialized = format.writeFeaturesNode(fs, {
featureProjection: 'EPSG:3857'
});
@@ -446,8 +443,8 @@ describe('ol.format.GPX', function() {
expect(f).to.be.an(ol.Feature);
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.Point);
expect(g.getCoordinates()).to.eql([2, 1, 3, 0]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getCoordinates()).to.eql([2, 1, 3]);
expect(g.getLayout()).to.be('XYZ');
var serialized = format.writeFeaturesNode(fs);
expect(serialized).to.xmleql(ol.xml.parse(text));
});
@@ -468,8 +465,8 @@ describe('ol.format.GPX', function() {
expect(f).to.be.an(ol.Feature);
var g = f.getGeometry();
expect(g).to.be.an(ol.geom.Point);
expect(g.getCoordinates()).to.eql([2, 1, 0, 1263115752]);
expect(g.getLayout()).to.be('XYZM');
expect(g.getCoordinates()).to.eql([2, 1, 1263115752]);
expect(g.getLayout()).to.be('XYM');
var serialized = format.writeFeaturesNode(fs);
expect(serialized).to.xmleql(ol.xml.parse(text));
});