Как получить три неколинейных точки на плоскости?- C ++ - PullRequest
4 голосов
/ 05 декабря 2011

Я пытаюсь реализовать на пересечении линии плоскости. Согласно Википедии Мне нужно три неколинейных точки на плоскости, чтобы сделать это.

Поэтому я попытался реализовать этот алгоритм в C ++, однако. Что-то определенно не так, потому что нет смысла выбирать любые координаты x и y, и они будут вписываться в плоскость. Что если плоскость вертикальная и вдоль оси х? Тогда точка с y = 1 не будет в плоскости.

Я понимаю, что эта проблема была много опубликована в StackOverflow, и я вижу много решений, где плоскость определяется 3 точками. Но у меня есть только нормальная и позиция. И я не могу проверить алгоритм пересечения линии и плоскости, прежде чем перебрать свой неколинейный точечный искатель.

Проблема сейчас в том, что я делю на normal.z, и это, очевидно, не будет работать, когда normal.z равно 0.

Я тестирую с этой плоскостью: Plane * p = новая плоскость (Color (), Vec3d (0.0,0.0,0.0), Vec3d (0.0,1.0,0.0)); // второй параметр: позиция, третий параметр: нормальный

Текущий код дает этот неправильный ответ:

{0 , 0 , 0} // alright, this is the original
{12.8377 , 17.2728 , -inf} // obviously this is not a non-colinear point on the given plane

Вот мой код:

std::vector<Vec3d>* Plane::getThreeNonColinearPoints() {
    std::vector<Vec3d>* v = new std::vector<Vec3d>();

    v->push_back(Vec3d(position.x, position.y, position.z)); // original position can serve as one of the three non-colinear points.

    srandom(time(NULL));

    double rx, ry, rz, start;

    rx = Plane::fRand(10.0, 20.0);
    ry = Plane::fRand(10.0, 20.0);
    // Formula from here: http://en.wikipedia.org/wiki/Plane_(geometry)#Definition_with_a_point_and_a_normal_vector
    // nx(x-x0) + ny(y-y0) + nz(z-z0) = 0
    // |-----------------| <- this is "start"
    //I'll try to insert position as x0,y0,z0 and normal as nx,ny,nz, and solve the equation
    start = normal.x * (rx - position.x) + normal.y * (ry - position.y);
    // nz(z-z0) = -start
    start = -start;
    // (z-z0) = start/nz
    start /= normal.z; // division by zero
    // z = start+z0
    start += position.z;
    rz = start;

    v->push_back(Vec3d(rx, ry, rz));

    // TODO one more point

    return v;
}

Я понимаю, что могу пытаться решить это совершенно неправильно. Если так, пожалуйста, свяжите конкретную реализацию этого. Я уверен, что он должен существовать, когда я вижу так много реализаций пересечения линии и плоскости.

Заранее спасибо.

Ответы [ 3 ]

5 голосов
/ 05 декабря 2011

Плоскость можно определить несколькими способами.Обычно используется точка на плоскости и вектор нормали.Чтобы получить вектор нормали из трех точек (P1, P2, P3), возьмите перекрестное произведение стороны треугольника

P1 = {x1, y1, z1};
P2 = {x2, y2, z2};
P3 = {x3, y3, z3};

N = UNIT( CROSS( P2-P1, P3-P1 ) );
Plane P = { P1, N }

Обратное, чтобы перейти из точки P1 и обычно N до трех точек, вы начинаете с любого направления G , а не вдоль нормального N, такого, что DOT(G,N)!=0.Тогда два ортогональных направления вдоль плоскости имеют вид

//try G={0,0,1} or {0,1,0} or {1,0,0}
G = {0,0,1};
if( MAG(CROSS(G,N))<TINY ) { G = {0,1,0}; }
if( MAG(CROSS(G,N))<TINY ) { G = {1,0,0}; }
U = UNIT( CROSS(N, G) );  
V = CROSS(U,N);
P2 = P1 + U;
P3 = P1 + V;

Линия определяется точкой и направлением.Обычно две точки (Q1, Q2) определяют линию

Q1 = {x1, y1, z1};
Q2 = {x2, y2, z2};
E = UNIT( Q2-Q1 );
Line L = { Q1, E }

Пересечение линии и плоскости определяется точкой на линии r=Q1+t*E, которая пересекает плоскость так, что DOT(r-P1,N)=0.Это решается для скалярного расстояния t вдоль линии как

t = DOT(P1-Q1,N)/DOT(E,N);

и местоположения как

r = Q1+(t*E);

ПРИМЕЧАНИЕ. DOT() возвращает точечное произведение двух векторов, CROSS() перекрестное произведение и UNIT() единичный вектор (с величиной = 1).

DOT(P,Q) = P[0]*Q[0]+P[1]*Q[1]+P[2]*Q[2];
CROSS(P,Q) = { P[1]*Q[2]-P[2]*Q[1], P[2]*Q[0]-P[0]*Q[2], P[0]*Q[1]-P[1]*Q[0] };
UNIT(P) = {P[0]/sqrt(DOT(P,P)), P[1]/sqrt(DOT(P,P)), P[2]/sqrt(DOT(P,P))};
t*P =  { t*P[0], t*P[1], t*P[2] };
MAG(P) = sqrt(P[0]*P[0]+P[1]*P[1]+P[2]*P[2]);
2 голосов
/ 05 декабря 2011

Один из подходов, который вы можете легко реализовать, - это увидеть, где плоскость пересекает оси координат. Для плоскости, заданной уравнением aX + bY + cZ - d = 0, держите две переменные в 0 и решите для третьей. Таким образом, решения были бы (предполагая, что a, b, c и d все ненулевые):

(d/a, 0, 0)
(0, d/b, 0)
(0, 0, d/c)

Вам нужно будет рассмотреть случаи, когда один или несколько коэффициентов равны 0, чтобы вы не получили вырожденные или коллинеарные решения. Например, если ровно один из коэффициентов равен 0 (скажем, a=0), вместо этого вы используете

(1, d/b, 0)
(0, d/b, 0)
(0, 0, d/c)

Если ровно два из коэффициентов равны 0 (скажем, a=0 и b=0), вы можете использовать:

(1, 0, d/c)
(0, 1, d/c)
(0, 0, d/c)

Если d=0, плоскость пересекает три оси в начале координат, поэтому вы можете использовать:

(1, 0, -a/c)
(0, -c/b, 1)
(-b/a, 1, 0)

Вам нужно будет разработать симуляционные случаи для d и ровно еще одного коэффициента, равного 0, а также d и двух других, равных 0. Всего должно быть 16 случаев, но есть несколько вещей что приходит на ум, что должно сделать это несколько более управляемым.

1 голос
/ 05 декабря 2011

Где N=(Nx,Ny,Nz) - нормаль, вы можете проецировать точки N, (Ny,Nz,Nx), (Nz,Nx,Ny) на плоскость: они гарантированно различаются.

В качестве альтернативы, если P и Q находятся в плоскости, P+t(Q-P)xN также находится в плоскости для любого t!=0, где x является перекрестным произведением.

В качестве альтернативы, если M!=N является произвольным вектором, K=MxN и L=KxN являются коллинеарными с плоскостью, и любая точка p на плоскости может быть записана как p=Origin+sK+tL для некоторых s,t.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...