【问题标题】:Nesting issue in Processing处理中的嵌套问题
【发布时间】:2014-03-01 16:09:44
【问题描述】:

我正在制作的动画有问题。主要思想是 6 个等边三角形围绕一个中心点旋转,同时也围绕它们自己旋转。

当我运行代码时,三角形的每个实例都使用前一个实例作为参考点,而不是中心。这会产生一种很酷的螺旋效果,但这不是我想要的。

代码如下:

//Declare
tri myTri1;
tri myTri2;
tri myTri3;
tri myTri4;
tri myTri5;
tri myTri6;

void setup() {
  size(600, 600);
  smooth();

  //Initialise
  myTri1 = new tri();
  myTri2 = new tri();
  myTri3 = new tri();
  myTri4 = new tri();
  myTri5 = new tri();
  myTri6 = new tri();
}

void draw() {
  background(0);

  //Call Functions
  myTri1.run();
  translate(width/2,height/2);
  rotate(PI/3);
  translate(-width/2,-height/2);
  myTri2.run();
  translate(width/2,height/2);
  rotate(PI/3);
  translate(-width/2,-height/2);
  myTri3.run();
  translate(width/2,height/2);
  rotate(PI/3);
  translate(-width/2,-height/2);
  myTri4.run();
  translate(width/2,height/2);
  rotate(PI/3);
  translate(-width/2,-height/2);
  myTri5.run();
  translate(width/2,height/2);
  rotate(PI/3);
  translate(-width/2,-height/2);
  myTri6.run();
}

第二个标签:

class tri {
  //Variables
  float ax, ay, bx, by, cx, cy; //triangle point coordinates
  float theta; //triangle angle
  float pi = PI; //pi reference

  //Construct
  tri() {
    theta = PI/6;
    ax = 0;
    ay = 0;
    bx = -50*(sin(theta));
    by = +50*(cos(theta));
    cx = +50*(sin(theta));
    cy = +50*(cos(theta));
  }

  //Functions
  void run() {

    translate(width/2, height/2);
    revolve(); //revolve triangle about centre
    spin(); //spin triangle about itself
    pulse(); //move triangle in/out
    display(); //show triangle
    translate(-width/2, -height/2);
  }

  void spin() {
    translate(0, by/2); //sets rotation axis to centre of triangle
    rotate(millis()*-0.0005*pi);
    translate(0, -by/2); //resets axis to centre of window
  }

  void revolve() {
    translate(-2*by, 0);
    ax = ax + 2*sin(millis()*0.005);
    ay = ay + 4*cos(millis()*0.005);
    bx = bx + 2*sin(millis()*0.005);
    by = by + 4*cos(millis()*0.005);
    cx = cx + 2*sin(millis()*0.005);
    cy = cy + 4*cos(millis()*0.005);
    translate(2*by, 0);
  }

  void pulse() {
    ay = ay + 5*sin(millis()*0.005);
    by = by + 5*sin(millis()*0.005);
    cy = cy + 5*sin(millis()*0.005);
  }

  void display() {
    fill(255);
    strokeWeight(0.8);
    triangle(ax, ay, bx, by, cx, cy);
  }
}

如果有人能指出我哪里出了问题,那就太棒了,如果你能建议任何优化重新形成六边形(而不是混乱的翻译),我会非常高兴。

【问题讨论】:

  • 翻译应该做什么?
  • Translate 将原点 (0,0) 重置为您指定的坐标。所有命令的描述(不同级别的详细信息)在这里processing.org/reference
  • 尝试在你的原点上渲染一个小点,因为我不认为翻译回你认为的地方。虽然我无法运行它,但无法检查自己:)
  • 我在重置原点的所有点上都试过了,点到了我期望它去的地方。我刚刚意识到我在 revolve 函数的中途重新定义了“by”,我会对其进行调整,看看它是否有帮助。
  • @Franchesca 非常好的建议使用调试图形(渲染原点)。另外,如果你想在不安装的情况下尝试处理代码,你可以试试sketchpad

标签: java processing hierarchy nested


【解决方案1】:

Franchesca 的建议很好。您应该知道原点在哪里以及您应用的坐标空间变换如何影响它,至少在您感觉到它并完全控制之前。

我也热烈推荐这个Processing tutorial on 2d transformations

现在,回到你的代码 :)

您可以改进的第一件事是习惯 for 循环和数组。 一开始它们可能看起来很吓人,但一旦你掌握了它们的窍门,它们就很容易了。 只要您能想到需要重复的情况,您都可以使用 for 循环让您的生活更轻松。 在您的情况下,可以使用循环和数组来生成三角形并存储它们。

