It's Saturday night (here at least); I'm ill so having to stay in... So what better way to pass the time than solve someone else's interesting problem?
Comments added for the sake of my sanity as well as explanation:
Code:int numPoints = 11;
int w = numPoints * 20;
int pointSpacing = (w / numPoints);
float xoffset, yoffset;
float amplitude = 3;
float theta = 0;
float theta_vel = 0.06;
float period = w * 1.5;
float dx = (TWO_PI / period) * pointSpacing;
float[] yvalues = new float[numPoints];
float[] xpos = new float[numPoints];
float[] ypos = new float[numPoints];
ScrollBar bar;
PFont font;
void setup() {
size(640, 480);
smooth();
background(0);
//noLoop();
font = loadFont("SansSerif-10.vlw");
textFont(font);
xoffset = (width - w) * 0.5;
yoffset = height * 0.5;
bar = new ScrollBar(int(width * 0.5) - 40, 60, 80, 10, 0, 100);
}
void draw() {
background(0);
bar.update(mouseX, mouseY);
bar.display();
calcWave();
renderPoints();
}
void calcWave() {
amplitude = norm(bar.getPos(), 0, 100) * 3;
if (amplitude <= 0.5) amplitude = 0.5;
theta += theta_vel;
float angle = theta;
// Calculate the position of the central points
for (int i = 0; i < numPoints; i++) {
yvalues[i] = sin(angle) * (amplitude * ((i % numPoints) + 1));
angle += dx;
xpos[i] = xoffset + i * pointSpacing;
ypos[i] = yoffset + yvalues[i];
}
}
int radius = 5;
float[] angle = new float[numPoints];
// For each point you're storing two additional points, above and
// below, so this array length needs to be numPoints * 2
Vector[] vertices = new Vector[numPoints*2];
void renderPoints() {
// Calculate the angle between the central points
float dx = xpos[1] - xpos[0];
float dy = ypos[1] - ypos[0];
angle[0] = atan2(dy, dx);
for (int i = 1; i < numPoints; i++) {
dx = xpos[i] - xpos[i - 1];
dy = ypos[i] - ypos[i - 1];
angle[i] = atan2(dy, dx);
}
// Draw the central points
for (int i = 0; i < numPoints; i++) {
stroke(0, 50, 100);
pushMatrix();
translate(xpos[i], ypos[i]);
rotate(angle[i]);
line(0, -50, 0, 50);
popMatrix();
noStroke();
fill(255,0,0);
ellipse(xpos[i], ypos[i], radius, radius);
}
// Populate the array of vertices
/* I think this is where you had the problem.
No need to use modulo - that just confuses the issue - well for me at least ;)
You have 11 central points, each of which has a corresponding point above and
below that needed to be stored in the vertices array. So for each central point you
wanted to store the top coordinate in even numbers, therefore simply multiply i by 2.
Bottom points are stored in odd numbers so multiply i by 2 and add 1...
It's as simple as that. Of course getting the multi-dimensional array out of the picture helped ;) */
for (int i = 0; i < numPoints; i++) {
// Also creating a simple 'Vector' class (see below) avoids
// the need for multi-dimensional array - they confuse me :)
// The top points - stored at even indices
vertices[i*2] = new Vector(xpos[i] + sin(-angle[i]) * -50, ypos[i] + cos(-angle[i]) * -50);
// The bottom points - stored at odd indices
vertices[i*2+1] = new Vector(xpos[i] + sin(-angle[i]) * 50,ypos[i] + cos(-angle[i]) * 50);
}
// Draw the points
// Here modulo makes sense as you want to treat top and
// bottom points differently,
// though once you're placing an image my guess is you
// won't need to use it...
for (int i = 0; i < numPoints*2; i++) {
if ((i % 2) == 0) {
fill(0, 180, 255);
text(i, vertices[i].x, vertices[i].y - 10);
fill(0, 180, 255);
ellipse(vertices[i].x, vertices[i].y, radius * 0.5, radius * 0.5);
}
else {
fill(0, 255, 0);
text(i, vertices[i].x, vertices[i].y + 20);
fill(0, 255, 0);
ellipse(vertices[i].x, vertices[i].y, radius * 0.5, radius * 0.5);
}
}
}
void mousePressed() {
bar.press(mouseX, mouseY);
}
void mouseReleased() {
bar.release();
}
// Simple 'vector' class
/* I know it's not really a vector but just an x y coordinate. I'm sure I picked up that bad nomenclature
from one of my Actionscript books :S
Anyway the point is that defining this class avoids the need for multidimensional arrays (which just make
everything that little bit more confusing and difficult to figure out).
And yes - I'm sure that strictly speaking I should define getter and setter methods - another bad
habit I picked up from Actionscript... */
class Vector {
float x,y;
Vector(float x, float y){
this.x = x;
this.y = y;
}
}