Letting a loop run back and forth in Processing - for-loop

Currently I am trying to get a loop "running forth and back" in a Processing sketch. I can do it with mouseY for example – but I want to have it automatically: the rect(); should appear horizontally line by line… like 1, 1+next, 1+next+next and after 15 lines reverse! 15, 14, 13, 12,11,10,9…
With frameCount; I can let them run down as I want… but not yet back. So I read about boolean statements… and tried to get it in syntax… syntax seems ok… but I can not really get the right logic to make it work. Does someone have an Idea how to really write it in the correct way?
This is my Code so far:
int a;
int i;
int step = 60;
void setup() {
size(1080, 1080);
}
void draw() {
background(0);
for (a = 0; a < 15; a++) {
for (i = 0; i < 5; i++) {
fill(255, 255, 255);
rect(216*i,60*a,216,60);
}
}
}
This creates the pattern – all at once – I know for (a = 0; a < mouseY; a++) or for (a = 0; a < frameCount; a++) would make it work but I thought to make it automatically this needs to appear somewhere – but how?
a+=step;
if ( a > 15 || a < 0 ){
step = -step;
}
Thank you for any help

It will probably be easier is you don't try to change the way you increment the steps but rather how many rectangles you generate for each step. To make it more clear consider this code:
MAX_RECTANGLES = 15;
let frameCount = 0;
while (frameCount < 100) {
frameCount++;
step = frameCount % (MAX_RECTANGLES * 2);
nbRect = MAX_RECTANGLES - Math.abs(MAX_RECTANGLES - step);
console.log(step, nbRect);
}
The frameCount variable and the while loop are only recreating the p5js loop, what is interesting here are the step and nbRect variables:
MAX_RECTANGLES is the number of rectangles you want to show when you show them all. In our example we want to show 15 rectangles.
step will will vary between 0 and MAX_RECTANGLES * 2 in our example this will vary between 0 and 30.
And we will vary nbRect between 0 and 15 with the following rules:
If 0 <= step <= 15 then 0 <= nbRect <= 15
If 16 <= step <= 30 then 15 >= nbRect >= 0
Running the code might make it easier to understand. With this mechanism you transform an ever increasing value (frameCount) to a value varying between 0 and 15.
You can have a look at this p5js codepen which does what you want with the method I just described.

Thank you statox! So i wrote it into Processing like this:
int MAX_RECT = 18;
int step = 60;
void setup() {
size(1080, 1080);
frameRate(30);
}
void draw() {
background(0);
int step = (frameCount/2 % MAX_RECT) *2;
int nbRectangles = MAX_RECT - Math.abs(MAX_RECT - step);
for (int a = 0; a < nbRectangles; a++) {
for (int i = 0; i < 5; i++) {
fill(255, 255, 255);
rect(216 * i, 60 * a, 216, 60);
}
}
}
Is there a way not to redraw the first line of rects? I have to check out the Math.abs(); function – I am not yet familiar with this… :-(

Related

How can I make a grid of tiles (that can be rotated randomly) in processing?

I have the following code in Processing that will produce a grid of randomly selected tiles from loaded files:
static int img_count = 6;
PImage[] img;
void setup() {
size(1200, 800);
img = new PImage[img_count];
for (int i = 0; i < img_count; i++) {
img[i] = loadImage("./1x/Artboard " + (i+1) + ".png");
}
}
void draw() {
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
int rand_index = int(random(img_count));
image(img[rand_index], 100 * i, 100 * j, 100, 100 );
}
}
}
By itself, it almost does what I want:
But I need that every tile be randomly rotated as well, so I tried this:
void draw() {
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
float r = int(random(4)) * HALF_PI; // I added this
rotate(r); // I added this
int rand_index= int(random(img_count));
image(img[rand_index], 100 * i, 100 * j, 100, 100 );
}
}
}
This second code doesn't act as I intended, as rotate() will rotate the entire image, including tiles that were already rendered. I couldn't find an appropriate way to rotate a tile the way I want, is there any way to rotate the tile before placing it?
You will probably need to translate before rotating.
The order of transformations is important (e.g. translating, then rotating will be a different location than rotation, then translating).
In your case image(img, x, y) makes it easy to miss that behind the scenes it's more like translate(x,y);image(img, 0, 0);.
I recommend:
void draw() {
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
float r = int(random(4)) * HALF_PI; // I added this
translate(100 * i, 100 * j); // translate first
rotate(r); // I added this
int rand_index= int(random(img_count));
image(img[rand_index], 0, 0, 100, 100 );
}
}
}
(depending on your setup, you might find imageMode(CENTER); (in setup()) handy to rotate from image centre (as opposed to top left corner (default)))

