Войти
ПрограммированиеФорум2D графика и изометрия

Скорость движения по сплайну (2 стр)

Страницы: 1 2 3 Следующая »
#15
13:02, 16 авг. 2012

А нет готовой библиотеки для работы с кривыми заточенную под сплайны и движение по ним?
(жетаельно на C# и желательно с открытым кодом)

Чтоб можно было без лишнего матана делать что-то вроде:

Spline spline;
void init() {
    spline = new Spline();
    spline.add(new Bezier(...));
    spline.add(new CatmullRom(...));
    spline.add(new WhateverCurve(...));
    spline.setLinearSpeed(100);
    spline.setStartPos(0);
}


void update(float dt) {
    spline.update(dt);
    Vector2 pos = spline.getCurrentPos();
    float l = spline.getLength();
}

void draw() {
    graphics.draw(space_ship_sprite, spline.getCurrentPos());
}


#16
15:55, 16 авг. 2012

AvrDragon
> А нет готовой библиотеки для работы с кривыми заточенную под сплайны и движение по ним?
Мне она не встречалась нигде - слишком высокого уровня надстройка. Матан почти не нужен в этом вопросе. Вся задача сводится к следующему. Есть функция движения в пространстве r(p(t)), где p - монотонно возрастающая функция от времени, рассматриваемая как параметр кривой. Условие постоянной скорости получается дифференцированием по времени.
|r'(p(t))*p'(t)|=v=const
Функция p(t) монотонно возрастает и поэтому имеет положительную производную. На этом основании выносим её за модуль
|r'(p(t))|*p'(t)=v
Получаем уравнение для поиска p и больше ничего не трогаем.
p'(t)=v/|r'(p(t))|
Интегрировать произвольную функцию модуля это ужасно для двух и трёх размерностей. В лучшем случае появится интеграл Эйлера, а в худшем вообще неберущийся. Поэтому переходим к численному решению через простые вычисления изменений аргументов.
dp=v*dt/|r'(p)|
Зная начальное значение параметра p0=0 получаем следующее значение.
p1=p0+dp
Так до тех пор, пока не дойдёт до конечного значения. Изменению подлежит здесь только dt в зависимости от предъявленных требований, таких как ограничения расстояния между точками или угловатость траектории.

#17
17:36, 16 авг. 2012

я попытался запрограммировать то что мне описали и вот что вышло я не пользовался нормированием потому как с ним результаты вообще удручающие я просто взял соотношени максимальной скорости и текущей и на него умножал dt, но у меня почему то скорость которую я вывожу логом просто линейно растет причем даже на изгибе там где она визуально падает. Помогите разобратся. Да пишу на кокос 2д икс.

//
//  BizerWithRotation.h

#include "cocos2d.h"
using namespace cocos2d;

class BizerWithRotation : public CCBezierBy
{
  //-----------------VARIABLES-------------------------
 
  float t_x;
  float t_y;
 
  float extremum_x;
  float extremum_y;
 
  CCPoint max_velocity_vector;
  CCPoint cur_velocity_vector;
  float dt;
 
  float kx;
  float ky;
 
  //-----------------FUNCTIONS-------------------------
 
  // bizier function
  static inline float bezierat( float a, float b, float c, float d, ccTime t )
  {
    return (powf(1-t,3) * a +
        3*t*(powf(1-t,2))*b +
        3*powf(t,2)*(1-t)*c +
        powf(t,3)*d );
  }
 
  //первая производная
  float first_derivative(float t, float p0, float p1, float p2, float p3);
 
  //экстермум
  float extremum(float p0, float p1, float p2, float p3);
 
  //Normalize vector
  void Normalize_by_vector(CCPoint &vector1, CCPoint &vector2);
 
  //длина вектора
  float vector_length(CCPoint vector)
  {
    return sqrtf(vector.x*vector.x+vector.y*vector.y);
  }
 
  // Update 
    virtual void update(ccTime t);
 
  void init();
 
  public:
 
  float speed;
 
  BizerWithRotation();
   
    static CCBezierBy* actionWithDuration(float t,ccBezierConfig k)
    {
        BizerWithRotation* b = new BizerWithRotation;
        b->CCBezierBy::initWithDuration(t,k); 
    b->init();
        return b;
    }
 
  };

#endif


//  BizierWithRotation.cpp


#include "BizerWithRotation.h"

BizerWithRotation::BizerWithRotation()
{
}

void BizerWithRotation::init()
{
  dt = .01f;
 
  kx = 1.f;
  ky = 1.f;
 
  t_x = 0;
  t_y = 0;
 
  float xa = 0;
  float xb = m_sConfig.controlPoint_1.x;
  float xc = m_sConfig.controlPoint_2.x;
  float xd = m_sConfig.endPosition.x;
 
  extremum_x = extremum(xa, xb, xc, xd);
 
  CCLog("x extremum: %f",extremum_x);
 
  float ya = 0;
  float yb = m_sConfig.controlPoint_1.y;
  float yc = m_sConfig.controlPoint_2.y;
  float yd = m_sConfig.endPosition.y; 
 
  extremum_y = extremum(ya, yb, yc, yd);
 
  CCLog("y extremum: %f",extremum_y);
 
  float velocity_x = first_derivative(extremum_x, xa, xb, xc, xd);
 
  float velocity_y = first_derivative(extremum_y, ya, yb, yc, yd);
 
  max_velocity_vector = CCPoint(velocity_x, velocity_y);
 
 
}

void BizerWithRotation::update(ccTime t)

  CCPoint oldpos = getTarget()->getPosition();
 
  float x;
  float y;
   
  if (m_pTarget)
  {
    float xa = 0;
    float xb = m_sConfig.controlPoint_1.x;
    float xc = m_sConfig.controlPoint_2.x;
    float xd = m_sConfig.endPosition.x;
   
    float ya = 0;
    float yb = m_sConfig.controlPoint_1.y;
    float yc = m_sConfig.controlPoint_2.y;
    float yd = m_sConfig.endPosition.y;     
   
    //текущая скорость
    cur_velocity_vector.x = first_derivative(t_x, xa, xb, xc, xd);//текущая скорость по X
    cur_velocity_vector.y = first_derivative(t_y, xa, xb, xc, xd);//текущая скорость по Y
    CCLog("speed %f", vector_length(cur_velocity_vector));
   
    //Normalize_by_vector(cur_velocity_vector, max_velocity_vector);//нормирование текущей скорости максимальной скоростью
   
    //коефициент соотношения скоростей   
    kx = max_velocity_vector.x / cur_velocity_vector.x;
    ky = max_velocity_vector.y / cur_velocity_vector.y;
   
    //CCLog("fx=%f fy=%f", fx, fy);
   
    //расчет параметра t для оси X
    t_x += dt; //* kx;
       
    //расчет параметра t для оси Y
    t_y += dt;// * ky;

    //CCLog("kx=%f ky=%f", kx, ky);
   
    x = bezierat(xa, xb, xc, xd, t_x);
    y = bezierat(ya, yb, yc, yd, t_y);     
       
    m_pTarget->setPosition(ccpAdd(m_startPosition, ccp(x, y)));
   
  }
 
  //вычисление поворота вдоль движения
  CCPoint newpos = getTarget()->getPosition();
  float angle = atan2(-newpos.y + oldpos.y, newpos.x - oldpos.x) * 180 / M_PI;
  getTarget()->setRotation(angle);
}

