Линия пересечения между двумя плоскостями - PullRequest
15 голосов
/ 20 июня 2011

Как я могу найти линию пересечения между двумя плоскостями?

Я знаю идею математики, и я сделал перекрестное произведение между плоскостями нормальных векторов

, но как получитьстрока из приведенного вектора программно

Ответы [ 6 ]

17 голосов
/ 20 июня 2011

Уравнение плоскости: ax + by + cz + d = 0, где (a, b, c) - нормаль плоскости, а d - расстояние до начала координат. Это означает, что каждая точка (x, y, z), которая удовлетворяет этому уравнению, является членом плоскости.

Даны две плоскости:

P1: a1x + b1y + c1z + d1 = 0
P2: a2x + b2y + c2z + d2 = 0

Пересечение между ними - это множество точек, которое проверяет оба уравнения. Чтобы найти точки вдоль этой линии, вы можете просто выбрать значение для x, любое значение, а затем решить уравнения для y и z.

y = (-c1z -a1x -d1) / b1
z = ((b2/b1)*(a1x+d1) -a2x -d2)/(c2 - c1*b2/b1)

Если вы сделаете x=0, это станет проще:

y = (-c1z -d1) / b1
z = ((b2/b1)*d1 -d2)/(c2 - c1*b2/b1)
12 голосов
/ 05 сентября 2015

Добавление этого ответа для полноты, поскольку на момент написания ни один из ответов здесь не содержал рабочего кода-примера, который непосредственно касается вопроса.

Хотя другие ответы здесь уже охватывали принципы .


Нахождение линии между двумя плоскостями можно рассчитать с использованием упрощенной версии алгоритма пересечения с 3 плоскостями.

2-й, «более надежный метод» из ответа Бобобо относится к перекрестку с 3 плоскостями.

Хотя это хорошо работает для 2 плоскостей (где 3-я плоскость может быть рассчитана с использованием перекрестного произведения первых двух) , проблема может быть дополнительно уменьшена для версии с 2 плоскостями.

  • Нет необходимости использовать матричный определитель 3x3,
    вместо этого мы можем использовать квадрат длины перекрестного произведения между первой и второй плоскостью (которое является направлением 3-й плоскости) .
  • Не нужно указывать расстояние до 3-х плоскостей,
    (вычисление конечного местоположения) .
  • Нет необходимости сводить на нет расстояния.
    Сохраните несколько циклов ЦП, поменяв местами перекрестный заказ.

Включая этот пример кода, поскольку он может быть не сразу очевиден.

// Intersection of 2-planes: a variation based on the 3-plane version.
// see: Graphics Gems 1 pg 305
//
// Note that the 'normal' components of the planes need not be unit length
bool isect_plane_plane_to_normal_ray(
        const Plane& p1, const Plane& p2,
        // output args
        Vector3f& r_point, Vector3f& r_normal)
{
    // logically the 3rd plane, but we only use the normal component.
    const Vector3f p3_normal = p1.normal.cross(p2.normal);
    const float det = p3_normal.length_squared();

    // If the determinant is 0, that means parallel planes, no intersection.
    // note: you may want to check against an epsilon value here.
    if (det != 0.0) {
        // calculate the final (point, normal)
        r_point = ((p3_normal.cross(p2.normal) * p1.d) +
                   (p1.normal.cross(p3_normal) * p2.d)) / det;
        r_normal = p3_normal;
        return true;
    }
    else {
        return false;
    }
}
12 голосов
/ 07 августа 2013

Нахождение точки на линии

Чтобы получить пересечение 2 плоскостей, вам нужна точка на линии и направление этой линии.

Нахождение направления этой линиидействительно просто, просто пересечь 2 нормали двух плоскостей, которые пересекаются.

lineDir = n1 × n2

Но эта линия проходит через начало координат, а линия, проходящая вдоль пересечений ваших плоскостей, может и не пройти.Таким образом, ответ Мартиньо обеспечивает отличное начало для нахождения точки на линии пересечения (в основном любая точка, находящаяся на обеих плоскостях).

