Allow orienting with the right-hand rule

This commit is contained in:
Tim Schaub
2015-03-25 16:47:58 -06:00
parent 5f6ceff3a7
commit ce36947bdb
2 changed files with 186 additions and 17 deletions

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 {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset. * @param {number} offset Offset.
* @param {Array.<number>} ends Ends. * @param {Array.<number>} ends Array of end indexes.
* @param {number} stride Stride. * @param {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false` * @param {boolean=} opt_right Test for right-hand orientation
* otherwise. * (counter-clockwise exterior ring and clockwise interior rings).
* @return {boolean} Rings are correctly oriented.
*/ */
ol.geom.flat.orient.linearRingsAreOriented = 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; var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) { for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i]; var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride); flatCoordinates, offset, end, stride);
if (i === 0 ? !isClockwise : isClockwise) { if (i === 0) {
return false; if ((right && isClockwise) || (!right && !isClockwise)) {
return false;
}
} else {
if ((right && !isClockwise) || (!right && isClockwise)) {
return false;
}
} }
offset = end; 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 {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset. * @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 {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false` * @param {boolean=} opt_right Test for right-hand orientation
* otherwise. * (counter-clockwise exterior ring and clockwise interior rings).
* @return {boolean} Rings are correctly oriented.
*/ */
ol.geom.flat.orient.linearRingssAreOriented = ol.geom.flat.orient.linearRingssAreOriented =
function(flatCoordinates, offset, endss, stride) { function(flatCoordinates, offset, endss, stride, opt_right) {
var i, ii; var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) { for (i = 0, ii = endss.length; i < ii; ++i) {
if (!ol.geom.flat.orient.linearRingsAreOriented( if (!ol.geom.flat.orient.linearRingsAreOriented(
flatCoordinates, offset, endss[i], stride)) { flatCoordinates, offset, endss[i], stride, opt_right)) {
return false; return false;
} }
} }
@@ -74,20 +91,29 @@ ol.geom.flat.orient.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 {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset. * @param {number} offset Offset.
* @param {Array.<number>} ends Ends. * @param {Array.<number>} ends Ends.
* @param {number} stride Stride. * @param {number} stride Stride.
* @param {boolean=} opt_right Follow the right-hand rule for orientation.
* @return {number} End. * @return {number} End.
*/ */
ol.geom.flat.orient.orientLinearRings = 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; var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) { for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i]; var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride); flatCoordinates, offset, end, stride);
var reverse = i === 0 ? !isClockwise : isClockwise; var reverse = i === 0 ?
(right && isClockwise) || (!right && !isClockwise) :
(right && !isClockwise) || (!right && isClockwise);
if (reverse) { if (reverse) {
ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride); 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 {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset. * @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 {number} stride Stride.
* @param {boolean=} opt_right Follow the right-hand rule for orientation.
* @return {number} End. * @return {number} End.
*/ */
ol.geom.flat.orient.orientLinearRingss = ol.geom.flat.orient.orientLinearRingss =
function(flatCoordinates, offset, endss, stride) { function(flatCoordinates, offset, endss, stride, opt_right) {
var i, ii; var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) { for (i = 0, ii = endss.length; i < ii; ++i) {
offset = ol.geom.flat.orient.orientLinearRings( offset = ol.geom.flat.orient.orientLinearRings(
flatCoordinates, offset, endss[i], stride); flatCoordinates, offset, endss[i], stride, opt_right);
} }
return offset; return offset;
}; };

View File

@@ -2,7 +2,7 @@ goog.provide('ol.test.geom.flat.orient');
describe('ol.geom.flat.orient', function() { describe('ol.geom.flat.orient', function() {
describe('ol.geom.flat.orient.linearRingIsClockwise', function() { describe('ol.geom.flat.orient.linearRingIsClockwise()', function() {
it('identifies clockwise rings', function() { it('identifies clockwise rings', function() {
var flatCoordinates = [0, 1, 1, 4, 4, 3, 3, 0]; var flatCoordinates = [0, 1, 1, 4, 4, 3, 3, 0];
@@ -20,6 +20,143 @@ describe('ol.geom.flat.orient', function() {
}); });
describe('ol.geom.flat.orient.linearRingsAreOriented()', function() {
var oriented = ol.geom.flat.orient.linearRingsAreOriented;
var rightCoords = [
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45
];
var leftCoords = [
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45
];
var ends = [10, 20];
it('checks for left-hand orientation by default', function() {
expect(oriented(rightCoords, 0, ends, 2)).to.be(false);
expect(oriented(leftCoords, 0, ends, 2)).to.be(true);
});
it('can check for right-hand orientation', function() {
expect(oriented(rightCoords, 0, ends, 2, true)).to.be(true);
expect(oriented(leftCoords, 0, ends, 2, true)).to.be(false);
});
});
describe('ol.geom.flat.orient.linearRingssAreOriented()', function() {
var oriented = ol.geom.flat.orient.linearRingssAreOriented;
var rightCoords = [
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45,
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45
];
var leftCoords = [
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45,
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45
];
var ends = [[10, 20], [30, 40]];
it('checks for left-hand orientation by default', function() {
expect(oriented(rightCoords, 0, ends, 2)).to.be(false);
expect(oriented(leftCoords, 0, ends, 2)).to.be(true);
});
it('can check for right-hand orientation', function() {
expect(oriented(rightCoords, 0, ends, 2, true)).to.be(true);
expect(oriented(leftCoords, 0, ends, 2, true)).to.be(false);
});
});
describe('ol.geom.flat.orient.orientLinearRings()', function() {
var orient = ol.geom.flat.orient.orientLinearRings;
var rightCoords = [
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45
];
var leftCoords = [
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45
];
var ends = [10, 20];
it('orients using the left-hand rule by default', function() {
var rightClone = rightCoords.slice();
orient(rightClone, 0, ends, 2);
expect(rightClone).to.eql(leftCoords);
var leftClone = leftCoords.slice();
orient(leftClone, 0, ends, 2);
expect(leftClone).to.eql(leftCoords);
});
it('can orient using the right-hand rule', function() {
var rightClone = rightCoords.slice();
orient(rightClone, 0, ends, 2, true);
expect(rightClone).to.eql(rightCoords);
var leftClone = leftCoords.slice();
orient(leftClone, 0, ends, 2, true);
expect(leftClone).to.eql(rightCoords);
});
});
describe('ol.geom.flat.orient.orientLinearRingss()', function() {
var orient = ol.geom.flat.orient.orientLinearRingss;
var rightCoords = [
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45,
-180, -90, 180, -90, 180, 90, -180, 90, -180, -90,
-100, -45, -100, 45, 100, 45, 100, -45, -100, -45
];
var leftCoords = [
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45,
-180, -90, -180, 90, 180, 90, 180, -90, -180, -90,
-100, -45, 100, -45, 100, 45, -100, 45, -100, -45
];
var ends = [[10, 20], [30, 40]];
it('orients using the left-hand rule by default', function() {
var rightClone = rightCoords.slice();
orient(rightClone, 0, ends, 2);
expect(rightClone).to.eql(leftCoords);
var leftClone = leftCoords.slice();
orient(leftClone, 0, ends, 2);
expect(leftClone).to.eql(leftCoords);
});
it('can orient using the right-hand rule', function() {
var rightClone = rightCoords.slice();
orient(rightClone, 0, ends, 2, true);
expect(rightClone).to.eql(rightCoords);
var leftClone = leftCoords.slice();
orient(leftClone, 0, ends, 2, true);
expect(leftClone).to.eql(rightCoords);
});
});
}); });
goog.require('ol.geom.flat.orient'); goog.require('ol.geom.flat.orient');