Пересечение бесконечного цилиндра и круга в трехмерном пространстве - PullRequest
0 голосов
/ 28 апреля 2020

Я пытаюсь определить, пересекаются ли бесконечный цилиндр и круг в трехмерном пространстве. Это было задано здесь: Нахождение пересечения Круга и Бесконечного Цилиндра в трехмерном пространстве

Однако, только математик может понять ответ Ив Дауста. Есть еще один ответ от MBo, который я кодировал (ниже). К сожалению, тестирование показывает, что оно не работает должным образом. Я ищу помощь в этом, что нематематик может понять. Заранее спасибо!

// cylinderLoc = infinite cylinder location (any location on the cylinder axis)
// cylinderDir = infinite cylinder direction (normalized)
// cylinderRadius = infinite cylinder radius
// circleLoc = circle location (circle center)
// circleDir = circle direction (normalized direction of the circle plane)
// circleRadius = circle radius
bool cylinderIntersectCircle(
    Vector3 cylinderLoc, Vector3 cylinderDir, double cylinderRadius,
    Vector3 circleLoc, Vector3 circleDir, double circleRadius)
{
    // get the perpendicular distance from the circle center to the cylinder axis
    Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
    diff = Vector3.Cross(cylinderDir, diff);
    double distance = diff.Length(); // the length is also called the magnitude

    // get the dot product (cosine) between the cylinder and circle directions
    double dot = Vector3.Dot(cylinderDir, circleDir);

    // determine if the cylinder and circle intersect
    return (distance <= cylinderRadius + circleRadius * Abs(dot));
}

ОБНОВЛЕНИЕ: Вот изображение, показывающее, что может сделать проще. Мне нужно это «сладкое пятно», где ободок круга находится глубоко в месте, которое имеет цилиндр на плоскости круга. Направление от центра круга, которое принимает его ближе всего к контуру цилиндра. Cylinder / circle intersection

ОБНОВЛЕНИЕ 2: Вот несколько примеров номеров для MBo, чтобы увидеть, которые демонстрируют его алгоритм, возвращающий false, когда он должен возвращать true. Ниже это изображение результата. Я сделал каждый объект разным цветом, чтобы помочь. Камера поворачивается на 180 градусов для лучшего обзора (если смотреть сзади). Зеленая рамка - это «расстояние». Синяя рамка - "цилиндр-радиус + круг-радиус * абс (точка)".

cylinderLoc = ( 0.0, 0.0, 0.0 )
cylinderDir = ( 0.0, 1.0, 0.0 )
cylinderRadius = 0.3

circleLoc = ( -0.25, 0.0, -0.5 )
circleDir = ( -0.6, -0.5, 0.6245 )
circleRadius = 0.45
// get the perpendicular distance from the circle center to the cylinder axis
Vector3 diff = Vector3.Subtract(circleLoc, cylinderLoc);
// ---> diff = ( -0.25, 0.0, -0.5 ) - ( 0.0, 0.0, 0.0 )
// ---> diff = ( -0.25, 0.0, -0.5 )
diff = Vector3.Cross(cylinderDir, diff);
// ---> diff = cross(( 0.0, 1.0, 0.0 ), ( -0.25, 0.0, -0.5 ))
// ---> cross.x = 1.0 * -0.5  -  0.0  * 0.0   = -0.5
// ---> cross.y = 0.0 * -0.25 - -0.5  * 0.0   =  0.0
// ---> cross.z = 0.0 *  0.0  - -0.25 * 1.0   =  0.25
// ---> diff = ( -0.5, 0.0, 0.25 ));
double distance = diff.Length(); // the length is also called the magnitude
// ---> distance = Sqrt(-0.5 * -0.5 + 0.0 * 0.0 + 0.25 * 0.25)
// ---> distance = Sqrt(0.25 + 0.0 + 0.0625)
// ---> distance = Sqrt(0.3125)
// ---> distance = 0.55901699437494742410229341718282 (0.559 is close enough)