For 循环的语法如下:

for keyword (3 elements: a start point,an end point(condition) and an increment,(separated by the ; character)

假设您想一次一步从 a(0) 移动到 b(10):

for(int currentPos = 0 ; currentPos < 10; currentPos++){
  println("step: " + currentPos);
}

如果你会走路,你也可以跳过:)

for(int currentPos = 0 ; currentPos < 10; currentPos+=2){
  println("step: " + currentPos);
}

如果你愿意,甚至可以倒退:

for(int currentPos = 10 ; currentPos > 0; currentPos--){
  println("step: " + currentPos);
}

这在遍历各种数据(场景中的三角形、三角形中的顶点等)时非常有用

您如何组织数据?你把它放在一个列表或数组中。 数组包含相同类型的元素并具有固定的长度。 声明数组的语法如下:

ObjectType[] nameOfArray;

你可以初始化一个空数组:

int[] fiveNumbers = new int[5];//new keyword then the data type and length in sq.brackets

或者你可以用值初始化数组:

String[] words = {"ini","mini","miny","moe"};

您可以使用方括号和要访问的列表中对象的索引来访问数组中的元素。数组具有长度属性,因此您可以轻松计算对象。

background(255);
String[] words = {"ini","mini","miny","moe"};
for(int i = 0 ; i < words.length; i++){
   fill(map(i,0,words.length, 0,255));
   text(words[i],10,10*(i+1));
}

现在回到你原来的问题。 这是使用 for 循环和数组简化的主要代码:

//Declare
int numTri = 6;//number of triangles
tri[] triangles = new tri[numTri];//a list/an array of tri objects (currently empty)
float angleIncrement = TWO_PI/numTri;
float radius = 100;
void setup() {
  size(600, 600);
  smooth();

  //Initialise
  for(int i = 0 ; i < numTri; i++){
    triangles[i] = new tri();//allocate/initialise each tri object into it's 'slot' in the list/array
  }
}

void draw() {
  background(0);
  translate(width * .5, height * .5);//move everything to the centre
  for(int i = 0 ; i < numTri; i++){
    pushMatrix();
      rotate(angleIncrement * i);//rotate from the last offset(centre)
      translate(radius,0);//move on (rotated) X axis away from the centre
      triangles[i].run();
    popMatrix();
  }
}
void drawAxes(int size){
  pushStyle();
  stroke(255,0,0);
  line(0,0,size,0);
  stroke(0,255,0);
  line(0,0,0,size);
  popStyle();
}

请注意,我在 push/pop matrix 调用中缩进了代码。 这不是必需的,但我已经添加了这一点,因此您可以了解坐标空间是如何嵌套的。 这些调用非常有用,因为它们为您处理幕后的细节数学部分。请注意我是如何在不使用极坐标到笛卡尔转换公式(cos(angle) * radius, sin(angle) * radius)的情况下将符号放在一个圆圈中的。

您可以使用其他选项卡中的此代码进行测试:

class tri {
  //Variables
  float ax, ay, bx, by, cx, cy; //triangle point coordinates
  float theta; //triangle angle
  float pi = PI; //pi reference

  //Construct
  tri() {
    theta = PI/6;
    ax = 0;
    ay = 0;
    bx = -50*(sin(theta));
    by = +50*(cos(theta));
    cx = +50*(sin(theta));
    cy = +50*(cos(theta));
  }

  //Functions
  void run() {
    pushMatrix();
    revolve(); //revolve triangle about centre
//    pulse(); //move triangle in/out
    display(); //show triangle
    popMatrix();
  }

  void revolve() {
    translate(-2*by, 0);
    float angle = millis()*0.005;
    float cos = cos(angle);
    float sin = sin(angle);
    ax = ax + 2*sin;
    ay = ay + 4*cos;
    bx = bx + 2*sin;
    by = by + 4*cos;
    cx = cx + 2*sin;
    cy = cy + 4*cos;
    translate(2*by, 0);
  }

  void pulse() {
    ay = ay + 5*sin(millis()*0.005);
    by = by + 5*sin(millis()*0.005);
    cy = cy + 5*sin(millis()*0.005);
  }

  void display() {
    fill(255);
    strokeWeight(0.8);
    triangle(ax, ay, bx, by, cx, cy);
  }
}

