I need to create an overlay image with variable-defined size. However, if I use surface.setSize() when I then try to store the resulting image with get() the sketch crashes with ArrayIndexOutOfBoundsException. Why? Does size() initialize the canvas differently?
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
surface.setSize(w, h); // remove it, and you're ok
background(0); // draw something
overlay = get(); // exception
}
I'm guessing that you're using surface.setSize() instead of size() because you got an error when you tried to pass variables into the size() function?
The solution to that problem is not to call the surface.setSize() function. Instead, you should define a settings() function that then calls the size() function with variables as parameters. The rest of your code would remain in the setup() function.
final int w = 320;
final int h = 240;
PImage overlay;
void settings() {
size(w, h);
}
void setup() {
background(0);
overlay = get();
}
More info can be found in the reference.
Another approach would be to get rid of the w and h variables entirely, and just pass in numbers to the size() function. Then you could just use the width and height variables wherever you were previously using the w and h variables.
Have a look at this issue, I can't comment much on the "why" of things here but as far as I can understand, setSize() runs after setup is finished because it can't run while things(in this case, the background) are being drawn. Moving that line to the end of setup doesn't produce the out of bounds exception:
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
background(0,200,150);
overlay = get();
surface.setSize(w, h);
}
void draw() {
tint(0,200,0);
image(overlay,50,0);
}
Edit: It seems like the get() in this case is grabbing only the default window size of pixels
There is a workaround for that- you can start by declaring size with some reasonable or basically any dimensions bigger than w and h, then use the get() method with 4 parameters to grab the image according to the w and h dimensions:
final int w = 320;
final int h = 240;
PImage overlay;
void setup() {
size(1000, 1000); //can be any numbers greater than w and h
background(0, 200, 150);
surface.setSize(w, h);
overlay = get(0, 0, w, h);
}
void draw() {
tint(0, 200, 0);
image(overlay, 50, 0);
}
Related
Im sure there is a pretty straight forward answer to this...cant quite figure it out though.
In my processing sketch's data folder, there is a folder named test_segments. test_segments contains a bunch of images.
I need to load an image from test_segments into my PImage.
It looks like this: http://imgur.com/a/iG3B6
My code:
final int len=25;
final float thresh=170;
boolean newDesign=false;
PImage pic;
ArrayList<PImage> imgContainer;
int n=3;
void setup() {
size(800, 800, P2D);
colorMode(RGB, 255);
background(250, 250, 250);
rectMode(CENTER);
//imageMode(CENTER);
pic=loadImage("hand.jpg");
pic.resize(width, height);
color c1 = color(200,25,25);
color c2 = color(25, 255, 200);
imgContainer=new ArrayList<PImage>();
PImage pimg1=loadImage("this is where test_0.png needs to go")
pimg1.resize(50, 50);
imgContainer.add(pimg1);
noLoop();
noStroke();
}
void draw() {
if (newDesign==false) {
return;
}
pic.loadPixels();
for (int y = 0; y < height; y+=40) {
for (int x = 0; x < width; x+=40) {
int index=y*width+x;
color pixelValue = pic.pixels[index];
color rgb = pixelValue;
int r = (rgb >> 16) & 0xFF; // Faster way of getting red(argb)
int g = (rgb >> 8) & 0xFF; // Faster way of getting green(argb)
int b = rgb & 0xFF;
//How far is the current color from white
float dista=dist(r,g,b,255,255,255);
//50 is a threshold value allowing close to white being identified as white
//This value needs to be adjusted based on your actual background color
//Next block is processed only if the pixel not white
if(dista>30){
float pixelBrightness = brightness(pixelValue);
float imgPicked=constrain(pixelBrightness/thresh, 0, n-1);
image(imgContainer.get((int)imgPicked),x,y);
}
}
}
}
void mouseReleased() {
newDesign=!newDesign;
redraw();
}
Thanks!
You should just be able to do:
PImage pimg1 = loadImage("test_segments/test_0.png");
If that doesn't work, please try to post a MCVE like we talked about before. Here's an example of an MCVE that would demonstrate your problem:
PImage pimg1 = loadImage("test_segments/test_0.png");
image(pimg1, 0, 0);
Don't forget to include exactly what you expect to happen, and exactly what's happening instead. Good luck.
I want to draw a shape based on the input of a slider. see the code below:
import controlP5.*;
ControlP5 cp5;
int people = 5;
int DMamt = 0;
int peoplehis;
Slider abc;
PShape vorm;
void setup() {
cp5 = new ControlP5(this);
size(displayWidth, displayHeight);
cp5.addSlider("people")
.setPosition(10,10)
.setWidth(400)
.setRange(0,20)
.setValue(0)
.setNumberOfTickMarks(20)
.setSliderMode(Slider.FIX)
;
cp5.addSlider("DMamt")
.setPosition(450,10)
.setWidth(400)
.setRange(0,255)
.setValue(0)
.setNumberOfTickMarks(5)
.setSliderMode(Slider.FIX)
;
vorm = createShape();
frameRate(10);
}
void draw(){
if(peoplehis != people){
vorm.beginShape();
vorm.fill(DMamt);
for(int i = 0; i <= people; i++){
vorm.vertex(random(500), random(500));
}
endShape();
}
peoplehis = people;
shape(vorm, 100,100);
}
the first time i set the slider value i get a shape with the desired amount of points. but when i change the slider value after the first time the value of the slider get added to the points that are already drawn. but i want a new shape. the old shape should be gone. see below for a example:
first value of slider = 5
this gives me a shape with 5 points (GREAT);
second value of silder = 12
this gives me a shape with 17 points (NOT GREAT)
i want 12 points instead of 17.
how do i do this?? i am not very experienced with code :(
A Processing PShape can consist of multiple shapes, which you can add by calling the beginShape(), vertex(), and endShape() functions multiple times.
If you just want to recreate a new shape instead of adding multiple shapes, then call the createShape() function again to start over with a new PShape instance. Also, make sure you clear out previous frames by calling the background() function.
Here is a simple example:
PShape shape;
void setup() {
size(500, 500);
shape = createShape();
frameRate(60);
}
void mousePressed(){
shape = createShape();
shape.beginShape();
for(int i = 0; i < 3; i++){
shape.vertex(random(width), random(height));
}
shape.endShape();
}
void draw(){
background(0);
shape(shape, 0,0);
}
I cant figure this out. I have a sketch with little rotating rectangles on it. They rotate on every draw(). However the previous rectangle remains visible. I tried moving background() around but it either gets rid of all the rectangles apart from one or it doesn't clear the screen. I would like to be able to clear all the rectangles after each draw.
Here is the code:
//Create array of objects
ArrayList<Circle> circles = new ArrayList<Circle>();
ArrayList<Connector> centrePoint = new ArrayList<Connector>();
void setup(){
size(800, 800);
frameRate(1);
rectMode(CENTER);
background(204);
for(int i = 1; i < 50; i++){
float r = random(100,height-100);
float s = random(100,width-100);
float t = 20;
float u = 20;
println("Print ellipse r and s " + r,s);
circles.add(new Circle(r,s,t,u,color(14,255,255),random(360),random(5),random(10)));
}
//Draw out all the circles from the array
for(Circle circle : circles){
circle.draw();
float connectStartX = circle.x1;
float connectStartY = circle.y1;
println("PrintconnectStartX and Y " + connectStartX,connectStartY);
for(Circle circleEnd : circles){
float connectEndX = (circleEnd.x1);
float connectEndY = (circleEnd.y1);
centrePoint.add(new Connector(connectStartX,connectStartY,connectEndX,connectEndY));
}
}
//For each ellipse, add the centre point of the ellipse to array
for(Connector connectUp : centrePoint){
println(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
stroke(100, 0, 0);
if (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75){
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
//For the line weight it should equal the fat of the node it has come from ie
//for each circle, for each connectUp if the x==connectStartX and y==connectStartY then make the line strokeWeight==fat
for(Circle circle : circles){
for(Connector connectUp : centrePoint){
if (connectUp.connectStartX == circle.x1 & connectUp.connectStartY == circle.y1 & (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75)){
print(" true "+ circle.fat);
float authority = circle.fat;
strokeWeight(authority*1.5);
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
}
}
void update(){
}
void draw() {
for(Circle circle : circles){
circle.rot =+0.02;
circle.draw();
circle.rot = random(-6,6);
}
}
//Need to connect each ellipse to all the other ellipses
class Connector {
public float connectStartX;
public float connectStartY;
public float connectEndX;
public float connectEndY;
public color cB;
public float thickness;
public Connector(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
this.connectStartX = connectStartX;
this.connectStartY = connectStartY;
this.connectEndX = connectEndX;
this.connectEndY = connectEndY;
//this.cB = tempcB;
//this.thickness = thickness;
}
void draw(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
line(connectStartX, connectStartY, connectEndX, connectEndY);
// float fat = random(255);
//fill(fat);
stroke(100, 0, 0);
}
}
class Circle{
public float x1;
public float y1;
public float x2;
public float y2;
public color cB;
public float rot;
public float fat = random(5);
public float fert = 0.1;
public Circle(float x1, float y1, float x2, float y2, color tempcB, float rot, float fat, float fert){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.cB = tempcB;
//Tilt - I think this is done in radians
this.rot = rot;
//Authority -this is the fill
this.fat = fat;
//Fertility- this is a multiplier for the tilt
this.fert = fert;
}
void draw(){
pushMatrix();
translate(x1, y1);
fert = random(0.5);
rot = random(-6,6);
rotate(rot*fert);
translate(-x1, -y1);
//float fat = random(255);
fill(fat);
rect(x1, y1, 24, 36);
popMatrix();
}
}
You've got a few things going on in your code that I've seen in your previous posts. The way you're doing your drawing doesn't make a ton of sense, and I'll explain why.
Here's what most Processing sketches do:
Use the setup() function to setup any data structures you'll use in your program. Don't do any drawing from the setup() function.
Call background() every frame to clear out old frames.
Draw everything you want to be drawn in the frame in the draw() function.
Modify the data structures to change what you're drawing on the screen.
Your code is a bit too long for an MCVE, so here's a little example that handles the drawing in a more standard way:
ArrayList<PVector> circles = new ArrayList<PVector>();
void setup() {
size(500, 500);
ellipseMode(RADIUS);
//setup your data structures here
circles.add(new PVector(250, 250));
//don't do any drawing yet
}
void mousePressed() {
//modify the data structure whenever you want to change what's on the screen
circles.add(new PVector(mouseX, mouseY));
}
void keyPressed() {
//modify the data structure whenever you want to change what's on the screen
if (!circles.isEmpty()) {
circles.remove(0);
}
}
void draw() {
//call background every frame to clear out old frames
background(0);
//draw everything
for (PVector p : circles) {
ellipse(p.x, p.y, 20, 20);
}
}
Notice how this is different from what you're doing. Here's what you do:
You use the setup() function to setup your data structures, but then you draw the background and some of the objects to the screen.
You then don't call background() from draw(), so you're always stuck with whatever has already been drawn.
You then only draw a subset of what you want on the screen, so you can't redraw your whole scene.
You have to modify your code to no longer draw anything from setup(), to call the background() function every frame, and to draw everything you want on the screen every frame.
What you are doing is printing every single circle or line...ect. You need to have a timer that removes them every so often. If you do it too fast you get a strobe like look. So have a timer that removes the first rect from the array list every so often.
I am creating something using classes in order to get used to them and I am trying to get the size of the ellipse I have drawn to get smaller and larger on its own so that it makes it look more interactive however I don't know what code to implement.
I have shown the code I am using below;
void setup()
{
size(640, 480);
}
void draw()
{
background(255);
for (int i = height-50; i > 0; i-= 20)
{
fill(random(255), random(255), random(255));
ellipse(width/2, height/2, i, i);
}
}
Just to add to Kevin's great answer, here are couple of variations on the same idea (keeping track if the size is increasing or not).
The first approach involves using using a growth speed variable that simply flips sign when a limit is reached. If the size is too small (lower limit) or too big (upper limit), flipping the sign ( multiplying the growth speed by -1 ) will change growing to shrinking and vice-versa:
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 1.5;
void setup()
{
size(640, 480);
}
void draw()
{
//if the size is either too small, or too big, flip the size speed sign (if it was positive (growing) - make it negative (shrink) - and vice versa)
if(size < minSize || size > maxSize) {
sizeSpeed *= -1;
}
//increment the size with the size speed (be it positive or negative)
size += sizeSpeed;
background(255);
fill(random(255), random(255), random(255));
ellipse(width/2, height/2, size,size);
}
Note that the motion is fairly linear. Since you want to grow and shrink a circle over time, you could get a smoother animation using the sin() function. It takes an angle as an argument and based on the angle value it returns a value between -1.0 and 1.0. You can use the map() function to remap this range to the desired ellipse size:
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
void setup()
{
size(640, 480);
}
void draw()
{
size = map(sin(frameCount * sizeSpeed),-1.0,1.0,minSize,maxSize);
background(255);
fill(random(255), random(255), random(255));
ellipse(width/2, height/2, size,size);
}
Update In terms of classes, you can start encapsulating the variables used for drawing the ellipse into a class. The syntax isn't that complex:
Use the class keyword, then the name of the class (Uppercase by convention) and add the class members within {} - the classes scope
Create an instance of the class using the new keyword and use . notation to access the instance members
Here's a really basic example using the above:
Ellipse e = new Ellipse();
void setup()
{
size(640, 480);
}
void draw()
{
e.size = map(sin(frameCount * e.sizeSpeed),-1.0,1.0,e.minSize,e.maxSize);
background(255);
fill(random(255), random(255), random(255));
ellipse(width/2, height/2, e.size,e.size);
}
class Ellipse{
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
}
That's a nice and easy start, but the drawing part isn't encapsulated.
The same way you declare and use variables in a class, you can declare and use functions. Here's a basic example of simply moving the ellipse drawing functionality into a function:
Ellipse e = new Ellipse();
void setup()
{
size(640, 480);
}
void draw()
{
background(255);
e.render();
}
class Ellipse{
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
void render(){
size = map(sin(frameCount * sizeSpeed),-1.0,1.0,minSize,maxSize);
fill(random(255), random(255), random(255));
ellipse(width/2, height/2, size,size);
}
}
As you notice, it now takes 2 lines to initialize and render an ellipse from the main sketch. There are still things that can be improved. If a second ellipse is created, the x and y is the same so they'd obscure each other. Adding x,y properties to the class will mean each instance will have independent coordinates.
On a similar note, frameCount is global, which means, each ellipse uses the same
angle/size. We can make that independent too.
Ellipse e1 = new Ellipse(320,240);
Ellipse e2 = new Ellipse(20,20);
void setup()
{
size(640, 480);
}
void draw()
{
background(255);
e1.render();
e2.render();
}
class Ellipse{
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
//position
float x,y;
//internal frameCount replacement
int tick;
//constructor
Ellipse(float x,float y){
this.x = x;//copy x argument value to the instance (this) x property
this.y = y;//copy x argument value to the instance (this) x property
}
void render(){
tick++;
size = map(sin(tick * sizeSpeed),-1.0,1.0,minSize,maxSize);
fill(random(255), random(255), random(255));
ellipse(x,y, size,size);
}
}
Notice we also added a constructor. A constructor is a very special: it's like an entry point to a new instance. Whenever you create a new instance of a class, the constructor is called, which usually initialises data. The previous example didn't explicitly define a constructor, but Processing provides one with no arguments by default. To take the above concepts a step further, we create a constructor with x,y coordinates:
Ellipse e1 = new Ellipse(320,240);
Ellipse e2 = new Ellipse(20,20);
void setup()
{
size(640, 480);
}
void draw()
{
background(255);
e1.render();
e2.render();
}
class Ellipse{
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
//position
float x,y;
//internal frameCount replacement
int tick;
//constructor
Ellipse(float x,float y){
this.x = x;//copy x argument value to the instance (this) x property
this.y = y;//copy x argument value to the instance (this) x property
}
void render(){
tick++;
size = map(sin(tick * sizeSpeed),-1.0,1.0,minSize,maxSize);
fill(random(255), random(255), random(255));
ellipse(x,y, size,size);
}
}
This is a very quick overview. For more details, be sure to check out Daniel Shiffman's Objects tutorial.
With that in mind, you can use an ArrayList to create new ellipses at runtime and have some fun randomising ellipse parameters:
ArrayList<Ellipse> ellipses = new ArrayList<Ellipse>();
void setup()
{
size(640, 480);
ellipses.add(new Ellipse(width / 2, height / 2));
}
void draw()
{
background(255);
for(Ellipse e : ellipses){
e.render();
}
}
//add an ellipse every 5th frame if mouse is dragged
void mouseDragged(){
if(frameCount % 5 == 0) ellipses.add(new Ellipse(mouseX,mouseY));
}
//remove all ellipses if SPACE is pressed
void keyPressed(){
if(key == ' ') ellipses.clear();
}
//ellipse class
class Ellipse{
//current size - continuously updated
float size = 10;
//minimum size
float minSize = 10;
//maximum size
float maxSize = 240;
//change speed for size (how much will the size increase/decrease each frame)
float sizeSpeed = 0.025;
//position
float x,y;
//internal frameCount replacement
int tick;
int fill;
//constructor
Ellipse(float x,float y){
this.x = x;//copy x argument value to the instance (this) x property
this.y = y;//copy x argument value to the instance (this) x property
fill = color(random(32,192));
sizeSpeed = random(0.025,0.01);
maxSize = random(120,240);
}
void render(){
tick++;
size = map(sin(tick * sizeSpeed),-1.0,1.0,minSize,maxSize);
fill(fill);
ellipse(x,y, size,size);
}
}
You just need to store the width and height of your circle in a variable, use that variable in the draw() function, and then change it whenever you want to change the circle size.
Here is an example program that changes the circle size when you click the mouse:
float radius = 50;
void setup(){
size(500, 500);
ellipseMode(RADIUS);
}
void mouseClicked(){
radius = 250.0*mouseX/width;
}
void draw(){
background(0);
ellipse(width/2, height/2, radius, radius);
}
Here is an example program that grows and shrinks the circle automatically:
float radius = 0;
boolean grow = true;
void setup() {
size(500, 500);
ellipseMode(RADIUS);
}
void draw() {
if (grow) {
radius++;
if (radius == 250) {
grow = false;
}
} else {
radius--;
if (radius == 0) {
grow = true;
}
}
background(0);
ellipse(width/2, height/2, radius, radius);
}
But the idea is the same in both examples: just store your circle radius in a variable, change that variable to change the size, and use that variable to draw your circle.
When trying to make a rectangle come back and forth from the Frame, it leaves behind a black rectangle covering the background.
Here is my code:
float x = 0;
float y = 0;
float speed = 1;
void setup() {
size(500,500);
background(255);
}
void draw() {
move();
display();
}
void move() {
x = x + speed;
if (x > width) {
x = 0;
}
}
void display() {
rect(x,y,30,10);
}
Now I hate that since it is almost the same exact code that is in the examples.
Edit: I don't want the black color that it leaves behind. Now do some research..
To avoid a trailing of your triangle, you need to redraw your background before redrawing your triangle, otherwise it just draws another triangle over the top.
You should add;
background(255);
to your draw() method before move() and display().
Hope this helps.
In Processing void setup() is only Called once when the sketch is started. This is why you define the size of the canvas in it. ( as the canvas side does not change)
On the other hand void draw() is constantly running. So any active content that changes when the program is running needs to be in it.
float x = 0;
float y = 0;
float speed = 1;
void setup() {
size(500,500);
}
void draw() {
background(255);
move();
display();
}
void move() {
x = x + speed;
if (x > width) {
x = 0;
}
}
void display() {
rect(x,y,30,10);
}