Set GeometryLayout correctly when reading GPX

Fixes #6148
This commit is contained in:
Roman Zoller
2016-11-21 17:47:41 +01:00
parent caef2b51b4
commit f56b2c8a75
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 {Array.<number>} flatCoordinates Flat coordinates.
* @param {ol.LayoutOptions} layoutOptions Layout options.
* @param {Node} node Node. * @param {Node} node Node.
* @param {Object} values Values. * @param {Object} values Values.
* @private * @private
* @return {Array.<number>} Flat coordinates. * @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, ol.DEBUG && console.assert(node.nodeType == Node.ELEMENT_NODE,
'node.nodeType should be ELEMENT'); 'node.nodeType should be ELEMENT');
flatCoordinates.push( flatCoordinates.push(
@@ -80,12 +81,14 @@ ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
if ('ele' in values) { if ('ele' in values) {
flatCoordinates.push(/** @type {number} */ (values['ele'])); flatCoordinates.push(/** @type {number} */ (values['ele']));
delete values['ele']; delete values['ele'];
layoutOptions.hasZ = true;
} else { } else {
flatCoordinates.push(0); flatCoordinates.push(0);
} }
if ('time' in values) { if ('time' in values) {
flatCoordinates.push(/** @type {number} */ (values['time'])); flatCoordinates.push(/** @type {number} */ (values['time']));
delete values['time']; delete values['time'];
layoutOptions.hasM = true;
} else { } else {
flatCoordinates.push(0); 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 {Node} node Node.
* @param {Array.<*>} objectStack Object stack. * @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 rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */ var flatCoordinates = /** @type {Array.<number>} */
(rteValues['flatCoordinates']); (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 trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */ var flatCoordinates = /** @type {Array.<number>} */
(trkValues['flatCoordinates']); (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'); ol.DEBUG && console.assert(node.localName == 'rte', 'localName should be rte');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({ var values = ol.xml.pushParseAndPop({
'flatCoordinates': [] 'flatCoordinates': [],
'layoutOptions': {}
}, ol.format.GPX.RTE_PARSERS_, node, objectStack); }, ol.format.GPX.RTE_PARSERS_, node, objectStack);
if (!values) { if (!values) {
return undefined; return undefined;
@@ -205,8 +258,11 @@ ol.format.GPX.readRte_ = function(node, objectStack) {
var flatCoordinates = /** @type {Array.<number>} */ var flatCoordinates = /** @type {Array.<number>} */
(values['flatCoordinates']); (values['flatCoordinates']);
delete 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); 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); ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry); var feature = new ol.Feature(geometry);
feature.setProperties(values); feature.setProperties(values);
@@ -227,7 +283,8 @@ ol.format.GPX.readTrk_ = function(node, objectStack) {
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({ var values = ol.xml.pushParseAndPop({
'flatCoordinates': [], 'flatCoordinates': [],
'ends': [] 'ends': [],
'layoutOptions': {}
}, ol.format.GPX.TRK_PARSERS_, node, objectStack); }, ol.format.GPX.TRK_PARSERS_, node, objectStack);
if (!values) { if (!values) {
return undefined; return undefined;
@@ -237,9 +294,11 @@ ol.format.GPX.readTrk_ = function(node, objectStack) {
delete values['flatCoordinates']; delete values['flatCoordinates'];
var ends = /** @type {Array.<number>} */ (values['ends']); var ends = /** @type {Array.<number>} */ (values['ends']);
delete 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); var geometry = new ol.geom.MultiLineString(null);
geometry.setFlatCoordinates( geometry.setFlatCoordinates(layout, flatCoordinates, ends);
ol.geom.GeometryLayout.XYZM, flatCoordinates, ends);
ol.format.Feature.transformWithOptions(geometry, false, options); ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry); var feature = new ol.Feature(geometry);
feature.setProperties(values); feature.setProperties(values);
@@ -263,9 +322,10 @@ ol.format.GPX.readWpt_ = function(node, objectStack) {
if (!values) { if (!values) {
return undefined; return undefined;
} }
var coordinates = ol.format.GPX.appendCoordinate_([], node, values); var layoutOptions = /** @type {ol.LayoutOptions} */ ({});
var geometry = new ol.geom.Point( var coordinates = ol.format.GPX.appendCoordinate_([], layoutOptions, node, values);
coordinates, ol.geom.GeometryLayout.XYZM); var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, coordinates);
var geometry = new ol.geom.Point(coordinates, layout);
ol.format.Feature.transformWithOptions(geometry, false, options); ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry); var feature = new ol.Feature(geometry);
feature.setProperties(values); feature.setProperties(values);

View File

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