"Mirroring" 具有处理功能的 PShape 对象(旋转/平移问题)
"Mirroring" a PShape object (rotation / translation issue) with Processing
我想要 "mirror" 一个 PShape 对象,如下图所示:
我知道如何显示多个形状以及如何反转它们(下面的屏幕截图)但是当我必须旋转它们(并且可能翻译它们)以便它们 "stick" 到前面的形状时事情变得复杂(第一张图)。
我一直在尝试用原始形状(不规则四边形)的前 2 个顶点和 atan2()
函数计算角度,但无济于事。
如果有人能帮助解决这个问题,我将不胜感激。
int W = 20;
int H = 20;
int D = 20;
PShape object;
void setup(){
size(600, 600, P2D);
smooth();
}
void draw(){
background(255);
pushMatrix();
translate(width/2, height/1.3);
int td = -1;
for (int i = 0; i < 6; i++){
translate(0, td*H*2);
scale(-1, 1);
rotate(PI);
object();
td *= -1;
}
popMatrix();
}
void object() {
beginShape(QUADS);
vertex(-20, 20);
vertex(20, 0);
vertex(20, -20);
vertex(-20, -20);
endShape();
}
要完成您想要的操作,您必须通过形状的顶部和底部的 2 个给定角度和“angleB”创建一个形状。原点 (0,0) 位于形状的中心。这导致旋转的枢轴位于形状斜坡的中间:
int W = 40;
int H = 40;
float angleT = -PI/18;
float angleB = PI/15;
PShape object;
void object() {
float H1 = -H/2 + W*tan(angleB);
float H2 = H/2 + W*tan(angleT);
beginShape(QUADS);
vertex(-W/2, -H/2);
vertex(W/2, H1);
vertex(W/2, H2);
vertex(-W/2, H/2);
endShape();
}
当你画零件的时候,你应该区分偶数和奇数部分。必须通过反转 y 轴 (scale(1, -1)
) 将零件水平翻转。偶数部分必须旋转 angleB
的两倍,奇数部分必须旋转 angleT
的两倍。对于旋转,斜坡(枢轴)的中心必须平移到原点:
void setup(){
size(600, 600, P2D);
smooth();
}
void draw(){
background(255);
translate(width/2, height/2);
float HC1 = -H/2 + W*tan(angleB)/2;
float HC2 = H/2 + W*tan(angleT)/2;
for (int i = 0; i < 15; i++){
float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;
translate(0, -HC);
rotate(angle*2);
translate(0, -HC);
object();
scale(1, -1);
}
}
该算法适用于任何角度,正角和负角,包括 0。
这个算法可以进一步改进。假设您有一个由 4 个点 (p0
、p1
、p2
、p3
) 定义的四边形:
float[] p0 = {10, 0};
float[] p1 = {40, 10};
float[] p2 = {60, 45};
float[] p3 = {0, 60};
PShape object;
void object() {
beginShape(QUADS);
vertex(p0[0], p0[1]);
vertex(p1[0], p1[1]);
vertex(p2[0], p2[1]);
vertex(p3[0], p3[1]);
endShape();
}
计算最小值、最大值、中心点、枢轴和角度:
float minX = min( min(p0[0], p1[0]), min(p2[0], p3[0]) );
float maxX = max( max(p0[0], p1[0]), max(p2[0], p3[0]) );
float minY = min( min(p0[1], p1[1]), min(p2[1], p3[1]) );
float maxY = max( max(p0[1], p1[1]), max(p2[1], p3[1]) );
float cptX = (minX+maxX)/2;
float cptY = (minY+maxY)/2;
float angleB = atan2(p1[1]-p0[1], p1[0]-p0[0]);
float angleT = atan2(p2[1]-p3[1], p2[0]-p3[0]);
float HC1 = p0[1] + (p1[1]-p0[1])*(cptX-p0[0])/(p1[0]-p0[0]);
float HC2 = p3[1] + (p2[1]-p3[1])*(cptX-p3[0])/(p2[0]-p3[0]);
像以前一样画出形状:
for (int i = 0; i < 6; i++){
float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;
translate(cptX, -HC);
rotate(angle*2);
translate(-cptX, -HC);
object();
scale(1, -1);
}
另一种方法是在两侧堆叠形状:
为此,您必须知道枢轴的高度 (HC1
、HC2
) 和角度 (angleB
、angleT
)。所以这可以基于以上两种方式来实现。
定义轴心点和上下边缘的方向:
PVector dir1 = new PVector(cos(angleB), sin(angleB));
PVector dir2 = new PVector(cos(angleT), sin(angleT));
PVector pv1 = new PVector(0, HC1); // or PVector(cptX, HC1)
PVector pv2 = new PVector(0, HC2); // or PVector(cptX, HC2)
计算两条边的交点(X
)。当然这只有在
边不平行:
PVector v12 = pv2.copy().sub(pv1);
PVector nDir = new PVector(dir2.y, -dir2.x);
float d = v12.dot(nDir) / dir1.dot(nDir);
PVector X = pv1.copy().add( dir1.copy().mult(d) );
堆栈算法的工作原理如下:
for (int i = 0; i < 8; i++){
float fullAngle = angleT-angleB;
float angle = fullAngle * floor(i/2);
if ((i/2) % 2 != 0)
angle += fullAngle;
if (i % 2 != 0)
angle = -angle;
float flip = 1.0;
if (i % 2 != 0)
flip *= -1.0;
if ((i/2) % 2 != 0)
flip *= -1.0;
pushMatrix();
translate(X.x, X.y);
rotate(angle);
scale(1, flip);
rotate(-angleB);
translate(-X.x, -X.y);
object();
popMatrix();
}
我想要 "mirror" 一个 PShape 对象,如下图所示:
我知道如何显示多个形状以及如何反转它们(下面的屏幕截图)但是当我必须旋转它们(并且可能翻译它们)以便它们 "stick" 到前面的形状时事情变得复杂(第一张图)。
我一直在尝试用原始形状(不规则四边形)的前 2 个顶点和 atan2()
函数计算角度,但无济于事。
如果有人能帮助解决这个问题,我将不胜感激。
int W = 20;
int H = 20;
int D = 20;
PShape object;
void setup(){
size(600, 600, P2D);
smooth();
}
void draw(){
background(255);
pushMatrix();
translate(width/2, height/1.3);
int td = -1;
for (int i = 0; i < 6; i++){
translate(0, td*H*2);
scale(-1, 1);
rotate(PI);
object();
td *= -1;
}
popMatrix();
}
void object() {
beginShape(QUADS);
vertex(-20, 20);
vertex(20, 0);
vertex(20, -20);
vertex(-20, -20);
endShape();
}
要完成您想要的操作,您必须通过形状的顶部和底部的 2 个给定角度和“angleB”创建一个形状。原点 (0,0) 位于形状的中心。这导致旋转的枢轴位于形状斜坡的中间:
int W = 40;
int H = 40;
float angleT = -PI/18;
float angleB = PI/15;
PShape object;
void object() {
float H1 = -H/2 + W*tan(angleB);
float H2 = H/2 + W*tan(angleT);
beginShape(QUADS);
vertex(-W/2, -H/2);
vertex(W/2, H1);
vertex(W/2, H2);
vertex(-W/2, H/2);
endShape();
}
当你画零件的时候,你应该区分偶数和奇数部分。必须通过反转 y 轴 (scale(1, -1)
) 将零件水平翻转。偶数部分必须旋转 angleB
的两倍,奇数部分必须旋转 angleT
的两倍。对于旋转,斜坡(枢轴)的中心必须平移到原点:
void setup(){
size(600, 600, P2D);
smooth();
}
void draw(){
background(255);
translate(width/2, height/2);
float HC1 = -H/2 + W*tan(angleB)/2;
float HC2 = H/2 + W*tan(angleT)/2;
for (int i = 0; i < 15; i++){
float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;
translate(0, -HC);
rotate(angle*2);
translate(0, -HC);
object();
scale(1, -1);
}
}
该算法适用于任何角度,正角和负角,包括 0。
这个算法可以进一步改进。假设您有一个由 4 个点 (p0
、p1
、p2
、p3
) 定义的四边形:
float[] p0 = {10, 0};
float[] p1 = {40, 10};
float[] p2 = {60, 45};
float[] p3 = {0, 60};
PShape object;
void object() {
beginShape(QUADS);
vertex(p0[0], p0[1]);
vertex(p1[0], p1[1]);
vertex(p2[0], p2[1]);
vertex(p3[0], p3[1]);
endShape();
}
计算最小值、最大值、中心点、枢轴和角度:
float minX = min( min(p0[0], p1[0]), min(p2[0], p3[0]) );
float maxX = max( max(p0[0], p1[0]), max(p2[0], p3[0]) );
float minY = min( min(p0[1], p1[1]), min(p2[1], p3[1]) );
float maxY = max( max(p0[1], p1[1]), max(p2[1], p3[1]) );
float cptX = (minX+maxX)/2;
float cptY = (minY+maxY)/2;
float angleB = atan2(p1[1]-p0[1], p1[0]-p0[0]);
float angleT = atan2(p2[1]-p3[1], p2[0]-p3[0]);
float HC1 = p0[1] + (p1[1]-p0[1])*(cptX-p0[0])/(p1[0]-p0[0]);
float HC2 = p3[1] + (p2[1]-p3[1])*(cptX-p3[0])/(p2[0]-p3[0]);
像以前一样画出形状:
for (int i = 0; i < 6; i++){
float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;
translate(cptX, -HC);
rotate(angle*2);
translate(-cptX, -HC);
object();
scale(1, -1);
}
另一种方法是在两侧堆叠形状:
为此,您必须知道枢轴的高度 (HC1
、HC2
) 和角度 (angleB
、angleT
)。所以这可以基于以上两种方式来实现。
定义轴心点和上下边缘的方向:
PVector dir1 = new PVector(cos(angleB), sin(angleB));
PVector dir2 = new PVector(cos(angleT), sin(angleT));
PVector pv1 = new PVector(0, HC1); // or PVector(cptX, HC1)
PVector pv2 = new PVector(0, HC2); // or PVector(cptX, HC2)
计算两条边的交点(X
)。当然这只有在
边不平行:
PVector v12 = pv2.copy().sub(pv1);
PVector nDir = new PVector(dir2.y, -dir2.x);
float d = v12.dot(nDir) / dir1.dot(nDir);
PVector X = pv1.copy().add( dir1.copy().mult(d) );
堆栈算法的工作原理如下:
for (int i = 0; i < 8; i++){
float fullAngle = angleT-angleB;
float angle = fullAngle * floor(i/2);
if ((i/2) % 2 != 0)
angle += fullAngle;
if (i % 2 != 0)
angle = -angle;
float flip = 1.0;
if (i % 2 != 0)
flip *= -1.0;
if ((i/2) % 2 != 0)
flip *= -1.0;
pushMatrix();
translate(X.x, X.y);
rotate(angle);
scale(1, flip);
rotate(-angleB);
translate(-X.x, -X.y);
object();
popMatrix();
}