#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# Transform a square into a circle

edited December 2013

Hello.

I'm trying to achieve a simple animation where a square gradually morphs into a square.

My initial attempt began with using the rect() function and increasing the border-radius property. However, unlike with CSS it seems you cannot seem to use border-radius to fully convert a square into a circle; there seems to be an upper limit to what the border-radius can be beyond which no value has any effect.

Is this right? And if so, are there any other techniques I might try?

Many thanks in advance for any help!

ben

Tagged:

• There was a recent topic about approximating a circle with Bézier curves. By doing this, then by playing with the parameters, you can do the morphing.

• You could also draw it by parts - 4 arcs and a few lines/rectangles.

• It looks like you're right about rect(). Here's a test:

``````void setup() {
size(400, 400);
rectMode(CENTER);
}

void draw() {
background(204);
float round = map(mouseX, 0, width, 0, 200);
rect(200, 200, 200, 200, round);
line(200, 0, 200, height);
}
``````

This should be an Issue at GitHub, it probably should go all the way to a circle as you expected.

• One way of doing it is to project from the centre of the square and circle in regular angular increments. The circular position is easily found [cx+r.cos(angle), cy+r.sin(angle)]. The square position just involves extending the radius to get one coordinate and fixing it to get the other depending on which of the four quadrants are being projected. For any given angle you can then just lerp() between the circle and square projections.

The best thing about doing this is that it gives me chance to use the word 'squarcle'.

Here's a working example:

```void setup()
{
size(400, 400);
}

void draw()
{
background(255);
fill(128);
noStroke();

drawSquarcle(map(mouseX,0,width,0,1));
}

// t should be between 0 (square) and 1 (circle)
void drawSquarcle(float t)
{
// Define position and size of shape.
float cx = width/2;
float cy = height/2;
float circleX, circleY, squareX, squareY;

float incAngle = radians(1);    // Resolution of shape.

beginShape();

for (float angle=0; angle<TWO_PI; angle +=incAngle)
{

{
}
else if ((angle > radians(45)) && (angle <= radians(135)))  // Bottom side
{
}
else if ((angle > radians(135)) && (angle <= radians(225)))  // Left side
{
}
else // Right side
{
}
vertex(lerp(squareX,circleX,t),lerp(squareY,circleY,t));
}
endShape();
}
```
• Darn, I am too late..................

and I didn't use the word drawSquarcle which is worse

``````// import java.*;
//
ArrayList<Ball> balls;
final int ballWidth = 12;
PVector [] rectsPoints = new PVector [ 360 ];
int time;
float speed = 1000.0;
//
// ---------------------------------------------------------------
//
void setup()
{
// init
size(800, 600);
// frameRate(3);
// Create an empty ArrayList
balls = new  ArrayList();

balls.clear();
int j=0;
//we define a rect and put it into an array of PVector
// ------
int magicNumber=90;
int magicNumber2=90*4;

int magicX=220;
int magicY=120;

for (int i = 0 ; i<magicNumber; i++) {
rectsPoints[j] = new PVector(magicX, i*4+magicY);
j++;
}

for (int i = 0 ; i<magicNumber; i++) {
rectsPoints[j] = new PVector(magicX+magicNumber2, i*4+magicY);
j++;
}
for (int i = 0 ; i<magicNumber; i++) {
rectsPoints[j] = new PVector(i*4+magicX, magicY+magicNumber2);
j++;
}
// ------
for (int i = 0 ; i<magicNumber; i++) {
rectsPoints[j] = new PVector(i*4+magicX, magicY);
j++;
}

randomize  (rectsPoints);

//  Collections.shuffle(Arrays.asList(rectsPoints));

// ------
// we define a circle
for (int i = 0 ; i<360; i++) {
float r = 200;
float x = r * cos ( radians(i-90) ) + width / 2 ;
float y = r * sin ( radians(i-90) ) + height / 2 ;
rectsPoints[i].x, rectsPoints[i].y,
6, color (255, 2, 2) ) );
//point(x, y);
//point(rectsPoints[i].x, rectsPoints[i].y);
}
rectsPoints=null;
//  exit();
} // func
//
//
void draw()
{
background(255);
//  noLoop();
Ball ball;

for (int i=0; i < balls.size(); i++) {
ball = balls.get(i);
float x = lerp(ball.x, ball.targetx, time/speed);
float y = lerp(ball.y, ball.targety, time/speed);
fill(ball.myColor);
//stroke(0,life);
ellipse(x, y, ball.w, ball.w);
// point(x, y);
// ball.move();
// ball.display();
}
//  for (int i=0; i < balls.size(); i++) {
//    ball = balls.get(i);
//    if (ball.finished()) {
//      balls.remove(i);
//    }
//  }

if (time<speed)
time++;
} // func
//