//первая производная
float BizerWithRotation::first_derivative(float t, float p0, float p1, float p2, float p3)
{
  return 3*( p0*(-t*t+2*t-1)+p1*(3*t*t-2*t+1)+p2*(-3*t*t+2*t)+p3*t*t );
}

//экстермум
float BizerWithRotation::extremum(float p0, float p1, float p2, float p3)
{
  return (p0-p1+p2) / (p0-3*p1+3*p2-p3);
}

//Normalize
void BizerWithRotation::Normalize_by_vector(CCPoint &vector1, CCPoint &vector2)
{
  vector1.x /= sqrtf( vector2.x * vector2.x + vector2.y * vector2.y );
  vector1.y /= sqrtf( vector2.x * vector2.x + vector2.y * vector2.y );
}

#18
20:25, 16 авг. 2012

Таки пришлось написать.

from math import pi,sin,cos,acos

## Импортировали нужные библиотечные функции

def derivative(f,p,prec):
    x2,y2=f(p+0.5*prec)
    x1,y1=f(p-0.5*prec)
    return ((x2-x1)/prec,(y2-y1)/prec)

## Задали функцию числового вычисления производной

def AbsVec(a):
    return (a[0]**2+a[1]**2)**0.5

## Задали функцию вычисления абсолютной величины вектора

def dist(r1,r2):
    return AbsVec((r2[0]-r1[0],r2[1]-r1[1]))

## Задали функцию вычисления расстояния между двумя точками

def angle(r1,r2,r3):
    return acos(((r2[0]-r1[0])*(r3[0]-r2[0])+(r2[1]-r1[1])*(r3[1]-r2[1]))\
                /dist(r1,r2)/dist(r2,r3))*180/pi

## Задали функцию вычисления угла в градусах между двумя
## примыкающими к точке отрезками до соседних точек

def r(p):
    return (p*(p-0.25)*(p-0.5)*(p-1)*100+sin(2*pi*p+pi/4),
            p*(p-0.8)*(p-1)*10+cos(6*pi*p))

## Задали функцию вычисления координат через параметр кривой

def points(r,v,dt=1.0,DistLim=2.0,AngleLim=1.5):

## Задаём начальные условия и запускаем цикл

    t,p=0,0
    while p<1:

## Вычисляем шаг параметра

        dp=v*dt/AbsVec(derivative(r,p,0.001))

