Чтобы найти координаты ближайшей точки на отрезке от точки

Мне нужно вычислить основание перпендикулярной линии, проведенной от точки P до отрезка AB. Мне нужны координаты точки C, где ПК перпендикулярен проведен от точки P к линии AB.

введите здесь описание изображения

Я нашел несколько ответов на SO здесь, но у меня не работает векторный процесс. Вот что я пробовал:

function nearestPointSegment(a, b, c) {
   var t = nearestPointGreatCircle(a,b,c);
   return t;
}

function nearestPointGreatCircle(a, b, c) {
  var a_cartesian = normalize(Cesium.Cartesian3.fromDegrees(a.x,a.y))
  var b_cartesian = normalize(Cesium.Cartesian3.fromDegrees(b.x,b.y))
  var c_cartesian = normalize(Cesium.Cartesian3.fromDegrees(c.x,c.y))
  var G = vectorProduct(a_cartesian, b_cartesian);
  var F = vectorProduct(c_cartesian, G);
  var t = vectorProduct(G, F);
  t = multiplyByScalar(normalize(t), R);
  return fromCartesianToDegrees(t);
}

function vectorProduct(a, b) {
    var result = new Object();
    result.x = a.y * b.z - a.z * b.y;
    result.y = a.z * b.x - a.x * b.z;
    result.z = a.x * b.y - a.y * b.x;
    return result;
}

function normalize(t) {
    var length = Math.sqrt((t.x * t.x) + (t.y * t.y) + (t.z * t.z));
    var result = new Object();
    result.x = t.x/length;
    result.y = t.y/length;
    result.z = t.z/length;
    return result;
}

function multiplyByScalar(normalize, k) {
    var result = new Object();
    result.x = normalize.x * k;
    result.y = normalize.y * k;
    result.z = normalize.z * k;
    return result;
}

function fromCartesianToDegrees(pos) {
  var carto  = Cesium.Ellipsoid.WGS84.cartesianToCartographic(pos);     
  var lon = Cesium.Math.toDegrees(carto.longitude); 
  var lat = Cesium.Math.toDegrees(carto.latitude); 
  return [lon,lat];
}

Что мне в этом не хватает?


person meen    schedule 03.11.2016    source источник


Ответы (1)


Вот один из способов:

// edge cases
if (a.x === b.x) {
  // AB is vertical
  c.x = a.x;
  c.y = p.y;
}
else if (a.y === b.y) {
  // AB is horizontal
  c.x = p.x;
  c.y = a.y;
}
else {
  // linear function of AB
  var m1 = (b.y - a.y) / (b.x - a.x);
  var t1 = a.y - m1 * a.x;
  // linear function of PC
  var m2 = -1 / m1; // perpendicular
  var t2 = p.y - m2 * p.x;
  // c.x * m1 + t1 === c.x * m2 + t2
  c.x = (t2 - t1) / (m1 - m2);
  c.y = m1 * c.x + t1;
}

Редактировать:

Вот гораздо лучший векторный способ:

function foot(A, B, P) {
  const AB = {
    x: B.x - A.x,
    y: B.y - A.y
  };
  const k = ((P.x - A.x) * AB.x + (P.y - A.y) * AB.y) / (AB.x * AB.x + AB.y * AB.y);
  return {
    x: A.x + k * AB.x,
    y: A.y + k * AB.y
  };
}

const A = { x: 1, y: 1 };
const B = { x: 4, y: 5 };
const P = { x: 4.5, y: 3 };
const C = foot(A, B, P);
console.log(C);

// perpendicular?
const AB = {
  x: B.x - A.x,
  y: B.y - A.y
};
const PC = {
  x: C.x - P.x,
  y: C.y - P.y
};
console.log((AB.x * PC.x + AB.y * PC.y).toFixed(3));

Изменить: теория

введите описание изображения здесь

Я начинаю с вектора от A к B, A➞B. Умножив этот вектор на скаляр k и добавив его к точке A, я могу попасть в любую точку C на прямой AB.

I) C = A + k × A➞B

Затем мне нужно установить угол 90 °, что означает, что скалярное произведение A➞B и P➞C равно нулю.

II) A➞B · P➞C = 0

Теперь решите относительно k.

person Chris G    schedule 03.11.2016
comment
Привет, @Chris, твое решение работает очень хорошо, не могли бы вы сказать мне, какую формулу / теорию вы использовали для этого? - person Ugnius Malūkas; 09.07.2021
comment
@ UgniusMalūkas Я добавил теорию :) - person Chris G; 09.07.2021