Векторная математика, поиск координат на плоскости между 2 векторами - PullRequest
3 голосов
/ 22 декабря 2010

Я пытаюсь создать 3d трубу вдоль сплайна.У меня есть координаты сплайна (x1, y1, z1 - x2, y2, z2 - и т. Д.), Которые вы можете видеть на рисунке желтым цветом.В этих точках мне нужно создать круги, вершины которых нужно соединить на более позднем стадионе.Круги должны быть перпендикулярны «углам» двух отрезков линии сплайна, чтобы сформировать правильную трубу.Обратите внимание, что сегменты поддерживаются на низком уровне для иллюстрации.

[очевидно, я не могу публиковать изображения, поэтому просмотрите изображение по этой ссылке] http://img191.imageshack.us/img191/6863/18720019.jpg

Я дошел довозможность вычислять вершины каждого кольца в каждой точке сплайна, но все они находятся на одной плоскости, то есть под одним углом.Мне нужно, чтобы они вращались в соответствии с их «ногами» (например, A & B для C).

Я обдумывал это и думал о следующем:

  • два отрезка линии можно рассматривать как 2 вектора (на иллюстрации A и B)
  • угол (на рисунке C) - это то место, где необходимо вычислить кольцо вершин
  • Мне нужнонайти планар, на котором будут находиться все вершины
  • Затем я могу использовать этот планар (= вектор?) для вычисления новых векторов из центральной точки, которая является C
  • , и найти их x, y, z, используя радиус * sin и cos

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

Может ли кто-нибудь указать мне правильное направление?

[править] Чтобы датьнемного больше информации о ситуации:

Мне нужно создать буфер с плавающей точкой, который в группах по 3 описывает позиции вершин и будет связан с OpenGL ES, учитывая еще один буфер с индексами для формирования полигонов.

Чтобы придать форму трубе, я сначала создал массив поплавков, которые в группах по 3 описывают контрольные точки в трехмерном пространстве.

Затем вместе с переменной плотности сегментов,Я передаю эти контрольные точки функции, которая использует эти контрольные точки для создания сплайна CatmullRom и возвращает его в виде другого массива с плавающей точкой, который - в группах по 3 - описывает вершины сплайна Catmull rom.

На каждой из этих вершин я хочу создать кольцо вершин, которое также может различаться по плотности (количество гладкости / вершин на кольцо).

Все прежние вершины (контрольные точки и точки, описывающие сплайны рома) отбрасываются.

Только те вершины, которые образуют кольца труб, будут переданы в OpenGL, который, в свою очередь, соединит те, чтобы сформировать окончательныетруба.

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

[/ edit]

Спасибо!

Ответы [ 4 ]

10 голосов
/ 22 декабря 2010

Предположим, у вас есть параметрическая кривая, такая как:

xx[t_] := Sin[t];
yy[t_] := Cos[t];
zz[t_] := t;  

Что дает: alt text

Вектор касательной к нашей кривой формируется производными в каждом направлении. В нашем случае

Tg[t_]:= {Cos[t], -Sin[t], 1}  

Ортогональная плоскость к этому вектору решает неявное уравнение:

Tg[t].{x - xx[t], y - yy[t], z - zz[t]} == 0  

В нашем случае это:

-t + z + Cos[t] (x - Sin[t]) - (y - Cos[t]) Sin[t] == 0  

Теперь мы находим круг в этой плоскости, центрированный по кривой. т.е.:

c[{x_, y_, z_, t_}] := (x - xx[t])^2 + (y - yy[t])^2 + (z - zz[t])^2 == r^2  

Решая оба уравнения, вы получите уравнение для кругов:

alt text

НТН!

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

И, нарисовав много кругов, вы можете получить (не эффективную) трубку:

alt text

Или с хорошей библиотекой Graphics 3D:

alt text

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

Так как вы настаиваете :) вот программа для расчета круга на стыках.

a = {1, 2, 3}; b = {3, 2, 1}; c = {2, 3, 4};
l1 = Line[{a, b}];
l2 = Line[{b, c}];