В случае, если вы хотеличтобы увидеть вывод, как решить эту проблему, вот математика:

Сначала позвольте x = 0.Теперь у нас есть 2 неизвестных в 2 уравнениях вместо 3 неизвестных в 2 уравнениях (мы произвольно выбрали одно из неизвестных).

Тогда плоские уравнения (члены были исключены, так как мы выбрали x = 0):

B 1 y + C 1 z + D 1 = 0

B 2 y + C 2 z + D 2 = 0

Мы хотим, чтобы y и z были такими, чтобы оба уравнения были решены правильно (= 0)для заданного значения B 1 , C 1 .

Итак, просто умножьте верхнее выражение на (-B 2 / B 1 ) чтобы получить

-B 2 y + (-B 2 / B 1 ) * C 1 z + (-B 2 / B 1 ) * D 1 = 0

B 2 y + C 2 z + D 2 = 0

Добавьте уравнения, чтобы получить

z =((-B 2 / B 1 ) * D 1 - D 2 ) / (C 2 * B 2 / B 1 ) * C 1 )

Бросокz теперь вы найдете в 1-м уравнении, чтобы найти y как

y = (-D 1 - C 1 z) / B 1

Обратите внимание, что переменная best , равная 0, - это переменная с низшими коэффициентами, поскольку она все равно не несет никакой информации.Поэтому, если C 1 и C 2 оба равны 0, лучше выбрать z = 0 (вместо x = 0).

Приведенное выше решение можетвсе еще облажаться, если B 1 = 0 (что не исключено).Вы можете добавить в некоторые операторы if, которые проверяют, если B 1 = 0, и если это так, убедитесь, что вместо этого решите для одной из других переменных.

Решение с использованием пересечения 3 плоскостей

Из пользовательского ответа решение для закрытой формы для пересечения 3-х плоскостей было фактически в Graphics Gems 1. Формула:

P_intersection = ((point_on1 • n1) (n2 × n3) + (point_on2 • n2) (n3 × n1) + (point_on3 • n3) (n1 × n2)) / det (n1, n2, n3)

Фактически point_on1 • n1 = -d1 (при условии, что вы пишете свои плоскости Ax + By + Cz + D = 0, а не = -D).Таким образом, вы можете переписать его как:

P_intersection = ((-d1) (n2 × n3) + (-d2) (n3 × n1) + (-d3) (n1 × n2))/ det (n1, n2, n3)

Функция, которая пересекает 3 плоскости:

// Intersection of 3 planes, Graphics Gems 1 pg 305
static Vector3f getIntersection( const Plane& plane1, const Plane& plane2, const Plane& plane3 )
{
  float det = Matrix3f::det( plane1.normal, plane2.normal, plane3.normal ) ;

  // If the determinant is 0, that means parallel planes, no intn.
  if( det == 0.f ) return 0 ; //could return inf or whatever

  return ( plane2.normal.cross( plane3.normal )*-plane1.d +
           plane3.normal.cross( plane1.normal )*-plane2.d + 
           plane1.normal.cross( plane2.normal )*-plane3.d ) / det ;            
}

Доказательство того, что это работает (желтая точка - это пересечение плоскостей rgb здесь)

enter image description here

Получение линии

Если у вас есть точка пересечения, общая для двух плоскостей, линия просто идет

P + t* d

Где P - точка пересечения, t может идти от (-inf, inf), а d - вектор направления, который является перекрестным произведением нормалей двух исходных плоскостей.

Линия пересечения между красной и синей плоскостями выглядит следующим образом

enter image description here

Эффективность и стабильность

«Надежный» (2-й способ) по моим подсчетам берет 48 элементарных операций против 36 элементарных операций, которые использует 1-й способ (изоляция x, y).Есть компромисс между стабильностью и # вычислениями между этими двумя способами.

