Rotate around its own axis in OoP with Processing - arrays

i am currently a bit stuck in programming a PROCESSING Sketch. Lets say I have a bunch of rectangles that move up the sketch window like bubbles… They have different sizing and color… And I want to let them rotate around its own axis while they move up. I tried using pushMatrix(); and popMatrix(); – and even translate(); but I guess its a bit more complicated because i use OoP and variables in the constructor for X and Y Position of each rectangle…
This is the code to my sketch:
Rectangle[] rectangles = new Rectangle[10];
void setup() {
size(360, 640);
for (int i = 0; i < rectangles.length; i++) {
rectangles[i] = new Rectangle(random(0, width), random(20, 200), random(0, 250));
}
}
void draw() {
background(255);
for (int i = 0; i < rectangles.length; i++) {
rectangles[i].display();
rectangles[i].ascend();
rectangles[i].top();
}
}
And for the Class Rectangle it is:
class Rectangle {
float x;
float y;
float speed;
float d;
float c;
Rectangle(float tempX, float tempD, float tempC) {
rectMode(CENTER);
x = tempX;
y = height + d/2;
d = tempD;
speed = random(0.5, 2.5);
c = tempC;
}
void display() {
noStroke();
fill(c);
rect(x, y, d, d);
}
void ascend() {
y = y - speed;
}
void top() {
if (y < -d/2) {
y = height + d/2;
}
}
}
This is what I tried, usually it works:
void display() {
noStroke();
fill(c);
pushMatrix();
translate(width/2, height/2);
rotate(radians(frameCount));
rect(x, y, d, d);
popMatrix();
}
If someone would have an idea or a hint what I am missing I'd be super greatful!
Thank you for any kind of help in advance!
All the best!

When rotating something in place, what usually works best is using translate in such a way that you're drawing it "at the origin". In your case, that means that you want to translate such that the first two parameters of rect() are both zero. So you translate, then rotate, then draw the rectangle "at the origin".
Solution:
pushMatrix();
translate(x, y);
rotate(radians(frameCount));
rect(0, 0, d, d);
popMatrix();

Related

How to check elements from array? Avoid overlapping of my circles and match the speed for the circle spawn behind

