You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.9 KiB
150 lines
3.9 KiB
// https://d3js.org/d3-polygon/ v1.0.5 Copyright 2018 Mike Bostock |
|
(function (global, factory) { |
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : |
|
typeof define === 'function' && define.amd ? define(['exports'], factory) : |
|
(factory((global.d3 = global.d3 || {}))); |
|
}(this, (function (exports) { 'use strict'; |
|
|
|
function area(polygon) { |
|
var i = -1, |
|
n = polygon.length, |
|
a, |
|
b = polygon[n - 1], |
|
area = 0; |
|
|
|
while (++i < n) { |
|
a = b; |
|
b = polygon[i]; |
|
area += a[1] * b[0] - a[0] * b[1]; |
|
} |
|
|
|
return area / 2; |
|
} |
|
|
|
function centroid(polygon) { |
|
var i = -1, |
|
n = polygon.length, |
|
x = 0, |
|
y = 0, |
|
a, |
|
b = polygon[n - 1], |
|
c, |
|
k = 0; |
|
|
|
while (++i < n) { |
|
a = b; |
|
b = polygon[i]; |
|
k += c = a[0] * b[1] - b[0] * a[1]; |
|
x += (a[0] + b[0]) * c; |
|
y += (a[1] + b[1]) * c; |
|
} |
|
|
|
return k *= 3, [x / k, y / k]; |
|
} |
|
|
|
// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of |
|
// the 3D cross product in a quadrant I Cartesian coordinate system (+x is |
|
// right, +y is up). Returns a positive value if ABC is counter-clockwise, |
|
// negative if clockwise, and zero if the points are collinear. |
|
function cross(a, b, c) { |
|
return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); |
|
} |
|
|
|
function lexicographicOrder(a, b) { |
|
return a[0] - b[0] || a[1] - b[1]; |
|
} |
|
|
|
// Computes the upper convex hull per the monotone chain algorithm. |
|
// Assumes points.length >= 3, is sorted by x, unique in y. |
|
// Returns an array of indices into points in left-to-right order. |
|
function computeUpperHullIndexes(points) { |
|
var n = points.length, |
|
indexes = [0, 1], |
|
size = 2; |
|
|
|
for (var i = 2; i < n; ++i) { |
|
while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size; |
|
indexes[size++] = i; |
|
} |
|
|
|
return indexes.slice(0, size); // remove popped points |
|
} |
|
|
|
function hull(points) { |
|
if ((n = points.length) < 3) return null; |
|
|
|
var i, |
|
n, |
|
sortedPoints = new Array(n), |
|
flippedPoints = new Array(n); |
|
|
|
for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i]; |
|
sortedPoints.sort(lexicographicOrder); |
|
for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]]; |
|
|
|
var upperIndexes = computeUpperHullIndexes(sortedPoints), |
|
lowerIndexes = computeUpperHullIndexes(flippedPoints); |
|
|
|
// Construct the hull polygon, removing possible duplicate endpoints. |
|
var skipLeft = lowerIndexes[0] === upperIndexes[0], |
|
skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], |
|
hull = []; |
|
|
|
// Add upper hull in right-to-l order. |
|
// Then add lower hull in left-to-right order. |
|
for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]); |
|
for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]); |
|
|
|
return hull; |
|
} |
|
|
|
function contains(polygon, point) { |
|
var n = polygon.length, |
|
p = polygon[n - 1], |
|
x = point[0], y = point[1], |
|
x0 = p[0], y0 = p[1], |
|
x1, y1, |
|
inside = false; |
|
|
|
for (var i = 0; i < n; ++i) { |
|
p = polygon[i], x1 = p[0], y1 = p[1]; |
|
if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside; |
|
x0 = x1, y0 = y1; |
|
} |
|
|
|
return inside; |
|
} |
|
|
|
function length(polygon) { |
|
var i = -1, |
|
n = polygon.length, |
|
b = polygon[n - 1], |
|
xa, |
|
ya, |
|
xb = b[0], |
|
yb = b[1], |
|
perimeter = 0; |
|
|
|
while (++i < n) { |
|
xa = xb; |
|
ya = yb; |
|
b = polygon[i]; |
|
xb = b[0]; |
|
yb = b[1]; |
|
xa -= xb; |
|
ya -= yb; |
|
perimeter += Math.sqrt(xa * xa + ya * ya); |
|
} |
|
|
|
return perimeter; |
|
} |
|
|
|
exports.polygonArea = area; |
|
exports.polygonCentroid = centroid; |
|
exports.polygonHull = hull; |
|
exports.polygonContains = contains; |
|
exports.polygonLength = length; |
|
|
|
Object.defineProperty(exports, '__esModule', { value: true }); |
|
|
|
})));
|
|
|