i made classic random moving circles as in the picture:
And here's what i want to realize:
when mouseClicked , the circles line up like:
i think i can check the position of all the circles. if theirs y position are within 1/2height, they should form the arc. if are larger then 1/2height, they form the line.
But the trick is : how to form those shape?
i mean, i know how to form a round , just move their centre of circle towards a point. but LINE(how to move theirs x position)??? even ARC ??? really have no idea.
Does anyone know? Thank you very much.
If I understand this correctly, you're trying to compute intermediary positions between two points. Those points can be be either on a line or on an arc.
Getting the intermediary positions on a line is fairly simple and there multiple ways to tackle this. One idea that comes to mind is to use the lerp() function (which does linear interpolation). Here's a very basic example:
//draw stuff
smooth();strokeWeight(5);
//line stuff
PVector start = new PVector(10,10);
PVector end = new PVector(90,90);
int numPts = 5;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point that should be on the line
float t = increment * i ; //'traversal' on the line (0.0 is at start 1.0 is at end)
point(lerp(start.x,end.x,t),//interpolate and draw
lerp(start.y,end.y,t));
}
Run this in a new sketch to see what I mean. This can also be done manually, making use of the PVector class and the interpolation formula:
point(percentage) = point(start) + ((point(end)-point(start)) * percentage)
hence:
//draw stuff
smooth();strokeWeight(5);
//line stuff
PVector start = new PVector(10,10);
PVector end = new PVector(90,90);
int numPts = 5;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point that should be on the line
float t = increment * i ; //'traversal' on the line (0.0 is at start 1.0 is at end)
PVector current = PVector.add(start,PVector.mult(PVector.sub(end,start),t));
point( current.x, current.y );
}
But lerp()
seems more lose and could easily fit into your existing setup.
For the arc, things are just a tad complicated as you'll need a bit of trigonometry: converting cartesian to polar coordinates. It sounds a bit more complicated that it should but it's not that hard once you visualize things mentally. Imagine you're looking at a clock.
You can tell precisely what time it is by looking at the positions of the two needles (one for hour and one for minute). Using the clock positions, or "coordinates" you can easily tell when it's noon/midnight. Similarly you can convert back from 'clock coordinates' and say what the needle positions for noon/midnight.
Looking at the clock you can also imagine the cartesian system overlayed: 0,0 is at the centre and noon/midnight in cartesian would be (0,1) if 1 would the unit used for a needle length. For 15:15 you'd get (1,0), (0,-1) for 18:30, (-1,0) for 20:45, etc. You're converting from one 2D coordinate system (cartesian with x and y) to another ("clock" with hour and minutes)
In a very similar way you can convert from cartesian (uses x and y) to polar( uses angle and radius) and back. For example, 12:00 would mean (0,1) but can also be expressed as (90 degrees, needle length).
Now back to the arc: you probably know the start and and end end angle and you know the radius (distance from centre of circle) so you've got the polar coordinates. You simply need to convert to cartesian(x,y) coordinates, which can be done using this formula:
x = cos(angle) * radius;
y = sin(angle) * radius;
At this point it's worth noting that all trigonometric function(sin/cos/tan/atan/etc.) use radians. Luckily Processing already provides a radians() which simplifies degrees to radians conversion.
Here's a basic sketch to illustrate the idea:
//draw stuff
smooth();strokeWeight(5);
//arc stuff
float distance = 35;//100 pixels away from the centre
float startAngle = radians(30);
float endAngle = radians(120);
int numPts = 10;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point on the arc
float intermediaryAngle = lerp(startAngle,endAngle,increment*i);
float x = cos(intermediaryAngle) * distance;
float y = sin(intermediaryAngle) * distance;
point(x+50,y+50);//50 is offset to draw from the centre of the sketch
}
I assume you should able to check if the y coordinate of your objects is smaller than height/2 and compute either start/end positions for line positioning or start angle/end angle, radius/distance and offset for the arc positioning
UPDATE If you want to animate/interpolate from the current position to the computed position (be it on the line or on the arc), you need to handle that as the code above handles only calculating the destinations. Here's a basic example of what I mean, based on some of your code:
int maxCircle = 10;
Circle[] circles = new Circle[maxCircle];
float increment = (1.0/maxCircle);
float traversal = 0.0;
void setup(){
size(400,400);
smooth();strokeWeight(5);
for(int i=0;i<maxCircle;i++){
circles[i] = new Circle(random(width),random(height),random(2,20));
}
}
void draw(){
background(255);
for(int i=0;i<maxCircle;i++){
if(!mousePressed) circles[i].update(width,height);//default
else{//if some event happens
//compute destination
float x,y;
float offx = width/2;
float offy = height/2;
//move to line
float startX = 0;
float endX = width;
float t = increment * i;
x = lerp(startX,endX,t);
y = offy-10;
//interpolate/move to computed position
if(traversal < 1.0){//if circle hasn't reached destination yet
traversal += 0.0001;//move closer to the destination
circles[i].x = lerp(circles[i].x,x,traversal);
circles[i].y = lerp(circles[i].y,y,traversal);
}
}
circles[i].display();
}
}
void mouseReleased(){
traversal = 0;
}
class Circle{
float x,y,vx,vy,r,speed;
Circle(float tempx, float tempy, float tempr){
x=tempx;
y=tempy;
vx=random(-1,1);
vy=random(-1,1);
r=tempr;
}
void update(int w,int h){
x+=vx;
y+=vy;
if(x<r || x>w-r){
vx*=-1;};
if(y<r || y>h-r){
vy*=-1;};
}
void display(){
fill(0,50);
noStroke();
ellipse(x,y,r,r);
}
}
When the mouse is pressed, the circles will animate towards the line positions.
Another way to do something similar to the above is to use velocities of Circle
:
Here's a code example:
int maxCircle = 10;
Circle[] circles = new Circle[maxCircle];
void setup() {
size(400, 400);
smooth();
strokeWeight(5);
for (int i=0;i<maxCircle;i++) {
circles[i] = new Circle(random(width), random(height), random(2, 20));
}
}
void draw() {
background(255);
for (int i=0;i<maxCircle;i++) {
if (!mousePressed) circles[i].update(width, height);//default
else {//if some event happens
//compute destination
float x = map(i,0,maxCircle,0,width);
float y = (height * .5) - 10;
//update to destination
circles[i].update(x,y,2);
}
circles[i].display();
}
}
class Circle {
float x, y, vx, vy, r, speed;
Circle(float tempx, float tempy, float tempr) {
x=tempx;
y=tempy;
vx=random(-1, 1);
vy=random(-1, 1);
r=tempr;
}
void update(int w, int h) {
x+=vx;
y+=vy;
if (x<r || x>w-r) {
vx*=-1;
};
if (y<r || y>h-r) {
vy*=-1;
};
}
void update(float x,float y,float speed){
//compute direction vector
float dx = x - this.x;
float dy = y - this.y;
//find the current 'speed': vector's length or magnitude
float len = sqrt(dx*dx + dy*dy);//PVector's mag() does this for you
//normalize the vector
dx /= len;
dy /= len;
//scale the vector
dx *= speed;
dy *= speed;
//interpolate/move to computed position
if(dist(this.x,this.y,x,y) > 2){//if circle hasn't reached destination yet (isn't close enough)
this.x += dx;
this.y += dy;
}
}
void display() {
fill(0, 50);
noStroke();
ellipse(x, y, r, r);
}
}
Which you can run bellow:
var maxCircle = 10;
var circles = new Array(maxCircle);
function setup() {
createCanvas(400, 400);
smooth();
fill(0,50);
noStroke();
for (var i=0;i<maxCircle;i++) {
circles[i] = new Circle(random(width), random(height), random(2, 20));
}
}
function draw() {
background(255);
for (var i=0;i<maxCircle;i++) {
if (!isMousePressed) circles[i].updateBounds(width, height);//default
else {//if some event happens
//compute destination
var x = map(i,0,maxCircle,0,width);
var y = (height * .5) - 10;
//update to destination
circles[i].update(x,y,2);
}
circles[i].display();
}
}
function Circle(tempx, tempy, tempr){
this.x=tempx;
this.y=tempy;
this.vx=random(-1, 1);
this.vy=random(-1, 1);
this.r=tempr;
this.updateBounds = function(w,h) {
this.x+=this.vx;
this.y+=this.vy;
if(this.x < this.r || this.x>this.w-this.r) {
this.vx*=-1;
}
if (this.y<this.r || this.y>this.h-this.r) {
this.vy*=-1;
}
}
this.update = function(ax,ay,speed){
//compute direction vector
var dx = ax - this.x;
var dy = ay - this.y;
//find the current 'speed': vector's length or magnitude
var len = sqrt(dx*dx + dy*dy);//PVector's mag() does this for you
//normalize the vector
dx /= len;
dy /= len;
//scale the vector
dx *= speed;
dy *= speed;
//varerpolate/move to computed position
if(dist(this.x,this.y,ax,ay) > 2){//if circle hasn't reached destination yet (isn't close enough)
this.x += dx;
this.y += dy;
}
}
this.display = function() {
ellipse(this.x, this.y, this.r, this.r);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>
A few quick notes:
void update(float x,float y,float speed)
might as well be void seek(float x,float y,float speed)
or void moveTo(float x,float y,float speed)
.HTH