Hi what I am trying to achieve here is not overlap the circle moving from left to right. the x coordinate is random generated, so should I check and make sure a minimum gap there so it execute draw? If so how do I do it.
Also speed is random as well, so I want to match the speed from behind to the front one(also not going backwards) and do no overtake it.
Sorry I am doing very basic coding now, so I can't use class or array for functions.
//declare global variables
int N_CARS_IN_LANE = 30;
int MIN_GAP = 50;
float xPed;
float yPed;
float dia;
boolean isCollide=false;
float [] xPos;
float [] yPos;
float [] dias;
float [] xSpeed;
void setup() {
size(1200, 400);
background(255);
xPed=width/2;
yPed=7*height/8;
dia=height/4;
init();
}
void init() {
xPos= new float[N_CARS_IN_LANE];
yPos= new float[N_CARS_IN_LANE];
dias= new float [N_CARS_IN_LANE];
xSpeed= new float [N_CARS_IN_LANE];
for ( int i=0; i<xPos.length; i++) {
for (int k=i+1; k< N_CARS_IN_LANE; k++) {
xPos[i]= random(-150);
xPos[k]=xPos[i]-k;
yPos[i]=height/8;
dias[i]=50;
xSpeed[i]=random(10);
}
}
}
void draw() {
//reset background
background(255);
balls();
moveballs();
ballsisOffscreen();
collideballs();
}
void balls() {
for (int i=0; i<N_CARS_IN_LANE; i++) {
if (isCollide!=true) {
fill(0, 255, 0);
circle (xPos[i], yPos[i], dias[i]);
//should I put conditions here to make sure balls are separated for a MIN_GAP when draw?
}
}
}
void moveballs() {
for (int i=0; i<N_CARS_IN_LANE; i++) {
//for (int k=i+1; k<N_CARS_IN_LANE; k++) {
xPos[i] = xPos[i] + xSpeed[i];
}
}
//check balls draw is not overlapping? and maintain a MIN_GAP
void collideballs() {
for (int i=0; i<N_CARS_IN_LANE; i++) {
for (int k=i+1; k< N_CARS_IN_LANE; k++) { //check elements from array?
if (isCollide&&xPos[i]!=xPos[k]) {
xSpeed[k]=xSpeed[i]; // match speed from behind to from?
}
}
}
}
boolean isCollide() {
for (int i=0; i<N_CARS_IN_LANE; i++) {
for (int k=i+1; k< N_CARS_IN_LANE; k++) {
// distance between balls
float leftright =((xPos[i]-dias[i]/2) -(xPos[k]+dias[k]/2));
float rightleft=((xPos[k]-dias[k]/2)-(xPos[i]+dias[i]/2));
if ((leftright<MIN_GAP)&&(xPos[i]!=xPos[k])&&rightleft>MIN_GAP) {
return true;
}
}
}
return false;
}
//reset ball
void ballsisOffscreen() {
for (int i=0; i<N_CARS_IN_LANE; i++) {
if (xPos[i]>width) {
xPos[i]=-200;
}
}
}
I'm not sure if I understud correctly what you were asking for, but I hope I did it right.
I just added the speed to the position of the ball and then checked if this moves it to close to the ball in the front of it. In that case I just set it right behind the ball in front.
But for this to work you have to know which ball is in front of the current ball.
For that you could loop through all of your balls and search for the ball whoose coordinate is closest but bigger than the current balls.
Also I think it would make your code much more readable if you used Objects for the balls. That way you also don't have to search for the next ball and it makes it easier to expand later.
Here is a version I've coded up quickly that implements the balls/cars as objects and also solves your problem with collision. I hope that helps you to fix your code [Or you just copy&paste this one ;-) ]
ArrayList<Car> cars;
int carAmount = 10;
int carSize = 50;
int gab = 5;
void setup(){
size(1200, 400);
cars = new ArrayList<Car>();
}
void draw(){
background(255);
float posLastCar = width+ carSize*2 + gab; //could also be any other big number
if(random(100) > 97 && cars.size()< carAmount){
//if there are not enought cars there is a 3% chance of a new one spaning
cars.add(new Car(carSize, gab, 100));
}
for(Car car: cars){ //loops through all cars
car.update(posLastCar);
posLastCar = car.posX; //save pos of this car for the next
}
if(cars.size() > 0){
if(cars.get(0).isAtEnd()){ //checks if first car is at the end
cars.remove(0); //then removes it
}
}
}
class Car {
float posY;
float radius;
float gab;
float posX;
float speed;
Car(float radius, float gab, float posY){
this.radius = radius;
this.gab = gab;
this.posY = posY;
speed = random(3, 10); //picks random speed between 3 and 10
// to reduce the amount of extremly slow, blocking cars
posX = 0;
}
void move(float posNextCar) {
posX += speed;
if(posX + radius + gab > posNextCar){
posX = posNextCar - radius - gab;
}
}
void update(float posNextCar){
move(posNextCar);
fill(0, 255, 0);
circle (posX, posY, radius);
}
boolean isAtEnd(){
if (posX >= width + radius){
return true;
}
return false;
}
}

Processing - Animation between two points

