【创意编程】《鸟巢》:向量、力、曲线与光

【创意编程】《鸟巢》:向量、力、曲线与光

在想这个实验要做什么的时候满脑子都是高中物理。思来想去除了摩擦力、能量和圆周运动之外也不记得什么特殊的东西了。突然想起之前做绳子小球以及杠杆小球的问题非常多,只是做起来没什么意思。写过一个牛顿摆,但是发现这也只是一个简单的能量传递,没有什么美感,于是就想到了双摆问题。
双摆曲线一直都是很优雅的曲线,也不知道为什么就是能产生很多好看的曲线来。
效果图:

在这里插入图片描述
一开始把两个摆球都放到同一边且都与竖直方向成90度角放下,不考虑阻力以及摆动过程中能量的损失,在重力的作用下,摆球将永远处于运动状态。如果我们记录下下方小球的途径的轨迹,在一段时间后我们将能够看到这样的图像:
在这里插入图片描述
由于拉住两个摆球的杠杆是不可伸缩的,轨迹永远不会超出离中心的锚点r1+r2之外。轨迹叠能够形成的图案下部分也会越来越接近圆周。
————————

原理

对于接近圆周或圆弧运动的物体来说,分析角速度、角加速度一般比分析线速度更有价值。我们首先回到高中,通过画图来分析一下双摆问题的受力和运动情况。
在这里插入图片描述
在这里插入图片描述
害,这里我也不看不大懂,不记得了。
总之最后可以求出一个角加速度只关于质量、角、速度以及摆长的公式了。
就是下面这个好东西。我们接下来就要针对这个公式进行运动还原。
在这里插入图片描述

————————

摆动实现

我们已经知道两个小球的运动过程,可以据此求出小球的加速度。因而也能够通过加速度来求得小球的速度。位置也就变得不难求了。
首先列出我们为了完成这一个双摆系统需要的参数:

float r1 = 200;
float r2 = 200;
float m1 = 40;
float m2 = 40;
float a1 = PI/2;
float a2 = PI/2;
float a1_v = 0;
float a2_v = 0;
float a1_a = 0;
float a2_a = 0;
float g = 1;

float px2 = 0;
float py2 = 0;
float cx, cy;

其中包括两条杆的长度、小球的质量以及各自的位置(夹角)、角速度、角加速度,以及计算中比较重要的重力加速度g。不过我们用代码模拟物理现象并不是真正的去仿真,而是在屏幕中恰切地表达自然现象,因此没有必要把g就设为9.8,按照我们想要的效果较好的参数来设置就好了。

现在根据上面推导出来的公式分别计算两个小球的加速度。

  float num1 = -g*(2*m1+m2)*sin(a1) - m2*g*sin(a1-2*a2);
  float num2 = -2*sin(a1-a2)*m2*(a2_v*a2_v*r2 + a1_v*a1_v*r1*cos(a1-a2));
  float num3 = r1*(2*m1+m2-m2*cos(2*a1-2*a2));
  a1_a = (num1+num2) / num3;
  
  num1 = 2*sin(a1-a2)*a1_v*a1_v*r1*(m1+m2);
  num2 = 2*sin(a1-a2)*g*(m1+m2)*cos(a1);
  num3 = 2*sin(a1-a2)*a2_v*a2_v*r2*m2*cos(a1-a2);
  float num4 = r2*(2*m1+m2-m2*cos(2*a1-2*a2));
  a2_a = (num1+num2+num3)/num4;

在draw()函数中对小球速度、加速度以及位置进行更新即可。

  float x1 = r1 * sin(a1);
  float y1 = r1 * cos(a1);
  float x2 = x1 + r2 * sin(a2);
  float y2 = y1 + r2 * cos(a2);  
  
  
  line(0, 0, x1, y1);
  fill(255);
  ellipse(x1, y1, m1, m1);
  line(x1, y1, x2, y2);
  ellipse(x2, y2, m2, m2);
  
  a1_v += a1_a;
  a2_v += a2_a;
  a1 += a1_v;
  a2 += a2_v;

————————

绘制轨迹

要想得到双摆运动全过程产生的曲线,我们就不能够在draw()函数中每一帧对背景进行清除,而问题在于,我们的双摆运动又要求我们每一帧都必须擦除上一帧绘制的图案,所以这不好实现。我们只有想办法像ps一样给画布叠加透明图层,把轨迹线画在另外一层不需要每一帧都进行清除的画布上。
而processing中的PGraphics类恰好就是完成这项工作的。它创建一层透明画布,像ps中的叠加图层一样使多层图案能够进行共同显示。

