We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › Trace a bezierpoint in 3D
Page Index Toggle Pages: 1
Trace a bezierpoint in 3D (Read 1796 times)
Trace a bezierpoint in 3D
Nov 29th, 2009, 12:28am
 
Hi,

I'm trying to throw together a quick little project for my team at work, but I've come unstuck with some basic maths  Cheesy

I basically want a flow of particles to follow a set of bezier curves. I can easily see how I could do this in 2D, but I'm not sure how to map the x coords to x,z coords for a 3D version. I want a set of particles to emit at a random angle parallel to the 'floor' and then flow to the top of the curve.

Any help would very very appreciated.
Re: Trace a bezierpoint in 3D
Reply #1 - Nov 29th, 2009, 1:18am
 
as beziers work in 3d i guess bezierCurve does too
http://processing.org/reference/bezierPoint_.html
you can use it to follow the path of the bezier
Re: Trace a bezierpoint in 3D
Reply #2 - Nov 29th, 2009, 10:25am
 
Unfortunately bezierPoint() does not appear to support 3D bezier curves even though the function bezier() does.

The class below will do the job of calculating points along a bezier curve in 3D.

In your Processing sketch click on the Tab icon and select new tab, name the file Bezier3D.java you must be exact with the naming including capitalization. Then copy any paste the code below into the new tab.

To use this class you must also be comfortable in using the PVector class (part of Processing) this has 3 attributes x,y,z to store 3D coordinates.

Once you have done that the key is the method
Code:

public PVector[] points(int steps){

this will return an array of PVectors representing coordinates along the 3D bezier curve. steps is the number of points reqd, the higher the number the smoother the curve.

Hope this helps
Smiley

Code:

import processing.core.PVector;

public class Bezier3D {

// Used to hold the control points
private float[] px;
private float[] py;
private float[] pz;

// Used to hold intermediate values when calculating
// a point on the curve
private float[] pxi;
private float[] pyi;
private float[] pzi;

private boolean useZ = false;
// degree = order + 1  i.e. degree = number of points
// order = cubic : degree = 4
private int degree;

/**
* Create a Bezier object based on points passed as a 2D
* array.
*
* @param app
* @param points 2D array[point no.][x/y]
* @param nbrPoints number of points to use from array
* @param useZ true 3D Bezier : false = 2D Bezier
*/
public Bezier3D(float[][] points, int nbrPoints, boolean useZ){
this.useZ = useZ;
degree = nbrPoints;
makeArrays();

for(int i = 0; i < degree; i++){
px[i] = points[i][0];
py[i] = points[i][1];
if(useZ == true){
pz[i] = points[i][2]; // ignored if useZ is false
}
}
}

/**
* Create a Bezier object based on an array of vectors. <br>
* The bezier curve will use all of the points in the array. <br>
*
* @param points array of control points
*/
public Bezier3D(PVector[] points, boolean useZ){
this.useZ = useZ;
degree = points.length;
System.out.println(""+degree);
makeArrays();
System.out.println("Arrays made"+degree);

for(int i = 0; i < degree; i++){
px[i] = points[i].x;
py[i] = points[i].y;
if(useZ == true)
pz[i] = points[i].z;
}
}

/**
* Used by the ctors
*/
private void makeArrays(){
px = new float[degree];
py = new float[degree];
pxi = new float[degree];
pyi = new float[degree];
if(useZ){
pz = new float[degree];
pzi = new float[degree];
}
}

/**
* Forces the bezier to ignore the z values i.e. makes
* it become 2D.
*/
public void force2D(){
useZ = false;
pz = null;
pzi = null;
}

/**
* Calculate the point for a given parametric point 't' on the curve.
* @param t
* @return
*/
public PVector point(float t){
float t1 = 1.0f - t;
System.arraycopy(px, 0, pxi, 0, degree);
System.arraycopy(py, 0, pyi, 0, degree);
if(useZ)
System.arraycopy(pz, 0, pzi, 0, degree);
for(int j = degree-1; j > 0; j--){
for(int i = 0; i < j; i++){
pxi[i] = t1 * pxi[i] + t* pxi[i+1];
pyi[i] = t1 * pyi[i] + t* pyi[i+1];
if(useZ){
pzi[i] = t1 * pzi[i] + t* pzi[i+1];
}
}
}
if(useZ)
return new PVector(pxi[0], pyi[0], pzi[0]);
else
return new PVector(pxi[0], pyi[0]);

}

/**
* Calculate the points along the Bezier curve. <br>
* @param steps the number of points to calculate
* @return array of PVector holding points
*/
public PVector[] points(int steps){
PVector points[] = new PVector[steps];
float t = 0.0f;
float dt = 1.0f/(steps -1);
for(int i = 0; i < steps; i++){
points[i] = point(t);
t += dt;
}
return points;
}

}
Re: Trace a bezierpoint in 3D
Reply #3 - Nov 29th, 2009, 10:37am
 
thats not true, although the example only uses a 2d bezier curve it is no problem to calculate a Z coordinate.
I just put together an example in 3d


Code:
void setup(){
size(300,300,P3D);
sphereDetail(4);
}
void draw(){
background(255);
translate(100,100);
noFill();
rotateY(radians(mouseX));
rotateX(radians(mouseY));
stroke(0, 0, 0);
bezier(30, 20,100, 80, 5,10, 80, 75,30, 30, 75,0);
int steps = 10;

for (int i = 0; i <= steps; i++) {
float t = i / float(steps);
float x = bezierPoint(30, 80, 80, 30, t);
float y = bezierPoint(20, 5, 75, 75, t);
float z = bezierPoint(100, 10, 30, 0, t);
pushMatrix();
translate(x,y,z);
fill(255,0,0);
noStroke();
sphere(2);
popMatrix();

}
}
Re: Trace a bezierpoint in 3D
Reply #4 - Nov 29th, 2009, 11:59am
 
My mistake I forgot that bezierPoint() is used separately for each axis.
Embarrassed
Re: Trace a bezierpoint in 3D
Reply #5 - Nov 29th, 2009, 10:15pm
 
Thanks for the replies guys - both very helpful - however I wasn't that clear in my first post (sorry!)

I basically want to take a 2d profile (bezier) and rotate it around the vertical axis (Lathe in 3D modelling) in n-steps.

My problem is more with the actual maths involved - I know to get curve rotated n-radians around that X & Z are some sort of derivative of PI and probably sin...maybe....

I'll need to factor in T to get a position along the curve (which you've both kindly provided) but that seems to be easier...

