Allow orienting coordinates when serializing GeoJSON

This commit is contained in:
Tim Schaub
2015-03-25 18:32:31 -06:00
parent 5d590bcf95
commit be0c9f3c8a
4 changed files with 149 additions and 13 deletions

View File

@@ -1538,7 +1538,8 @@ olx.format;
/**
* @typedef {{dataProjection: ol.proj.ProjectionLike,
* featureProjection: ol.proj.ProjectionLike}}
* featureProjection: ol.proj.ProjectionLike,
* rightHanded: (boolean|undefined)}}
* @api
*/
olx.format.ReadOptions;
@@ -1567,7 +1568,8 @@ olx.format.ReadOptions.prototype.featureProjection;
/**
* @typedef {{dataProjection: ol.proj.ProjectionLike,
* featureProjection: ol.proj.ProjectionLike}}
* featureProjection: ol.proj.ProjectionLike,
* rightHanded: (boolean|undefined)}}
* @api
*/
olx.format.WriteOptions;
@@ -1593,6 +1595,22 @@ olx.format.WriteOptions.prototype.dataProjection;
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,
* geometryName: (string|undefined)}}

View File

@@ -68,7 +68,8 @@ ol.format.Feature.prototype.adaptOptions = function(options) {
updatedOptions = {
featureProjection: options.featureProjection,
dataProjection: goog.isDefAndNotNull(options.dataProjection) ?
options.dataProjection : this.defaultDataProjection
options.dataProjection : this.defaultDataProjection,
rightHanded: options.rightHanded
};
}
return updatedOptions;

View File

@@ -178,7 +178,8 @@ ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
goog.asserts.assert(goog.isDef(geometryWriter));
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 {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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);
return /** @type {GeoJSONGeometry} */ ({
'type': 'LineString',
@@ -231,10 +233,12 @@ ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry) {
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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.assert(
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 {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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);
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPoint',
@@ -261,24 +266,30 @@ ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry) {
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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);
var right;
if (goog.isDef(opt_options)) {
right = opt_options.rightHanded;
}
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPolygon',
'coordinates': geometry.getCoordinates()
'coordinates': geometry.getCoordinates(right)
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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);
return /** @type {GeoJSONGeometry} */ ({
'type': 'Point',
@@ -289,14 +300,19 @@ ol.format.GeoJSON.writePointGeometry_ = function(geometry) {
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @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);
var right;
if (goog.isDef(opt_options)) {
right = opt_options.rightHanded;
}
return /** @type {GeoJSONGeometry} */ ({
'type': 'Polygon',
'coordinates': geometry.getCoordinates()
'coordinates': geometry.getCoordinates(right)
});
};
@@ -320,7 +336,7 @@ ol.format.GeoJSON.GEOMETRY_READERS_ = {
/**
* @const
* @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_ = {
'Point': ol.format.GeoJSON.writePointGeometry_,

View File

@@ -558,6 +558,106 @@ describe('ol.format.GeoJSON', function() {
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() {
var collection = new ol.geom.GeometryCollection([
new ol.geom.Point([10, 20]),
@@ -611,6 +711,7 @@ goog.require('ol.geom.Circle');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.LineString');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');