处理中的“旋转”和“翻译”给我带来了麻烦

时间:2012-11-19 23:16:44

标签: rotation processing

作为进入Processing的小作业,我必须编写一些代码来获得以下内容: task

使用

public void setup() {
   size(300,200);
   noFill();
   rect(100, 20, 40, 80);
   ellipseMode(CENTER);
   fill(#000000);
   ellipse(width/2, height/2, 5,5);

   noFill();
   translate(width/2, height/2);
   rotate(radians(65));
   rect(-20, -40, 40, 80);
}
public void draw() {
}
到目前为止,这项工作非常好。但我不喜欢我必须更改底部rect指令内部的坐标才能使旋转正确。我知道通过旋转你不会旋转单个元素,实际上是整个坐标系。 我不知道的是要在translate指令中输入哪些值以使输出如上图所示,同时仍在rect命令中使用相同的坐标。

任务已经完成了我使用的代码,我只是不太喜欢它。所以这不仅仅是要求别人做我的作业而是纯粹的兴趣。

编辑:问题的更广泛尝试:如何知道哪些值在旋转之前进入平移以获得我想要的任何结果?有没有办法计算它们?当然,这不只是尝试,是吗?

3 个答案:

答案 0 :(得分:6)

处理中的许多困惑是坐标系。在处理中,原点(0,0)位于屏幕的左上角,并且屏幕上仅显示正坐标。解决此问题的常见解决方法是:

translate(width/2, height/2);

void draw()方法的开头。这样,0,0现在位于草图的中心,任何后续的方法(如rotate(radians(65)))都将从草图的中心开始执行。

这也很好,因为使用P3DOPENGL渲染器的草图通常会调用translate来将坐标系更改为更易于使用的内容。例如,0,0或0,0,0处的物体位于中心,这使得相机围绕物体绕轨道运行更容易,或者物体围绕其中心旋转。

另一种流行的绘制对象的方法是将原点设置为上面而不是给出每个对象的坐标,即rect(-100, -50, 50, 50)是在翻译之前使用popMatrix()和pushMatrix,然后将每个对象绘制为0 ,0如下图所示:

translate(width/2, height/2);
pushMatrix();
  translate(-100, -50);
  rect(0,0,50,50);
popMatrix();

如果您认为最终可能会移动到3d渲染器,这是在二维渲染器中使用的好方法,因为您可以轻松地将rect()替换为box()sphere()或创建您的假设原点位于0,0,自己绘制几何体的方法或对象。

如果用变量替换x和y坐标,或者在for循环中迭代数组,那么在2d或3d中绘制数百或数千个形状变得非常容易,只需要很少的工作量和最少的代码重写。


更新:根据他们的评论补充原始海报的说明。


我稍微改变了问题,告诉你我将如何处理这个问题。我正在使用push和pop矩阵显示我上面描述的translate / rotate方法。我只是猜测值,但如果你想要像素精确的像素,你可以在像photoshop或预览的图像编辑程序中进行测量。

rect1

translate(180, 150);
rect(0, 0, 180, 80);

rect2

translate(185, 170);
rotate(radians(65));
rect(0, 0, 180, 80);

ellipse

translate(180, 250);
ellipse(0, 0, 8, 8);

将所有内容与pushMatrix()popMatrix()放在一起。

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

void draw(){
  // rect1
  noFill();
  pushMatrix();
    translate(180, 150);
    rect(0, 0, 180, 80);
  popMatrix();
  // rect2
  pushMatrix();
    translate(185, 170);
    rotate(radians(65));
    rect(0, 0, 180, 80);
  popMatrix();
  // ellipse
  fill(0);
  pushMatrix();
    translate(180, 250);
    ellipse(0, 0, 8, 8);
  popMatrix();
}

答案 1 :(得分:3)

旋转距离应用于原点(0,0),因此您需要绘制轴以在原点旋转。或者将坐标系原点移动到轴上。这确实令人困惑。当使用变换时,我倾向于始终在原点绘制。试试这个看看它是否让事情更清楚......或更少:) 还有push / popMatrix()来控制转换的范围...

public void setup() {
  size(300, 380);
  smooth();
}
public void draw() {
  background(0);
  stroke(255);
  //use push/pop Matrix to control scope of translate and rotate
  pushMatrix();
  //move coordinates system origin to center of screen
  translate(width/2, height/2);
  // rotate with origin as axis
  rotate(radians(mouseY));
  //draw at origin (now temp moved to center of screen)
  // white line 
  line(0, 0, 150, 0);
  // here all coordinate system is back to normal
  popMatrix();

  //draw with normal system red line at origin
  stroke(255, 0, 0);
  line(0, 0, 150, 0);

    //draw with normal system blue line at centre
  stroke(0, 0, 255);
  line(width/2, height/2, width/2 + 150, height/2);
}

答案 2 :(得分:3)

  

在我的特定示例中,知道如何翻译和旋转以获得   导致图片没有改变矩形坐标?

嗯,你需要在原点绘制以正确使用旋转,所以你只是处理矩形的原点...因为它在你的代码中,默认情况下,原点是左上角,所以你做了一个偏移集(从(0,0))在坐标(0,0)处绘制它的中心而不是角落,然后从中间旋转。做得好。您发现的值是负半宽度(-20)和负半高度(-40)并非巧合。如果更改为rectMode(CENTER),则只能在(0,0)处绘制。这同样适用于翻译,你可以只转换到所需的点,屏幕的中心,有椭圆的地方。使用半宽和半高完成了什么......

外观:

public void setup() {
  size(300, 200);
  smooth();
  ellipseMode(CENTER);
  rectMode(CENTER);
  noFill();
  // here converting the coordinates to work with CENTER mode
  //could have changed the rect mode just after this
  // but i kept as an illustration
  int rwidth = 40;
  int rheight = 80;
  int xpos = 100 + rwidth/2;
  int ypos = height/2 - rheight/2 ;

  rect(xpos, ypos, rwidth, rheight);

  fill(#000000);
  ellipse(width/2, height/2, 5, 5);

  noFill();
  pushMatrix();

  translate(width/2, height/2);

  //draw at origin gray
  stroke(150);
  rect(0, 0, 40, 80);
  // then rotate
  rotate(radians(65));
  // draw again black
  stroke(0);
  rect(0, 0, 40, 80);

  popMatrix();


  // here using the cordinates calculated before as a translate value 
  // we draw at origin, but it appears at same place
  stroke(230,230,100);
  // a bit to the left...
  translate(xpos-2, ypos-2);

  rect(0, 0, 40, 80);

}