Будет использовать Javascript для демонстрации этого (а также предоставления кода), но я могу сделать это на любом языке после процесса.
Ссылки
Концепция
В Для этого мы будем использовать проекции углов на оси другого прямоугольника 2 (X и Y). Два прямоугольника сталкиваются только тогда, когда 4 проекции на одном прямоугольнике соприкасаются с другими:
- Прямоугольные синие углы на прямоугольной оранжевой оси X
- Прямоугольные синие углы на прямоугольной оранжевой оси Y
- Прямоугольники оранжевого цвета на оси X Rect Blue
- Прямоугольники оранжевого цвета на оси Y Rect Blue
Процесс
1- Найдите ось прямоугольника
Начните с создания 2 векторов для оси 0; от 0 (центр прямоугольника) до X (OX ) и Y (OY), затем поверните их оба, чтобы выровнять их по оси прямоугольников.
Википедия о повороте 2D-вектора
const getAxis = (rect) => {
const OX = new Vector({x:1, y:0});
const OY = new Vector({x:0, y:1});
// Do not forget to transform degree to radian
const RX = OX.Rotate(rect.angle * Math.PI / 180);
const RY = OY.Rotate(rect.angle * Math.PI / 180);
return [
new Line({...rect.center, dx: RX.x, dy: RX.y}),
new Line({...rect.center, dx: RY.x, dy: RY.y}),
];
}
Где вектор простой объект x,y
class Vector {
constructor({x=0,y=0}={}) {
this.x = x;
this.y = y;
}
Rotate(theta) {
return new Vector({
x: this.x * Math.cos(theta) - this.y * Math.sin(theta),
y: this.x * Math.sin(theta) + this.y * Math.cos(theta),
});
}
}
И линия представляет собой уклон с использованием 2 векторов:
- origin: вектор для начальной позиции
- direction: вектор для единицы Направление
class Line {
constructor({x=0,y=0, dx=0, dy=0}) {
this.origin = new Vector({x,y});
this.direction = new Vector({x:dx,y:dy});
}
}
Результат шага
2- Используйте прямую ось для получения углов
* 10 76 * Сначала нужно расширить нашу ось (у нас размер единицы 1 пиксель), чтобы получить половину ширины (для X) и высоты (для Y), чтобы можно было, добавив, когда (и обратное), получить все углы.
const getCorners = (rect) => {
const axis = getAxis(rect);
const RX = axis[0].direction.Multiply(rect.w/2);
const RY = axis[1].direction.Multiply(rect.h/2);
return [
rect.center.Add(RX).Add(RY),
rect.center.Add(RX).Add(RY.Multiply(-1)),
rect.center.Add(RX.Multiply(-1)).Add(RY.Multiply(-1)),
rect.center.Add(RX.Multiply(-1)).Add(RY),
]
}
Использование этих 2 методов новостей для Vector:
// Add(5)
// Add(Vector)
// Add({x, y})
Add(factor) {
const f = typeof factor === 'object'
? { x:0, y:0, ...factor}
: {x:factor, y:factor}
return new Vector({
x: this.x + f.x,
y: this.y + f.y,
})
}
// Multiply(5)
// Multiply(Vector)
// Multiply({x, y})
Multiply(factor) {
const f = typeof factor === 'object'
? { x:0, y:0, ...factor}
: {x:factor, y:factor}
return new Vector({
x: this.x * f.x,
y: this.y * f.y,
})
}
Результат шага
3- Получить проекции углов
Для каждого угла прямоугольника получить координаты проекции по обеим осям другого прямоугольника.
Просто добавив эту функцию в класс Vector:
Project(line) {
let dotvalue = line.direction.x * (this.x - line.origin.x)
+ line.direction.y * (this.y - line.origin.y);
return new Vector({
x: line.origin.x + line.direction.x * dotvalue,
y: line.origin.y + line.direction.y * dotvalue,
})
}
(Особая благодарность Mbo за решение для получения проекции.)
Результат шага
4- Выберите внешние углы на проекциях
Чтобы отсортировать (по оси прямоугольника) все проецируемые точки и взять минимальные и Максимальное количество спроецированных точек, которые мы можем:
- Создать вектор для представления: Прямоугольник от центра до проецируемого угла
- Получить расстояние с помощью Vector Ma Функция gnitude.
get magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
- Используйте скалярное произведение , чтобы узнать, обращен ли вектор в том же направлении оси обратного (где расстояние со знаком "отрицательное")
getSignedDistance = (rect, line, corner) => {
const projected = corner.Project(line);
const CP = projected.Minus(rect.center);
// Sign: Same directon of axis : true.
const sign = (CP.x * line.direction.x) + (CP.y * line.direction.y) > 0;
const signedDistance = CP.magnitude * (sign ? 1 : -1);
}
Затем, используя простой l oop и тест min / max, мы можем найти 2 внешних угла. Сегмент между ними - это проекция прямоугольника на другую ось.
Результат шага
5- Финал: все ли проекции попадают в прямоугольник?
Используя простой одномерный тест вдоль оси, мы можем узнать, попадают ли они или нет:
const isProjectionHit = (minSignedDistance < 0 && maxSignedDistance > 0
|| Math.abs(minSignedDistance) < rectHalfSize
|| Math.abs(maxSignedDistance) < rectHalfSize);
Готово
Проверка всех 4 прогнозов даст вам окончательный результат. =] !!
Надеюсь, этот ответ поможет как можно большему количеству людей. Любые комментарии приветствуются.