Col
Re: Trace a bezierpoint in 3D
Reply #6 - Nov 29th, 2009, 10:41pm
 
so this is what you want : Creates a 3D polygon mesh by rotating a 2D path. ?

maybe this helps :

// MeshFrom2DPath.pde
// Marius Watz - http://workshop.evolutionzone.com
//
// Creates a 3D polygon mesh by rotating a 2D path.

import processing.opengl.*;

int numrot;
float px[],py[],mesh[][][];

void setup() {
size(700,700, OPENGL);

// To create a mesh, first create two arrays to hold the
// X and Y coordinates of the path you will use to create it
px=new float[20];
py=new float[20];
float t=0;
for(int i=0; i< px.length; i++) {
  px[i]=bezierPoint(0,130, 130, 0, t);
  py[i]=bezierPoint(450,350,150,50, t);
  t+=(1.0/(float)(px.length-1));
}

// use createMesh to create the mesh. createMesh takes three parameters:
// num == number of rotations
// startDeg == start degree of rotation
// endDeg == end degree of rotation

mesh=createMesh(px,py,20, -60,60);
}

void draw() {

translate(width/2,height/2);
pushMatrix();

background(0);
lights();

rotateY(radians(frameCount));
rotateX(radians(frameCount)/2);

stroke(255);
noStroke();
fill(255,120,0);

translate(0,0);
for(int i=0; i< 6; i++) {
  rotateZ(radians(60));
  pushMatrix();
  rotateX(radians(-60));

  // to draw the mesh, use drawMesh and pass your mesh variable to it
  drawMesh(mesh);
  popMatrix();
}

popMatrix();
}

float [][][] createMesh(float px[],float py[],int numrot,
float startDeg,float endDeg) {

float deg,x,z;
double cosval,sinval,tmp1,tmp2;

float [][][] mesh=new float[numrot][px.length][3];
endDeg-=startDeg;

int meshindex=0;
for(int i=0; i< numrot; i++) {
  deg=radians(startDeg+(endDeg/(float)(numrot-1))*(float)i);
  for(int j=0; j< px.length; j++) {
    x=px[j];
    z=0;
    cosval=Math.cos(deg);
    sinval=Math.sin(deg);
    tmp1=x*cosval - z*sinval;
    tmp2=x*sinval + z*cosval;
    mesh[i][j][0]=(float)tmp1;
    mesh[i][j][1]=py[j];
    mesh[i][j][2]=(float)tmp2;
  }
}

return mesh;
}

void drawMesh(float mesh[][][]) {
println(mesh.length+" "+mesh[0].length+" "+mesh[0][0].length);
for(int i=0; i< mesh.length-1; i++) {
  beginShape(QUAD_STRIP);
  for(int j=0; j< mesh[0].length; j++) {
    vertex(mesh[i][j][0],mesh[i][j][1],mesh[i][j][2]);
    vertex(mesh[i+1][j][0],mesh[i+1][j][1],mesh[i+1][j][2]);
  }
  endShape();
}
}
Re: Trace a bezierpoint in 3D
Reply #7 - Dec 7th, 2009, 3:35pm
 
Sorry about the delay in replying - but this was exactly what I needed.
Stupid question though - This is the piece of maths I wanted:

for(int j=0; j< px.length; j++) {
   x=px[j];
   z=0;
   cosval=Math.cos(deg);
   sinval=Math.sin(deg);
   tmp1=x*cosval - z*sinval;
   tmp2=x*sinval + z*cosval;
   mesh[i][j][0]=(float)tmp1;
   mesh[i][j][1]=py[j];
   mesh[i][j][2]=(float)tmp2;
 }

What exactly is the point of the var Z - and muliplying it against sinval/cosval - it looks like it's always 0?
Re: Trace a bezierpoint in 3D
Reply #8 - Dec 8th, 2009, 1:51am
 
silver2k wrote on Dec 7th, 2009, 3:35pm:
   cosval=Math.cos(deg);
   sinval=Math.sin(deg);
[...]
What exactly is the point of the var Z - and muliplying it against sinval/cosval - it looks like it's always 0

Perhaps a little mistake (judging only from the fragment I cite and the variable name!): Math.sin(), which can be written just sin() in Processing, takes angles in radian. You can use radians() to make the conversion.
Page Index Toggle Pages: 1