// get the dot product (cosine) between the cylinder and circle directions
double dot = Vector3.Dot(cylinderDir, circleDir);
// ---> dot = dot((0.0, 1.0, 0.0), (-0.6, -0.5, 0.6245))
// ---> dot = 0.0 * -0.6 + 1.0 * -0.5 + 0.0 * 0.6245
// ---> dot = -0.5

// determine if the cylinder and circle intersect
return (distance <= cylinderRadius + circleRadius * Abs(dot));
// ---> return (0.559 <= 0.3 + 0.45 * Abs(-0.5));
// ---> return (0.559 <= 0.525);
// ---> This returns false, but the circle does in fact intersect the cylinder.

enter image description here

Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

Картина говорит тысячу слов. Это то, что я придумал на данный момент. Это не на 100% идеально, но это довольно близко. Все пурпурные точки на рисунке могут быть рассчитаны, что означает, что можно рассчитать желтые линии Просто посмотрите, пересекает ли желтая линия цилиндр, что легко сделать.

  • Получите перпендикулярное направление от расположения оси цилиндра к плоскости круга.
  • Пересеките его с помощью ось цилиндра, чтобы получить горизонтальное перекрестие.
  • Пересечь это с осью цилиндра, чтобы получить вертикальное перекрестие.
  • Сместить ось цилиндра по ее радиусу вдоль вертикального перекрестия в обоих направлениях.
  • Пересекают обе оси (лучи) с плоскостью окружности для двух конечных точек эллипса.
  • Сейчас мы по существу в 2D:
  • Эти две точки находятся на Плоскость круга. Соедините их для длинной оси эллипса.
  • Найдите ближайшую точку на этой линии к центру круга. Сопоставьте его с радиусом круга.
  • Возьмите линию от центра круга до центра эллипса. Сопоставьте его с радиусом круга.
  • Центром этих двух мест является пурпурная точка на рисунке. Сопоставьте его с радиусом круга.
  • Центром круга в этом месте является желтая линия. Пересечь его с цилиндром.

enter image description here

0 голосов
/ 29 апреля 2020

Я сделал быстрый тест - буквальная реализация в Delphi моего ответа в приведенной топи c, и результаты выглядят правильно.

Радиус цилиндра 2 по OX, центр круга в by=5.

Для окружности, нормальной вдоль OX (параллельный цилиндр, закомментированный bdx, bdy в коде), существует пересечение для радиуса окружности br = 4 и 5, и нет пересечения для br = 2.

Для окружности нормальное наклонение на 45 (bdx, bdy = 0.707 в коде) пересечение существует для радиуса окружности br = 5 и пересечение для br = 2, 4 отсутствует (в последнем случае проекция радиуса окружности становится ~2.8 < 3).

Не могли бы вы проверить Ваша функция с теми же наборами данных?
Вы действительно нормализовали векторы направления?

Также обратите внимание, что этот подход дает только факт пересечения, для ближайшей точки мы должны работать немного больше.

var
  ax, ay, az, bx, by, bz: Double;
  adx, ady, adz, bdx, bdy, bdz, ar, br: Double;
  cdx, cdy, cdz, vpx, vpy, vpz, vplen: Double;
  adot: Double;
begin
  ax := 0;
  ay := 0;
  az := 0;
  bx := 3;
  by := 5;
  bz := 0;
  adx := 1;
  ady := 0;
  adz := 0;
  bdx := 0.7071;
  bdy := 0.7071;
  //bdx := 1
  //bdy := 0;
  bdz := 0;
  ar := 2;
  br := 5; //2,4
  cdx := bx - ax;
  cdy := by - ay;
  cdz := bz - az;
  vpx := ady * cdz - adz * cdy;
  vpy := adz * cdx - adx * cdz;
  vpz := adx * cdy - ady * cdx;
  vplen := sqrt(vpx * vpx + vpy * vpy + vpz * vpz);
  adot := Abs(adx * bdx + ady * bdy + adz * bdz);
  if vplen <= ar + br * adot then
    Caption := 'Intersection'
  else
    Caption := 'No';
...