k = Cross[(b - a), (c - b)] + b; (*Cross Product*)
angle = -ArcCos[(a - b).(c - b)/(Norm[(a - b)] Norm[(c - b)])]/2;
q = RotationMatrix[angle, k - b].(a - b);
circle[t_] := (k - b)/Norm[k - b] Sin@t + (q)/Norm[q] Cos@t + b;

Show[{Graphics3D[{
    Red, l1,
    Blue, l2,
    Black, Line[{b, k}],
    Green, Line[{b, q + b}]}, Axes -> True],
  ParametricPlot3D[circle[t], {t, 0, 2 Pi}]}]

alt text

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

Здесь у вас есть сетка, построенная этим методом. Это не красиво, ИМХО:

alt text

1 голос
/ 22 декабря 2010

Я не знаю, какой язык вы выберете, но если вы говорите на MatLab, уже есть несколько доступных реализаций. Даже если вы используете другой язык, часть кода может быть достаточно ясной, чтобы вызвать повторную реализацию.

Ключевым моментом является то, что если вы не хотите, чтобы трубка скручивалась при соединении вершин, вы не можете определить базис локально, а должны распространять его вдоль кривой. Рамка Frenet , предложенная jalexiou, является одним из вариантов, но более простые вещи работают также хорошо.

Я сделал простую реализацию MatLab под названием tubeplot.m в мои годы становления (основываясь на простом распространении не по Френету), и, взглянув на нее, я вижу, что Андерс Сандберг из kth.se сделал (re?) реализация с тем же именем, доступная по адресу http://www.nada.kth.se/~asa/Ray/Tubeplot/tubeplot.html.

TubePlot.m illustration

Edit: Ниже приведен псевдокод для простой реализации в tubeplot.m. Я нашел, что это было довольно надежно.

План состоит в том, чтобы распространить две нормали a и b вдоль кривой, поэтому что в каждой точке кривой a, b и касательная к кривой сформирует ортогональный базис, который "как можно ближе" к основа, использованная в предыдущем пункте. Используя эту основу, мы можем найти точки на окружности трубы.

// *** Input/output ***
// v[0]..v[N-1]: Points on your curve as vectors
//               No neighbours should overlap
// nvert: Number of vertices around tube, integer.
// rtube: Radius of tube, float.
// xyz: (N, nvert)-array with vertices of the tube as vectors


// *** Initialization ***
// 1: Tangent vectors
for i=1 to N-2:
    dv[i]=v[i+1]-v[i-1]
dv[0]=v[1]-v[0], dv[N-1]=v[N-1]-v[N-2]

// 2: An initial value for a (must not be pararllel to dv[0]):
idx=<index of smallest component of abs(dv[0])>
a=[0,0,0], a[idx]=1.0

// *** Loop ***
for i = 0 to N-1:
    b=normalize(cross(a,dv[i]));
    a=normalize(cross(dv[i],b));
    for j = 0 to nvert-1:
        th=j*2*pi/nvert 
        xyz[i,j]=v[i] + cos(th)*rtube*a + sin(th)*rtube*b

Детали реализации: Вероятно, вы можете ускорить процесс, предварительно рассчитав cos и sin. Кроме того, чтобы получить надежную производительность, вы должны слить точки входа ближе, чем, скажем, 0.1*rtube, или хотя бы проверить, что все векторы dv отличны от нуля.

НТН

1 голос
/ 22 декабря 2010

Вам нужно взглянуть на формулы Фенета в Дифференциальной геометрии. Смотрите рисунок 2.1 для примера со спиралью.

Поверхности и кривые

0 голосов
/ 22 декабря 2010

Взяв перекрестное произведение сегмента линии и вектора вверх, мы получим вектор под прямыми углами к ним обоим (если сегмент линии не направлен точно вверх или вниз), который я назову горизонтальным.Взяв перекрестное произведение горизонтали и сегмента линии, мы получим еще один вектор, который находится под прямым углом к ​​сегменту линии и другому (назовем его вертикальным).Затем вы можете получить координаты окружности по lineStart + cos theta * горизонтальный + sin theta * вертикальный для theta в 0 - 2Pi.

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

...