Circles not appearing on Canvas

I'm trying to build a connect4 game with processing, following a tutorial.
What I have so far is here.
The tutorial is here.
I stopped at the 4:05 mark to check my code but I noticed something...I don't know why but circles should pop up when I click but they aren't....can someone help pls? Thanks.
Just in case, here's the code:
int h = 6;
int w = 7;
int bs = 100;
int[][] board = new int[h][w];
int player = 1;
void setup() {
size(700, 600);
ellipseMode(CORNER);
}
int nextSpace(int x){
for (int y = h - 1; y >= 0; y--) if (board[y][x] == 0) return y;
return -1;
}
void mousePressed(){
int x = mouseX / bs;
int y = nextSpace(x);
if (y >= 0){
board[y][x] = player;
player = player == 1 ? 2 : 1;
}
}
void draw() {
for (int j = 0; j < h; j++){
for (int i = 0; i < w; i++){
fill(255);
rect(i * bs, j * bs, bs, bs);
if (board[j][i] > 0){
fill(board[j][i] == 1 ? 255 : 0, board[j][i] == 2 ? 255 : 0, 0);
ellipse(i * bs, j * bs, bs, bs);
}
}
}
}
Next time you have this kind of issue try to use a systematic approach to define where is your bug:
Is your draw() function broken? To check that put something in your board and see if it shows. For example add board[1][1]=1 in your setup() and you'll see a circle appearing so the issue is not in draw()
So if you click on the screen does it update your board as expected? The first thing is to add a simple println("Clicked"); in mousePressed(). Now you see that your click event is working well since the string is shown each time you click, so it must be an issue with how you get your x and y.
Use println(x); and println(y); in mousePressed() to have an idea of your values. You will notice that you don't get integers for x you get decimal number.
And this is your issue: you can not access board[1.543] it doesn't make sense, so you need to keep only the integer part of mouseX / bs. To do that you can use int() like this:
int x = int(mouseX / bs);
And your sketch is now working fine.

Processing - Loops - amount of circles decrease

Here is a grid of crosses in circles currently 5x5. I'm attempting to get a row of 5, followed by a row of 4 underneath, then 3, then 2 etc. I've tried changing the for loops and the values but nothing is working. Do I need to use rows and columns?
int x=20;
int y=30;
size(100,100); //set size of canvas screen
for(int i=0; i<5 ; i++)
{
for (int j=0; j<5; j++)
{
x=x+10; //add 10 to value stored in variable x
ellipse(x,y,10,10);
line (x-5,y,x+5,y);
line (x,y-5,x,y+5);
}
x=20;
y=y+10;
}
Thank you!
Like I said in your last post, the best thing you can do is to get out a piece of graph paper and a pencil and draw out a few examples. Do this until you find a pattern, and you can use that in your for loops. Shameless self-promotion: I've written a tutorial on for loops in Processing available here.
Another thing you might try is separating each row into its own for loop. Don't worry about nested for loops right now; just get it working with 5 individual for loops, one for each row. When you have that working, you'll be able to look for patterns that you can use to condense the whole thing into one nested for loop.
One more thing you might do is separate drawing a row of circles into its own function, which might be defined like this:
void drawRow(float circleY, int circleCount){
Then you'd put your inner for loop inside this function. Now that you have this, you can write another for loop that calls this function.
The trick is to reduce the number of circles drawn in the OUTER FOR LOOP. Compare with something I did :)
size(500, 500);
background(255);
int gridSize = 15;
int nTimes = gridSize;
int num = 1; //number the circles
float circleD = (width/gridSize);
float w = (width/gridSize)/2;
float h = (height/gridSize)/2;
float hOffset = h;
float wOffset = w;
int count = 1;
for(int i = 0; i < nTimes; i++){
for(int j = 1; j <= gridSize; j++){ //horizontal
if(count %2 == 1){
fill(0, 0, 255);
}
else{
fill(255, 0, 0);
}
ellipse(wOffset, hOffset, circleD, circleD);
fill(14);
textSize(circleD/6);
textAlign(CENTER, CENTER);
text(num, wOffset, hOffset);
num++;
wOffset += circleD;
}
gridSize -= 1;
wOffset = w;
hOffset += circleD;
count += 1;
}