还请注意,我添加了一个 drawAxes 函数。这只是一个实用程序,可以让您更容易理解您的绘图在哪个坐标空间中。

再次回到数组和 for 循环,这里是您的代码的修改版本:

class tri {
  //Variables
  float ai = TWO_PI/3;//angle increment
  float r  = 50;
  float sr = r * 1.5;//spin radius
  float vt = 5;//vertical translation(for pulse)
  PVector[] verts = new PVector[3];

  boolean rotateAroundCentre = true;
  boolean translateAroundCentre = false;
  boolean translateVertically = false;
  //Construct
  tri() {
    for(int i = 0 ; i < 3; i++){
      verts[i] = new PVector(cos(ai * i) * r,sin(ai * i) * r);
    }
  }

  //Functions
  void run() {
    pushMatrix();
      float angle = millis()*0.0005;
      if(rotateAroundCentre) rotate(angle);
      if(translateVertically) translate(sin(angle)*vt,0);
      if(translateAroundCentre){
//        translate(cos(angle) * sr,sin(angle) * r);
//        or          
          rotate(angle);
          translate(sr,0);   
      }
    display(); //show triangle
    popMatrix();
  }
  void display() {
    fill(255);
    strokeWeight(0.8);
    triangle(verts[0].x, verts[0].y, verts[1].x, verts[1].y, verts[2].x, verts[2].y);
    drawAxes(10);
  }
}

您可以随意使用 boolean rotateAroundCentre、translateAroundCentre、translateVertically 变量,玩转坐标和几何图形:)

例如,这是一个草图版本,您可以使用键盘上的 1/2/3 键切换上述 3 个选项:

//Declare
int numTri = 6;//number of triangles
tri[] triangles = new tri[numTri];//a list/an array of tri objects (currently empty)
float angleIncrement = TWO_PI/numTri;
float radius = 100;
boolean[] options = {false,false,false}; 
void setup() {
  size(600, 600);
  smooth();

  //Initialise
  for(int i = 0 ; i < numTri; i++){
    triangles[i] = new tri();//allocate/initialise each tri object into it's 'slot' in the list/array
  }
}

void draw() {
  background(0);
  translate(width * .5, height * .5);//move everything to the centre
  for(int i = 0 ; i < numTri; i++){
    pushMatrix();
      rotate(angleIncrement * i);//rotate from the last offset(centre)
      translate(radius,0);//move on (rotated) X axis away from the centre
      drawAxes(20);
      triangles[i].run();
    popMatrix();
  }
}
void drawAxes(int size){
  pushStyle();
  stroke(255,0,0);
  line(0,0,size,0);
  stroke(0,255,0);
  line(0,0,0,size);
  popStyle();
}
void keyReleased(){
  for(int i = 0 ; i < 3; i++) if(key == (49+i)) options[i] = !options[i];//quick'n'dirty option toggling
  for(int i = 0; i < numTri; i++) {
    triangles[i].rotateAroundCentre = options[0];
    triangles[i].translateAroundCentre = options[1];
    triangles[i].translateVertically = options[2];
  }
}
class tri {
  //Variables
  float ai = TWO_PI/3;//angle increment
  float r  = 50;
  float sr = r * 1.5;//spin radius
  float vt = 5;//vertical translation(for pulse)
  PVector[] verts = new PVector[3];

  boolean rotateAroundCentre = false;
  boolean translateAroundCentre = false;
  boolean translateVertically = false;
  //Construct
  tri() {
    for(int i = 0 ; i < 3; i++){
      verts[i] = new PVector(cos(ai * i) * r,sin(ai * i) * r);
    }
  }

  //Functions
  void run() {
    pushMatrix();
      float angle = millis()*0.0005;
      if(rotateAroundCentre) rotate(angle);
      drawAxes(30);

      if(translateVertically) translate(sin(angle)*vt,0);
      drawAxes(40);

      if(translateAroundCentre){
//        translate(cos(angle) * sr,sin(angle) * r);
//        or          
          rotate(angle);
          drawAxes(40);

          translate(sr,0);   
      }
    display(); //show triangle
    popMatrix();
  }
  void display() {
    fill(255);
    strokeWeight(0.8);
    triangle(verts[0].x, verts[0].y, verts[1].x, verts[1].y, verts[2].x, verts[2].y);
    drawAxes(10);
  }
}

【讨论】:

  • 你的解释真的比我看过的教程更有帮助,非常感谢:)
猜你喜欢
  • 2016-04-04
  • 2015-02-21
  • 2020-06-22
  • 2022-06-25
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多