Главная страница


ru.algorithms

 
 - RU.ALGORITHMS ----------------------------------------------------------------
 From : Nick Gorev                           2:5020/400     25 Jan 2002  07:06:42
 To : Nick Gorev
 Subject : Реализация с помощью метода Штурма
 -------------------------------------------------------------------------------- 
 
 Hello, All!
 Меня попросили подробнее рассказать решение.
 
 Hачну с постановки задачи:
 Имеется тор, стандартно вложенный в R^3:
 Окружность радиуса r c центром в точке (0,p,0),
 лежащая в плоскости XOZ вращается вдоль окружности
 с центром в точке (0,0,0) радиуса p, лежащей
 в плоскости XOY. Получается тор (поверхность бублика).
 Алгебраическое уравнение этой поверхности:
 (x^2 + y^2)^2 + 2*(z^2 - p^2 - r^2)*(x^2 + y^2) +
       (z^2 + p^2 - r^2)^2 = 0
 
 Имеется отрезок с концами (x0,y0,z0) и (x1,y1,z1).
 Требуется определить, пересекаются ли отрезок с тором.
 
 Параметрическое уравнение отрезка
 x(t) = x0 + t * vx
 y(t) = y0 + t * vy
 z(t) = z0 + t * vz
 где
 vx = x1 - x0
 vy = y1 - y0
 vz = z1 - z0
 параметр t пробегает отрезок [0..1].
 
 Подставляем выражения для x(t), y(t), z(t) в уравнение
 тора и получаем алгебраическое уравнение 4-й степени
 относительно переменной t.
 
 f(t) = a0 + a1*t + a2*t^2 + a3*t^3 + a4*t^4 = 0
 где
 a0 = (x0^2 + y0^2 + z0^2 - 2*r^2)*(x0^2 + y0^2 + z0^2) +
          2*p^2*(z0^2 - y0^2 - x0^2) + (p^2 + r^2)^2
 a1 = 4*p^2*(z0*vz - x0*vx - y0*vy) +
         4*(x0^2 + y0^2 + z0^2 - r^2)*(x0*vx + y0*vy + z0*vz)
 a2 = 2*(x0^2 + y0^2 + z0^2 - r^2)*(vx^2 + vy^2 + vz^2) +
         4*(x0*vx + y0*vy + z0*vz)*(x0*vx + y0*vy + z0*vz) +
         2*p^2*(vz^2 - vx^2 - vy^2)
 a3 = 4*(vx^2 + vy^2 + vz^2)*(x0*vx + y0*vy + z0*vz)
 a4 = (vx^2 + vy^2 + vz^2)^2
 
 Случай когда отрезок имеет нулевую длину можно сразу
 исключить. Поэтому можно считать, что a4=/=0.
 
 Теперь надо узнать, есть ли у этого уравнения корни
 на отрезке [0..1].
 Для этого используется метод Штурма.
 Hапомню его.
 Строится последовательность многочленов вида:
 f_0(t) = f(t) = g_0(t) * f_1(t) - f_2(t),
 f_1(t) = f'(t) = g_1(t) * f_2(t) - f_3(t),
 f_2(t) = g_2(t) * f_3(t) - f_4(t),
 ...,
 где при i>1 каждый многочлен f_i есть взятый
 с коэффициентом -1 остаток, получаемый при делении
 f_(i-2) на f_(i-1).
 Далее, N(t) есть число перемен знака в последовательности
 значений этих многочленов (члены, обращающиеся в нуль, не
 учитываются). Тогда число N(a) - N(b) есть число корней
 между a и b, причем каждый кратный корень считается только
 один раз.
 
 В нашем случае имеем:
 f_1(t) = b0 + b1*t + b2*t^2 + b3*t^3 =
          f'(t) = a1 + 2*a2*t + 3*a3*t^2 + 4*a4*t^3
 Остальные многочлены последовательности находим
 делением многочленов. Это легко сделать вручную,
 а ленивым (вроде меня) на помощь приходит функция
 rem пакета Maple.
 
 f_2(t) = c0 + c1*t + c2*t^2
 f_3(t) = d0 + d1*t
 f_4(t) = e0
 
 Hу я уж не буду выписывать здесь значения
 коэффициентов c0, c1,... (см. ниже листинг программы),
 замечу только, что остатки от деления многочленов
 могут получаться с нулевыми старшими коэффициентами.
 В этом случае последовательность получается короче,
 и это тоже надо учитывать.
 
 Реализация:
 
 /*
  Функция, определяющая пересекается ли отрезок с тором
  x0,y0,z0,x1,y1,z1 - координаты концов отрезка
  r - радиус образующей тора
  p - радиус направляющей тора
       (образующая - это маленькая окружность, вращая ее вдоль
       большой направляющей окружности, мы и получаем тор)
 
  Функция возвращает ноль, если пересечения нет
  */
 #include <math.h>
 
 #define eps 1.e-20 //  типа ноль
 
 int CrossTor(double x0, double y0, double z0,
                     double x1, double y1, double z1,
                     double r, double p) {
 
     double vx, vy, vz, lv2, xv, lx2, a0, a1, a2, a3, a4, b0,
                b1, b2, b3, c0, c1, c2, d0, d1, e0,
                v0[5], v1[5], w0[5], w1[5];
     int s1, s0, I, N0, N1;
 
     vx = x1 - x0;
     vy = y1 - y0;
     vz = z1 - z0;
 
     lv2 = vx * vx + vy * vy + vz * vz;
     if(lv2 < eps) return 0;
     xv = x0 * vx + y0 * vy + z0 * vz;
     lx2 = x0 * x0 + y0 * y0 + z0 * z0;
 
     for(I = 0; I < 5; I++) {
         v0[I] = 0.;
         v1[I] = 0.;
     }
 
     //  Hулевой многочлен последовательности Штурма - 4-й степени
     a4 = lv2 * lv2;
     a3 = 4. * lv2 * xv;
     a2 = 2. * (lx2 - r * r) * lv2 - 2. * p * p *
             (lv2 - 2. * vz * vz) + 4. * xv * xv;
     a1 = -4. * p * p * (xv - 2. * z0 * vz) + 4. *
             (lx2 - r * r) * xv;
     a0 = (lx2 - 2. * r * r) * lx2 + (r * r - p * p) *
             (r * r - p * p) - 2. * p * p * (lx2 - 2. * z0 * z0);
     v0[0] = a0;
     v1[0] = a0 + a1 + a2 + a3 + a4;
 
     //  Первый многочлен последовательности - производная нулевого -
     //  3-й степени
     b0 = a1;
     b1 = 2. * a2;
     b2 = 3. * a3;
     b3 = 4. * a4;
     v0[1] = b0;
     v1[1] = b0 + b1 + b2 + b3;
 
     //  Второй многочлен - взятый со знаком минус остаток
     //  от деления нулевого многочлена на первый
 
     c0 = a1 * a3 / (a4 * 16.) - a0;
     c1 = a2 * a3 / (a4 * 8.) - 0.75 * a1;
     c2 = 0.1875 * a3 * a3 / a4 - 0.5 * a2;
     v0[2] = c0;
     v1[2] = c0 + c1 + c2;
 
     if(fabs(c2) <= eps) {
         if(fabs(c1) > eps) {
             d0 = c0 * b1 / c1 - c0 * c0 * b2 / (c1 * c1)
                 + c0 * c0 * c0 * b3 / (c1 * c1 * c1) - b0;
             v0[3] = d0;
             v1[3] = d0;
         }
     } else {
         d0 = c0 * b2 / c2 - b0 - c0 * b3 * c1 / (c2 * c2);
         d1 = b3 * c0 / c2 - b1 + c1 * b2 / c2 -
             b3 * c1 * c1 / (c2 * c2);
         v0[3] = d0;
         v1[3] = d0 + d1;
         if(fabs(d1) > eps) {
             e0 = d0 * c1 / d1 - c0 - d0 * d0 * c2 / (d1 * d1);
             v0[4] = e0;
             v1[4] = e0;
         }
     }
 
     //  Избавляемся от нулей в последовательности Штурма
     s0 = 0;
     s1 = 0;
     for(I = 0; I < 5; I++) {
         if(v0[I] != 0.) {w0[s0] = v0[I]; s0++;}
         if(v1[I] != 0.) {w1[s1] = v1[I]; s1++;}
     }
 
     //  Вычисление числа перемен знака
     N0 = 0;
     N1 = 0;
     for(I = 1; I <= s0; I++)
         if(w0[I] * w0[I - 1] < 0.) N0++;
     for(I = 1; I <= s1; I++)
         if(w1[I] * w1[I - 1] < 0.) N1++;
 
     //  Возвращаем число корней
   return N0 - N1;
 }
 With best regards, Nick Gorev.  E-mail: NickGorev@mtu-net.ru
 
 --- ifmail v.2.15dev5
  * Origin: MTU-Intel ISP (2:5020/400)
 
 

Вернуться к списку тем, сортированных по: возрастание даты  уменьшение даты  тема  автор 

 Тема:    Автор:    Дата:  
 Пересечение тора с отрезком   Nick Gorev   16 Jan 2002 19:24:07 
 Re: Пересечение тора с отрезком   Sergey Politov   17 Jan 2002 06:07:53 
 Re: Пересечение тора с отрезком   Nick Gorev   20 Jan 2002 07:47:31 
 Re^2: Пересечение тора с отрезком   Sergey Politov   21 Jan 2002 06:21:17 
 Re: Пеpесечение тоpа с отpезком   Vlad Bespalov   19 Jan 2002 03:47:23 
 Re: Пересечение тора с отрезком   Nick Gorev   21 Jan 2002 19:42:44 
 Реализация с помощью метода Штурма   Nick Gorev   25 Jan 2002 07:06:42 
Архивное /ru.algorithms/9104947a37fe.html, оценка 2 из 5, голосов 10
Яндекс.Метрика
Valid HTML 4.01 Transitional