Если вы хотите вычислить вектор от точки pA до точки pB , тогда вы должны вычесть pA форму pB (pB-pA
) вместо pB с pA (pA-pB
) .
Примечание, .subVectors( a : Vector3, b : Vector3 )
рассчитывает a-b
.
Короткий ответ :
Убедитесь, что расстояние между pA
и pToCheck
и расстояние между pB
и pToCheck
меньше илиравно расстоянию между pA
и pB
.
и проверьте, равен ли угол между векторной формой pA
до pToCheck
соответственно pB
до pToCheck
и вектором от pA
до pB
близко к 0:
Это можно сделать с помощью .distanceTo
соответственно с .angleTo
:
function isPointbetweenTwoOthers (pA, pB, pToCheck) {
let distAtoB = pA.distanceTo(pB);
let distAtoC = pA.distanceTo(pToCheck);
let distBtoC = pB.distanceTo(pToCheck);
if (distAtoC > distAtoB || distBtoC > distAtoB)
return false;
let vAtoB = pB.clone().sub(pA);
let vBtoA = pA.clone().sub(pB);
let vAtoC = pToCheck.clone().sub(pA);
let vBtoC = pToCheck.clone().sub(pB);
let angleAC = vAtoB.angleTo(vAtoC);
let angleBC = vBtoA.angleTo(vBtoC);
let epsilon = 0.0017; // 0.1° in radians
if (Math.abs(angleAC) > epsilon || Math.abs(angleBC) > epsilon)
return false;
return true;
}
Длинный ответ :
Произведение Dot между вектором A и вектором B равно произведениювеличина (длина) векторов и косинус угла между векторами.
A dot B == |A| * |B| * cos(alpha)
Если 2 вектора Единичные векторы (нормализованные), тогда произведение точек равно косинусу угла между двумя векторами:
uA = normalize(A)
uB = normalize(B)
uA dot uB == cos(alpha)
Косинус угла больше 0, если угол альфа в гвведите значение -90 ° и меньше 90 °. Это значение равно 0 для 90 ° или -90 ° и меньше, чем 0.
Косинус равен 1,0, если угол равен 0 °, и -1,0, если угол равен 180 °.
Если вы просто хотите проверить, находится ли pC на линии между pA и pB , то вам нужно проверить,угол между векторами равен 0 ° (или 180 °), а косинус угла равен 1,0 (или -1,0).
Из-за ограниченной точности операций вы не можете напрямую сравнить с 1,0. Вы должны убедиться, что косинус больше, чем значение, близкое к 1,0.
Векторы должны быть нормализованы и использовать эпсилон из ~ 0,0016, что соответствуеткосинус (0,1 °):
pA pC pB
x-------x-------x
vAtoB |-------------->|
vAtoC |------>|
vBtoC |<------|
nvAtoB = normalize(pB-pA)
nvAtoC = normalize(pC-pA)
nvBtoC = normalize(pC-pB)
isOn = dot(nvAtoB, nvAtoC) > (1-epsilon) AND dot(nvAtoB, nvBtoC) < -(1-epsilon)
Функция должна быть:
function isPointbetweenTwoOthers (pA, pB, pToCheck) {
var nvAtoB = new THREE.Vector3();
nvAtoB.subVectors(pB, pA).normalize();
var nvAtoC = new THREE.Vector3();
nvAtoC.subVectors(pToCheck, pA).normalize();
var nvBtoC = new THREE.Vector3();
nvBtoC.subVectors(pToCheck, pB).normalize();
let epsilon = 0.0016;
let cos90epsi = 1.0 - epsilon;
return nvAtoB.dot(nvAtoC) > cos90epsi && nvAtoB.dot(nvBtoC) < -cos90epsi;
}
Другой подход - найти ближайшую точку pX до pC на линии от pA до pB . Если pX находится между pA и pB , а расстояние от pX до pC ниже определенного порога,тогда рС составляет от пА до пБ . Поскольку pX находится на линии, определяемой от pA до pB , достаточно сравнить косинус угла с 0,0.
Еслиу вас есть линия, определенная точкой O
на единичном векторе направления D
, тогда точку пересечения X
можно рассчитать, сдвинув точку O
вдоль линии (D
) на расстояниеd
:
X = O + D * d
Таким образом, формула для точки пересечения:
O ... any point on the line
D ... unit vector which points in the direction of the line
P ... the "Point"
X = O + D * dot(P-O, D);
Расчет по точкамна линии A
, B
и точка P
выглядит так:
D = normalize(B-A);
X = A + D * dot(P-A, D);
К счастью THREE.js обеспечивает .projectOnVector()
, что делаетрасчет D * dot(P-A, D)
. См. Также Векторная проекция :
function isPointbetweenTwoOthers (pA, pB, pToCheck) {
let vAtoB = pB.clone().sub(pA);
let vAtoC = pToCheck.clone().sub(pA);
let vBtoC = pToCheck.clone().sub(pB);
// fast exit, C can't be between A and B
if (nvAtoB.dot(nvAtoC) < 0.0 || nvAtoB.dot(nvBtoC) > 0.0)
return false;
// nearest point X to C on the line A, B
let X = pA.clone().add( vAtoC.clone().projectOnVector( vAtoB ) );
// distance between X and C
let distXtoC = X.distanceTo( C );
let threshold = 1.0; // ???
return distXtoC < threshold;
}
Это может быть дополнительно упрощено с помощью Cross product . Величина перекрестного произведения двух векторов равна площади параллелограмма, на которую распространяются векторы.
Это означает, что если перекрестное произведение близко к 0,0, то векторы параллельны и pC равнона линии от пА до пБ :
function isPointbetweenTwoOthers (pA, pB, pToCheck) {
let vAtoB = pB.clone().sub(pA);
let vAtoC = pToCheck.clone().sub(pA);
let vBtoC = pToCheck.clone().sub(pB);
// fast exit, C can't be between A and B
if (nvAtoB.dot(nvAtoC) < 0.0 || nvAtoB.dot(nvBtoC) > 0.0)
return false;
// cross product and area spawned by the normalized vectors B-A and C-A
let nv = vAtoB.normalize().cross(vAtoC.normalize());
let area = nv.length();
let epsilon = 0.0016; // ???
return Math.abs(area) < epsilon;
}