mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-28 08:23:46 +00:00
Refactor geometric math functions from geo.js to geom.js
This commit is contained in:
@@ -39,15 +39,6 @@ export function geoMetersToLon(m, atLat) {
|
||||
}
|
||||
|
||||
|
||||
export function geoOffsetToMeters(offset, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
return [
|
||||
offset[0] * TAU * EQUATORIAL_RADIUS / tileSize,
|
||||
-offset[1] * TAU * POLAR_RADIUS / tileSize
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
export function geoMetersToOffset(meters, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
return [
|
||||
@@ -57,6 +48,15 @@ export function geoMetersToOffset(meters, tileSize) {
|
||||
}
|
||||
|
||||
|
||||
export function geoOffsetToMeters(offset, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
return [
|
||||
offset[0] * TAU * EQUATORIAL_RADIUS / tileSize,
|
||||
-offset[1] * TAU * POLAR_RADIUS / tileSize
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// Equirectangular approximation of spherical distances on Earth
|
||||
export function geoSphericalDistance(a, b) {
|
||||
var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
|
||||
@@ -65,13 +65,6 @@ export function geoSphericalDistance(a, b) {
|
||||
}
|
||||
|
||||
|
||||
// zoom to scale
|
||||
export function geoZoomToScale(z, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
return tileSize * Math.pow(2, z) / TAU;
|
||||
}
|
||||
|
||||
|
||||
// scale to zoom
|
||||
export function geoScaleToZoom(k, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
@@ -80,203 +73,11 @@ export function geoScaleToZoom(k, tileSize) {
|
||||
}
|
||||
|
||||
|
||||
export function geoEdgeEqual(a, b) {
|
||||
return (a[0] === b[0] && a[1] === b[1]) ||
|
||||
(a[0] === b[1] && a[1] === b[0]);
|
||||
// zoom to scale
|
||||
export function geoZoomToScale(z, tileSize) {
|
||||
tileSize = tileSize || 256;
|
||||
return tileSize * Math.pow(2, z) / TAU;
|
||||
}
|
||||
|
||||
|
||||
// Return the counterclockwise angle in the range (-pi, pi)
|
||||
// between the positive X axis and the line intersecting a and b.
|
||||
export function geoAngle(a, b, projection) {
|
||||
return geoVecAngle(projection(a.loc), projection(b.loc));
|
||||
}
|
||||
|
||||
|
||||
// Rotate all points counterclockwise around a pivot point by given angle
|
||||
export function geoRotate(points, angle, around) {
|
||||
return points.map(function(point) {
|
||||
var radial = [point[0] - around[0], point[1] - around[1]];
|
||||
return [
|
||||
radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
|
||||
radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Choose the edge with the minimal distance from `point` to its orthogonal
|
||||
// projection onto that edge, if such a projection exists, or the distance to
|
||||
// the closest vertex on that edge. Returns an object with the `index` of the
|
||||
// chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
|
||||
export function geoChooseEdge(nodes, point, projection, skipID) {
|
||||
var dist = geoVecLength;
|
||||
var points = nodes.map(function(n) { return projection(n.loc); });
|
||||
var ids = nodes.map(function(n) { return n.id; });
|
||||
var min = Infinity;
|
||||
var idx;
|
||||
var loc;
|
||||
|
||||
for (var i = 0; i < points.length - 1; i++) {
|
||||
if (ids[i] === skipID || ids[i + 1] === skipID) continue;
|
||||
|
||||
var o = points[i];
|
||||
var s = geoVecSubtract(points[i + 1], o);
|
||||
var v = geoVecSubtract(point, o);
|
||||
var proj = geoVecDot(v, s) / geoVecDot(s, s);
|
||||
var p;
|
||||
|
||||
if (proj < 0) {
|
||||
p = o;
|
||||
} else if (proj > 1) {
|
||||
p = points[i + 1];
|
||||
} else {
|
||||
p = [o[0] + proj * s[0], o[1] + proj * s[1]];
|
||||
}
|
||||
|
||||
var d = dist(p, point);
|
||||
if (d < min) {
|
||||
min = d;
|
||||
idx = i + 1;
|
||||
loc = projection.invert(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (idx !== undefined) {
|
||||
return { index: idx, distance: min, loc: loc };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the intersection point of 2 line segments.
|
||||
// From https://github.com/pgkelley4/line-segments-intersect
|
||||
// This uses the vector cross product approach described below:
|
||||
// http://stackoverflow.com/a/565282/786339
|
||||
export function geoLineIntersection(a, b) {
|
||||
var p = [a[0][0], a[0][1]];
|
||||
var p2 = [a[1][0], a[1][1]];
|
||||
var q = [b[0][0], b[0][1]];
|
||||
var q2 = [b[1][0], b[1][1]];
|
||||
var r = geoVecSubtract(p2, p);
|
||||
var s = geoVecSubtract(q2, q);
|
||||
var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
|
||||
var denominator = geoVecCross(r, s);
|
||||
|
||||
if (uNumerator && denominator) {
|
||||
var u = uNumerator / denominator;
|
||||
var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
|
||||
|
||||
if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
|
||||
return geoVecInterp(p, p2, t);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
export function geoPathIntersections(path1, path2) {
|
||||
var intersections = [];
|
||||
for (var i = 0; i < path1.length - 1; i++) {
|
||||
for (var j = 0; j < path2.length - 1; j++) {
|
||||
var a = [ path1[i], path1[i+1] ];
|
||||
var b = [ path2[j], path2[j+1] ];
|
||||
var hit = geoLineIntersection(a, b);
|
||||
if (hit) {
|
||||
intersections.push(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return intersections;
|
||||
}
|
||||
|
||||
|
||||
// Return whether point is contained in polygon.
|
||||
//
|
||||
// `point` should be a 2-item array of coordinates.
|
||||
// `polygon` should be an array of 2-item arrays of coordinates.
|
||||
//
|
||||
// From https://github.com/substack/point-in-polygon.
|
||||
// ray-casting algorithm based on
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
//
|
||||
export function geoPointInPolygon(point, polygon) {
|
||||
var x = point[0];
|
||||
var y = point[1];
|
||||
var inside = false;
|
||||
|
||||
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||||
var xi = polygon[i][0], yi = polygon[i][1];
|
||||
var xj = polygon[j][0], yj = polygon[j][1];
|
||||
|
||||
var intersect = ((yi > y) !== (yj > y)) &&
|
||||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
|
||||
export function geoPolygonContainsPolygon(outer, inner) {
|
||||
return _every(inner, function(point) {
|
||||
return geoPointInPolygon(point, outer);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
|
||||
function testSegments(outer, inner) {
|
||||
for (var i = 0; i < outer.length - 1; i++) {
|
||||
for (var j = 0; j < inner.length - 1; j++) {
|
||||
var a = [ outer[i], outer[i + 1] ];
|
||||
var b = [ inner[j], inner[j + 1] ];
|
||||
if (geoLineIntersection(a, b)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function testPoints(outer, inner) {
|
||||
return _some(inner, function(point) {
|
||||
return geoPointInPolygon(point, outer);
|
||||
});
|
||||
}
|
||||
|
||||
return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
|
||||
}
|
||||
|
||||
|
||||
export function geoPathLength(path) {
|
||||
var length = 0;
|
||||
for (var i = 0; i < path.length - 1; i++) {
|
||||
length += geoVecLength(path[i], path[i + 1]);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// If the given point is at the edge of the padded viewport,
|
||||
// return a vector that will nudge the viewport in that direction
|
||||
export function geoViewportEdge(point, dimensions) {
|
||||
var pad = [80, 20, 50, 20]; // top, right, bottom, left
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
|
||||
if (point[0] > dimensions[0] - pad[1])
|
||||
x = -10;
|
||||
if (point[0] < pad[3])
|
||||
x = 10;
|
||||
if (point[1] > dimensions[1] - pad[2])
|
||||
y = -10;
|
||||
if (point[1] < pad[0])
|
||||
y = 10;
|
||||
|
||||
if (x || y) {
|
||||
return [x, y];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
213
modules/geo/geom.js
Normal file
213
modules/geo/geom.js
Normal file
@@ -0,0 +1,213 @@
|
||||
import _every from 'lodash-es/every';
|
||||
import _some from 'lodash-es/some';
|
||||
|
||||
import {
|
||||
geoVecAngle,
|
||||
geoVecCross,
|
||||
geoVecDot,
|
||||
geoVecInterp,
|
||||
geoVecLength,
|
||||
geoVecSubtract
|
||||
} from './vector.js';
|
||||
|
||||
|
||||
// Return the counterclockwise angle in the range (-pi, pi)
|
||||
// between the positive X axis and the line intersecting a and b.
|
||||
export function geoAngle(a, b, projection) {
|
||||
return geoVecAngle(projection(a.loc), projection(b.loc));
|
||||
}
|
||||
|
||||
export function geoEdgeEqual(a, b) {
|
||||
return (a[0] === b[0] && a[1] === b[1]) ||
|
||||
(a[0] === b[1] && a[1] === b[0]);
|
||||
}
|
||||
|
||||
// Rotate all points counterclockwise around a pivot point by given angle
|
||||
export function geoRotate(points, angle, around) {
|
||||
return points.map(function(point) {
|
||||
var radial = [point[0] - around[0], point[1] - around[1]];
|
||||
return [
|
||||
radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
|
||||
radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Choose the edge with the minimal distance from `point` to its orthogonal
|
||||
// projection onto that edge, if such a projection exists, or the distance to
|
||||
// the closest vertex on that edge. Returns an object with the `index` of the
|
||||
// chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
|
||||
export function geoChooseEdge(nodes, point, projection, skipID) {
|
||||
var dist = geoVecLength;
|
||||
var points = nodes.map(function(n) { return projection(n.loc); });
|
||||
var ids = nodes.map(function(n) { return n.id; });
|
||||
var min = Infinity;
|
||||
var idx;
|
||||
var loc;
|
||||
|
||||
for (var i = 0; i < points.length - 1; i++) {
|
||||
if (ids[i] === skipID || ids[i + 1] === skipID) continue;
|
||||
|
||||
var o = points[i];
|
||||
var s = geoVecSubtract(points[i + 1], o);
|
||||
var v = geoVecSubtract(point, o);
|
||||
var proj = geoVecDot(v, s) / geoVecDot(s, s);
|
||||
var p;
|
||||
|
||||
if (proj < 0) {
|
||||
p = o;
|
||||
} else if (proj > 1) {
|
||||
p = points[i + 1];
|
||||
} else {
|
||||
p = [o[0] + proj * s[0], o[1] + proj * s[1]];
|
||||
}
|
||||
|
||||
var d = dist(p, point);
|
||||
if (d < min) {
|
||||
min = d;
|
||||
idx = i + 1;
|
||||
loc = projection.invert(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (idx !== undefined) {
|
||||
return { index: idx, distance: min, loc: loc };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the intersection point of 2 line segments.
|
||||
// From https://github.com/pgkelley4/line-segments-intersect
|
||||
// This uses the vector cross product approach described below:
|
||||
// http://stackoverflow.com/a/565282/786339
|
||||
export function geoLineIntersection(a, b) {
|
||||
var p = [a[0][0], a[0][1]];
|
||||
var p2 = [a[1][0], a[1][1]];
|
||||
var q = [b[0][0], b[0][1]];
|
||||
var q2 = [b[1][0], b[1][1]];
|
||||
var r = geoVecSubtract(p2, p);
|
||||
var s = geoVecSubtract(q2, q);
|
||||
var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
|
||||
var denominator = geoVecCross(r, s);
|
||||
|
||||
if (uNumerator && denominator) {
|
||||
var u = uNumerator / denominator;
|
||||
var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
|
||||
|
||||
if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
|
||||
return geoVecInterp(p, p2, t);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
export function geoPathIntersections(path1, path2) {
|
||||
var intersections = [];
|
||||
for (var i = 0; i < path1.length - 1; i++) {
|
||||
for (var j = 0; j < path2.length - 1; j++) {
|
||||
var a = [ path1[i], path1[i+1] ];
|
||||
var b = [ path2[j], path2[j+1] ];
|
||||
var hit = geoLineIntersection(a, b);
|
||||
if (hit) {
|
||||
intersections.push(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return intersections;
|
||||
}
|
||||
|
||||
|
||||
// Return whether point is contained in polygon.
|
||||
//
|
||||
// `point` should be a 2-item array of coordinates.
|
||||
// `polygon` should be an array of 2-item arrays of coordinates.
|
||||
//
|
||||
// From https://github.com/substack/point-in-polygon.
|
||||
// ray-casting algorithm based on
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
//
|
||||
export function geoPointInPolygon(point, polygon) {
|
||||
var x = point[0];
|
||||
var y = point[1];
|
||||
var inside = false;
|
||||
|
||||
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||||
var xi = polygon[i][0];
|
||||
var yi = polygon[i][1];
|
||||
var xj = polygon[j][0];
|
||||
var yj = polygon[j][1];
|
||||
|
||||
var intersect = ((yi > y) !== (yj > y)) &&
|
||||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
|
||||
export function geoPolygonContainsPolygon(outer, inner) {
|
||||
return _every(inner, function(point) {
|
||||
return geoPointInPolygon(point, outer);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
|
||||
function testSegments(outer, inner) {
|
||||
for (var i = 0; i < outer.length - 1; i++) {
|
||||
for (var j = 0; j < inner.length - 1; j++) {
|
||||
var a = [ outer[i], outer[i + 1] ];
|
||||
var b = [ inner[j], inner[j + 1] ];
|
||||
if (geoLineIntersection(a, b)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function testPoints(outer, inner) {
|
||||
return _some(inner, function(point) {
|
||||
return geoPointInPolygon(point, outer);
|
||||
});
|
||||
}
|
||||
|
||||
return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
|
||||
}
|
||||
|
||||
|
||||
export function geoPathLength(path) {
|
||||
var length = 0;
|
||||
for (var i = 0; i < path.length - 1; i++) {
|
||||
length += geoVecLength(path[i], path[i + 1]);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// If the given point is at the edge of the padded viewport,
|
||||
// return a vector that will nudge the viewport in that direction
|
||||
export function geoViewportEdge(point, dimensions) {
|
||||
var pad = [80, 20, 50, 20]; // top, right, bottom, left
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
|
||||
if (point[0] > dimensions[0] - pad[1])
|
||||
x = -10;
|
||||
if (point[0] < pad[3])
|
||||
x = 10;
|
||||
if (point[1] > dimensions[1] - pad[2])
|
||||
y = -10;
|
||||
if (point[1] < pad[0])
|
||||
y = 10;
|
||||
|
||||
if (x || y) {
|
||||
return [x, y];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
export { geoAngle } from './geo.js';
|
||||
export { geoChooseEdge } from './geo.js';
|
||||
export { geoEdgeEqual } from './geo.js';
|
||||
export { geoExtent } from './extent.js';
|
||||
export { geoRawMercator } from './raw_mercator.js';
|
||||
export { geoRotate } from './geo.js';
|
||||
|
||||
export { geoLatToMeters } from './geo.js';
|
||||
export { geoLineIntersection } from './geo.js';
|
||||
export { geoLonToMeters } from './geo.js';
|
||||
export { geoMetersToLat } from './geo.js';
|
||||
export { geoMetersToLon } from './geo.js';
|
||||
export { geoMetersToOffset } from './geo.js';
|
||||
export { geoOffsetToMeters } from './geo.js';
|
||||
export { geoPathIntersections } from './geo.js';
|
||||
export { geoPathLength } from './geo.js';
|
||||
export { geoPointInPolygon } from './geo.js';
|
||||
export { geoPolygonContainsPolygon } from './geo.js';
|
||||
export { geoPolygonIntersectsPolygon } from './geo.js';
|
||||
export { geoScaleToZoom } from './geo.js';
|
||||
export { geoSphericalDistance } from './geo.js';
|
||||
export { geoZoomToScale } from './geo.js';
|
||||
|
||||
export { geoAngle } from './geom.js';
|
||||
export { geoChooseEdge } from './geom.js';
|
||||
export { geoEdgeEqual } from './geom.js';
|
||||
export { geoRotate } from './geom.js';
|
||||
export { geoLineIntersection } from './geom.js';
|
||||
export { geoPathIntersections } from './geom.js';
|
||||
export { geoPathLength } from './geom.js';
|
||||
export { geoPointInPolygon } from './geom.js';
|
||||
export { geoPolygonContainsPolygon } from './geom.js';
|
||||
export { geoPolygonIntersectsPolygon } from './geom.js';
|
||||
export { geoViewportEdge } from './geom.js';
|
||||
|
||||
export { geoRawMercator } from './raw_mercator.js';
|
||||
|
||||
export { geoVecAdd } from './vector.js';
|
||||
export { geoVecAngle } from './vector.js';
|
||||
export { geoVecCross } from './vector.js';
|
||||
@@ -28,5 +34,4 @@ export { geoVecInterp } from './vector.js';
|
||||
export { geoVecLength } from './vector.js';
|
||||
export { geoVecSubtract } from './vector.js';
|
||||
export { geoVecScale } from './vector.js';
|
||||
export { geoZoomToScale } from './geo.js';
|
||||
export { geoViewportEdge } from './geo.js';
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
|
||||
<script src='spec/geo/extent.js'></script>
|
||||
<script src='spec/geo/geo.js'></script>
|
||||
<script src='spec/geo/geom.js'></script>
|
||||
<script src='spec/geo/vector.js'></script>
|
||||
|
||||
<script src='spec/lib/d3.combobox.js'></script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
describe('iD.geo', function() {
|
||||
describe('iD.geo - geography', function() {
|
||||
|
||||
describe('geoLatToMeters', function() {
|
||||
it('0 degrees latitude is 0 meters', function() {
|
||||
@@ -144,298 +144,4 @@ describe('iD.geo', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoEdgeEqual', function() {
|
||||
it('returns false for inequal edges', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['a', 'c'])).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true for equal edges along same direction', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['a', 'b'])).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true for equal edges along opposite direction', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['b', 'a'])).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoAngle', function() {
|
||||
it('returns angle between a and b', function() {
|
||||
var projection = function (_) { return _; };
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[1, 0]}, projection)).to.be.closeTo(0, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[0, 1]}, projection)).to.be.closeTo(Math.PI / 2, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[-1, 0]}, projection)).to.be.closeTo(Math.PI, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[0, -1]}, projection)).to.be.closeTo(-Math.PI / 2, 1e-6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoRotate', function() {
|
||||
it('rotates points around [0, 0]', function() {
|
||||
var points = [[5, 0], [5, 1]];
|
||||
var angle = Math.PI;
|
||||
var around = [0, 0];
|
||||
var result = iD.geoRotate(points, angle, around);
|
||||
expect(result[0][0]).to.be.closeTo(-5, 1e-6);
|
||||
expect(result[0][1]).to.be.closeTo(0, 1e-6);
|
||||
expect(result[1][0]).to.be.closeTo(-5, 1e-6);
|
||||
expect(result[1][1]).to.be.closeTo(-1, 1e-6);
|
||||
});
|
||||
|
||||
it('rotates points around [3, 0]', function() {
|
||||
var points = [[5, 0], [5, 1]];
|
||||
var angle = Math.PI;
|
||||
var around = [3, 0];
|
||||
var result = iD.geoRotate(points, angle, around);
|
||||
expect(result[0][0]).to.be.closeTo(1, 1e-6);
|
||||
expect(result[0][1]).to.be.closeTo(0, 1e-6);
|
||||
expect(result[1][0]).to.be.closeTo(1, 1e-6);
|
||||
expect(result[1][1]).to.be.closeTo(-1, 1e-6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoChooseEdge', function() {
|
||||
var projection = function (l) { return l; };
|
||||
projection.invert = projection;
|
||||
|
||||
it('returns null for a degenerate way (no nodes)', function() {
|
||||
expect(iD.geoChooseEdge([], [0, 0], projection)).to.be.null;
|
||||
});
|
||||
|
||||
it('returns null for a degenerate way (single node)', function() {
|
||||
expect(iD.geoChooseEdge([iD.osmNode({loc: [0, 0]})], [0, 0], projection)).to.be.null;
|
||||
});
|
||||
|
||||
it('calculates the orthogonal projection of a point onto a segment', function() {
|
||||
// a --*--- b
|
||||
// |
|
||||
// c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [2, 1];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('returns the starting vertex when the orthogonal projection is < 0', function() {
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [-3, 4];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(5);
|
||||
expect(choice.loc).to.eql([0, 0]);
|
||||
});
|
||||
|
||||
it('returns the ending vertex when the orthogonal projection is > 1', function() {
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [8, 4];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(5);
|
||||
expect(choice.loc).to.eql([5, 0]);
|
||||
});
|
||||
|
||||
it('skips the given nodeID at end of way', function() {
|
||||
//
|
||||
// a --*-- b
|
||||
// e |
|
||||
// | |
|
||||
// d - c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [5, 5];
|
||||
var d = [2, 5];
|
||||
var e = [2, 0.1]; // e.g. user is dragging e onto ab
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: a}),
|
||||
iD.osmNode({id: 'b', loc: b}),
|
||||
iD.osmNode({id: 'c', loc: c}),
|
||||
iD.osmNode({id: 'd', loc: d}),
|
||||
iD.osmNode({id: 'e', loc: e})
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, e, projection, 'e');
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(0.1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('skips the given nodeID in middle of way', function() {
|
||||
//
|
||||
// a --*-- b
|
||||
// d |
|
||||
// / \ |
|
||||
// e c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [5, 5];
|
||||
var d = [2, 0.1]; // e.g. user is dragging d onto ab
|
||||
var e = [0, 5];
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: a}),
|
||||
iD.osmNode({id: 'b', loc: b}),
|
||||
iD.osmNode({id: 'c', loc: c}),
|
||||
iD.osmNode({id: 'd', loc: d}),
|
||||
iD.osmNode({id: 'e', loc: e})
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, d, projection, 'd');
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(0.1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('returns null if all nodes are skipped', function() {
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [5, 0]}),
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, [2, 2], projection, 'a');
|
||||
expect(choice).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoLineIntersection', function() {
|
||||
it('returns null if lines are colinear with overlap', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[-5, 0], [5, 0]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns null if lines are colinear but disjoint', function() {
|
||||
var a = [[5, 0], [10, 0]];
|
||||
var b = [[-10, 0], [-5, 0]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns null if lines are parallel', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[0, 5], [10, 5]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns the intersection point between 2 lines', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[5, 10], [5, -10]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.eql([5, 0]);
|
||||
});
|
||||
it('returns null if lines are not parallel but not intersecting', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[-5, 10], [-5, -10]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPointInPolygon', function() {
|
||||
it('says a point in a polygon is on a polygon', function() {
|
||||
var poly = [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]];
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geoPointInPolygon(point, poly)).to.be.true;
|
||||
});
|
||||
it('says a point outside of a polygon is outside', function() {
|
||||
var poly = [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]];
|
||||
var point = [0.5, 1.5];
|
||||
expect(iD.geoPointInPolygon(point, poly)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPolygonContainsPolygon', function() {
|
||||
it('says a polygon in a polygon is in', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonContainsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
it('says a polygon outside of a polygon is out', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 9], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonContainsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPolygonIntersectsPolygon', function() {
|
||||
it('returns true when outer polygon fully contains inner', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true when outer polygon partially contains inner (some vertices contained)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[-1, -1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false when outer polygon partially contains inner (no vertices contained - lax test)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, -1], [1, 4], [2, 4], [2, -1], [1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true when outer polygon partially contains inner (no vertices contained - strict test)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, -1], [1, 4], [2, 4], [2, -1], [1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner, true)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false when outer and inner are fully disjoint', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[-1, -1], [-1, -2], [-2, -2], [-2, -1], [-1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPathLength', function() {
|
||||
it('calculates a simple path length', function() {
|
||||
var path = [[0, 0], [0, 1], [3, 5]];
|
||||
expect(iD.geoPathLength(path)).to.eql(6);
|
||||
});
|
||||
|
||||
it('does not fail on single-point path', function() {
|
||||
var path = [[0, 0]];
|
||||
expect(iD.geoPathLength(path)).to.eql(0);
|
||||
});
|
||||
|
||||
it('estimates zero-length edges', function() {
|
||||
var path = [[0, 0], [0, 0]];
|
||||
expect(iD.geoPathLength(path)).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoViewportEdge', function() {
|
||||
var dimensions = [1000, 1000];
|
||||
it('returns null if the point is not at the edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 500], dimensions)).to.be.null;
|
||||
});
|
||||
it('nudges top edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 5], dimensions)).to.eql([0, 10]);
|
||||
});
|
||||
it('nudges top-right corner', function() {
|
||||
expect(iD.geoViewportEdge([995, 5], dimensions)).to.eql([-10, 10]);
|
||||
});
|
||||
it('nudges right edge', function() {
|
||||
expect(iD.geoViewportEdge([995, 500], dimensions)).to.eql([-10, 0]);
|
||||
});
|
||||
it('nudges bottom-right corner', function() {
|
||||
expect(iD.geoViewportEdge([995, 995], dimensions)).to.eql([-10, -10]);
|
||||
});
|
||||
it('nudges bottom edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 995], dimensions)).to.eql([0, -10]);
|
||||
});
|
||||
it('nudges bottom-left corner', function() {
|
||||
expect(iD.geoViewportEdge([5, 995], dimensions)).to.eql([10, -10]);
|
||||
});
|
||||
it('nudges left edge', function() {
|
||||
expect(iD.geoViewportEdge([5, 500], dimensions)).to.eql([10, 0]);
|
||||
});
|
||||
it('nudges top-left corner', function() {
|
||||
expect(iD.geoViewportEdge([5, 5], dimensions)).to.eql([10, 10]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
297
test/spec/geo/geom.js
Normal file
297
test/spec/geo/geom.js
Normal file
@@ -0,0 +1,297 @@
|
||||
describe('iD.geo - geometry', function() {
|
||||
|
||||
describe('geoAngle', function() {
|
||||
it('returns angle between a and b', function() {
|
||||
var projection = function (_) { return _; };
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[1, 0]}, projection)).to.be.closeTo(0, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[0, 1]}, projection)).to.be.closeTo(Math.PI / 2, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[-1, 0]}, projection)).to.be.closeTo(Math.PI, 1e-6);
|
||||
expect(iD.geoAngle({loc:[0, 0]}, {loc:[0, -1]}, projection)).to.be.closeTo(-Math.PI / 2, 1e-6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoEdgeEqual', function() {
|
||||
it('returns false for inequal edges', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['a', 'c'])).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true for equal edges along same direction', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['a', 'b'])).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true for equal edges along opposite direction', function() {
|
||||
expect(iD.geoEdgeEqual(['a', 'b'], ['b', 'a'])).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoRotate', function() {
|
||||
it('rotates points around [0, 0]', function() {
|
||||
var points = [[5, 0], [5, 1]];
|
||||
var angle = Math.PI;
|
||||
var around = [0, 0];
|
||||
var result = iD.geoRotate(points, angle, around);
|
||||
expect(result[0][0]).to.be.closeTo(-5, 1e-6);
|
||||
expect(result[0][1]).to.be.closeTo(0, 1e-6);
|
||||
expect(result[1][0]).to.be.closeTo(-5, 1e-6);
|
||||
expect(result[1][1]).to.be.closeTo(-1, 1e-6);
|
||||
});
|
||||
|
||||
it('rotates points around [3, 0]', function() {
|
||||
var points = [[5, 0], [5, 1]];
|
||||
var angle = Math.PI;
|
||||
var around = [3, 0];
|
||||
var result = iD.geoRotate(points, angle, around);
|
||||
expect(result[0][0]).to.be.closeTo(1, 1e-6);
|
||||
expect(result[0][1]).to.be.closeTo(0, 1e-6);
|
||||
expect(result[1][0]).to.be.closeTo(1, 1e-6);
|
||||
expect(result[1][1]).to.be.closeTo(-1, 1e-6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoChooseEdge', function() {
|
||||
var projection = function (l) { return l; };
|
||||
projection.invert = projection;
|
||||
|
||||
it('returns null for a degenerate way (no nodes)', function() {
|
||||
expect(iD.geoChooseEdge([], [0, 0], projection)).to.be.null;
|
||||
});
|
||||
|
||||
it('returns null for a degenerate way (single node)', function() {
|
||||
expect(iD.geoChooseEdge([iD.osmNode({loc: [0, 0]})], [0, 0], projection)).to.be.null;
|
||||
});
|
||||
|
||||
it('calculates the orthogonal projection of a point onto a segment', function() {
|
||||
// a --*--- b
|
||||
// |
|
||||
// c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [2, 1];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('returns the starting vertex when the orthogonal projection is < 0', function() {
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [-3, 4];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(5);
|
||||
expect(choice.loc).to.eql([0, 0]);
|
||||
});
|
||||
|
||||
it('returns the ending vertex when the orthogonal projection is > 1', function() {
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [8, 4];
|
||||
var nodes = [ iD.osmNode({loc: a}), iD.osmNode({loc: b}) ];
|
||||
var choice = iD.geoChooseEdge(nodes, c, projection);
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(5);
|
||||
expect(choice.loc).to.eql([5, 0]);
|
||||
});
|
||||
|
||||
it('skips the given nodeID at end of way', function() {
|
||||
//
|
||||
// a --*-- b
|
||||
// e |
|
||||
// | |
|
||||
// d - c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [5, 5];
|
||||
var d = [2, 5];
|
||||
var e = [2, 0.1]; // e.g. user is dragging e onto ab
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: a}),
|
||||
iD.osmNode({id: 'b', loc: b}),
|
||||
iD.osmNode({id: 'c', loc: c}),
|
||||
iD.osmNode({id: 'd', loc: d}),
|
||||
iD.osmNode({id: 'e', loc: e})
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, e, projection, 'e');
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(0.1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('skips the given nodeID in middle of way', function() {
|
||||
//
|
||||
// a --*-- b
|
||||
// d |
|
||||
// / \ |
|
||||
// e c
|
||||
//
|
||||
// * = [2, 0]
|
||||
var a = [0, 0];
|
||||
var b = [5, 0];
|
||||
var c = [5, 5];
|
||||
var d = [2, 0.1]; // e.g. user is dragging d onto ab
|
||||
var e = [0, 5];
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: a}),
|
||||
iD.osmNode({id: 'b', loc: b}),
|
||||
iD.osmNode({id: 'c', loc: c}),
|
||||
iD.osmNode({id: 'd', loc: d}),
|
||||
iD.osmNode({id: 'e', loc: e})
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, d, projection, 'd');
|
||||
expect(choice.index).to.eql(1);
|
||||
expect(choice.distance).to.eql(0.1);
|
||||
expect(choice.loc).to.eql([2, 0]);
|
||||
});
|
||||
|
||||
it('returns null if all nodes are skipped', function() {
|
||||
var nodes = [
|
||||
iD.osmNode({id: 'a', loc: [0, 0]}),
|
||||
iD.osmNode({id: 'b', loc: [5, 0]}),
|
||||
];
|
||||
var choice = iD.geoChooseEdge(nodes, [2, 2], projection, 'a');
|
||||
expect(choice).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoLineIntersection', function() {
|
||||
it('returns null if lines are colinear with overlap', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[-5, 0], [5, 0]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns null if lines are colinear but disjoint', function() {
|
||||
var a = [[5, 0], [10, 0]];
|
||||
var b = [[-10, 0], [-5, 0]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns null if lines are parallel', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[0, 5], [10, 5]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
it('returns the intersection point between 2 lines', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[5, 10], [5, -10]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.eql([5, 0]);
|
||||
});
|
||||
it('returns null if lines are not parallel but not intersecting', function() {
|
||||
var a = [[0, 0], [10, 0]];
|
||||
var b = [[-5, 10], [-5, -10]];
|
||||
expect(iD.geoLineIntersection(a, b)).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPointInPolygon', function() {
|
||||
it('says a point in a polygon is on a polygon', function() {
|
||||
var poly = [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]];
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geoPointInPolygon(point, poly)).to.be.true;
|
||||
});
|
||||
it('says a point outside of a polygon is outside', function() {
|
||||
var poly = [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]];
|
||||
var point = [0.5, 1.5];
|
||||
expect(iD.geoPointInPolygon(point, poly)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPolygonContainsPolygon', function() {
|
||||
it('says a polygon in a polygon is in', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonContainsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
it('says a polygon outside of a polygon is out', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 9], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonContainsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPolygonIntersectsPolygon', function() {
|
||||
it('returns true when outer polygon fully contains inner', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true when outer polygon partially contains inner (some vertices contained)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[-1, -1], [1, 2], [2, 2], [2, 1], [1, 1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false when outer polygon partially contains inner (no vertices contained - lax test)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, -1], [1, 4], [2, 4], [2, -1], [1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true when outer polygon partially contains inner (no vertices contained - strict test)', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[1, -1], [1, 4], [2, 4], [2, -1], [1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner, true)).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false when outer and inner are fully disjoint', function() {
|
||||
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
|
||||
var inner = [[-1, -1], [-1, -2], [-2, -2], [-2, -1], [-1, -1]];
|
||||
expect(iD.geoPolygonIntersectsPolygon(outer, inner)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoPathLength', function() {
|
||||
it('calculates a simple path length', function() {
|
||||
var path = [[0, 0], [0, 1], [3, 5]];
|
||||
expect(iD.geoPathLength(path)).to.eql(6);
|
||||
});
|
||||
|
||||
it('does not fail on single-point path', function() {
|
||||
var path = [[0, 0]];
|
||||
expect(iD.geoPathLength(path)).to.eql(0);
|
||||
});
|
||||
|
||||
it('estimates zero-length edges', function() {
|
||||
var path = [[0, 0], [0, 0]];
|
||||
expect(iD.geoPathLength(path)).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('geoViewportEdge', function() {
|
||||
var dimensions = [1000, 1000];
|
||||
it('returns null if the point is not at the edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 500], dimensions)).to.be.null;
|
||||
});
|
||||
it('nudges top edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 5], dimensions)).to.eql([0, 10]);
|
||||
});
|
||||
it('nudges top-right corner', function() {
|
||||
expect(iD.geoViewportEdge([995, 5], dimensions)).to.eql([-10, 10]);
|
||||
});
|
||||
it('nudges right edge', function() {
|
||||
expect(iD.geoViewportEdge([995, 500], dimensions)).to.eql([-10, 0]);
|
||||
});
|
||||
it('nudges bottom-right corner', function() {
|
||||
expect(iD.geoViewportEdge([995, 995], dimensions)).to.eql([-10, -10]);
|
||||
});
|
||||
it('nudges bottom edge', function() {
|
||||
expect(iD.geoViewportEdge([500, 995], dimensions)).to.eql([0, -10]);
|
||||
});
|
||||
it('nudges bottom-left corner', function() {
|
||||
expect(iD.geoViewportEdge([5, 995], dimensions)).to.eql([10, -10]);
|
||||
});
|
||||
it('nudges left edge', function() {
|
||||
expect(iD.geoViewportEdge([5, 500], dimensions)).to.eql([10, 0]);
|
||||
});
|
||||
it('nudges top-left corner', function() {
|
||||
expect(iD.geoViewportEdge([5, 5], dimensions)).to.eql([10, 10]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
describe('iD.geo vector', function() {
|
||||
describe('iD.geo - vector', function() {
|
||||
|
||||
describe('geoVecEqual', function() {
|
||||
it('tests vectors for equality', function() {
|
||||
|
||||
Reference in New Issue
Block a user