Just before Christmas I started tutoring an 11 year old in Processing. At first we worked on 2D shapes (rect(), ellipse(), triangle() and line()) together with fill() and stroke().
I thought it was Napoleon who said that no battle plan survives contact with the enemy, but google says otherwise. Even so, I've learnt that no lesson plan survives contact with the student, and I was delighted when he started to say "can we do ... ?"
I working on blobs, moving them around and connecting them in pairs. I've given the Blob class a Boolean isConnected which I set if the blob is connected to another blob, and have an array called connections which stores the array index of the blob's pair or -1 if it's not connected.
I have pared down my code to the test version below where the blobs are joined by a fading line (a la nodeGarden).
There are two errors (that I've spotted), which may or may not be symptoms of the same thing:
• sometimes a blob connects to more than one other blob
• sometimes the blob doesn't return to its unconnected ("I'm free") state. If I leave the program running for some time (> hour) gradually all the blobs disappear, in roughly reverse array order.
I would appreciate help untangling my illogic!
Thanks
Blob[] blobs;
int numBlobs = 11;
Boolean showOutlines = false;
int[] connections;
float someMultiplier = 2.3;
void setup()
{
size(800, 800);
smooth();
blobs = new Blob[numBlobs];
connections = new int[numBlobs];
for (int b = 0; b < numBlobs; b++)
{
PVector position = new PVector(random(width), random(height));
PVector velocity = new PVector(random(-2, 2), random(-2, 2));
color fillColour = color(random(150, 250), random(150, 250), random(150, 250));
float fillAlpha = 96;
//for testing
float radius = map(b, 0, numBlobs, 20, 80);
// float radius = random(20, 70);
blobs[b] = new Blob(position, velocity, radius, fillColour, fillAlpha);
connections[b] = -1;
}
}
void draw()
{
background(255);
for (int b = 0; b < numBlobs; b++)
{
blobs[b].update();
blobs[b].checkEdges();
if (showOutlines) blobs[b].showLines();
if (!blobs[b].isConnected) blobs[b].display();
}
for (int b = 0; b < numBlobs - 1; b++)
{
Blob thisBlob = blobs[b];
//if I comment out the second of these conditions
//the blobs seem more likely to join to more than one other blob
if ((thisBlob.isConnected) && (b < connections[b]))
I've written a bit of code that manipulates an image and, before I post it on openprocessing, I thought that it would be nice to provide it with a larger pool of images to play with than I can reasonably copy there. I would like it to look at a directory of images on a different website and choose one of those to manipulate.
I've found two ways of finding/listing files
here and
here.
The first does this:
String path = sketchPath;
String[] filenames = commandToListFileNames(path);
and I can change path to an absolute local path and get the right results.
The second does this:
java
.io.File folder
=new java
.io.File(dataPath
("")); and if I have files matching the search criteria in the dataPath, I get results. I can't successfully change this to another path, relative or absolute. I've looked at the help for java.io.File and don't understand the syntax required.
I can't, with either of these, provide an
http:// address. Is there a way of doing this?
void draw()
{
// image(someImage, 0, 0, 50, 77); //red value is red(background)
image(someImage, 0, 0); //red value is 238
//if I comment both out, I get the value of the background colour
println(red(get(55, 100)));
}
Can I find the colour of a pixel in an image without displaying the image?
A few weeks ago someone asked for a collaborator on a fun project for print involving shape and colour. Me, me, me!
Essentially we took an RGB colour and converted into other colour spaces such as CMYK and HSL (HSB), and used the new values as co-ordinates for shapes. I learnt a lot:
- that every manufacturer has their own conversion formulae
- that there are loads of other colour spaces
- and it was the first time I'd coded for someone else
When we'd finished I animated some of the shapes we'd created. The result is
here .
I'm considering adding sweep tests (nicely descirbed
here), but am struggling with getting my head round how to do so when the ball colliding with a moving object - in this case a rotating line. The ball "knows" its velocity, but the line's position and rotation are passed to it. So I can tell where the ball will be in the next frame, but I won't (necessarily) be able to tell where the line will be.
Do I
- pretend that the line is stationary and call that good enough
- store its previous position and rotation just in case it's going to hit a ball in the next frame
- rewrite it (though that doesn't really make sense given the type of beast it is)
If you run this code, you'll see exactly what I'm doing! The collision works just fine if the ball hits the correct side of the flipper.
It occurs to me that I ought to be able to pass the co-ordinates of the ends of a line to the collision function, and have the ball bouncing off it correctly regardless of the angle of velocity or of the line,
without a mountain of ifs and elses.
I've slogging away at this in varying forms for quite some time, and have finally got close. The balls are swinging - mimicking SHM*. The collisions are working the best ever. But I've been staring at it so long that I can't figure out how to drag the balls to the side to start it all off.
*Note that I say mimicking SHM, though I got that to work and have left in the code for it. Because the movement is frame-based it played hell with the collisions.
Note also that there's a lot of testing stuff in the code that I'd normally strip out before posting. And there's lots more to do that I can't test until I get the dragging to work.
Thanks
string
main tab
int numBobs = 5; int[] swingDegrees; float[] swingAngles; Pendulum[] bobs; float stringLength = 100; float bobSize = 30; color[] colours; int frameSpeed = 32; //don't change this! 25-32 float xoffset; float closestAngle = 100; int closestAngleCount = 100; void setup() { size(300, 300); background(255); smooth(); frameRate(frameSpeed); // noLoop(); swingAngles = new float[17]; //magic number and angles found by experiment and observation int[] swingDegrees = {38, 37, 34, 31, 26, 20, 14, 7, 0, -7, -14, -20, -26, -31, -34, -37, -38}; for(int a = 0; a < swingDegrees.length; a++) { swingAngles[a] = radians(swingDegrees[a]); } // println(swingAngles);
if(pmouseX > mouseX) // drag clockwise { closestAngle = 100; closestAngleCount = 100; println("CLOCK"); for(int a = 8; a < 17; a++) //swingAngles array is 17 long { float compareAngle = abs(swingAngles[a] - dragAngle); if(compareAngle < closestAngle) { closestAngle = compareAngle; closestAngleCount = a; } } for(int c = 0; c <= b; c++) // drag all those to left too { bobs[c].setCount(closestAngleCount); } } else if(pmouseX < mouseX) //drag anticlockwise { closestAngle = 100; closestAngleCount = 100; println("ANTI"); for(int a = 0; a <= 8; a++) //swingAngles array is 17 long { float compareAngle = abs(swingAngles[a] - dragAngle); println(compareAngle); if(compareAngle < closestAngle) { closestAngle = compareAngle; closestAngleCount = a; println("a= " + a); } } for(int c = b; c < numBobs; c++) // drag all those to right too { bobs[c].count = closestAngleCount; } } } } } } void keyPressed() { if(keyCode == 32) //spacebar { for(int b = 0; b < numBobs; b++) bobs[b].setVertical(); } if(key == 'l' || key == 'L') { autoStartLeft(); } if(key == 'r' || key == 'R') { autoStartRight(); } }
Pendulum class
//comments #1 - uncomment these to see correct swinging motion (SHM) // comments #2 - uncomment for good enough swinging motion // neither will work with the other tabs here (the code has since evolved) // for sensible results set framerate to 25-32, and stringLength to 100 // I've moved on to a fixed swing as the collision wasn't working well class Pendulum { float angle; float stringLength; float bobSize; color colour; // float velocity = 0; //#1 // float gravity = 100;//98 //#1 // float swingGravity = gravity / frameSpeed; //#1 float[] swingAngles; float friction = 0.99;
void click(Pendulum[] bobs) { for(int b = 0; b < numBobs - 1; b++) { if(bobs[b].count > bobs[b+1].count) { // if both swinging if((bobs[b].swinging == true) && (bobs[b+1].swinging == true)) { // println("both"); int tempCount = bobs[b].count; bobs[b].count = bobs[b+1].count; bobs[b+1].count = tempCount; bobs[b].setSwingLeft(); bobs[b+1].setSwingRight(); } else // if left one swinging, right one still and so vertical if((bobs[b].swinging == true) && (bobs[b+1].swinging == false)) { // println("left swinging"); bobs[b].setVertical(); bobs[b+1].setSwingRight(); } else // if left one still and so vertical, right one swinging if((bobs[b+1].swinging == true) && (bobs[b].swinging == false)) { // println("right swinging"); bobs[b+1].setVertical(); bobs[b].setSwingLeft(); } } } }
Here are two more blob animations with shapes and/or movement inspired by posts here. The other two originated as exercises in Flash Math(s) Creativity, but I doubt that the authors would recognise them now.
Now that I've found how easy it is, I've put four exhibits on openprocessing. The first three are variations/extensions of examples in Flash Math(s) Creativity, and the fourth is nodeGarden from Foundation ActionScript converted to use vectors.
I've been playing around with some of the code in Flash Math(s) Creativity. One of the sections is called Alien message; my processing version gave the sample result here. I have the tiles generated at random from a short list of variations. I'd like to extend it so that it you click on one of the bulbs at the edge, the whole path from there is highlighted/filled in. Though I put pipe dream in the title, I'm not really thinking of incremental (flowing) fill - yet.
I can't get my head around how to approach it!
Do I keep a record of each tile and its entrances and exits? Say, "tile A has entrance at north joining to east, and deadends at south and west". How do I deal with the tile where the route splits? How do I deal with the tile that has a pair of entrances and exits?
How do I keep track of where in the grid the route has got to?
I've deliberately not included code as it's methods that I'd like help with; a good method might necessitate the rewriting of the code!
I've put the blobs into a triangluar-base grid now. Here's a diagram to show what's happening behind the scenes. I've also put the the code where you can turn the blobs off and see what's going on underneath.
I'd hoped to upload a zip file of the code, but can't see how, so here it all is ...
string
triangleBlobs
int numColumns = 8; int numRows = 10; float gridWidth, gridHeight; //blobs movement determined by balls at vertices Ball[][]balls = new Ball[numColumns][numRows]; float radius = 5; float vel = 1; //0.2 calm, 1 less so //balls movement constrained by invisible rings centred on each ball start point Boolean ballCollision = true; //internal collision Ball[][]rings = new Ball[numColumns][numRows]; Boolean ringCollision = false; //normal billiard ball collision
Blob[]blobs = new Blob[2*numColumns*numRows]; color[]colours = new color[2 * numRows];
class Blob //a shape with rounded corners or rounded sides { float[] xpos, ypos; //vertices color colour; float[] xoff, yoff; //offsets from vertices int numPoints; float offset = 2; //2 or 0.3: fraction of each end of line converted to rounded corners Boolean niceShape = true; //set offset to < 1 and this to false ...
Extending the
blobflowers in a direction suggested by
this post, I put the blobs in a moving grid.
Code below.
string
//gridBlobs - allonestring //invisible grid contrains motion int numColumns = 6; //must be at least 3 int numRows = 4; //must be at least 3 float gridSizeX, gridSizeY;
//invisible balls provide corners of blobs Ball[][]balls = new Ball[numColumns][numRows]; float radius = 0; float vel = 0.5;
//blob colour componenents determined by dist from centrestage //and angle from rotating hueAngle Blob[][]blobs = new Blob[numColumns-1][numRows-1]; float stageDiagonal; float hueAngle0, hueAngleInc0; float hueAngle1, hueAngleInc1; float colourInc = 0.02;
//top and bottom row and left and right columns are offstage //they're there to allow blobs to overlap stageedge gridSizeX = width / (numColumns - 2); gridSizeY = height / (numRows - 2);
//populate Balls array with balls, one in each gridcell for(int i = 0; i < numColumns; i++) { for(int j = 0; j < numRows; j++) { float startX = gridSizeX * (random(i, i + 1) - 1); float startY = gridSizeY * (random(j, j + 1) - 1); balls[i][j] = new Ball(startX, startY, random(-vel, vel), random(-vel, vel), radius, 0); balls[i][j].bounce = -1; } } }
//create and colour blobs //provide point in current gridcell, in one to right, in one to below right and one below for(int i = 0; i < numColumns-1; i++) { for(int j = 0; j < numRows-1; j++) { float[]xpos = {balls[i][j].x, balls[i+1][j].x, balls[i+1][j+1].x, balls[i][j+1].x}; float[]ypos = {balls[i][j].y, balls[i+1][j].y, balls[i+1][j+1].y, balls[i][j+1].y};
//find centre of blob and its distance and angle from stagecentre float centreX = 0; for(int k = 0; k < 4; k++) centreX += xpos[k]; float centreY = 0; for(int k = 0; k < 4; k++) centreY += ypos[k]; float dx = width / 2 - centreX / 4; float dy = height / 2 - centreY / 4; float centreAngle = atan2(dy, dx); float centreDist = dist(width / 2, height / 2, centreX / 4, centreY / 4);
//some mapping to vary colour components //sin and cos used to provide nice flow float someHue0 = map(sin(centreAngle - hueAngle0) * centreDist, -stageDiagonal, stageDiagonal, 0, 255); float someHue1 = map(cos(centreAngle - hueAngle1) * centreDist, -stageDiagonal, stageDiagonal, 0, 255); float someHue2 = 255 - ((someHue0 + someHue1) / 2); //arbitrary manipulation to determine third colour component float blobAlpha = someHue2 - (someHue0 + someHue1); //some arbitrary manipulation to vary alpha
//arbitrary colour creation from components (I like this best) color blobColour = color(someHue2, someHue0, someHue1, map(blobAlpha, -510, 255, 0, 255));
blobs[i][j] = new Blob(xpos, ypos, blobColour); blobs[i][j].display(); } } //rotate the colour angle so that the blobs change colour hueAngle0 += hueAngleInc0; hueAngle1 += hueAngleInc1; }
Ball class
// Ball class class Ball { float x, y; float vx, vy; float radius; color colour = color(0, 0, 255);
class Blob //a shape with rounded corners { float[] xpos, ypos; //vertices color colour; float[] xoffcw, yoffcw; //"clockwise" offsets from vertices int numPoints; int offset = 2; //2 or 3: fraction of each end of line converted to rounded corners
int numBlobs; blob[] blobs; color[] colour; float bRadius = 100;
int numVertices; float[][] xBlobVertices, yBlobVertices; //all the vertices used by a blob float[] xShared, yShared; //vertices shared by blobs (one for each blob) int numUnshared; float[][] xUnshared, yUnshared; //vertices not shared
numBlobs = (int)random(2, 10); numVertices = (int)random(3, 10); //shapes must have at least 3 vertices numUnshared = numVertices - 3; // unshared vertices (total - 2 shared - centre)
blobs = new blob[numBlobs]; colour = new color[numBlobs];
xShared = new float[numBlobs]; yShared = new float[numBlobs]; xUnshared = new float[numBlobs][numUnshared]; yUnshared = new float[numBlobs][numUnshared];
for(int b = 0; b < numBlobs; b++) { blobs[b] = new blob(xBlobVertices[b], yBlobVertices[b], colour[b]); } translate(width / 2, height / 2); for(int b = 0; b < numBlobs; b++) { blobs[b].display(); }
//jiggle all the vertices except the centre one for(int i = 0; i < numBlobs; i++) { xShared[i] += random(moveMin, moveMax); yShared[i] += random(moveMin, moveMax); for(int j = 0; j < numUnshared; j++) { xUnshared[i][j] += random(moveMin, moveMax); yUnshared[i][j] += random(moveMin, moveMax); } } }
class blob //a shape with rounded corners { float[] xpos, ypos; //vertices color colour; float[] xoffcw, yoffcw; //"clockwise" offsets from vertices int n; int offset = 3; //fraction of each end of line converted to rounded corners