// =====================================================================

void keyPressed() {
time =0;
}

//void mouseReleased() {
//  // A new ball object is added to the ArrayList (by default to the end)
//  color (random(0, 255), random(0, 255), random(0, 255))));
//}

// =====================================================================

//method for randomizing
void randomize (PVector[] arrMy) {

for (int k=0; k < arrMy.length-1; k++) {
// Goal: swap the value at pos k with a rnd value at pos x.
// Make rnd index x
int x = (int)random(0, arrMy.length);
// swap pos k and x
arrMy = swapValues(arrMy, k, x);
} // for

// display(a, 39);
// return arrMy;
} // func

PVector[] swapValues (PVector[] myArray, int a, int b) {
// Goal: swap the value at pos a with a value at pos b in
// Array myArray, return the changed array.
// save current value from pos/index a into temp
PVector temp=myArray[a].get() ;
// overwrite value at current pos a with value at index b
println (a+"   "+b);
myArray[a].set(myArray[b].get());
// finish swapping by giving the old value at pos a to the
// pos b.
myArray[b]=temp.get();
// return the changed array
return myArray;
} // func
//

// =====================================================================
// Simple bouncing ball class

class Ball {
float x;
float y;
float targetx;
float targety;
color myColor;
float speed;
float gravity;
float w;
float life = 255;

Ball(float tempX, float tempY,
float tempX2, float tempY2,
float tempW, color tempmyColor1 ) {
x = tempX;
y = tempY;
w = tempW;

targetx=tempX2;
targety=tempY2;

myColor=tempmyColor1;

speed = 0;
gravity = 0.1;
}

void move() {
speed = speed + gravity;
// Add speed to y location
y = y + speed;
// If ball reaches the bottom
// Reverse speed
if (y >= height-19) {
// Dampening
speed = speed * -0.8;
y = height-19;
}
}

boolean finished() {
life--;
if (life < 0) {
return true;
}
else {
return false;
}
}

void display() {
// Display the ball
//fill(0, life);
fill(myColor);
//stroke(0,life);
ellipse(x, y, w, w);
}
} // class

// =====================================================================
``````
• @jwo

besides:

`````` Collections.shuffle(Arrays.asList(myArray));
``````

how can I use this? He can't find Collections.

What do I have to import? java util?

And how can I get my result back into myArray?

Or is it there automatically?

Thanks.

• First approach, based from code I link to in http://forum.processing.org/two/discussion/1797/how-to-use-bezier-curve-to-approximate-one-quarter-of-a-circle

``````// Ratio for perfect circle
float pcr = 0.5522847498;
float f = 1;

void setup()
{
size(550, 550);
smooth();
}

void draw()
{
background(222);

fill(0x8800EE00);
stroke(#2288FF);
drawCircle(width / 2, height / 2, 250);
if (f < 1.9)
{
f *= 1.01;
}
}

void drawCircle(float x, float y, float r)
{
float l = (1 - pcr * f) * r;
float d = 2 * r;
// Assume here default CENTER mode
x -= r; y -= r;

beginShape();
vertex(x, y + r); // Left
bezierVertex(x, y + l,
x + l, y,
x + r, y); // Top
bezierVertex(x + d - l, y,
x + d, y + l,
x + d, y + r); // Right
bezierVertex(x + d, y + d - l,
x + d - l, y + d,
x + r, y + d); // Bottom
bezierVertex(x + l, y + d,
x, y + d - l,
x, y + r); // Back to left
endShape();
}
``````
• yep util:

``````// to be specific..
import java.util.Collections;
import java.util.Arrays;

// won't work with primitives types, so Integer
Integer[] arr = new Integer;

for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}

