@vuemap/district-cluster
Version:
98 lines (96 loc) • 2.96 kB
text/typescript
function polygonClip(subjectPolygon, clipPolygon) {
let cp1,
cp2,
s,
e,
outputList = subjectPolygon
cp1 = clipPolygon[clipPolygon.length - 2]
for (let j = 0, jlen = clipPolygon.length - 1; j < jlen; j++) {
cp2 = clipPolygon[j]
const inputList = outputList
outputList = []
s = inputList[inputList.length - 1]
for (let i = 0, len = inputList.length; i < len; i++) {
e = inputList[i]
if (clipInside(e, cp1, cp2)) {
clipInside(s, cp1, cp2) || outputList.push(clipIntersection(cp1, cp2, s, e))
outputList.push(e)
} else clipInside(s, cp1, cp2) && outputList.push(clipIntersection(cp1, cp2, s, e))
s = e
}
cp1 = cp2
}
if (outputList.length < 3) return []
outputList.push(outputList[0])
return outputList
}
function pointOnSegment(p, p1, p2) {
const tx = ((p2[1] - p1[1]) / (p2[0] - p1[0])) * (p[0] - p1[0]) + p1[1]
return Math.abs(tx - p[1]) < 1e-6 && p[0] >= p1[0] && p[0] <= p2[0]
}
function pointOnPolygon(point, vs) {
for (let i = 0, len = vs.length; i < len - 1; i++) if (pointOnSegment(point, vs[i], vs[i + 1])) return !0
return !1
}
function pointInPolygon(point, vs) {
let inside = !1
for (let x = point[0], y = point[1], i = 0, len = vs.length, j = len - 1; i < len; j = i++) {
const xi = vs[i][0],
yi = vs[i][1],
xj = vs[j][0],
yj = vs[j][1],
intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
intersect && (inside = !inside)
}
return inside
}
function getClosestPointOnSegment(p, p1, p2) {
let t,
x = p1[0],
y = p1[1]
const dx = p2[0] - x,
dy = p2[1] - y,
dot = dx * dx + dy * dy
if (dot > 0) {
t = ((p[0] - x) * dx + (p[1] - y) * dy) / dot
if (t > 1) {
x = p2[0]
y = p2[1]
} else if (t > 0) {
x += dx * t
y += dy * t
}
}
return [x, y]
}
function sqClosestDistanceToSegment(p, p1, p2) {
const p3 = getClosestPointOnSegment(p, p1, p2),
dx = p[0] - p3[0],
dy = p[1] - p3[1]
return dx * dx + dy * dy
}
function sqClosestDistanceToPolygon(p, points) {
let minSq = Number.MAX_VALUE
for (let i = 0, len = points.length; i < len - 1; i++) {
const sq = sqClosestDistanceToSegment(p, points[i], points[i + 1])
sq < minSq && (minSq = sq)
}
return minSq
}
function clipInside(p, cp1, cp2) {
return (cp2[0] - cp1[0]) * (p[1] - cp1[1]) > (cp2[1] - cp1[1]) * (p[0] - cp1[0])
}
function clipIntersection(cp1, cp2, s, e) {
const dc = [cp1[0] - cp2[0], cp1[1] - cp2[1]],
dp = [s[0] - e[0], s[1] - e[1]],
n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
n2 = s[0] * e[1] - s[1] * e[0],
n3 = 1 / (dc[0] * dp[1] - dc[1] * dp[0])
return [(n1 * dp[0] - n2 * dc[0]) * n3, (n1 * dp[1] - n2 * dc[1]) * n3]
}
export default {
sqClosestDistanceToPolygon,
pointOnPolygon,
pointInPolygon,
polygonClip
}