Как найти две точки перпендикулярные отрезку на заданном расстоянии?
Имеется две точки: c, d, через них проходит прямая. Имеется точки AB - отрезок. Вопрос: как выставить c и d таким образом, чтобы они были перпендикулярны отрезку AB?
P.S. Известны координаты только точек AB, а расстояние между c и d составляет 1.
Ответы (3 шт):
Автор решения: MBo
→ Ссылка
Направляющий вектор
dx, dy = B.x-A.x, B.y - A.y
Длина
len = sqrt(dx*dx+dy*dy)
Нормализованный вектор (единичной длины)
udx = dx / len
udy = dy / len
Перпендикулярный единичный вектор
nx = - udy
ny = udx
Точки (C, D) на перпендикуляре на расстоянии R
A.x + nx * R, A.y + ny * R
A.x - nx * R, A.y - ny * R
Автор решения: Kromster
→ Ссылка
Алгоритм:
- Все расчеты удобнее вести от точки
A, принимая её координаты за 0:0 - Найти перпендикуляр к вектору
AB - Нормализовать его (чтобы он был единичной длины)
- Умножить на половину ширины - это ваше
c - Умножить на минус половину ширины - это ваше
d
Автор решения: prisoner849
→ Ссылка
Раз уж речь про three.js и 2D, то:
var a = new THREE.Vector2(...);
var b = new THREE.Vector2(...);
var ab = new THREE.Vector2().subVectors(b, a); //базовый вектор
var c = new THREE.Vector2(-ab.y, ab.x).setLength(0.5); // перпендикуляр к (x, y) есть (-y, x)
var d = new THREE.Vector2().copy(c).negate(); // можно использовать d = c.clone().negate()
c.add(a);
d.add(a);
И если 2D на XY по каким-то причинам не мил, то можно это организовать на XZ в 3D:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import { OrbitControls } from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 10, 0);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.enablePan = false;
scene.add(new THREE.GridHelper());
let ptsBase = [new THREE.Vector3(1, 0, -2), new THREE.Vector3(4, 0, -4)];
let ptsNorm = ptsBase.map((p, idx, arr) => {
let v = new THREE.Vector3();
getNormAt(v, 0.5 * (idx % 2 == 0 ? 1 : -1), arr);
v.add(ptsBase[0]);
return v;
});
let baseLine = new THREE.Line(
new THREE.BufferGeometry()
.setFromPoints(ptsBase)
.setAttribute(
"color",
new THREE.Float32BufferAttribute([0, 0, 1, 0, 1, 1], 3)
),
new THREE.LineBasicMaterial({ vertexColors: true })
);
let normLine = new THREE.Line(
new THREE.BufferGeometry()
.setFromPoints(ptsNorm)
.setAttribute(
"color",
new THREE.Float32BufferAttribute([1, 0, 0, 1, 1, 0], 3)
),
new THREE.LineBasicMaterial({ vertexColors: true })
);
scene.add(baseLine, normLine);
renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});
function getNormAt(vector, distance, basePoints) {
let v3 = new THREE.Vector3().subVectors(basePoints[1], basePoints[0]);
vector.set(v3.z, 0, -v3.x).setLength(distance); // вся магия тут
}
</script>
A - синий, B - аква, С - красный, D - желтый