Finding a Tangent Line at a Point on a Randomized Slope

I have a piece of processing code that I was given, which appears to be setting up a randomized Fourier series. Unfortunately, despite my efforts to improve my mathematical skills, I have no idea what it is doing and the articles I have found are not much help.
I'm trying to extend this code so that I can draw a line tangent to a point on the slope created by the code bellow. The closest I can find to answering this is in the mathematics forum. Unfortunately, I don't really understand what is being discussed or if it really is relevant to my situation.
Any assistance on how I would go about calculating a tangent line at a particular point on this curve would be much appreciated.
UPDATE As of 06/17/13
I've been trying to play around with this, but without much success. This is the best I can do, and I doubt that I'm applying the derivative correctly to find the tangent (or even if I have found the derivative at the point correctly). Also, I'm beginning to worry that I'm not drawing the line correctly even if I have everything else correct. If anyone can provide input on this I'd appreciate it.
final int w = 800;
final int h = 480;
double[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
double[] derivatives;
void setup() {
noStroke();
size(w, h);
fill(0,128,255);
rect(0,0,w,h);
int t[] = terrain(w,h);
fill(77,0,0);
for(int i=0; i < w; i++){
rect(i, h, 1, -1*t[i]);
}
time = millis();
timeDelay = 100;
iter =0;
img = get();
}
void draw() {
int dnum = 0; //Current position of derivatives
if(iter == numOfDeriv) iter = 0;
if (millis() > time + timeDelay){
image(img, 0, 0, width, height);
strokeWeight(4);
stroke(255,0,0);
point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
strokeWeight(1);
stroke(255,255,0);
print("At x = ");
print(iter);
print(", y = ");
print(skyline[iter]);
print(", derivative = ");
print((float)derivatives[iter]);
print('\n');
lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], 100);
lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], -100);
stroke(126);
time = millis();
iter += 1;
}
}
void lineAngle(int x, int y, float angle, float length)
{
line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}
int[] terrain(int w, int h){
width = w;
height = h;
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
//allocating horizon for screen width
int[] horizon = new int[width];
skyline = new double[width];
derivatives = new double[numOfDeriv];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for(int i = 0; i < n*2 ; i ++){
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*height);
int dnum = 0; //Current number of derivatives
for(int i = 0 ; i < width; i ++){
skyline[i] = 0;
double derivative = 0.0;
for(int j = 0; j < n; j++){
if(i % derivModBy == 0){
derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) -
sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
}
skyline[i] += ( sin( (f[j]*PI*i/height) ) + cos(f[j+n]*PI*i/height) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (height/2);
skyline[i] = (int)skyline[i];
horizon[i] = (int)skyline[i];
derivative *= amp/(n*2);
if(i % derivModBy == 0){
derivatives[dnum++] = derivative;
derivative = 0;
}
}
return horizon;
}
void reset() {
time = millis();
}
Well it seems in this particular case that you don't need to understand much about the Fourier Series, just that it has the form:
A0 + A1*cos(x) + A2*cos(2*x) + A3*cos(3*x) +... + B1*sin(x) + B2*sin(x) +...
Normally you're given a function f(x) and you need to find the values of An and Bn such that the Fourier series converges to your function (as you add more terms) for some interval [a, b].
In this case however they want a random function that just looks like different lumps and pits (or hills and valleys as the context might suggest) so they choose random terms from the Fourier Series between min and max and set their coefficients to 1 (and conceptually 0 otherwise). They also satisfy themselves with a Fourier series of 4 sine terms and 4 cosine terms (which is certainly easier to manage than an infinite number of terms). This means that their Fourier Series ends up looking like different sine and cosine functions of different frequencies added together (and all have the same amplitude).
Finding the derivative of this is easy if you recall that:
sin(n*x)' = n * cos(x)
cos(n*x)' = -n * sin(x)
(f(x) + g(x))' = f'(x) + g'(x)
So the loop to calculate the the derivative would look like:
for(int j = 0; j < n; j++){
derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) - \
sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
}
At some point i (Note the derivative is being taken with respect to i since that is the variable that represents our x position here).
Hopefully with this you should be able to calculate the equation of the tangent line at a point i.
UPDATE
At the point where you do skyline[i] *= amp/(n*2); you must also adjust your derivative accordingly derivative *= amp/(n*2); however your derivative does not need adjusting when you do skyline[i] += height/2;
I received an answer to this problem via "quarks" on processing.org form. Essentially the problem is that I was taking the derivative of each term of the series instead of taking the derivative of the sum of the entire series. Also, I wasn't applying my result correctly anyway.
Here is the code that quarks provided that definitively solves this problem.
final int w = 800;
final int h = 480;
float[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
float[] tangents;
public void setup() {
noStroke();
size(w, h);
fill(0, 128, 255);
rect(0, 0, w, h);
terrain(w, h);
fill(77, 0, 0);
for (int i=0; i < w; i++) {
rect(i, h, 1, -1*(int)skyline[i]);
}
time = millis();
timeDelay = 100;
iter =0;
img = get();
}
public void draw() {
if (iter == numOfDeriv) iter = 0;
if (millis() > time + timeDelay) {
image(img, 0, 0, width, height);
strokeWeight(4);
stroke(255, 0, 0);
point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
strokeWeight(1);
stroke(255, 255, 0);
print("At x = ");
print(iter);
print(", y = ");
print(skyline[iter]);
print(", derivative = ");
print((float)tangents[iter]);
print('\n');
lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], 100);
lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], -100);
stroke(126);
time = millis();
iter += 1;
}
}
public void lineAngle(int x, int y, float angle, float length) {
line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}
public void terrain(int w, int h) {
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
skyline = new float[w];
tangents = new float[w];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for (int i = 0; i < n*2 ; i ++) {
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*h);
for (int i = 0 ; i < w; i ++) {
skyline[i] = 0;
for (int j = 0; j < n; j++) {
skyline[i] += ( sin( (f[j]*PI*i/h) ) + cos(f[j+n]*PI*i/h) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (h/2);
}
for (int i = 1 ; i < w - 1; i ++) {
tangents[i] = atan2(skyline[i+1] - skyline[i-1], 2);
}
tangents[0] = atan2(skyline[1] - skyline[0], 1);
tangents[w-1] = atan2(skyline[w-2] - skyline[w-1], 1);
}
void reset() {
time = millis();
}

cvDilate/cvErode: How to avoid connection between separated objects?

I would like to separate objects in OpenCv like the following image it shows:
But if I am using cvDilate or cvErode the objects grow together... how to do that with OpenCv?
It looks like you will need to write your own dilate function and then add xor functionality yourself.
Per the opencv documentation, here is the rule that cvdilate uses:
dst=dilate(src,element): dst(x,y)=max((x',y') in element))src(x+x',y+y')
Here is pseudocode for a starting point (this does not include xor code):
void my_dilate(img) {
for(i = 0; i < img.height; i++) {
for(j = 0; j < img.width; j++) {
max_pixel = get_max_pixel_in_window(img, i, j);
img.pixel(i,j) = max_pixel;
}
}
}
int get_max_pixel_in_window(img, center_row, center_col) {
int window_size = 3;
int cur_max = 0;
for(i = -window_size; i <= window_size; i++) {
for(j = -window_size; j <= window_size; j++) {
int cur_col = center_col + i;
int cur_row = center_row + j;
if(out_of_bounds(img, cur_col, cur_row)) {
continue;
}
int cur_pix = img.pixel(center_row + i, center_col + j);
if(cur_pix > cur_max) {
cur_max = cur_pix;
}
}
}
return cur_max;
}
// returns true if the x, y coordinate is outside of the image
int out_of_bounds(img, x, y) {
if(x >= img.width || x < 0 || y >= img.height || y <= 0) {
return 1;
}
return 0;
}
As far as I know OpenCV does not have "dilation with XOR" (although that would be very nice to have).
To get similar results you might try eroding (as in 'd'), and using the eroded centers as seeds for a Voronoi segmentation which you could then AND with the original image.
after erosion and dilate try thresholding the image to eliminate weak elements. Only strong regions should remain and thus improve the object separation. By the way could you be a little more clear about your problem with cvDilate or cvErode.

Resources