Merge pull request #3401 from tschaub/geojson-orientation

Allow GeoJSON to be serialized according to the right-hand rule.
This commit is contained in:
Tim Schaub
2015-03-26 08:44:57 -06:00
10 changed files with 427 additions and 36 deletions

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

@@ -29,22 +29,34 @@ ol.geom.flat.orient.linearRingIsClockwise =
/**
* Determines if linear rings are oriented. By default, left-hand orientation
* is tested (first ring must be clockwise, remaining rings counter-clockwise).
* To test for right-hand orientation, use the `opt_right` argument.
*
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {Array.<number>} ends Array of end indexes.
* @param {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false`
* otherwise.
* @param {boolean=} opt_right Test for right-hand orientation
* (counter-clockwise exterior ring and clockwise interior rings).
* @return {boolean} Rings are correctly oriented.
*/
ol.geom.flat.orient.linearRingsAreOriented =
function(flatCoordinates, offset, ends, stride) {
function(flatCoordinates, offset, ends, stride, opt_right) {
var right = goog.isDef(opt_right) ? opt_right : false;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride);
if (i === 0 ? !isClockwise : isClockwise) {
return false;
if (i === 0) {
if ((right && isClockwise) || (!right && !isClockwise)) {
return false;
}
} else {
if ((right && !isClockwise) || (!right && isClockwise)) {
return false;
}
}
offset = end;
}
@@ -53,19 +65,24 @@ ol.geom.flat.orient.linearRingsAreOriented =
/**
* Determines if linear rings are oriented. By default, left-hand orientation
* is tested (first ring must be clockwise, remaining rings counter-clockwise).
* To test for right-hand orientation, use the `opt_right` argument.
*
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {Array.<Array.<number>>} endss Array of array of end indexes.
* @param {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false`
* otherwise.
* @param {boolean=} opt_right Test for right-hand orientation
* (counter-clockwise exterior ring and clockwise interior rings).
* @return {boolean} Rings are correctly oriented.
*/
ol.geom.flat.linearRingssAreOriented =
function(flatCoordinates, offset, endss, stride) {
ol.geom.flat.orient.linearRingssAreOriented =
function(flatCoordinates, offset, endss, stride, opt_right) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
if (!ol.geom.flat.orient.linearRingsAreOriented(
flatCoordinates, offset, endss[i], stride)) {
flatCoordinates, offset, endss[i], stride, opt_right)) {
return false;
}
}
@@ -74,20 +91,29 @@ ol.geom.flat.linearRingssAreOriented =
/**
* Orient coordinates in a flat array of linear rings. By default, rings
* are oriented following the left-hand rule (clockwise for exterior and
* counter-clockwise for interior rings). To orient according to the
* right-hand rule, use the `opt_right` argument.
*
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {boolean=} opt_right Follow the right-hand rule for orientation.
* @return {number} End.
*/
ol.geom.flat.orient.orientLinearRings =
function(flatCoordinates, offset, ends, stride) {
function(flatCoordinates, offset, ends, stride, opt_right) {
var right = goog.isDef(opt_right) ? opt_right : false;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride);
var reverse = i === 0 ? !isClockwise : isClockwise;
var reverse = i === 0 ?
(right && isClockwise) || (!right && !isClockwise) :
(right && !isClockwise) || (!right && isClockwise);
if (reverse) {
ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride);
}
@@ -98,18 +124,24 @@ ol.geom.flat.orient.orientLinearRings =
/**
* Orient coordinates in a flat array of linear rings. By default, rings
* are oriented following the left-hand rule (clockwise for exterior and
* counter-clockwise for interior rings). To orient according to the
* right-hand rule, use the `opt_right` argument.
*
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {Array.<Array.<number>>} endss Array of array of end indexes.
* @param {number} stride Stride.
* @param {boolean=} opt_right Follow the right-hand rule for orientation.
* @return {number} End.
*/
ol.geom.flat.orient.orientLinearRingss =
function(flatCoordinates, offset, endss, stride) {
function(flatCoordinates, offset, endss, stride, opt_right) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
offset = ol.geom.flat.orient.orientLinearRings(
flatCoordinates, offset, endss[i], stride);
flatCoordinates, offset, endss[i], stride, opt_right);
}
return offset;
};

View File

@@ -162,12 +162,30 @@ ol.geom.MultiPolygon.prototype.getArea = function() {
/**
* Get the coordinate array for this geometry. This array has the structure
* of a GeoJSON coordinate array for multi-polygons.
*
* @param {boolean=} opt_right Orient coordinates according to the right-hand
* rule (counter-clockwise for exterior and clockwise for interior rings).
* If `false`, coordinates will be oriented according to the left-hand rule
* (clockwise for exterior and counter-clockwise for interior rings).
* By default, coordinate orientation will depend on how the geometry was
* constructed.
* @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates.
* @api stable
*/
ol.geom.MultiPolygon.prototype.getCoordinates = function() {
ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) {
var flatCoordinates;
if (goog.isDef(opt_right)) {
flatCoordinates = this.getOrientedFlatCoordinates().slice();
ol.geom.flat.orient.orientLinearRingss(
flatCoordinates, 0, this.endss_, this.stride, opt_right);
} else {
flatCoordinates = this.flatCoordinates;
}
return ol.geom.flat.inflate.coordinatesss(
this.flatCoordinates, 0, this.endss_, this.stride);
flatCoordinates, 0, this.endss_, this.stride);
};
@@ -213,7 +231,7 @@ ol.geom.MultiPolygon.prototype.getInteriorPoints = function() {
ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() {
if (this.orientedRevision_ != this.getRevision()) {
var flatCoordinates = this.flatCoordinates;
if (ol.geom.flat.linearRingssAreOriented(
if (ol.geom.flat.orient.linearRingssAreOriented(
flatCoordinates, 0, this.endss_, this.stride)) {
this.orientedFlatCoordinates_ = flatCoordinates;
} else {

View File

@@ -151,12 +151,30 @@ ol.geom.Polygon.prototype.getArea = function() {
/**
* Get the coordinate array for this geometry. This array has the structure
* of a GeoJSON coordinate array for polygons.
*
* @param {boolean=} opt_right Orient coordinates according to the right-hand
* rule (counter-clockwise for exterior and clockwise for interior rings).
* If `false`, coordinates will be oriented according to the left-hand rule
* (clockwise for exterior and counter-clockwise for interior rings).
* By default, coordinate orientation will depend on how the geometry was
* constructed.
* @return {Array.<Array.<ol.Coordinate>>} Coordinates.
* @api stable
*/
ol.geom.Polygon.prototype.getCoordinates = function() {
ol.geom.Polygon.prototype.getCoordinates = function(opt_right) {
var flatCoordinates;
if (goog.isDef(opt_right)) {
flatCoordinates = this.getOrientedFlatCoordinates().slice();
ol.geom.flat.orient.orientLinearRings(
flatCoordinates, 0, this.ends_, this.stride, opt_right);
} else {
flatCoordinates = this.flatCoordinates;
}
return ol.geom.flat.inflate.coordinatess(
this.flatCoordinates, 0, this.ends_, this.stride);
flatCoordinates, 0, this.ends_, this.stride);
};