我制作了经典的随机移动圆圈,如图所示:
这就是我想要实现的目标:
当鼠标点击时,圆圈排列如下:
我想我可以查看所有圈子的位置。如果它们的位置在1/2的高度之内,它们应该形成弧形。 如果它们大于1/2高度,则形成直线。
但诀窍是:如何形成这些形状?
我的意思是,我知道如何形成一个圆形,只需将它们的圆心移向一个点。 但LINE(如何移动他们的x位置)??? ARC甚至?真的不知道。
有谁知道吗? 非常感谢你。
答案 0 :(得分:1)
如果我理解正确的话,你会尝试计算两点之间的中间位置。这些点可以是一条线也可以是一条弧。
获得中间位置非常简单,有多种方法可以解决这个问题。想到的一个想法是使用lerp()函数(它进行线性插值)。 这是一个非常基本的例子:
//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));
}
在新草图中运行此操作以查看我的意思。这也可以手动完成,使用PVector类和插值公式:
point(percentage) = point(start) + ((point(end)-point(start)) * percentage)
因此:
//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 );
}
但lerp()
似乎更失败,可以很容易地适应您现有的设置。
对于弧线,事情只是有点复杂,因为你需要一点三角学:将笛卡尔坐标转换为极坐标。这听起来有点复杂,但是一旦你在精神上想象事物就不那么难了。想象一下,你正在看一个时钟。
你可以通过查看两根针的位置来准确判断它是什么时间(一小时一小时一分钟)。使用时钟位置或“坐标”,您可以轻松判断它是在中午/午夜。同样,您可以从“时钟坐标”转换回来,并说出中午/午夜的针位置。
查看时钟,您还可以想象笛卡尔系统重叠:0,0位于中心,笛卡儿中午/午夜将是(0,1),如果单位用于针长度<1 / strong>即可。 15:15你得到(1,0),(0,-1)为18:30,( - 1,0)为20:45,等等。 您将从一个2D坐标系(带有 x 和 y 的笛卡尔坐标系)转换为另一个(小时和分钟的“时钟”) 强>)
以非常类似的方式,您可以将笛卡尔坐标(使用 x 和 y )转换为极坐标(使用角度和半径)然后回来。例如,12:00表示(0,1),但也可表示为( 90度,针长)。
现在回到弧线:你可能知道起点和终点角度,你知道半径(距离圆心的距离),所以你得到了极坐标。您只需转换为笛卡尔坐标(x,y),可以使用以下公式完成:
x = cos(angle) * radius;
y = sin(angle) * radius;
此时值得注意的是,所有三角函数(sin / cos / tan / atan /等)都使用弧度。幸运的是,Processing已经提供了radians(),它简化了弧度转换的度数。
这是一个基本的草图来说明这个想法:
//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
}
我假设您应该能够检查物体的y坐标是否小于高度/ 2,并计算线定位的起点/终点位置或起始角/终点角,半径/距离和弧定位的偏移量< / p>
<强>更新强> 如果要从当前位置动画/插值到计算位置(无论是在线上还是在弧上),您需要处理它,因为上面的代码只处理计算目标。基于您的一些代码,这是我的意思的基本示例:
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);
}
}
按下鼠标时,圆圈将以线条位置为动画。
另一种做与上述类似的方法是使用Circle
:
这是一个代码示例:
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);
}
}
你可以在下面运行:
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>
一些快速说明:
void update(float x,float y,float speed)
也可能是void seek(float x,float y,float speed)
或void moveTo(float x,float y,float speed)
。HTH