Allow orienting coordinates when serializing GeoJSON
This commit is contained in:
+20
-2
@@ -1538,7 +1538,8 @@ olx.format;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{dataProjection: ol.proj.ProjectionLike,
|
* @typedef {{dataProjection: ol.proj.ProjectionLike,
|
||||||
* featureProjection: ol.proj.ProjectionLike}}
|
* featureProjection: ol.proj.ProjectionLike,
|
||||||
|
* rightHanded: (boolean|undefined)}}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
olx.format.ReadOptions;
|
olx.format.ReadOptions;
|
||||||
@@ -1567,7 +1568,8 @@ olx.format.ReadOptions.prototype.featureProjection;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{dataProjection: ol.proj.ProjectionLike,
|
* @typedef {{dataProjection: ol.proj.ProjectionLike,
|
||||||
* featureProjection: ol.proj.ProjectionLike}}
|
* featureProjection: ol.proj.ProjectionLike,
|
||||||
|
* rightHanded: (boolean|undefined)}}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
olx.format.WriteOptions;
|
olx.format.WriteOptions;
|
||||||
@@ -1593,6 +1595,22 @@ olx.format.WriteOptions.prototype.dataProjection;
|
|||||||
olx.format.WriteOptions.prototype.featureProjection;
|
olx.format.WriteOptions.prototype.featureProjection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When writing geometries, follow the right-hand rule for linear ring
|
||||||
|
* orientation. This means that polygons will have counter-clockwise exterior
|
||||||
|
* rings and clockwise interior rings. By default, coordinates are serialized
|
||||||
|
* as they are provided at construction. If `true`, the right-hand rule will
|
||||||
|
* be applied. If `false`, the left-hand rule will be applied (clockwise for
|
||||||
|
* exterior and counter-clockwise for interior rings). Note that not all
|
||||||
|
* formats support this. The GeoJSON format does use this property when writing
|
||||||
|
* geometries.
|
||||||
|
*
|
||||||
|
* @type {boolean|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.format.WriteOptions.prototype.rightHanded;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{defaultDataProjection: ol.proj.ProjectionLike,
|
* @typedef {{defaultDataProjection: ol.proj.ProjectionLike,
|
||||||
* geometryName: (string|undefined)}}
|
* geometryName: (string|undefined)}}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ ol.format.Feature.prototype.adaptOptions = function(options) {
|
|||||||
updatedOptions = {
|
updatedOptions = {
|
||||||
featureProjection: options.featureProjection,
|
featureProjection: options.featureProjection,
|
||||||
dataProjection: goog.isDefAndNotNull(options.dataProjection) ?
|
dataProjection: goog.isDefAndNotNull(options.dataProjection) ?
|
||||||
options.dataProjection : this.defaultDataProjection
|
options.dataProjection : this.defaultDataProjection,
|
||||||
|
rightHanded: options.rightHanded
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return updatedOptions;
|
return updatedOptions;
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
|
|||||||
var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
|
var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
|
||||||
goog.asserts.assert(goog.isDef(geometryWriter));
|
goog.asserts.assert(goog.isDef(geometryWriter));
|
||||||
return geometryWriter(/** @type {ol.geom.Geometry} */ (
|
return geometryWriter(/** @type {ol.geom.Geometry} */ (
|
||||||
ol.format.Feature.transformWithOptions(geometry, true, opt_options)));
|
ol.format.Feature.transformWithOptions(geometry, true, opt_options)),
|
||||||
|
opt_options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -217,10 +218,11 @@ ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
|
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
|
||||||
return /** @type {GeoJSONGeometry} */ ({
|
return /** @type {GeoJSONGeometry} */ ({
|
||||||
'type': 'LineString',
|
'type': 'LineString',
|
||||||
@@ -231,10 +233,12 @@ ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writeMultiLineStringGeometry_ =
|
||||||
|
function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString);
|
goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString);
|
||||||
goog.asserts.assert(
|
goog.asserts.assert(
|
||||||
geometry.getType() == ol.geom.GeometryType.MULTI_LINE_STRING);
|
geometry.getType() == ol.geom.GeometryType.MULTI_LINE_STRING);
|
||||||
@@ -247,10 +251,11 @@ ol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint);
|
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint);
|
||||||
return /** @type {GeoJSONGeometry} */ ({
|
return /** @type {GeoJSONGeometry} */ ({
|
||||||
'type': 'MultiPoint',
|
'type': 'MultiPoint',
|
||||||
@@ -261,24 +266,30 @@ ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon);
|
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon);
|
||||||
|
var right;
|
||||||
|
if (goog.isDef(opt_options)) {
|
||||||
|
right = opt_options.rightHanded;
|
||||||
|
}
|
||||||
return /** @type {GeoJSONGeometry} */ ({
|
return /** @type {GeoJSONGeometry} */ ({
|
||||||
'type': 'MultiPolygon',
|
'type': 'MultiPolygon',
|
||||||
'coordinates': geometry.getCoordinates()
|
'coordinates': geometry.getCoordinates(right)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writePointGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
|
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
|
||||||
return /** @type {GeoJSONGeometry} */ ({
|
return /** @type {GeoJSONGeometry} */ ({
|
||||||
'type': 'Point',
|
'type': 'Point',
|
||||||
@@ -289,14 +300,19 @@ ol.format.GeoJSON.writePointGeometry_ = function(geometry) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.geom.Geometry} geometry Geometry.
|
* @param {ol.geom.Geometry} geometry Geometry.
|
||||||
|
* @param {olx.format.WriteOptions=} opt_options Write options.
|
||||||
* @private
|
* @private
|
||||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.writePolygonGeometry_ = function(geometry) {
|
ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) {
|
||||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||||
|
var right;
|
||||||
|
if (goog.isDef(opt_options)) {
|
||||||
|
right = opt_options.rightHanded;
|
||||||
|
}
|
||||||
return /** @type {GeoJSONGeometry} */ ({
|
return /** @type {GeoJSONGeometry} */ ({
|
||||||
'type': 'Polygon',
|
'type': 'Polygon',
|
||||||
'coordinates': geometry.getCoordinates()
|
'coordinates': geometry.getCoordinates(right)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -320,7 +336,7 @@ ol.format.GeoJSON.GEOMETRY_READERS_ = {
|
|||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
* @private
|
* @private
|
||||||
* @type {Object.<string, function(ol.geom.Geometry): (GeoJSONGeometry|GeoJSONGeometryCollection)>}
|
* @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>}
|
||||||
*/
|
*/
|
||||||
ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
|
ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
|
||||||
'Point': ol.format.GeoJSON.writePointGeometry_,
|
'Point': ol.format.GeoJSON.writePointGeometry_,
|
||||||
|
|||||||
@@ -558,6 +558,106 @@ describe('ol.format.GeoJSON', function() {
|
|||||||
format.readGeometry(geojson).getCoordinates());
|
format.readGeometry(geojson).getCoordinates());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('maintains coordinate order by default', function() {
|
||||||
|
|
||||||
|
var cw = [[-180, -90], [-180, 90], [180, 90], [180, -90], [-180, -90]];
|
||||||
|
var ccw = [[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]];
|
||||||
|
|
||||||
|
var right = new ol.geom.Polygon([ccw, cw]);
|
||||||
|
var rightMulti = new ol.geom.MultiPolygon([[ccw, cw]]);
|
||||||
|
var left = new ol.geom.Polygon([cw, ccw]);
|
||||||
|
var leftMulti = new ol.geom.MultiPolygon([[cw, ccw]]);
|
||||||
|
|
||||||
|
var rightObj = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [ccw, cw]
|
||||||
|
};
|
||||||
|
|
||||||
|
var rightMultiObj = {
|
||||||
|
type: 'MultiPolygon',
|
||||||
|
coordinates: [[ccw, cw]]
|
||||||
|
};
|
||||||
|
|
||||||
|
var leftObj = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [cw, ccw]
|
||||||
|
};
|
||||||
|
|
||||||
|
var leftMultiObj = {
|
||||||
|
type: 'MultiPolygon',
|
||||||
|
coordinates: [[cw, ccw]]
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(JSON.parse(format.writeGeometry(right))).to.eql(rightObj);
|
||||||
|
expect(
|
||||||
|
JSON.parse(format.writeGeometry(rightMulti))).to.eql(rightMultiObj);
|
||||||
|
expect(JSON.parse(format.writeGeometry(left))).to.eql(leftObj);
|
||||||
|
expect(JSON.parse(format.writeGeometry(leftMulti))).to.eql(leftMultiObj);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows serializing following the right-hand rule', function() {
|
||||||
|
|
||||||
|
var cw = [[-180, -90], [-180, 90], [180, 90], [180, -90], [-180, -90]];
|
||||||
|
var ccw = [[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]];
|
||||||
|
var right = new ol.geom.Polygon([ccw, cw]);
|
||||||
|
var rightMulti = new ol.geom.MultiPolygon([[ccw, cw]]);
|
||||||
|
var left = new ol.geom.Polygon([cw, ccw]);
|
||||||
|
var leftMulti = new ol.geom.MultiPolygon([[cw, ccw]]);
|
||||||
|
|
||||||
|
var rightObj = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [ccw, cw]
|
||||||
|
};
|
||||||
|
|
||||||
|
var rightMultiObj = {
|
||||||
|
type: 'MultiPolygon',
|
||||||
|
coordinates: [[ccw, cw]]
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = format.writeGeometry(right, {rightHanded: true});
|
||||||
|
expect(JSON.parse(json)).to.eql(rightObj);
|
||||||
|
json = format.writeGeometry(rightMulti, {rightHanded: true});
|
||||||
|
expect(JSON.parse(json)).to.eql(rightMultiObj);
|
||||||
|
|
||||||
|
json = format.writeGeometry(left, {rightHanded: true});
|
||||||
|
expect(JSON.parse(json)).to.eql(rightObj);
|
||||||
|
json = format.writeGeometry(leftMulti, {rightHanded: true});
|
||||||
|
expect(JSON.parse(json)).to.eql(rightMultiObj);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows serializing following the left-hand rule', function() {
|
||||||
|
|
||||||
|
var cw = [[-180, -90], [-180, 90], [180, 90], [180, -90], [-180, -90]];
|
||||||
|
var ccw = [[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]];
|
||||||
|
var right = new ol.geom.Polygon([ccw, cw]);
|
||||||
|
var rightMulti = new ol.geom.MultiPolygon([[ccw, cw]]);
|
||||||
|
var left = new ol.geom.Polygon([cw, ccw]);
|
||||||
|
var leftMulti = new ol.geom.MultiPolygon([[cw, ccw]]);
|
||||||
|
|
||||||
|
var leftObj = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [cw, ccw]
|
||||||
|
};
|
||||||
|
|
||||||
|
var leftMultiObj = {
|
||||||
|
type: 'MultiPolygon',
|
||||||
|
coordinates: [[cw, ccw]]
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = format.writeGeometry(right, {rightHanded: false});
|
||||||
|
expect(JSON.parse(json)).to.eql(leftObj);
|
||||||
|
json = format.writeGeometry(rightMulti, {rightHanded: false});
|
||||||
|
expect(JSON.parse(json)).to.eql(leftMultiObj);
|
||||||
|
|
||||||
|
json = format.writeGeometry(left, {rightHanded: false});
|
||||||
|
expect(JSON.parse(json)).to.eql(leftObj);
|
||||||
|
json = format.writeGeometry(leftMulti, {rightHanded: false});
|
||||||
|
expect(JSON.parse(json)).to.eql(leftMultiObj);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
it('encodes geometry collection', function() {
|
it('encodes geometry collection', function() {
|
||||||
var collection = new ol.geom.GeometryCollection([
|
var collection = new ol.geom.GeometryCollection([
|
||||||
new ol.geom.Point([10, 20]),
|
new ol.geom.Point([10, 20]),
|
||||||
@@ -611,6 +711,7 @@ goog.require('ol.geom.Circle');
|
|||||||
goog.require('ol.geom.GeometryCollection');
|
goog.require('ol.geom.GeometryCollection');
|
||||||
goog.require('ol.geom.LineString');
|
goog.require('ol.geom.LineString');
|
||||||
goog.require('ol.geom.LinearRing');
|
goog.require('ol.geom.LinearRing');
|
||||||
|
goog.require('ol.geom.MultiPolygon');
|
||||||
goog.require('ol.geom.Point');
|
goog.require('ol.geom.Point');
|
||||||
goog.require('ol.geom.Polygon');
|
goog.require('ol.geom.Polygon');
|
||||||
goog.require('ol.proj');
|
goog.require('ol.proj');
|
||||||
|
|||||||
Reference in New Issue
Block a user