I am developing the below code. To give you a brief description, it is allowing the user to click on different points on the screen, then these mouse coordinates and positions are stored in an array and also seen on the screen. When the user clicks enter there is a movement from the first point to the last point, using the linear interpolation technique. I am having difficulty in the for loop as the PVector v is storing the coordinates. Could anyone please guide me accordingly?.
ArrayList vectors;
PVector v = new PVector();
boolean animate = false; //declare a boolean variable you can use to switch from building points to animating the movement
int FirstMouseClick; //declare an int variable to store the frameCount of the first mouseclick
int AnimationStart; //declare an int variable to store the frameCount of the animation start
void setup()
{
size(500, 500);
frameRate(60);
vectors = new ArrayList();
}
void draw()
{
if(!animate)//if the boolean variable animate is true
{
float output = frameCount - AnimationStart; // subract the animation start frameCount from the current frameCount so you know which framecount from the vectors array you should be showing
for(int i=0; i<vectors.size(); i++) //loop through the vectors array
//until you find the (next PVector's frameCount - frameCount of first mouseClick) > above subtraction result
{
v = (PVector)vectors.get(frameCount); //until you find the (next PVector's frameCount)
}
ellipse(v.x,v.y,10,10);// use the current pvector's xpos and ypos to draw the ellipse
}
}
void mouseClicked()
{
frameCount = 0; //if not yet set, set the first frameCount value
vectors.add(new PVector(mouseX, mouseY,frameCount));// <--- store the framecount in the z axis
ellipse(mouseX,mouseY,10,10);
println("Mouse Coordinates are: " + vectors);
}
void keyPressed()
{
if(keyCode == ENTER)
{
animate = true; //set the boolean variable animate to true
AnimationStart = 3; //set the framecount of the animation start
}
}
I'm really not sure, what you were trying to do, but if I got you right you want to do something like this:
Draw some circles, if user clicked on canvas
If user pressed Enter, start animation
Animation means: another circle (v) moves linear from circle to circle
I really don't know, what your frameCount was for. May be you can add it to this code easier now? Note, that you can add new targets by clicking with the mouse, even if animation is true.
You can do this:
ArrayList<PVector> vectors = new ArrayList();
PVector v = new PVector();
boolean animate = false; // true means, the circles moves
int nextTarget = 0; // defines the index of the next circle, the point is going to
void setup()
{
size(500, 500);
frameRate(60);
v = new PVector(width/2, height/2);
}
void draw() {
// draw background to delete old drawings
background(128);
// show all circles
for (int i=0; i<vectors.size(); i++) {
fill(255);
ellipse(vectors.get(i).x, vectors.get(i).y, 10, 10);
}
// if the boolean variable animate is true
if (animate) {
// compute angle to target circle and remaining distance
float diffX = vectors.get(nextTarget).x - v.x;
float diffY = vectors.get(nextTarget).y - v.y;
float angle = atan2(diffX, diffY);
// defines the speed of the circle
float movement = 2;
// compute new position of v
v = new PVector(v.x + sin(angle)*movement, v.y + cos(angle)*movement);
// if v reached the target circle, move on to the next one
if (dist(v.x, v.y, vectors.get(nextTarget).x, vectors.get(nextTarget).y) < 1 && nextTarget < vectors.size()-1) {
nextTarget++;
}
}
fill(0);
ellipse(v.x, v.y, 10, 10); // use the current pvector's xpos and ypos to draw the ellipse
}
void mouseClicked()
{
vectors.add(new PVector(mouseX, mouseY));
ellipse(mouseX, mouseY, 10, 10);
println("Mouse Coordinates are: " + vectors);
}
// toggle animation mode
void keyReleased() {
if (key == ENTER) {
animate = !animate;
println("animation: "+ animate);
}
}

how to use ArrayList in Processing?