Это было быдовольно катастрофично получить (0, inf, inf) обратно от вызова к 1-му способу в случае, если B 1 было 0, а вы не проверяли. Таким образом, добавление операторов if и отсутствие деления на 0 для 1-го способа может дать вам стабильность за счет раздувания кода и дополнительного ветвления (что может быть довольно дорогим). Метод пересечения с 3 плоскостями почти не имеет ответвлений и не даст вам бесконечности.

6 голосов
/ 13 июля 2013

Этот метод позволяет избежать деления на ноль, если две плоскости не параллельны.

Если это самолеты:

A1*x + B1*y + C1*z + D1 = 0
A2*x + B2*y + C2*z + D2 = 0

1) Найти вектор, параллельный линии пересечения. Это также нормаль для 3-й плоскости, которая перпендикулярна двум другим плоскостям:

(A3,B3,C3) = (A1,B1,C1) cross (A2,B2,C2)

2) Сформировать систему из 3 уравнений. Они описывают 3 плоскости, которые пересекаются в точке:

A1*x1 + B1*y1 + C1*z1 + D1 = 0
A2*x1 + B2*y1 + C2*z1 + D2 = 0
A3*x1 + B3*y1 + C3*z1 = 0

3) Решите их, чтобы найти x1, y1, z1. Это точка на линии пересечения.

4) Параметрическими уравнениями линии пересечения являются:

x = x1 + A3 * t
y = y1 + B3 * t
z = z1 + C3 * t
0 голосов
/ 01 декабря 2015

Подход, основанный на детерминантах, аккуратен, но трудно понять, почему он работает.

Вот еще один интуитивно понятный способ.

Идея состоит в том, чтобы сначала пройти от начала координат до ближайшей точки на первой плоскости (p1), а затем оттуда перейти к ближайшей точке на линии пересечения двух плоскостей. (Вдоль вектора, который я называю v ниже.)

Given
=====
 First plane: n1 • r = k1
Second plane: n2 • r = k2

Working
=======
dir = n1 × n2
p1 = (k1 / (n1 • n1)) * n1
v = n1 × dir
pt = LineIntersectPlane(line = (p1, v), plane = (n2, k2))

LineIntersectPlane
==================
#We have n2 • (p1 + lambda * v) = k2
lambda = (k2 - n2 • p1) / (n2 • v)
Return p1 + lambda * v

Output
======
Line where two planes intersect: (pt, dir)

Это должно дать тот же смысл, что и подход, основанный на детерминантах. Существует почти наверняка связь между ними. По крайней мере, знаменатель n2 • v одинаков, если мы применяем правило «скалярного тройного произведения». Таким образом, эти методы, вероятно, похожи в том, что касается номеров условий.

Не забудьте проверить (почти) параллельные плоскости. Например: if (dir • dir < 1e-8) должно работать хорошо, если используются единицы измерения.

0 голосов
/ 20 июня 2011

Перекрестное произведение линии - это направление линии пересечения.Теперь вам нужна точка на перекрестке.

Вы можете сделать это, взяв точку на перекрестном произведении, затем вычтя нормаль плоскости A * расстояние до плоскости A и нормаль плоскости B * расстояние до плоскости b.Очиститель:

p = Точка на перекрестном произведении

точка пересечения = ([p] - ([Нормаль плоскости A] * [расстояние от p до плоскости A]) - ([Нормалаплоскость B] * [расстояние от p до плоскости B]))

Редактировать:

У вас есть две плоскости с двумя нормалями:

N1 and N2

.Направление линии пересечения:

C = N1 x N2

В приведенном выше классе есть функция для вычисления расстояния между точкой и плоскостью.Используйте его, чтобы получить расстояние некоторой точки p на C до обеих плоскостей:

p = C //p = 1 times C to get a point on C
d1 = plane1.getDistance(p)
d2 = plane2.getDistance(p)

Линия пересечения:

resultPoint1 = (p - (d1 * N1) - (d2 * N2))
resultPoint2 = resultPoint1 + C
...