
Added some more animation features to my Bezier Flower Demo - which you can view by clicking on the link below -
View Petal Demo @ http://www.javaimage.co.uk/flower.html
int displayWidth,displayHeight ;
String mode ;
float CX,CY ;
float degreesToRadians(float th)
{
return PI * th /180.0f ;
}
float translateX(float x)
{
return x+CX ;
}
float translateY(float y)
{
return -y+displayHeight-CY ;
}
PVector [] calcControlPoints(float angle,float ro,float radius,float tilt,float petalLength)
{
PVector [] bezControlPoints = new PVector[4] ;
float halfRo = ro / 2.0f ;
PVector[] cPoints = calcPetalPointPair(angle-halfRo,tilt,petalLength) ;
PVector startPt = cPoints[0] ;
PVector fPoint = cPoints[1] ;
bezControlPoints[0] = new PVector(startPt.x * radius,startPt.y * radius) ;
bezControlPoints[1] = new PVector(startPt.x * radius + fPoint.x,startPt.y * radius + fPoint.y) ;
PVector [] cPoints2 = calcPetalPointPair(angle+halfRo,-tilt,petalLength) ;
startPt = cPoints2[0] ;
fPoint = cPoints2[1] ;
bezControlPoints[3] = new PVector(startPt.x * radius,startPt.y * radius) ;
bezControlPoints[2] = new PVector(startPt.x * radius + fPoint.x,startPt.y * radius + fPoint.y) ;
return bezControlPoints ;
}
void drawBezier(PVector [] cps)
{
drawBezier(cps[0].x,cps[0].y,cps[1].x,cps[1].y,cps[2].x,cps[2].y,cps[3].x,cps[3].y) ;
}
void drawBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)
{
noFill() ;
stroke(0,0,0) ;
bezier(translateX(x1),translateY(y1),
translateX(x2),translateY(y2),
translateX(x3),translateY(y3),
translateX(x4),translateY(y4)) ;
}
void drawControlPoints(PVector[] cps)
{
stroke(255,0,0) ;
drawLine(cps[0].x,cps[0].y,cps[1].x,cps[1].y) ;
stroke(0,255,0) ;
drawLine(cps[2].x,cps[2].y,cps[3].x,cps[3].y) ;
}
PVector[] calcPetalPointPair(float angle,float tilt,float petalLength)
{
PVector startPt = new PVector(1.0*sin(degreesToRadians(angle)),1.0*cos(degreesToRadians(angle)));
PVector vert = new PVector(0,0,1.0f) ; // Unit Vector Perp to XY Plane
PVector nCPc = startPt.cross(vert) ; // Calculate Tangent to Circle at startPt.x,startPt.y
PMatrix2D iMat = new PMatrix2D() ;
iMat.rotate(degreesToRadians(tilt < 0 ? 180+tilt : tilt)) ; // Petal Tilt
PMatrix2D cMat = new PMatrix2D(nCPc.x,startPt.x,0f,nCPc.y,startPt.y,0.0f) ;
// Matrix
// | nCPc.x startx |
// | nCPc.y starty |
cMat.preApply(iMat) ; // Apply our orthog axis to the rotation matrix
PVector fPoint = new PVector() ;
PVector sPoint = new PVector(petalLength,0) ; // Petal Length
cMat.mult(sPoint,fPoint) ; // Apply Full transformation to petal Vector
PVector [] points = new PVector[2] ;
points[0] = startPt ;
points[1] = fPoint ;
return points;
}
void setup()
{
mode = JAVA2D ;
displayHeight = screen.height/2 ;
displayWidth = screen.width/2 ;
CX = displayWidth / 2 ;
CY = displayHeight / 2 ;
size(displayWidth, displayHeight,mode);
loop() ;
}
void drawLine(float x,float y,float x2,float y2) {
line(translateX(x),translateY(y),translateX(x2),translateY(y2)) ;
}
void drawCircle(float x,float y,float rad)
{
ellipse(translateX(x), translateY(y), rad,rad) ;
}
void draw() {
background(255);
float dt = 1/frameRate ; // We should calculate dt - time passed since last update-draw
float radius = 20.0f ;
float tilt = 70.0f ;
float petalLength = 250.0f ;
float ro = 15.0f ;
float step = 7.0f ;
float numpetals = 360.0f / step ;
noFill() ;
ellipseMode(RADIUS) ;
stroke(0,0,0) ;
drawCircle(0,0,radius) ;
for (float angle = 0.0f ; angle < step*numpetals ; angle+=step)
{
PVector [] cps = calcControlPoints(angle,ro,radius,tilt,petalLength) ;
drawBezier(cps) ;
}
}
/*
Demo showing Objects moving over 2D space using Bezier curves -
JW October 18th 2008
http://www.javaimage.co.uk/bez.html
*/
public static final int BEZ_ARCFROMTOPLEFT = 0;
public static final int BEZ_ARCFROMTOPRIGHT = 1;
public static final int BEZ_UTURNFROMTOPLEFT = 2;
public static final int BEZ_UTURNFROMTOPRIGHT = 3;
public static final int BEZ_CENTRALTOPTWIRLRIGHT = 4;
public static final int BEZ_CENTRALTOPTWIRLLEFT = 5;
public static final int BEZ_HELIXFROMTOPLEFT = 6;
public static final int BEZ_HELIXFROMTOPRIGHT = 7;
public static final int BEZ_RBEND = 8;
public static final int BEZ_RBEND_INVERTED = 9;
public static final int BEZ_DOWN_RIGHT = 10;
public static final int BEZ_DOWN_LEFT = 11;
public static final int BEZ_FLAT_LEFT_23 = 12;
public static final int BEZ_FLAT_RIGHT_23 = 13;
public static final int BEZ_FLAT_LEFT_13 = 14;
public static final int BEZ_FLAT_RIGHT_13 = 15;
public static final int BEZ_UP_RIGHT = 16;
public static final int BEZ_UP_LEFT = 17;
public static final int BEZ_S = 18;
public static final int BEZ_S_INVERTED = 19;
public static final int BEZ_FLAT_LEFT_34 = 20;
public static final int BEZ_FLAT_RIGHT_34 = 21;
public static final int BEZ_UTURNFROMBOTTOMLEFT = 22;
public static final int BEZ_UTURNFROMBOTTOMRIGHT = 23;
public static final int BEZ_SWOOPTOPLEFT_TORIGHT = 24;
public static final int BEZ_SWOOPTOPRIGHT_TOLEFT = 25;
public static final int BEZ_REVERSESINEWAVE = 26;
public static final int BEZ_COSINEWAVE = 27;
public static final int BEZ_LEFTNOSE = 28;
public static final int BEZ_RIGHTNOSE = 29;
public static final int BEZ_CSHAPE = 30;
public static final int BEZ_CSHAPE_MIRROR = 31;
public static final int BEZ_DIAGONAL_FROMTOPLEFT = 32;
public static final int BEZ_DIAGONAL_FROMTOPRIGHT = 33;
public static final int BEZ_SHEARED_S = 34;
public static final int BEZ_SHEARED_S_MIRROR = 35;
public static final int BEZ_DOWN_CENTRE = 36;
public static final int NUM_BEZIERS = 37;
int displayWidth,displayHeight ;
String mode ;
BezierCP [] bez = new BezierCP[NUM_BEZIERS] ;
// Curve table
public class BezierCP {
float cx,cy ;
float cx2,cy2 ;
float cx3,cy3 ;
float cx4,cy4 ;
public BezierCP(float cx,float cy,float cx2, float cy2, float cx3, float cy3,float cx4,float cy4)
{
this.cx = cx ; this.cy = cy ;
this.cx2 = cx2 ; this.cy2 = cy2 ;
this.cx3 = cx3 ; this.cy3 = cy3 ;
this.cx4 = cx4 ; this.cy4 = cy4 ;
}
float getX(float t) {
return bezierPoint(cx,cx2,cx3,cx4,t) ;
}
float getY(float t) {
return bezierPoint(cy,cy2,cy3,cy4,t) ;
}
public void draw() {
bezier(cx,cy,cx2,cy2,cx3,cy3,cx4,cy4) ;
}
}
public class Galaxian {
float time, duration ;
BezierCP gbez ; // bezier curve this Galaxian follows
boolean randomchoice = false ;
color col = color(random(255),random(255),random(255),255) ; // random colour
// Default Glaxian contructor
public Galaxian() {
time = 0f ;
duration = 4.0 ;
gbez = bez[0] ;
randomchoice = true ;
}
public Galaxian(BezierCP gbez,float duration) {
this.duration = duration ;
time = 0f ;
this.gbez = gbez ;
}
public Galaxian(int bezidx,float duration) {
this(bez[bezidx],duration) ;
}
public void update(float dt) {
if (time > duration) {
// Galaxian has finished - start again
time = 0f ;
if (randomchoice)
gbez = bez[(int)random(NUM_BEZIERS)] ;
} else {
}
time = time + dt ;
}
public void draw() {
debug() ; // Draw Curve the Galaxian is following.
if (time < duration) {
float t = time/duration ;
float xpos = gbez.getX(t) ;
float ypos = gbez.getY(t) ;
fill(col) ;
rect(xpos,ypos,20,20) ;
}
}
public void debug() {
noFill() ;
stroke(col) ;
gbez.draw() ;
}
}
/*
Create a global Array of Bezier Objects -
This object is just a wrapper for a Processing Bezier Object for storing control points.
*/
void InitBezier(int width,int height)
{
bez[BEZ_ARCFROMTOPLEFT] =
new BezierCP( 0, 100,
width, 0,
width/2, height/2,
width, height);
bez[BEZ_ARCFROMTOPRIGHT] =
new BezierCP( width, 100,
0, 0,
width/2, height/2,
0, height);
bez[BEZ_UTURNFROMTOPLEFT] =
new BezierCP( 100, -100,
100, 100.0f +height/2,
width-100, 100.0f + height/2,
width-100, 0);
bez[BEZ_UTURNFROMTOPRIGHT] =
new BezierCP( width-100, -100,
width-100, +200.0f + height/2,
100, +200.0f + height/2,
100, 0);
bez[BEZ_CENTRALTOPTWIRLRIGHT] =
new BezierCP( width/2, 0,
width, height*0.25f,
0, height*0.75f,
width/2, height);
bez[BEZ_CENTRALTOPTWIRLLEFT] =
new BezierCP( width/2, 0,
0, height*0.25f,
width, height*0.75f,
width/2, height);
bez[BEZ_HELIXFROMTOPLEFT] =
new BezierCP( 0, 0,
0, height/2,
width, height/2,
width, height);
bez[BEZ_HELIXFROMTOPRIGHT] =
new BezierCP( width, 0,
width, height/2,
0, height/2,
0, height);
bez[BEZ_RBEND] =
new BezierCP( width, height*0.25f,
width, height*0.25f,
100, height*0.25f,
100, height);
bez[BEZ_RBEND_INVERTED] =
new BezierCP( 0, height*0.25f,
width, height*0.25f,
width, height*0.25f,
width, height*0.25f);
bez[BEZ_DOWN_RIGHT] =
new BezierCP( width*0.75f, 0,
width*0.75f, 0,
width*0.75f, height,
width*0.75f, height);
bez[BEZ_DOWN_LEFT] =
new BezierCP( width*0.25f, 0,
width*0.25f, 0,
width*0.25f, height,
width*0.25f, height);
bez[BEZ_FLAT_LEFT_23] =
new BezierCP( width, height*0.33f,
width, height*0.33f,
0, height*0.33f,
0, height*0.33f);
bez[BEZ_FLAT_RIGHT_23] =
new BezierCP( 0, height*0.33f,
0, height*0.33f,
width, height*0.33f,
width, height*0.33f);
bez[BEZ_FLAT_LEFT_34] =
new BezierCP( width, height*0.25f,
width, height*0.25f,
0, height*0.25f,
0, height*0.25f);
bez[BEZ_FLAT_RIGHT_34] =
new BezierCP( 0, height*0.25f,
0, height*0.25f,
width, height*0.25f,
width, height*0.25f);
bez[BEZ_FLAT_LEFT_13] =
new BezierCP( width, height*0.66f,
width, height*0.66f,
0, height*0.66f,
0, height*0.66f);
bez[BEZ_FLAT_RIGHT_13] =
new BezierCP( 0, height*0.66f,
0, height*0.66f,
width, height*0.66f,
width, height*0.66f);
bez[BEZ_UP_RIGHT] =
new BezierCP( width*0.75f, height,
width*0.75f, height,
width*0.75f, 0,
width*0.75f, 0);
bez[BEZ_UP_LEFT] =
new BezierCP( width*0.25f, height,
width*0.25f, height,
width*0.25f, 0,
width*0.25f, 0);
bez[BEZ_S] =
new BezierCP( width/2, 0,
0, 0,
width, height*0.66f,
width/2, height);
bez[BEZ_S_INVERTED] =
new BezierCP( width/2, 0,
width, 0,
0, height*0.66f,
width/2, height);
bez[BEZ_UTURNFROMBOTTOMLEFT] =
new BezierCP( 0, height,
0, -100,
width, -100,
width+100, height+100);
bez[BEZ_UTURNFROMBOTTOMRIGHT] =
new BezierCP( width, height+100,
width, -100,
0, -100,
-100, height+100);
bez[BEZ_SWOOPTOPLEFT_TORIGHT] =
new BezierCP( 100, -100,
200, height-400,
200, height-400,
width+100, height-200);
bez[BEZ_SWOOPTOPRIGHT_TOLEFT] =
new BezierCP( width-100, -100,
width-200, height-400,
width-200, height-400,
-100, height-200);
bez[BEZ_REVERSESINEWAVE] =
new BezierCP( width+100, 100,
200, 100,
width+100, height-200,
-100, height-200);
bez[BEZ_COSINEWAVE] =
new BezierCP( -100, 100,
width+100, 100,
200, height-200,
width+100, height-200);
bez[BEZ_LEFTNOSE] =
new BezierCP( width/2 - 100, -100,
width/2 + 200, 200,
-800, 400,
width+100, height-200);
bez[BEZ_RIGHTNOSE] =
new BezierCP( width/2 + 100, -100,
width/2 - 200, 200,
width+800, 400,
-100, height-200);
bez[BEZ_CSHAPE] =
new BezierCP( width + 100, 0,
-200, 0,
-200, height-100,
width+100, height-100);
bez[BEZ_CSHAPE_MIRROR] =
new BezierCP( -100, 0,
width+200, 0,
width+200, height-100,
-100, height-100);
bez[BEZ_DIAGONAL_FROMTOPLEFT] =
new BezierCP( -100, 0,
-100, 0,
width/2, height+100,
width/2, height+100);
bez[BEZ_DIAGONAL_FROMTOPRIGHT] =
new BezierCP( width+100, 0,
width+100, 0,
width/2, height+100,
width/2, height+100);
bez[BEZ_SHEARED_S_MIRROR] =
new BezierCP( -100, 50,
width+600, 180,
-1000, 360,
width+100, height-50);
bez[BEZ_SHEARED_S] =
new BezierCP( width+100, 50,
-600, 180,
width+1000, 360,
-100, height-50);
bez[BEZ_DOWN_CENTRE] =
new BezierCP( width/2, -100,
width/2, -100,
width/2, height+100,
width/2, height+100);
}
/*
Define some Galaxians
*/
int MAX_GALAXIANS = 20 ;
Galaxian [] galaxians = new Galaxian[MAX_GALAXIANS] ;
void setup() {
mode = JAVA2D ;
displayHeight = screen.height/2 ;
displayWidth = screen.width/2 ;
InitBezier(displayWidth,displayHeight) ;
for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i] = new Galaxian((int)random(NUM_BEZIERS),2.0f + random(4.0f)) ; // pick a random Bezier 'curve' and a random duration between 2 and 6 seconds
}
size(displayWidth, displayHeight,mode);
loop() ;
}
void draw() {
background(255);
float dt = 1/frameRate ; // We should calculate dt - time passed since last update-draw
// but this should be approx equal to 1 / frameRate
// Update the Galaxians
for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i].update(dt) ;
}
// Draw Galaxians
for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i].draw() ;
}
}