RCrowe @ 在折线中查找离 latlng 最近的点
/* desc Static function. Find point on lines nearest test point
test point pXy with properties .x and .y
lines defined by array aXys with nodes having properties .x and .y
return is object with .x and .y properties and property i indicating nearest segment in aXys
and property fFrom the fractional distance of the returned point from aXy[i-1]
and property fTo the fractional distance of the returned point from aXy[i] */
function getClosestPointOnLines(pXy, aXys) {
var minDist;
var fTo;
var fFrom;
var x;
var y;
var i;
var dist;
if (aXys.length > 1) {
for (var n = 1 ; n < aXys.length ; n++) {
if (aXys[n].x != aXys[n - 1].x) {
var a = (aXys[n].y - aXys[n - 1].y) / (aXys[n].x - aXys[n - 1].x);
var b = aXys[n].y - a * aXys[n].x;
dist = Math.abs(a * pXy.x + b - pXy.y) / Math.sqrt(a * a + 1);
}
else
dist = Math.abs(pXy.x - aXys[n].x)
// length^2 of line segment
var rl2 = Math.pow(aXys[n].y - aXys[n - 1].y, 2) + Math.pow(aXys[n].x - aXys[n - 1].x, 2);
// distance^2 of pt to end line segment
var ln2 = Math.pow(aXys[n].y - pXy.y, 2) + Math.pow(aXys[n].x - pXy.x, 2);
// distance^2 of pt to begin line segment
var lnm12 = Math.pow(aXys[n - 1].y - pXy.y, 2) + Math.pow(aXys[n - 1].x - pXy.x, 2);
// minimum distance^2 of pt to infinite line
var dist2 = Math.pow(dist, 2);
// calculated length^2 of line segment
var calcrl2 = ln2 - dist2 + lnm12 - dist2;
// redefine minimum distance to line segment (not infinite line) if necessary
if (calcrl2 > rl2)
dist = Math.sqrt(Math.min(ln2, lnm12));
if ((minDist == null) || (minDist > dist)) {
if (calcrl2 > rl2) {
if (lnm12 < ln2) {
fTo = 0;//nearer to previous point
fFrom = 1;
}
else {
fFrom = 0;//nearer to current point
fTo = 1;
}
}
else {
// perpendicular from point intersects line segment
fTo = ((Math.sqrt(lnm12 - dist2)) / Math.sqrt(rl2));
fFrom = ((Math.sqrt(ln2 - dist2)) / Math.sqrt(rl2));
}
minDist = dist;
i = n;
}
}
var dx = aXys[i - 1].x - aXys[i].x;
var dy = aXys[i - 1].y - aXys[i].y;
x = aXys[i - 1].x - (dx * fTo);
y = aXys[i - 1].y - (dy * fTo);
}
return { 'x': x, 'y': y, 'i': i, 'fTo': fTo, 'fFrom': fFrom };
}
以下是根据这篇原始的博客,为TypeScript量身定制的更简单的解决方案。
export function findNearestPointOnLine(px: number, py: number, ax: number, ay: number, bx: number, by: number)
{
const atob = { x: bx - ax, y: by - ay };
const atop = { x: px - ax, y: py - ay };
const len = (atob.x * atob.x) + (atob.y * atob.y);
let dot = (atop.x * atob.x) + (atop.y * atob.y);
const t = Math.min(1, Math.max(0, dot / len));
dot = ((bx - ax) * (py - ay)) - ((by - ay) * (px - ax));
return { x: ax + (atob.x * t), y: ay + (atob.y * t) };
}
export function findNearestPointOnRect(px: number, py: number, x: number, y: number, width: number, height: number)
{
const left = x;
const right = x + width;
const top = y;
const bottom = top + height;
// top, right, bottom, left
const { x: topX, y: topY } = findNearestPointOnLine(px, py, left, top, right, top);
const { x: rightX, y: rightY } = findNearestPointOnLine(px, py, right, top, right, bottom);
const { x: bottomX, y: bottomY } = findNearestPointOnLine(px, py, left, bottom, right, bottom);
const { x: leftX, y: leftY } = findNearestPointOnLine(px, py, left, top, left, bottom);
const topD = distanceBetween(px, py, topX, topY);
const rightD = distanceBetween(px, py, rightX, rightY);
const bottomD = distanceBetween(px, py, bottomX, bottomY);
const leftD = distanceBetween(px, py, leftX, leftY);
const points: {
side: 'top' | 'right' | 'bottom' | 'left';
d: number;
x: number;
y: number;
}[] = [
{ side: 'top', d: topD, x: topX, y: topY },
{ side: 'right', d: rightD, x: rightX, y: rightY },
{ side: 'bottom', d: bottomD, x: bottomX, y: bottomY },
{ side: 'left', d: leftD, x: leftX, y: leftY },
];
points.sort((a, b) =>
{
if (a.d < b.d)
{
return -1;
}
if (a.d > b.d)
{
return 1;
}
return 0;
});
return points[0];
}
dot = ((bx - ax) * (py - ay)) - ((by - ay) * (px - ax))
不是必要的,也没有被使用,并且它会得到相同的结果。看起来像是之前版本的遗留问题。 - Glantucan设A、B、C为double[],其中A = {a的x坐标,a的y坐标},B = {b的x坐标,b的y坐标},C = {c的x坐标,c的y坐标}。 如果线段ab是y = mx + z,则
m = (A[1]-B[1])/(A[0]-B[0])
z = A[1] - m*A[0]
现在我们需要通过c点作ab线段的垂线。如果这条线段是y = m'x + z',则
m' = -1/m = (A[0]-B[0])/(B[1]-A[1])
z' = C[1] - m'*C[0]
最后我们需要求出这些线段的交点。我们令y=y并解决
mx+z = m'x + z'
x(m-m') = z'-z
x = (z'-z)/(m-m')
y = m*x + z
D = {(z'-z)/(m-m'), m*x + z}。 现在只需将其转换为字符串即可。 希望对您有所帮助!
通常可以通过绘制与点相交的垂线来确定直线上距离该点最近的点。 要找到垂直斜率,请执行以下代码:
var slope = (Number(a.substring(a.indexOf(",") + 1, a.length)) //The Y coordinate of A
- Number(b.substring(b.indexOf(",") + 1, b.length))) // The Y coordinate of B
/ (Number(a.substring(0, a.indexOf(","))) // The X coordinate of A
- Number(b.substring(0, b.indexOf(",")))); //The Y coordinate of B
这是斜率公式 (y2 - y1) / (x2 - x1)
现在我们有了斜率,将其转换为垂直斜率就很容易了。
var perpendicularSlope = -1 / slope;
var newPointX = Number(c.substring(0, c.indexOf(",")); //Gets the X value of new point
var newPointY = Number(c.substring(c.indexOf(",") + 1, c.length)); //Gets the Y value of new point
//Note that in the formula provided above, y and x are not going to be assigned in code.
//I'm going to bypass formatting it like that and go right to the slope intercept form
var perpendicularBValue = newPointY - perpendicularSlope * newPointX;
//Slope intercept form is y = mx + b. (m is slope and b is where the line intersects the y axis)
var lineX = Number(a.substring(0, a.indexOf(","));
var lineY = Number(a.substring(a.indexOf(",") + 1, a.length));
var lineB = lineY - slope * newPointY;
var xCollision = (lineB - perpendicularBValue) / (perpendicularSlope - slope);
var yCollision = slope * xCollosion + lineB;
var d = xCollision + "," + yCollision;
我使用传递属性消除了y变量并联合了方程。 然后我解出了x的值。 然后我将x的值代入并解出了y的值。 这就是原始线和垂直线相交的地方。
还记得我之前说过这通常有效吗?
因为你正在使用线段而不是线,有时最近点将是端点。
以下是如何修复d值的方法
var aDistance = Math.sqrt(
Math.pow(lineX - newPointX, 2) +
Math.pow(lineY - newPointY, 2));
var bDistance = Math.sqrt(
Math.pow(Number(b.substring(0, b.indexOf(",")) - newPointX, 2) +
Math.pow(Number(b.substring(b.indexOf(",") + 1, b.length) - newPointY, 2));
var dDistance = Math.sqrt(
Math.pow(xCollision - newPointX, 2) +
Math.pow(yCollision - newPointY, 2));
var closestEndpoint = aDistance < bDistance ? aDistance : bDistance;
var closestPoint = closestEndpoint < dDistance ? closestEndpoint : dDistance;