Пересечение цилиндра и прямоугольно параллелепипеда (куба в частном случае)
Бокс задан двумя точками Bmax(X_max, Y_max, Z_max) и Bmin(X_min, Y_min, Z_min). По этим двум точкам можно определить остальные 6 вершин бокса, например: (X_max, Y_max, Z_min), (X_max, Y_min, Z_max) и так далее...
Цилиндр задан двумя центрами его оснований O1(x1,y1,z1), O2(x2,y2,z2) и радиусом R.
Т.е. цилиндр может находиться под разными углами, необязательно в строго вертикальном положении, а куб всегда строго выровнен по осям.
Моя задача, определить пересекается ли цилиндр с кубом.
Сперва я хотел реализовать следующий алгоритм:
- Определить если хотя бы один конец находится внутри бокса, то значит пересекается
- Если оба конца за пределами бокса, то для каждой грани куба найти уравнение плоскости, и проверить пересекается ли плоскость с цилиндром Но так и не нашей способ проверить пересекается ли плоскость с цилиндром, да и не уверен что это правильный алгоритм проверки.
Далее я нашел документ в котором описан другой алгоритм: https://www.geometrictools.com/Documentation/IntersectionBoxCylinder.pdf
и его исходный код: https://www.geometrictools.com/Downloads/Downloads.html файл - (GTEngine 7.0 Distribution (ZIP))
Начал тестировать алгоритм, но результат не соответствует ожидаемому результату.
Как тестировал:
- Распаковал архив
- Открыл решение GeometricTools\GTE\Samples\Intersection\IntersectBoxCylinder\IntersectBoxCylinderDX11.v16.sln
- Запустил отладку рендерится сцена:
Разобравшись в IntersectBoxCylinderWindow3.cpp понял что когда бокс пересекает цилиндр то он становится красным метод TestIntersection(). Там же можно поменять начальные координаты и размеры фигур (бокса и цилиндра) в методе CreateScene()
Установил для бокса параметры :
mCylinder.axis.origin = { 0.0f, 0.0f, 1.5f }; // основание цилиндра
mCylinder.axis.direction = { 0.0f, 0.0f, 1.0f };// направление (можно вычислить если знаем координаты конца и начала)
mCylinder.radius = 1.0f; // радиус
mCylinder.height = 1.0f; // высота
mBox.center = { 0.5f, 0.5f, 0.5f }; // центр
mBox.axis[0] = { 1.0f, 0.0f, 0.0f }; // угол поворота бокса (в моем случае никогда не изменяется)
mBox.axis[1] = { 0.0f, 1.0f, 0.0f };
mBox.axis[2] = { 0.0f, 0.0f, 1.0f };
mBox.extent = { 0.5f, 0.5f, 0.5f }; // Эксцент
Отлаживаем видим, что никакого пересечения нет, но алгоритм его фиксирует и делает бокс красным
- тоже самое проверил написав следующий код:
#include <iostream>
#include "Mathematics/IntrAlignedBox3Cylinder3.h"
#include "Mathematics/Cylinder3.h"
#include "Mathematics/Vector3.h"
#include "Mathematics/Vector.h"
#include "Mathematics/AlignedBox.h"
#include <cmath>
#include <limits.h>
#include <float.h>
// расстояние между точками в пространстве
static double PointPointDistance(Vector3<double> const& point1, Vector3<double> const& point2)
{
return sqrt(pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2) + pow(point1[2] - point2[2], 2));
}
int32_t main()
{
// центры оснований
Vector3<double> start = {0,0,1.5};
Vector3<double> end = {0,0,2.5};
// высота цилиндра
double height = PointPointDistance(start, end);
// направление цилиндра
Vector3<double> dir = end - start;
Normalize(dir);
Cylinder3<double> cylinder;
cylinder.axis.direction = dir;
cylinder.axis.origin = start;
cylinder.radius = 1;
cylinder.height = height;
AlignedBox3<double> box;
// минимальная/максимальная вершина
box.min = { 0,0,0 };
box.max = { 1,1,1 };
// хит тест
TIQuery<double, AlignedBox3<double>, Cylinder3<double>> mQuery;
bool result = mQuery(box,cylinder).intersect;
return 0;
}
результат тоже true, хотя по факту это не так
Помимо этого, не проходят еще несколько тестов
Других библиотек с реализацией не нашел, и так не смог реализовать алгоритм самостоятельно.
Поделитесь методом, если знаете
Ответы (1 шт):
Действительно цилиндр нужно определять через центр оси, а не через центр основания. Вот тут пример с правильным применением модуля https://github.com/SebWouters/AabbCyl/tree/main