PGraphics canvas;
canvas = createGraphics(width, height);
canvas.beginDraw();
canvas.background(0);
canvas.endDraw();

draw()函数中:

  image(canvas, 0, 0);
  //background(0);
  stroke(255);
  strokeWeight(2);
  translate(cx, cy);

我们想要在小球经过的路上绘制小球的运动轨迹,我们有可能会想到花点,但是经过我的实验,画点的效果并不好,因为我们需要的是路径,而不是当速度快的时候就有可能会出现的散点。所以我们用直线。
我们将要记录下每一帧小球被更新之前的旧位置,绘制出一条从旧位置到新的位置的线,并在绘制完成后将旧位置更新为当期的位置。

  
  line(0, 0, x1, y1);
  fill(255);
  ellipse(x1, y1, m1, m1);
  line(x1, y1, x2, y2);
  ellipse(x2, y2, m2, m2);
  
  a1_v += a1_a;
  a2_v += a2_a;
  a1 += a1_v;
  a2 += a2_v;

  canvas.beginDraw();
  canvas.translate(cx,cy);
  float blue = map(py2, 0, r1 + r2, 0, 255);
  canvas.stroke(blue, blue, 255);
  canvas.strokeWeight(4);
  if (frameCount > 1){
    canvas.line(px2, py2, x2, y2);
  }
  canvas.endDraw();
  
  px2 = x2;
  py2 = y2;
——————————————

色彩渐变

像实验0中的色彩映射一样,这里也是把小球可能走到的最低点到小球能走到的最高点之间的距离映射到(0,255)。这样我们就可以通过观测点的位置为画出来的轨迹线赋予不同的颜色。

  float blue = map(py2, 0, r1 + r2, 0, 255);
  canvas.stroke(blue, blue, 255);

emmmmm好长时间没管它发现它现在这样了
在这里插入图片描述

完整代码

float r1 = 200;
float r2 = 200;
float m1 = 40;
float m2 = 40;
float a1 = PI/2;
float a2 = PI/2;
float a1_v = 0;
float a2_v = 0;
float a1_a = 0;
float a2_a = 0;
float g = 1;

float px2 = 0;
float py2 = 0;
float cx, cy;

PGraphics canvas;

void setup(){
  size(1600,900);
  cx = width/2;
  cy = 300;
  canvas = createGraphics(width, height);
  canvas.beginDraw();
  canvas.background(0);
  canvas.endDraw();
}

void draw(){
  float num1 = -g*(2*m1+m2)*sin(a1) - m2*g*sin(a1-2*a2);
  float num2 = -2*sin(a1-a2)*m2*(a2_v*a2_v*r2 + a1_v*a1_v*r1*cos(a1-a2));
  float num3 = r1*(2*m1+m2-m2*cos(2*a1-2*a2));
  a1_a = (num1+num2) / num3;
  
  num1 = 2*sin(a1-a2)*a1_v*a1_v*r1*(m1+m2);
  num2 = 2*sin(a1-a2)*g*(m1+m2)*cos(a1);
  num3 = 2*sin(a1-a2)*a2_v*a2_v*r2*m2*cos(a1-a2);
  float num4 = r2*(2*m1+m2-m2*cos(2*a1-2*a2));
  a2_a = (num1+num2+num3)/num4;
  
  image(canvas, 0, 0);
  //background(0);
  stroke(255);
  strokeWeight(2);
  translate(cx, cy);
  
  float x1 = r1 * sin(a1);
  float y1 = r1 * cos(a1);
  float x2 = x1 + r2 * sin(a2);
  float y2 = y1 + r2 * cos(a2);  
  
  
  line(0, 0, x1, y1);
  fill(255);
  ellipse(x1, y1, m1, m1);
  line(x1, y1, x2, y2);
  ellipse(x2, y2, m2, m2);
  
  a1_v += a1_a;
  a2_v += a2_a;
  a1 += a1_v;
  a2 += a2_v;

  canvas.beginDraw();
  canvas.translate(cx,cy);
  float blue = map(py2, 0, r1 + r2, 0, 255);
  canvas.stroke(blue, blue, 255);
  canvas.strokeWeight(4);
  if (frameCount > 1){
    canvas.line(px2, py2, x2, y2);
  }
  canvas.endDraw();
  
  px2 = x2;
  py2 = y2;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值