Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: Emil_halim on July 05, 2007
-
Hi all
I really need a good tutorial For Spline , my idea is to put some control point for not only translation but for translation and rotation and scaling and may be color to be smooth interplated.
so the first step is to know a good on for translation , any help ?
-
Hey,
perhaps you might want to check this one here.
Spline-Tutorial (http://syn9.thingie.net/?table=simple_spline)
Cheers,
SLiPPY
-
Any idea what kind of splines you want? Easiest is Bezier, but they might not do what you want.
Jim
-
@slippy
thanks for your post , but in this tutorial the object didnot move on control point.
@Jim
i think the catmull_rom or Bezier will be nice.
-
I wrote a bezier routine, you can have it if you like, it's in the lib attached to this post;
http://dbfinteractive.com/index.php?topic=1455.0
Catmull Rom might be more useful to you though if you need more control.
-
thanks shocky very much. :)
did you mean the CURVE rotine by a bezier, because i did not find any bezier routine there.
could you point me to a Catmull Rom toturial please ?
-
ok , I have changed my mind , so I will use a Linear interpolated instead of spline , but still have a small problem , I want my Object to smooth move when it reachs to control points.
For Example. suppose you have 10 points , p1,p2,p3 .......... so on.
first we will interpolat btween P1 and p2 and when object reachs to p2 we will interpolat btween P2 and p3 , and so on.
the problem is when the object reachs to p2 it will change the path from P1-p2 to P2-P3 in non smooth change .
any idea to solve this problem please ?
-
Catmull-Rom spline:
#ifndef Tcoord
type Tcoord
x as single
y as single
End Type
#endif
type Tspline2d
Public:
'' constructors and destructors
declare constructor()
declare constructor(byval _maxpoints as integer)
declare destructor()
'' properties
'' getters
declare property x() as single
declare property y() as single
declare property t() as single
declare property speed() as single
declare property index() as integer
declare property maxindex() as integer
declare property p(byval _index as integer) as Tcoord
'' setters
declare property x(byval _n as single)
declare property y(byval _n as single)
declare property t(byval _n as single)
declare property speed(byval _n as single)
declare property index(byval _n as integer)
declare property maxindex(byval _n as integer)
declare property p(byval _index as integer, byval _value as Tcoord)
'' methods
declare sub initcoords(byval _maxpoints as integer)
declare sub update()
'' members
private:
m_x as single
m_y as single
m_t as single
m_speed as single
m_index as integer
m_maxindex as integer
p_coords as Tcoord ptr
end type
constructor Tspline2d()
m_t = 0
m_speed = 0.001
m_index = 0
m_maxindex = 0
end constructor
constructor Tspline2d(byval _maxpoints as integer)
m_t = 0
m_speed = 0.001
m_index = 0
m_maxindex = _maxpoints
p_coords = new Tcoord[_maxpoints]
end constructor
destructor Tspline2d()
delete[] p_coords
end destructor
'' properties
'' getters
property Tspline2d.x() as single
property = m_x
End Property
property Tspline2d.y() as single
property = m_y
End Property
property Tspline2d.t() as single
property = m_t
End Property
property Tspline2d.speed() as single
property = m_speed
End Property
property Tspline2d.index() as integer
property = m_index
End Property
property Tspline2d.maxindex() as integer
property = m_maxindex
End Property
property Tspline2d.p(byval _index as integer) as Tcoord
if _index > -1 and _index < m_maxindex then
property = p_coords[_index]
end if
End Property
'' setters
property Tspline2d.x(byval _n as single)
m_x = _n
End Property
property Tspline2d.y(byval _n as single)
m_y = _n
End Property
property Tspline2d.t(byval _n as single)
m_t = _n
End Property
property Tspline2d.speed(byval _n as single)
m_speed = _n
End Property
property Tspline2d.index(byval _n as integer)
m_index = _n
End Property
property Tspline2d.maxindex(byval _n as integer)
m_maxindex = _n
End Property
property Tspline2d.p(byval _index as integer, byval _n as Tcoord)
if _index > -1 and _index < m_maxindex then
p_coords[_index].x = _n.x
p_coords[_index].y = _n.y
end if
End Property
'' methods
sub Tspline2d.initcoords(byval _maxpoints as integer)
m_maxindex = _maxpoints
p_coords = new Tcoord[_maxpoints]
End Sub
sub Tspline2d.update()
dim as single t1 = m_t
dim as single t2 = t * t
dim as single t3 = t2 * t
dim as Tcoord p0, p1, p2, p3
p0.x = p_coords[m_index].x
p0.y = p_coords[m_index].y
p1.x = p_coords[(m_index + 1) mod m_maxindex].x
p1.y = p_coords[(m_index + 1) mod m_maxindex].y
p2.x = p_coords[(m_index + 2) mod m_maxindex].x
p2.y = p_coords[(m_index + 2) mod m_maxindex].y
p3.x = p_coords[(m_index + 3) mod m_maxindex].x
p3.y = p_coords[(m_index + 3) mod m_maxindex].y
m_x = 0.5 * ( ( 2.0 * p1.x ) +_
( -p0.x + p2.x ) * t1 +_
( 2.0 * p0.x - 5.0 * p1.x + 4 * p2.x - p3.x ) * t2 +_
( -p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x ) * t3 )
m_y = 0.5 * ( ( 2.0 * p1.y ) +_
( -p0.y + p2.y ) * t1 +_
( 2.0 * p0.y - 5.0 * p1.y + 4 * p2.y - p3.y ) * t2 +_
( -p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y ) * t3 )
'' increment t
m_t += m_speed
if m_t > 1.0 then
m_t -= 1.0
m_index = (m_index + 1) mod m_maxindex
endif
End Sub
cls
screen 18,,2
randomize timer
const MAXPOINTS = 10
dim as Tspline2d catmull '= Tspline2d(MAXPOINTS)
catmull.initcoords(MAXPOINTS)
for i as integer = 0 to catmull.maxindex-1
dim as Tcoord p
p.x = rnd * 640
p.y = rnd * 480
catmull.p(i) = p
next i
dim as integer current_color = 1, colorchanged = 0
catmull.speed = 0.005
screenset 0,1
for i as integer = 0 to catmull.maxindex-1
dim as Tcoord p
p = catmull.p(i)
circle (p.x,p.y), 3,i + 1
next i
do
'line (0,0)-(639,479),0,bf
catmull.update
'circle (catmull.x,catmull.y),15, current_color
pset (catmull.x,catmull.y),15
if catmull.index = 0 and colorchanged = 0 then
current_color = 1 + rnd * 15
colorchanged = -1
elseif catmull.index = 1 then
colorchanged = 0
end if
screensync
screencopy
Loop until inkey<>""
-
thanks relsoft for your code.
I will study it.
-
the problem is when the object reachs to p2 it will change the path from P1-p2 to P2-P3 in non smooth change .
any idea to solve this problem please ?
Well, obviously not, since two lines don't form a continuous function. Perhaps you want to stop at P2 for a whlie and rotate the camera/object around to the new orientation? You probably want a curve which goes through the control points, which Bezier doesn't, but Cubic splines and Catmull-Rom splines do.
Jim
-
Ok Jim, i have tested the Catmull-Rom Spline that posted by relsoft and found that it is very useful, and did not see any Cubic splines.
Only the Littile thing about the Catmull-Rom Spline is that the path is a curve not a strait line between each points.
-
So you don't want the movement to curve?
That seems strange to me but then I don't know what you're using this for.
Btw the curve in my library is a bezier routine and it is also a cubic spline. You can render beziers in other ways (quadratic etc) of course.
You'll be better off using Rels Catmull rom routine. The movement is much nicer and you have the fact that hitting the control points is guaranteed.
-
Yes shocky , I want that the pass is a strait line and at the same time at the control points the change in path is smooth.
But I think this is impossible , so I will use relsoft Catmull-Rom Spline.
I want that routine to allow my Library users to define a path that control the translation and rotation and scaling and may be the color of sprite in the animation scene. So first I was searching for good translation spline then I will modify it suit my needs.
-
Relsoft:
Your spline code is very helpful and very close to my coding style. So thank you very much for your help.
Just I want an other thing , suppose you have a ship space that follows this spline ,so how to control the rotation of the ship to insure that it face the next point, I.E if our ship face to left hand and the next point is in the right direction so can you adjust your update routine to allow the ship smoothly change the rotation to face to next point?
-
Emil_halim: Easy. Compute the angle between the current point and next ( or previous ) one using something like Math.atan2( nextX-currentX, nextY-currentY ).you can of course interpolate the ship's current angle to the new one, but I doubt it's necessary.
-
Nice p01.
It is really easy , and you open my mind for new idea , which is you did not have to interpolate the angle instead you calculate the angle between each interpolated point and the previous one.
-
Ok, I have made it with C++ :) , big thanks must go to Relsoft and P01.
Here are my OgreMagic functions , may be it useful for someone else.
/**********************************************************
2 D p a t h s t u f f
***********************************************************/
struct Tcoord
{
float x,y;
};
struct Path2D
{
float m_x;
float m_y;
float m_t;
float m_speed;
int m_index;
int m_maxindex;
Tcoord* p_coords;
float m_old_x;
float m_old_y;
double m_angle;
double m_RotOffset;
};
DLL_EXPORT Path2D* ML_Create2DPath(int MaxPoints,float Speed,float RotOffset)
{
Path2D* path = new Path2D;
path->m_maxindex = MaxPoints;
path->p_coords = new Tcoord[MaxPoints];
path->m_speed = Speed;
path->m_x = path->m_y = path->m_t =
path->m_index = path->m_old_x = path->m_old_y =
path->m_angle = 0;
path->m_RotOffset = RotOffset;
return path;
}
DLL_EXPORT void ML_AddpointTo2DPath(Path2D* path,float x,float y)
{
if(path->m_maxindex>path->m_index && path->m_index>=0)
{
path->p_coords[path->m_index].x = x;
path->p_coords[path->m_index].y = y;
path->m_index++;
}
}
DLL_EXPORT void ML_AddpointTo2DPathByIndex(Path2D* path,int index,float x,float y)
{
if(path->m_maxindex>index && path->m_index>=0)
{
path->p_coords[index].x = x;
path->p_coords[index].y = y;
}
}
DLL_EXPORT void ML_SetPathSpeed(Path2D* path,float speed)
{
path->m_speed = speed;
}
// big thanks to Relsoft for catmull
DLL_EXPORT void ML_Update2DPath(Path2D* path)
{
float t1 = path->m_t;
float t2 = t1 * t1;
float t3 = t2 * t1;
Tcoord p0, p1, p2, p3;
p0.x = path->p_coords[path->m_index].x;
p0.y = path->p_coords[path->m_index].y;
p1.x = path->p_coords[(path->m_index + 1) % path->m_maxindex].x;
p1.y = path->p_coords[(path->m_index + 1) % path->m_maxindex].y;
p2.x = path->p_coords[(path->m_index + 2) % path->m_maxindex].x;
p2.y = path->p_coords[(path->m_index + 2) % path->m_maxindex].y;
p3.x = path->p_coords[(path->m_index + 3) % path->m_maxindex].x;
p3.y = path->p_coords[(path->m_index + 3) % path->m_maxindex].y;
path->m_x = 0.5 * ( ( 2.0 * p1.x ) + ( -p0.x + p2.x ) * t1 +
( 2.0 * p0.x - 5.0 * p1.x + 4 * p2.x - p3.x ) * t2 +
( -p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x ) * t3 );
path->m_y = 0.5 * ( ( 2.0 * p1.y ) + ( -p0.y + p2.y ) * t1 +
( 2.0 * p0.y - 5.0 * p1.y + 4 * p2.y - p3.y ) * t2 +
( -p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y ) * t3 );
path->m_t += path->m_speed;
if(path->m_t > 1.0)
{
path->m_t -= 1.0;
path->m_index = (path->m_index + 1) % path->m_maxindex;
}
path->m_angle = atan2(path->m_x - path->m_old_x , path->m_y - path->m_old_y)- path->m_RotOffset;
path->m_old_x = path->m_x;
path->m_old_y = path->m_y;
}