## Понижаем изменение параметра в соответствии с заданными условиями

        while dist(r(p),r(p+dp))>DistLim or angle(r(p-dp),r(p),r(p+dp))>AngleLim:
            dp/=2

## Повышаем изменение параметра до максимально допустимого

        while dist(r(p),r(p+dp))<=DistLim/2 and angle(r(p-dp),r(p),r(p+dp))<=AngleLim/2:
            dp*=1.2

## Находим соответствующее изменению параметра изменение времени

        dt=dist(r(p),r(p+dp))/v

## Смотрим на полученный результат

        print "t=%.2f,dt=%.2f,p=%.2f,x=%.2f,y=%.2f,dist=%.2f,angle=%.2f" % \
              ((t,dt,p)+r(p)+(dist(r(p),r(p+dp)),angle(r(p-dp),r(p),r(p+dp))))

## Увеличиваем значения параметра и времени

        t+=dt
        p+=dp

## Запускаем функцию генерации списка точек

points(r,2.5)
Код не оптимизирован под производительность. Избыточность оставлена для лучшего понимания.

#19
22:00, 16 авг. 2012

Большое спасибо за то что не полинился написать но увы я не знаю этот язык и явно не понимаю что тут написано

#20
23:49, 16 авг. 2012

Emissar
> Большое спасибо за то что не полинился написать но увы я не знаю этот язык и явно не понимаю что тут написано
Я добавил комментарии. Питон очень простой в изучении язык и в сети полно двухчасовых курсов. Скачай 2.7, запусти на выполнение и посмотри, хорошо ли получается. Если пишет что требуется, то я могу переписать на C, C++, D или Java.

#21
0:34, 17 авг. 2012

Алексей Патрашов
Леша, мне бы твой энтузиазм :)

#22
2:42, 17 авг. 2012

Вы как-то замудийно всё-равно делаете. Расскажу как делал я в далёком детстве, когда ещё не знал про интегралы, и стырил готовую ф-цию рисования кривой безье на паскале.
Так вот, ф-ция рисовала толщиной в 1 пиксель эту самую кривую, после чего я её проапгрейдил:
1. Заставил возвращать количество нарисованых точек
2. Научил останавливать рисование после n-го вызова putpixel
3. Научил ничего не рисовать, а возвращать координаты точки для n-го вызова putpixel

тепер, например, чтобы получить "середину пути", нужно было два вызова: первый для подсчёта общего количества точек в кривой (например их 100500), и получить координаты 50250-й точки.

в общем, соединяем 1, 2, 3 и получаем ф-цию, которая на вход получает float из диапазона 0..1. и возвращает координаты точки.

#23
2:56, 17 авг. 2012

Гопник Хаскель
У тебя точки при постоянном шаге будут натыканы неравномерно.

#24
3:06, 17 авг. 2012

MarkoPolo
ты не понял, у меня шаг это и есть энное количество точек

#25
3:29, 17 авг. 2012

Гопник Хаскель
Как у тебя функция рисовала кривую на паскале? Она считала новую точку кривой, перед тем как ее поставить. Если функция выдает точки неравномерно, сколько ты не считай их число расстояние между ними равным не станет, если только там внутри этой функции кто-то не сделал ту штуку, что Алексея или ту фигню, что описывал я.


Emissar
Что-то не так делаешь, сейчас утро надо спать. Вечерком набросаю.

#26
3:54, 17 авг. 2012

MarkoPolo
ф-ция конечно генерила точки, и рисовала линии между этими точками, при генерации точек точка отбрасывалась, если её координата была равна предыдущей сгенерированной, линии рисовались от начала до конца без вывода последней точки, вызовом putpixel,  отсюда следует что количество вызовов putpixel было в точности равно количеству горящих на экране пикселей.

#27
12:41, 17 авг. 2012

Гопник Хаскель
> Вы как-то замудийно всё-равно делаете. Расскажу как делал я в далёком детстве,
> когда ещё не знал про интегралы, и стырил готовую ф-цию рисования кривой безье
> на паскале.
>...
Вот это я бы сказал "замудийно".

#28
12:53, 17 авг. 2012

Товарищи програмисты, я делаю комерческий проект у меня уже все дедлайны прогорели, на работе им заниматся не могу просто нет времени, по этому прошу вас помочь и написать на С++ код или поправить мой который я выложил. Если кто не понял использую кокос 2д икс. Но лучше конечно просто класс на С++ универсальный что бы все могли пользоватся, обещаю что потом его доработаю что бы можно было тоже самое проделать только для Катмулл-Рома и выложу что бы ни у кого не было больше такого замечательного головняка.

#29
12:55, 17 авг. 2012

А писать на паскале через пут пиксель это для 9 класса пардон)))

Страницы: 1 2 3 Следующая »
ПрограммированиеФорум2D графика и изометрия

Тема в архиве.