Clarifying my last question:
I would like to display, in Processing, many photos fading up and fading down over 15 seconds, with one second between their start times, so there are about 15 images on the screen at a time, at various levels of fading.
This example displays 15 objects, but they all start together:
PImage[] imgs = new PImage[42];
Pic[] pics = new Pic[15];
void setup() {
size(1000, 880);
for (int i = 0; i < pics.length; i++) {
pics[i] = new Pic(int(random(0, 29)), random(0, 800), random(0, height));
}
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
}
void draw() {
background(255);
for (int i = 0; i < pics.length; i++) {
pics[i].display();
}
}
class Pic {
float x;
float y;
int num;
int f = 0;
boolean change = true;
Pic(int tempNum, float tempX, float tempY) {
num = tempNum;
x = tempX;
y = tempY;
}
void display() {
imageMode(CENTER);
if (change)f++;
else f--;
if (f==0||f==555)change=!change;
tint(0, 153, 204, f);
image(imgs[num], x, y);
}
}
If you can fade an image, then you can also cross fade an image by subtracting the fade amount from the maximum fade value (e.g. inverting the fade value).
In your case you're using tint so it's a value from 0-255.
Let's say tint is your variable: 255 - tint would be the inverted value.
Here's a basic sketch you can run that illustrates this (using fill() instead of tint()):
void draw(){
float fade = map(sin(frameCount * 0.03), -1.0, 1.0, 0, 255);
background(0);
noStroke();
// use fade value
fill(192, 0, 192, fade);
ellipse(45, 50, 60, 60);
// invert the fade value (by subtracting it from the max value)
fill(0, 192, 192, 255 - fade);
ellipse(60, 50, 60, 60);
}
Continuing from the previous question and answer you can tweak the code to use an inverted tint value to crossfade. The catch is you'd need to store a reference to the previous image to apply the inverted tint to:
PImage[] imgs = new PImage[42];
ImagesFader fader;
void setup(){
size(255, 255);
frameRate(60);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// setup fader instance
// constructor args: PImage[] images, float transitionDurationSeconds, int frameRate
// use imgs as the images array, transition in and out within 1s per image at 60 frames per second
fader = new ImagesFader(imgs, 3.0, 60);
}
void draw(){
background(0);
fader.draw();
}
class ImagesFader{
int numFrames;
int numFramesHalf;
int frameIndex = 0;
PImage[] images;
int maxImages = 15;
int randomImageIndex;
float randomX, randomY;
PImage previousImage;
float previousX, previousY;
ImagesFader(PImage[] images, float transitionDurationSeconds, int frameRate){
numFrames = (int)(frameRate * transitionDurationSeconds);
numFramesHalf = numFrames / 2;
println(numFrames);
this.images = images;
// safety check: ensure maxImage index isn't larger than the total number of images
maxImages = min(maxImages, images.length - 1);
// pick random index
randomizeImage();
}
void draw(){
updateFrameAndImageIndices();
PImage randomImage = imgs[randomImageIndex];
// isolate drawing style (so only the image fades, not everything in the sketch)
pushStyle();
// if there is a previous image, cross fade it
float tintAlpha = tintFromFrameIndex();
if(previousImage != null){
// invert tint -> max(255) - value
tint(255, 255 - tintAlpha);
image(previousImage, previousX, previousY);
}
// render current random image (on top of the previous one, if any)
tint(255, tintAlpha);
image(randomImage, randomX, randomY);
popStyle();
}
float tintFromFrameIndex(){
int frameIndexToTint = abs(frameIndex - numFramesHalf);
return map(frameIndexToTint, 0, numFramesHalf, 255, 0);
}
void updateFrameAndImageIndices(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
// update previous image before generating another random image
previousImage = imgs[randomImageIndex];
previousY = randomX;
previousY = randomY;
frameIndex = 0;
// randomize index and position
randomizeImage();
println("fade transition complete, next image: ", randomImageIndex);
}
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
}
The above skeetch might not be 100% accurate (as I don't fully get the randomisation logic), but hopefully it illustrates the mechanism of crossfading.
Related
I'm trying to code a canvas full of shapes(houses) and animate them in processing.
Here's an example of shape:
void house(int x, int y) {
pushMatrix();
translate(x, y);
fill(0, 200, 0);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
By animation I mean moving them in random directions.
I would also like to add basic interaction: when hovering over a house it's colour would change.
At the moment I've managed to render a canvas full of houses:
void setup() {
size(500, 500);
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
house(i, j);
}
}
}
void house(int x, int y) {
pushMatrix();
translate(x, y);
fill(0, 200, 0);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
Without seeing source code: your attempted sketch it's very hard to tell.
They can be animated in many ways and it's unclear what you mean. For example, is that the position/rotation/scale of each square, is it the corners/vertices of each square, both ?
You might have a clear idea in your mind, but the current form of the question is ambiguous. We also don't know you're comfort level with various notions such as classes/objects/PVector/PShape/etc. If you were to 'story board' this animation what would it look like ? Breaking the problem down and explaining it in a way that anyone can understand might actually help you figure out a solution on your own as well.
Processing has plenty of examples. Here are a few I find relevant based on what my understanding is of your problem.
You can have a look at the Objects and Create Shapes examples:
File > Examples > Basics > Objects > Objects: Demonstrates grouping drawing/animation (easing, damping). You can tweak this example draw a single square and once you're happy with the look/motion you can animate multiple using an array or ArrayList
File > Examples > Topics > Create Shapes > PolygonPShapeOOP3: Great example using PShape to animate objects.
File > Examples > Topics > Create Shapes > WigglePShape: This example demonstrates how to access and modify the vertices of a PShape
For reference I'm simply copy/pasting the examples mentioned above here as well:
Objects
/**
* Objects
* by hbarragan.
*
* Move the cursor across the image to change the speed and positions
* of the geometry. The class MRect defines a group of lines.
*/
MRect r1, r2, r3, r4;
void setup()
{
size(640, 360);
fill(255, 204);
noStroke();
r1 = new MRect(1, 134.0, 0.532, 0.1*height, 10.0, 60.0);
r2 = new MRect(2, 44.0, 0.166, 0.3*height, 5.0, 50.0);
r3 = new MRect(2, 58.0, 0.332, 0.4*height, 10.0, 35.0);
r4 = new MRect(1, 120.0, 0.0498, 0.9*height, 15.0, 60.0);
}
void draw()
{
background(0);
r1.display();
r2.display();
r3.display();
r4.display();
r1.move(mouseX-(width/2), mouseY+(height*0.1), 30);
r2.move((mouseX+(width*0.05))%width, mouseY+(height*0.025), 20);
r3.move(mouseX/4, mouseY-(height*0.025), 40);
r4.move(mouseX-(width/2), (height-mouseY), 50);
}
class MRect
{
int w; // single bar width
float xpos; // rect xposition
float h; // rect height
float ypos ; // rect yposition
float d; // single bar distance
float t; // number of bars
MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
w = iw;
xpos = ixp;
h = ih;
ypos = iyp;
d = id;
t = it;
}
void move (float posX, float posY, float damping) {
float dif = ypos - posY;
if (abs(dif) > 1) {
ypos -= dif/damping;
}
dif = xpos - posX;
if (abs(dif) > 1) {
xpos -= dif/damping;
}
}
void display() {
for (int i=0; i<t; i++) {
rect(xpos+(i*(d+w)), ypos, w, height*h);
}
}
}
PolygonPShapeOOP3:
/**
* PolygonPShapeOOP.
*
* Wrapping a PShape inside a custom class
* and demonstrating how we can have a multiple objects each
* using the same PShape.
*/
// A list of objects
ArrayList<Polygon> polygons;
// Three possible shapes
PShape[] shapes = new PShape[3];
void setup() {
size(640, 360, P2D);
shapes[0] = createShape(ELLIPSE,0,0,100,100);
shapes[0].setFill(color(255, 127));
shapes[0].setStroke(false);
shapes[1] = createShape(RECT,0,0,100,100);
shapes[1].setFill(color(255, 127));
shapes[1].setStroke(false);
shapes[2] = createShape();
shapes[2].beginShape();
shapes[2].fill(0, 127);
shapes[2].noStroke();
shapes[2].vertex(0, -50);
shapes[2].vertex(14, -20);
shapes[2].vertex(47, -15);
shapes[2].vertex(23, 7);
shapes[2].vertex(29, 40);
shapes[2].vertex(0, 25);
shapes[2].vertex(-29, 40);
shapes[2].vertex(-23, 7);
shapes[2].vertex(-47, -15);
shapes[2].vertex(-14, -20);
shapes[2].endShape(CLOSE);
// Make an ArrayList
polygons = new ArrayList<Polygon>();
for (int i = 0; i < 25; i++) {
int selection = int(random(shapes.length)); // Pick a random index
Polygon p = new Polygon(shapes[selection]); // Use corresponding PShape to create Polygon
polygons.add(p);
}
}
void draw() {
background(102);
// Display and move them all
for (Polygon poly : polygons) {
poly.display();
poly.move();
}
}
// A class to describe a Polygon (with a PShape)
class Polygon {
// The PShape object
PShape s;
// The location where we will draw the shape
float x, y;
// Variable for simple motion
float speed;
Polygon(PShape s_) {
x = random(width);
y = random(-500, -100);
s = s_;
speed = random(2, 6);
}
// Simple motion
void move() {
y+=speed;
if (y > height+100) {
y = -100;
}
}
// Draw the object
void display() {
pushMatrix();
translate(x, y);
shape(s);
popMatrix();
}
}
WigglePShape:
/**
* WigglePShape.
*
* How to move the individual vertices of a PShape
*/
// A "Wiggler" object
Wiggler w;
void setup() {
size(640, 360, P2D);
w = new Wiggler();
}
void draw() {
background(255);
w.display();
w.wiggle();
}
// An object that wraps the PShape
class Wiggler {
// The PShape to be "wiggled"
PShape s;
// Its location
float x, y;
// For 2D Perlin noise
float yoff = 0;
// We are using an ArrayList to keep a duplicate copy
// of vertices original locations.
ArrayList<PVector> original;
Wiggler() {
x = width/2;
y = height/2;
// The "original" locations of the vertices make up a circle
original = new ArrayList<PVector>();
for (float a = 0; a < radians(370); a += 0.2) {
PVector v = PVector.fromAngle(a);
v.mult(100);
original.add(new PVector());
original.add(v);
}
// Now make the PShape with those vertices
s = createShape();
s.beginShape(TRIANGLE_STRIP);
s.fill(80, 139, 255);
s.noStroke();
for (PVector v : original) {
s.vertex(v.x, v.y);
}
s.endShape(CLOSE);
}
void wiggle() {
float xoff = 0;
// Apply an offset to each vertex
for (int i = 1; i < s.getVertexCount(); i++) {
// Calculate a new vertex location based on noise around "original" location
PVector pos = original.get(i);
float a = TWO_PI*noise(xoff,yoff);
PVector r = PVector.fromAngle(a);
r.mult(4);
r.add(pos);
// Set the location of each vertex to the new one
s.setVertex(i, r.x, r.y);
// increment perlin noise x value
xoff+= 0.5;
}
// Increment perlin noise y value
yoff += 0.02;
}
void display() {
pushMatrix();
translate(x, y);
shape(s);
popMatrix();
}
}
Update
Based on your comments here's an version of your sketch modified so the color of the hovered house changes:
// store house bounding box dimensions for mouse hover check
int houseWidth = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;
void setup() {
size(500, 500);
}
void draw(){
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
// check if the cursor is (roughly) over a house
// and render with a different color
if(overHouse(i, j)){
house(i, j, color(0, 0, 200));
}else{
house(i, j, color(0, 200, 0));
}
}
}
}
void house(int x, int y, color fillColor) {
pushMatrix();
translate(x, y);
fill(fillColor);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
// from Processing RollOver example
// https://processing.org/examples/rollover.html
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
// offset half the house width since the pivot is at the tip of the house
// the horizontal center
return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}
The code is commented, but here are the main takeaways:
the house() function has been changed so you can specify a color
the overRect() function has been copied from the Rollover example
the overHouse() function uses overRect(), but adds a horizontal offset to take into account the house is drawn from the middle top point (the house tip is the shape's pivot point)
Regarding animation, Processing has tons of examples:
https://processing.org/examples/sinewave.html
https://processing.org/examples/additivewave.html
https://processing.org/examples/noise1d.html
https://processing.org/examples/noisewave.html
https://processing.org/examples/arrayobjects.html
and well as the Motion / Simulate / Vectors sections:
Let's start take sine motion as an example.
The sin() function takes an angle (in radians by default) and returns a value between -1.0 and 1.0
Since you're already calculating positions for each house within a 2D grid, you can offset each position using sin() to animate it. The nice thing about it is cyclical: no matter what angle you provide you always get values between -1.0 and 1.0. This would save you the trouble of needing to store the current x, y positions of each house in arrays so you can increment them in a different directions.
Here's a modified version of the above sketch that uses sin() to animate:
// store house bounding box dimensions for mouse hover check
int houseWidth = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;
void setup() {
size(500, 500);
}
void draw(){
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
// how fast should each module move around a circle (angle increment)
// try changing i with j, adding i + j or trying other mathematical expressions
// also try changing 0.05 to other values
float phase = (i + frameCount) * 0.05;
// try changing amplitude to other values
float amplitude = 30.0;
// map the sin() result from it's range to a pixel range (-30px to 30px for example)
float xOffset = map(sin(phase), -1.0, 1.0, -amplitude, amplitude);
// offset each original grid horizontal position (i) by the mapped sin() result
float x = i + xOffset;
// check if the cursor is (roughly) over a house
// and render with a different color
if(overHouse(i, j)){
house(x, j, color(0, 0, 200));
}else{
house(x, j, color(0, 200, 0));
}
}
}
}
void house(float x, float y, color fillColor) {
pushMatrix();
translate(x, y);
fill(fillColor);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
// from Processing RollOver example
// https://processing.org/examples/rollover.html
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
// offset half the house width since the pivot is at the tip of the house
// the horizontal center
return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}
Read through the comments and try to tweak the code to get a better understanding of how it works and have fun coming up with different animations.
The main changes are:
modifying the house() function to use float x,y positions (instead of int): this is to avoid converting float to int when using sin(), map() and get smoother motions (instead of motion that "snaps" to whole pixels)
Mapped sine to positions which can be used to animate
Wrapping the 3 instructions that calculate the x offset into a reusable function would allow you do further experiment. What if you used a similar technique the y position of each house ? What about both x and y ?
Go through the code step by step. Try to understand it, change it, break it, fix it and make new sketches reusing code.
I'm new to p5js and I'm trying to plot incoming x y data by drawing circles which initially expand and then shrink becoming 'fixed' , but the speed at which the circles expand slows down over time - and I can't work out why. I have one array which stores the animated expanding / shrinking circle and another which stores the final state of the fixed circle.
let circles = [];
let circlesStatic = [];
function setup() {
createCanvas(640, 480);
frameRate(60);
smooth();
// e1 = new Ellipse(320,240);
// e2 = new Ellipse(20,20);
background(0);
}
function mouseClicked() {
let e = new Ellipse(mouseX, mouseY);
circles.push(e);
}
function draw() {
for (let i = 0; i < circles.length; i++) {
circles[i].render();
}
for (let i = 0; i < circlesStatic.length; i += 2) {
// noFill();
fill('rgba(50,50,50, 0.1)');
strokeWeight(1);
stroke('rgba(100,100,100, 0.25)');
circle(circlesStatic[i], circlesStatic[i + 1], 20);
}
}
class Ellipse {
// constructor
constructor(x, 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
// current size - continuously updated
this.size = 10;
// minimum size
this.minSize = 10;
// maximum size
this.maxSize = random(30, 35);
// change speed for size (how much will the size increase/decrease each frame)
this.sizeSpeed = 3;
// internal frameCount replacement
this.tick = 0;
// this.fill=(255,0,0);
}
render() {
// 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 (this.size < this.minSize || this.size > this.maxSize) {
this.sizeSpeed *= -1;
}
// increment the size with the size speed (be it positive or negative)
this.size += this.sizeSpeed;
console.log(this.sizeSpeed);
if (this.size < this.minSize) {
this.sizeSpeed = 0;
circlesStatic.push(this.x);
circlesStatic.push(this.y);
}
background(0);
// noStroke();
fill(200, 50, 0);
ellipse(this.x, this.y, this.size, this.size);
// this.tick++;
// this.size = map(sin(this.tick * this.sizeSpeed),-1.0,1.0,this.minSize,this.maxSize);
// fill(random(255), random(255), random(255));
// ellipse(this.x,this.y, this.size,this.size);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.1/lib/p5.js"></script>
The problem is that every time you render a circle it checks if it should become "static," and if it should it adds new values to circlesStatic. However, there is nothing to stop the animating circle to continue being rendered on subsequent frames. This results in massive numbers of entries being added to circlesStatic which means longer and longer render times. I've implemented one possible fix below. I also made it so that if you hold the shift key down you will see the previous behavior (watch the length of circlesStatic skyrocket after a few clicks). As soon as you release the shift key the fix will run and the number of entries in circlesStatic will plateau.
let circles = [];
let circlesStatic = [];
function setup() {
createCanvas(640, 480);
frameRate(60);
smooth();
// e1 = new Ellipse(320,240);
// e2 = new Ellipse(20,20);
textSize(16);
}
function mouseClicked() {
let e = new Ellipse(mouseX, mouseY);
circles.push(e);
}
function draw() {
background(0);
push();
noStroke();
fill('red')
text(`circles: ${circles.length}; circlesStatic: ${circlesStatic.length}`, 20, 20);
pop();
for (let i = 0; i < circles.length; i++) {
circles[i].render();
if (!keyIsDown(SHIFT)) {
if (circles[i].isStatic()) {
circles.splice(i, 1);
i--;
}
}
}
for (let i = 0; i < circlesStatic.length; i += 2) {
// noFill();
fill('rgba(50,50,50, 1)');
strokeWeight(1);
stroke('rgba(100,100,100, 1)');
circle(circlesStatic[i], circlesStatic[i + 1], 20);
}
}
class Ellipse {
// constructor
constructor(x, 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
// current size - continuously updated
this.size = 10;
// minimum size
this.minSize = 10;
// maximum size
this.maxSize = random(30, 35);
// change speed for size (how much will the size increase/decrease each frame)
this.sizeSpeed = 3;
// internal frameCount replacement
this.tick = 0;
// this.fill=(255,0,0);
}
isStatic() {
return this.sizeSpeed === 0;
}
render() {
// 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 (this.size < this.minSize || this.size > this.maxSize) {
this.sizeSpeed *= -1;
}
// increment the size with the size speed (be it positive or negative)
this.size += this.sizeSpeed;
console.log(this.sizeSpeed);
if (this.size < this.minSize) {
this.sizeSpeed = 0;
circlesStatic.push(this.x);
circlesStatic.push(this.y);
}
// background(0);
// noStroke();
fill(200, 50, 0);
ellipse(this.x, this.y, this.size, this.size);
// this.tick++;
// this.size = map(sin(this.tick * this.sizeSpeed),-1.0,1.0,this.minSize,this.maxSize);
// fill(random(255), random(255), random(255));
// ellipse(this.x,this.y, this.size,this.size);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.1/lib/p5.js"></script>
Lets say I have a pixelated image… and I want to redraw it using Processing.
At first there should be a random colored grid of pixels – and after some time the pixelated image would appear through this pixelated grid.
I thought I could manage this with a system like this: if a specific random colored pixel matches the color of the pixelated image – there should a new pixel be drawn.
For a better understanding take a look at this code:
PImage img;
float rows;
float cols;
float pixel;
color gridcolor;
color imagecolor;
color[][] grid = new color[500][500];
color[] colors = new color[4];
void setup() {
size(600, 600);
img = loadImage("bw.jpg");
cols = grid.length;
rows = grid[0].length;
pixel = width/cols;
noStroke();
colors[0] = color(0, 0, 0);
colors[1] = color(219, 219, 219);
colors[2] = color(218, 218, 218);
colors[3] = color(255, 255, 255);
}
void draw() {
background(255);
for (int x = 0; x < rows; x++) {
for (int y = 0; y < cols; y++) {
int selector = int(random(colors.length));
grid[x][y] = colors[selector];
gridcolor = grid[x][y];
fill(gridcolor);
rect(x*pixel, y*pixel, pixel, pixel);
imagecolor = img.get(int(x*pixel), int(y*pixel));
if (imagecolor == gridcolor) {
fill(imagecolor);
rect(x*pixel, y*pixel, pixel, pixel);
}
}
}
}
So I was able to draw pixels if the color matches – but because the colored noise is tied using random – they dissappear again…
How can I transfer the rectangled pixels out of the if statement?
How to make them stay? I tried connecting it to a boolean statement… but this is only tangled...
BTW, this is my PImage img:
Thank you for any kind of help! I am really stuck with this one...
Here is the solution that I found using PGraphics… With PGraphics everything gets drawn on a second layer – and then redrawn on the sketch window using the image function:
PGraphics pg;
PImage img;
float rows;
float cols;
float pixel;
color gridcolor;
color imagecolor;
color[][] grid = new color[100][100];
color[] colors = new color[9];
void setup() {
size(600, 600);
pg = createGraphics(600, 600);
img = loadImage("1.bmp");
cols = grid.length;
rows = grid[0].length;
pixel = width/cols;
noStroke();
colors[0] = color(0, 0, 0);
colors[1] = color(255, 255, 0);
colors[2] = color(66, 94, 171);
colors[3] = color(240, 85, 90);
colors[4] = color(161, 205, 12);
colors[5] = color(93, 76, 132);
colors[6] = color(202, 132, 184);
colors[7] = color(16, 208, 208);
colors[8] = color(255, 255, 255);
}
void draw() {
background(255);
for (int x = 0; x < rows; x++) {
for (int y = 0; y < cols; y++) {
int selector = int(random(colors.length));
grid[x][y] = colors[selector];
gridcolor = grid[x][y];
fill(gridcolor);
rect(x*pixel, y*pixel, pixel, pixel);
pg.beginDraw();
imagecolor = img.get(int(x*pixel), int(y*pixel));
if (imagecolor == gridcolor) {
pg.noStroke();
pg.fill(imagecolor);
pg.rect(x*pixel, y*pixel, pixel, pixel);
pg.endDraw();
}
}
}
image(pg, 0, 0);
}
I want to get the width and the height of a GROUP PShape, but I only get 0.0.
For example:
// Example code from "https://processing.org/reference/PShape_addChild_.html"
PShape house;
void setup() {
size(200, 200);
// Make a group PShape
house = createShape(GROUP);
// Make three shapes
PShape path = createShape();
path.beginShape();
path.vertex(-20, -20);
path.vertex(0, -40);
path.vertex(20, -20);
path.endShape();
PShape rectangle = createShape(RECT, -20, -20, 40, 40);
PShape circle = createShape(ELLIPSE, 0, 0, 20, 20);
// Add all three as children
house.addChild(path);
house.addChild(rectangle);
house.addChild(circle);
println(house.width, house.getWidth());
println(house.height, house.getHeight());
}
void draw() {
background(52);
translate(mouseX, mouseY);
shape(house);
}
In this code, println(house.width, house.getWidth()); and println(house.height, house.getHeight()); show 0.0 0.0
So, how can I get the width and the height of any PShape?
Edit
Following the advice from #Rabbid76, I have created a getBoundingBoxLimits() function:
float[][] getBoundingBoxLimits(PShape s){
float[][] coords = {{1000000.0, -1000000.0}, {1000000.0, -1000000.0}};
// coords represents {{min_x, max_x}, {min_y, max_y}}
float ii, jj;
for(int i=0; i<1000; i++){
for(int j=0; i<1000; j++){
ii = i*1.0;
jj = j*1.0;
if(s.contains(ii,jj)){ // contains() expects floats, not ints
if(ii < coords[0][0]) { coords[0][0] = ii; }
if(ii > coords[0][1]) { coords[0][1] = ii; }
if(jj < coords[1][0]) { coords[1][0] = jj; }
if(jj > coords[1][1]) { coords[1][1] = jj; }
}
}
}
return coords;
}
But it returns an IllegalArgumentException: The contains() method is only implemented for paths..
So, at first glance, it seems that I cannot determine if a (x, y) point is in any PShape other than a PATH PShape.
Anyway, I am expecting a more straightforward way of getting the width and the height of any PShape (as I am sure this information is stored inside any of these objects).
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.