Collections.shuffle(Arrays.asList(arr));

println(arr);
``````
• @ _vk: thanks a lot!

That should make my code much shorter.....

• Processing's newest structure IntList got a shuffle() method too! ;))
No need to import anything and no wrapper types like Integer either! :P

• cool viz, Chrisir! got to digest it!

• @ GoToLoop

my array is of type PVector, not int

@ oat

Thank you!

I didn't really use the class, so some re-writing needs to be done here.

When you get rid of the random and adjust circle angle to the rect, we should get straight lines from circle to rect.

Chrisir

• my array is of type PVector, not `int`.

I was referring to @_vk's example: ;;)

``````// won't work with primitives types, so Integer
Integer[] arr = new Integer;
``````
• clearer version...

the values that go into the ArrayList balls are the start and stop of their flight

(not the position which gets calculated per lerp in display() )

``````//
import java.util.Collections;
import java.util.Arrays;

//
ArrayList<Ball> balls;
int time;
float speed = 1000.0;

//
// ---------------------------------------------------------------
//
void setup()
{
// init
size(800, 600);
// frameRate(3);
// Create an empty ArrayList
balls = new  ArrayList();

// balls.clear();
int j=0;
//we define a rect and put it into an array of PVector
// ------
int magicNumber=90;
int magicNumber2=90*4;

int magicX=220;
int magicY=120;
PVector [] rectsPoints = new PVector [ 362 ];

for (int i = 1; i<magicNumber+1; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX, i*4+magicY);
j++;
}
for (int i = 0 ; i<magicNumber; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX+magicNumber2, (i+0)*4+magicY);
j++;
}
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector((i+0)*4+magicX, magicY+magicNumber2);
j++;
}
// ------
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector(i*4+magicX, magicY);
j++;
}

println (rectsPoints);
// randomize rectsPoints
// Collections.shuffle(Arrays.asList(rectsPoints));
println (rectsPoints);

// ------
// we define a circle
for (int i = 0 ; i<362; i++) {
float r = 200;
float x = r * cos ( radians(i-0) ) + width / 2 ;
float y = r * sin ( radians(i-0) ) + height / 2 ;
// and put both together into our ArrayList balls
rectsPoints[i].x, rectsPoints[i].y,
3,
color (255, 2, 2) ) );
}
rectsPoints=null;
} // func
//
void draw()
{
background(255);
Ball ball;
for (int i=0; i < balls.size(); i++) {
ball = balls.get(i);
ball.display();
}
if (time<speed)
time++;
} // func
//

// =====================================================================

void keyPressed() {
time = 0;
}

// =====================================================================
// Simple bouncing ball class

class Ball {
float startx;
float starty;
float targetx;
float targety;
color myColor;
// float speed;
//float gravity;
float w;
//float life = 255;

Ball(float tempstartX, float tempstartY,
float tempX2, float tempY2,
float tempW, color tempmyColor1 ) {
startx = tempstartX;
starty = tempstartY;
w = tempW;

targetx=tempX2;
targety=tempY2;

myColor=tempmyColor1;
}

void display() {
fill(myColor);
//noStroke();
float x1 = lerp(startx, targetx, time/speed);
float y1 = lerp(starty, targety, time/speed);
ellipse(x1, y1, w, w);
}
} // class

// =====================================================================
``````
• and 3D..............

``````//
import java.util.Collections;
import java.util.Arrays;

//
ArrayList<Ball> balls;
int time;
float speed = 1000.0;

// cam stuff
float camX=0, camY=445.0, camZ= 0;  // its position
float camAngle=0;   // rotation
float camr = 400;   // radius

