我重新实现 Processing 的 rotate() 方法时出现错误
Bug in my reimplementation of Processing's rotate() method
为了更好地理解 Processing 的绘图技术(尤其是 translate()
和 rotate()
函数),我开始寻求重新实现 translate()
、rotate()
和 point()
方法。
这样做的时候,我很快就遇到了游戏结束的情况,当时我完全卡在了 rotate()
方法上,它的行为简直是疯了。显示围绕多个轴的一些奇怪的 (3D) 旋转。
每个点旋转的代码:
x = x * c - y * s; // cos(a) * cos(b) - sin(a) * sin(b)
y = y * c + x * s; // sin(a) * cos(b) + cos(a) * sin(b)
完整代码
class MyRenderer {
/* Added to every point - set through translation. */
int xOffset = 0;
int yOffset = 0;
/** Prevents unnecessary rotations around an angle of 0. Owed to the architecture. */
boolean rotated = false;
/** The values of c(osine) and s(ine) in the unit circle, for the given angle.
* This way they don't have to be recalculated for every single point. */
float c, s;
private void myTranslate(final int x, final int y) {
xOffset += x;
yOffset += y;
}
/** Actual rotation, transforming each point's coordinates, done in myPoint() */
private void myRotate(final int deg) {
c = cos(radians(deg));
s = sin(radians(deg));
rotated = true;
}
/** Draws the points to the screen with respect to the set translation and rotation. */
private void myPoint(float x, float y) {
// First rotate...
if (rotated) { // Only do the transformation if a rotation actually occured.
x = x * c - y * s; // cos(a) * cos(b) - sin(a) * sin(b)
y = y * c + x * s; // sin(a) * cos(b) + cos(a) * sin(b)
}
// ... then translate.
x += xOffset; y += yOffset;
// Finally draw.
point(x, y);
}
// Needed to reset the translation and rotation with every draw call - like the original.
private int debugAngle = 0;
public void myDraw() {
reset();
background(255);
myTranslate(50, 50);
myRotate(debugAngle++);
// Point cloud in shape of a square.
myPoint(0, 0);
myPoint(-10, -10);
myPoint( 0, -10);
myPoint( 10, -10);
myPoint( 10, 0);
myPoint( 10, 10);
myPoint( 0, 10);
myPoint(-10, 10);
myPoint(-10, 0);
}
/** Reset all scene transforms, mirroring the behavior of Processing's draw() method. */
private void reset() {
xOffset = 0;
yOffset = 0;
c = 1; // cos for 0 degrees.
s = 0; // sin for 0 degrees.
rotated = false;
}
}
/* ========================================================================================= */
MyRenderer r;
void setup() {
size(200, 100, FX2D);
frameRate(30);
r = new MyRenderer();
}
int debugAngle = 0;
void draw() {
r.myDraw();
debugRender();
}
/** Diplay a second 'rectangle' to compare the results of my renderer reimplementation to. */
void debugRender() {
translate(100, 50);
rotate(radians(debugAngle++));
// Point cloud in shape of a square.
point(0, 0);
point(-10, -10);
point( 0, -10);
point( 10, -10);
point( 10, 0);
point( 10, 10);
point( 0, 10);
point(-10, 10);
point(-10, 0);
}
在总结我的问题时,我发现了错误。写下来可能有帮助。还是很尴尬,时不时重蹈初学者的覆辙!
我还是上传了那个问题,因为我已经写完了。可能对我还不知道的人有帮助。
错误是覆盖 x
太快了,错误地使用了已经旋转的 x 值,而不是未转换的 x,导致 y
计算错误。
而不是
x = x * c - y * s; <== ERROR
y = y * c + x * s;
转换后的 x 必须被缓冲,直到所有依赖于原始 x 的计算完成:
float tmpX = x * c - y * s;
y = y * c + x * s;
x = tmpX;
为了更好地理解 Processing 的绘图技术(尤其是 translate()
和 rotate()
函数),我开始寻求重新实现 translate()
、rotate()
和 point()
方法。
这样做的时候,我很快就遇到了游戏结束的情况,当时我完全卡在了 rotate()
方法上,它的行为简直是疯了。显示围绕多个轴的一些奇怪的 (3D) 旋转。
每个点旋转的代码:
x = x * c - y * s; // cos(a) * cos(b) - sin(a) * sin(b)
y = y * c + x * s; // sin(a) * cos(b) + cos(a) * sin(b)
完整代码
class MyRenderer {
/* Added to every point - set through translation. */
int xOffset = 0;
int yOffset = 0;
/** Prevents unnecessary rotations around an angle of 0. Owed to the architecture. */
boolean rotated = false;
/** The values of c(osine) and s(ine) in the unit circle, for the given angle.
* This way they don't have to be recalculated for every single point. */
float c, s;
private void myTranslate(final int x, final int y) {
xOffset += x;
yOffset += y;
}
/** Actual rotation, transforming each point's coordinates, done in myPoint() */
private void myRotate(final int deg) {
c = cos(radians(deg));
s = sin(radians(deg));
rotated = true;
}
/** Draws the points to the screen with respect to the set translation and rotation. */
private void myPoint(float x, float y) {
// First rotate...
if (rotated) { // Only do the transformation if a rotation actually occured.
x = x * c - y * s; // cos(a) * cos(b) - sin(a) * sin(b)
y = y * c + x * s; // sin(a) * cos(b) + cos(a) * sin(b)
}
// ... then translate.
x += xOffset; y += yOffset;
// Finally draw.
point(x, y);
}
// Needed to reset the translation and rotation with every draw call - like the original.
private int debugAngle = 0;
public void myDraw() {
reset();
background(255);
myTranslate(50, 50);
myRotate(debugAngle++);
// Point cloud in shape of a square.
myPoint(0, 0);
myPoint(-10, -10);
myPoint( 0, -10);
myPoint( 10, -10);
myPoint( 10, 0);
myPoint( 10, 10);
myPoint( 0, 10);
myPoint(-10, 10);
myPoint(-10, 0);
}
/** Reset all scene transforms, mirroring the behavior of Processing's draw() method. */
private void reset() {
xOffset = 0;
yOffset = 0;
c = 1; // cos for 0 degrees.
s = 0; // sin for 0 degrees.
rotated = false;
}
}
/* ========================================================================================= */
MyRenderer r;
void setup() {
size(200, 100, FX2D);
frameRate(30);
r = new MyRenderer();
}
int debugAngle = 0;
void draw() {
r.myDraw();
debugRender();
}
/** Diplay a second 'rectangle' to compare the results of my renderer reimplementation to. */
void debugRender() {
translate(100, 50);
rotate(radians(debugAngle++));
// Point cloud in shape of a square.
point(0, 0);
point(-10, -10);
point( 0, -10);
point( 10, -10);
point( 10, 0);
point( 10, 10);
point( 0, 10);
point(-10, 10);
point(-10, 0);
}
在总结我的问题时,我发现了错误。写下来可能有帮助。还是很尴尬,时不时重蹈初学者的覆辙!
我还是上传了那个问题,因为我已经写完了。可能对我还不知道的人有帮助。
错误是覆盖 x
太快了,错误地使用了已经旋转的 x 值,而不是未转换的 x,导致 y
计算错误。
而不是
x = x * c - y * s; <== ERROR
y = y * c + x * s;
转换后的 x 必须被缓冲,直到所有依赖于原始 x 的计算完成:
float tmpX = x * c - y * s;
y = y * c + x * s;
x = tmpX;