The official explanation is here: ArrayList
However, it uses iteration and confuses me.
I am trying to make a drawing pen but something is wrong here:
drawings.get(i) = drawing.get(i-1);
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup(){
size(400,400);
background(255);
colorMode(HSB);
}
void draw(){}
void mouseDragged(){
drawings.add(new Drawing(mouseX,mouseY));
for(int i = drawings.size()-1;i>0;i--){
drawings.get(i) = drawing.get(i-1);
}
for(int i=0;i<drawings.size;i++){
fill(c,100);
drawings.get(i).display();}
}
class Drawing{
float x,y,r;
color c;
Drawing(float ax,float ay){
x=as;
y=ay;
r=random(2,20);
c=color(random(100,200),255,255);
}
void display(){
fill(c,100);
ellipse(drawing[i],r,r);}
}
I still don't know how to use ArrayList.
Does anyone know?
Thank you.
You mentioned iteration confuses you. It's a simple for loop. In case you're having trouble understanding those, they look harder compared to other statements, but that's just because a loop does 3 things at once:
Initialize a counter
Compare the current counter value to a limit (boolean expression)
Increments a counter
In your code, there are two loops:
for(int i = drawings.size()-1;i>0;i--)
and
for(int i=0;i<drawings.size();i++)
The first loop counts backwards, therefore:
the counter is initialized with the highest value (i =
drawings.size())
the limit is 1 (i>0)
the counter is decremented (i--) (or incremented by -1 if you like)
drawings.size() simply retrieves the size of the array list (similar to the length property of an array). So in simple terms, the first loop starts with the last element added to the list (the most recent), who's index is equal to the list size -1 and it stops at the 2nd element, who's index is 1 (since arrays/array lists start indexing from 0).
The second loop is simpler, since is counts from 0 to the size of the array list, basically all the elements of the list in the order they were stored (oldest to newest).
In the first loop, it looks like you're shifting all the elements except the first by one.
You should try it like so:
for (int i = drawings.size()-1;i>0;i--) {
Drawing current = drawings.get(i);//store the current drawing
Drawing previous = drawings.get(i-1);//store the previous drawing
current = previous;//point the current to the previous
}
And here is your code listing with the errors fixed:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
color c = color(0,0,192);
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
for (int i = drawings.size()-1;i>0;i--) {
Drawing current = drawings.get(i);//store the current drawing
Drawing previous = drawings.get(i-1);//store the previous drawing
current = previous;//point the current to the previous
//drawings.get(i) = drawing.get(i-1);
}
for (int i=0;i<drawings.size();i++) {
fill(c, 100);
drawings.get(i).display();
}
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
// ellipse(drawing[i], r, r);
ellipse(x,y,r,r);
}
}
UPDATE
Because of the reverse loop I assumed you needed to store a list of drawing and offset it, like so:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
smooth();
noStroke();
colorMode(HSB);
}
void draw() {
background(0,0,255);
for (int i=0;i<drawings.size();i++){
drawings.get(i).display();
}
}
void mouseDragged() {
for (int i = drawings.size()-1;i>0;i--) {
drawings.get(i).copy(drawings.get(i-1));
}
drawings.add(0,new Drawing(mouseX, mouseY));
}
class Drawing {
float x, y, r;
color c;
void copy(Drawing copyFrom){
x = copyFrom.x;
y = copyFrom.y;
r = copyFrom.r;
c = copyFrom.c;
}
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
If you simply want to draw a line between Drawing objects based on distance, you can do it without the reverse loop:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
for (int i=0;i<drawings.size();i++) {
Drawing curr = drawings.get(i);
if(i > 0){ //if the current index is greather than 0
Drawing prev = drawings.get(i-1); //we can access the previous
if(dist(curr.x,curr.y,prev.x,prev.y) < 20) {//check the distance, if it's within a certain threshold
line(curr.x,curr.y,prev.x,prev.y); //draw the line
}
}
curr.display();
}
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
In fact, since you're not clearing the background, you don't need a list at all. All you need is a reference to the previous Drawing object so you can check the distance and draw a line:
Drawing prev;//variable to store the previous drawing
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
Drawing curr = new Drawing(mouseX, mouseY);//create a new drawing
curr.display();//display it
if(prev != null){//check if there was a previous one
if(dist(curr.x,curr.y,prev.x,prev.y) < 20) {//if so, check if the distance is within the threshold
line(curr.x,curr.y,prev.x,prev.y);//then simply draw a line
}
}
prev = curr;
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
HTH

Adding to vector of objects with attributes determined by constantly changing values

For this issue, I have done research, but I am not sure I have been searching for the right terms? Maybe someone can help...
I am writing an app in openframeworks that is basically a sound visualizer. What I am trying to do is have the program create and draw a rectangle at a certain point, the height of which is determined by the frequency of audio input at the moment of the rectangle's creation. Then, I want the program to draw another rectangle next to it, the height of which determined by the frequency at THAT moment, so forth and so on. (I am also planning to pan this to the left every time, so that it is creating a very long chain of rectangles).
The rectangles are going to look like buildings (drawing a city scape as it goes), so I have created a class of them with very simple attributes: position, height, etc. and the main work (correct me if I am wrong) is going to be in the main part of the application.
The problems I have been having are in the drawing of the object and then having its height correspond to a frequency. Also, I don't want the height of the rectangle to change once it is created, so I am having trouble getting that to happen correctly. Right now, I have only managed to create a single large rectangle that flickers up and down with the sound input.
I am not entirely sure how I should be adding to the vector an object with the correct attributes each second and having that instance of the object's property stay static.
I am not sure if I am asking the right questions correctly, but maybe someone can help?
Here is the top level of the app code:
#include "testApp.h"
//--------------------------------------------------------------
void testApp::setup(){
ofSetFrameRate(60);
ofBackground(0,30,60);
//sound stream setup and such
ofSoundStreamSetup(0,2,this, 44100, BUFFER_SIZE, 4);
left = new float[BUFFER_SIZE];
right = new float[BUFFER_SIZE];
FFTanalyzer.setup(44100, BUFFER_SIZE/2, 1);
FFTanalyzer.peakHoldTime = 15; // hold longer
FFTanalyzer.peakDecayRate = 0.95f; // decay slower
FFTanalyzer.linearEQIntercept = 0.9f; // reduced gain at lowest frequency
FFTanalyzer.linearEQSlope = 0.01f; // increasing gain at higher frequencies
numOctaves=1;
//control panel setup
panel.setup("control", 770, 0, 300, 150);
panel.addPanel("fft settings", 1, false);
panel.setWhichPanel("fft settings");
panel.addSlider("Number of Sub Octaves","NUM_OCT", 1, 1,12, false);
//set up buildings
for (int i = 0; i < bldgs.size() ; i+= 20){
}
}
//--------------------------------------------------------------
void testApp::update(){
panel.update();
if(numOctaves != panel.getValueI("NUM_OCT")){
numOctaves = panel.getValueI("NUM_OCT");
panel.setValueI("NUM_OCT", numOctaves,0);
FFTanalyzer.setup(44100, BUFFER_SIZE/2, numOctaves);
}
}
//--------------------------------------------------------------
void testApp::draw(){
panel.draw();
static int index=0;
float avg_power = 0.0f;
/* do the FFT */
myfft.powerSpectrum(0,(int)BUFFER_SIZE/2, left,BUFFER_SIZE,&magnitude[0],&phase[0],&power[0],&avg_power);
for (int i = 0; i < (int)(BUFFER_SIZE/2); i++){
freq[i] = magnitude[i];
}
FFTanalyzer.calculate(freq);
float binDrawWidth = (ofGetWidth()-20)/FFTanalyzer.nAverages;
//float bldgHeighTemp;
for (int i = 0; i < 1000 ; i+=30){
for (int f = 0; f < (int)(BUFFER_SIZE/2); f++){
bldg temp;
freqs[i] = freq[f]*-6;
temp.bldgPosX = i;
temp.bldgPosY = ofGetHeight()/2;
temp.bldgWidth = 30;
temp.bldgHeight = freqs[i];
temp.draw();
bldgs.push_back(temp);
}
}
}
//--------------------------------------------------------------
void testApp::keyPressed(int key){
}
//--------------------------------------------------------------
void testApp::keyReleased(int key){
}
//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
panel.mouseDragged(x,y,button);
}
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
panel.mousePressed(x,y,button);
}
//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
panel.mouseReleased();
}
//--------------------------------------------------------------
void testApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void testApp::audioReceived (float * input, int bufferSize, int nChannels){
// samples are "interleaved"
for (int i = 0; i < bufferSize; i++){
left[i] = input[i*2];
right[i] = input[i*2+1];
}
}
[edit] testapp.h
#ifndef _TEST_APP
#define _TEST_APP
#include "ofMain.h"
#include "fft.h"
#include "FFTOctaveAnalyzer.h"
#include "ofxControlPanel.h"
#include "bldg.h"
#define BUFFER_SIZE 512
class testApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed (int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void audioReceived (float * input, int bufferSize, int nChannels);
ofxControlPanel panel;
int numOctaves;
FFTOctaveAnalyzer FFTanalyzer;
float * left;
float * right;
int bufferCounter;
fft myfft;
float magnitude[BUFFER_SIZE];
float phase[BUFFER_SIZE];
float power[BUFFER_SIZE];
float freq[BUFFER_SIZE/2];
vector <float> freqs;
vector <bldg> bldgs;
};
#endif
what isn't working is that it isn't creating single instances of the object and/or each instance's attributes are constantly changing according to frequency, which isn't the behavior I'm trying to achieve; what I want is for each object to be created at a certain height and stay that way, then a new ones created next to it so forth and so on, like every second or so.
Make any sense? I am still trying to figure out how to ask the right questions.
Thanks,
Bree
Ok as far as I understand your problem you need to do this, maybe this helps:
Try to store pointers in your bldgs vector
vector<bldg*> bldgs;
and add new objects to it with
bldg* temp;
freqs[i] = freq[f]*-6;
temp->bldgPosX = i;
temp->bldgPosY = ofGetHeight()/2;
temp->bldgWidth = 30;
temp->bldgHeight = freqs[i];
bldgs.push_back(temp);
remove the draw method from here and draw every bldg on every frame. add this to your draw method:
for(int i = 0; i < bldgs.size(); i++)
{
bldgs[i]->draw();
}
it would be a better practise to move everything not directly related to draw to put in the update method of your testApp. so for example move your creation and filling the vector stuff to the update method.