//
// ---------------------------------------------------------------
//
void setup()
{
// init
size(800, 600, OPENGL);
// frameRate(3);
// Create an empty ArrayList
balls = new  ArrayList();

// balls.clear();
int j=0;
float j2 = -4;
//we define a rect and put it into an array of PVector
// ------
int magicNumber=90;
int magicNumber2=90*4;

int magicX=220;
int magicY=120;
PVector [] rectsPoints = new PVector [ 362 ];

for (int i = 1; i<magicNumber+1; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX, i*4+magicY, j2);
j++;
}
for (int i = 0 ; i<magicNumber; i++) {  // x const, y moves
rectsPoints[j] = new PVector(magicX+magicNumber2, (i+0)*4+magicY, j2);
j++;
}
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector((i+0)*4+magicX, magicY+magicNumber2, j2);
j++;
}
// ------
for (int i = 0 ; i<magicNumber+1; i++) {
rectsPoints[j] = new PVector(i*4+magicX, magicY, j2);
j++;
}

println (rectsPoints);
// randomize rectsPoints
Collections.shuffle(Arrays.asList(rectsPoints));
println (rectsPoints);

// ------
// we define a circle
for (int i = 0 ; i<362; i++) {
float r = 200;
float x = r * cos ( radians(i-0) ) + width / 2 ;
float y = r * sin ( radians(i-0) ) + height / 2 ;
float z = 8;
// and put both together into our ArrayList balls
balls.add (new Ball(  x, y, z,
rectsPoints[i].x, rectsPoints[i].y, rectsPoints[i].z,
8,
color (255, 2, 2) ) );
}
rectsPoints=null;
sphereDetail(11);
} // func
//
void draw()
{
background(255);
camX= camr * cos ( radians(camAngle) ) +330 ;
camZ= camr * sin ( radians(camAngle) ) +0 ;
camera(camX, camY, camZ,
330.0, 331.0, 0.0,
0.0, 1.0, 0.0);
lights();
Ball ball;
for (int i=0; i < balls.size(); i++) {
ball = balls.get(i);
ball.display();
}
if (time<speed)
time++;
// camZ--;
camAngle+=.6;
if (camAngle>360)
camAngle=0;

fill(2, 2, 222);
//sphere(222);
} // func
//

// =====================================================================

void keyPressed() {
time = 0;
}

// =====================================================================
// Simple bouncing ball class

class Ball {
float startx;
float starty;
float startz;

float targetx;
float targety;
float targetz;

color myColor;

float w;

float controlPointX1=random(-width, width);
float controlPointY1=random(-width, width);
float controlPointZ1=random(-width, width);

float controlPointX2=random(-width, width);
float controlPointY2=random(-width, width);
float controlPointZ2=random(-width, width);

Ball(float tempstartX, float tempstartY, float tempstartZ,
float tempX2, float tempY2, float tempZ2,
float tempW, color tempmyColor1 ) {
startx = tempstartX;
starty = tempstartY;
startz = tempstartZ;
w = tempW;

targetx=tempX2;
targety=tempY2;
targetz=tempZ2;

myColor=tempmyColor1;
}

void display() {
fill(myColor);
noStroke();
//float x1 = lerp(startx, targetx, time/speed);
//float y1 = lerp(starty, targety, time/speed);
// curve(startx, controlPointX1, controlPointX2, targetx);
float x1 = curvePoint(controlPointX1, startx, targetx, controlPointX2, time/speed);
float y1 = curvePoint(controlPointY1, starty, targety, controlPointY2, time/speed);
float z1 = curvePoint(controlPointZ1, startz, targetz, controlPointZ2, time/speed); // lerp(startz, targetz, time/speed);
//
//ellipse(x1, y1, w, w);
pushMatrix();
translate(x1, y1, z1);
sphere (w);
popMatrix();
}
} // class

// =====================================================================
``````
• thanks for sharing, Sir Chris! will let you know if I'm having indigestion issues ... :P

• when you in the 2D version more cleverly than I place the balls in the circle next to those in the rect it looks better (so one ball in the circle can fly to the position in the rect that is closest to him).