Make A Spiral With One for/While or do while loop

Is it possible to make a spiral with single loop? I've made spirals before, but only with multiple loops. Bonus for code that will show the output.
#include "conio.h"
#include "dos.h"
#include "stdlib.h"
void main()
{
int p,q,r,s,t;
clrscr();
for(p=8; p<14; p++)
{
for(q=5 ; q<26; q++)
{
gotoxy(5,q);
printf("Û");
}
for(r=5; r<50; r++)
{
printf("Ü");
}
for(s=25; s>4; s--)
{
gotoxy(50,s);
printf("Û");
}
for(t=50; t>6; t--)
{
gotoxy(t,4);
printf("Ü");
}
for(q=5; q<25; q++)
{
gotoxy(7,q);
printf("Û");
}
// etc. . . I didn't write the full code.
}
One possible approach:
const float centerX = 10, centerY = 10;
const float speed = 0.1;
const float max_angle = 10;
const float angleStep = 0.1;
for (float angle = 0; angle < max_angle; angle += angleStep) {
float radius = angle*speed;
float sX = centerX+cos(angle)*radius;
float sY = centerY+sin(angle)*radius;
createPoint(sX,sY);
}
Substitute any drawing function for createPoint and play with the parameters.
One approach (similar to what's above) for createPoint would be:
void createPoint(int x, int y) {
gotoxy(x,y);
putchar('*');
}
If you want to use a graphics library later, you can change just this method.

Resources