代码之家  ›  专栏  ›  技术社区  ›  solub

“镜像”具有处理功能的pshape对象(旋转/平移问题)

  •  1
  • solub  · 技术社区  · 6 年前

    我想“镜像”一个pshape对象,如下图所示:

    https://i.imgur.com/kwTQ7vA.png

    我知道如何显示多个形状以及如何反转它们(下面的屏幕截图),但是当我必须旋转它们(可能还要翻译它们)以便它们“粘”到前面的形状(第一张图片)时,事情就会变得复杂起来。

    enter image description here

    我一直在尝试用原始形状的前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();
    }
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Rabbid76    6 年前

    要想做你想做的,你必须为形状的顶部和底部创建两个给定角度的形状。 angleT 和“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 奇数部分必须旋转两倍 小天使 . 对于旋转,必须将斜面(枢轴)的中心平移到原点:

    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 )以及角度( 盎格鲁 , 小天使 )因此,这可以基于上述两种方法来实现。

    定义轴点和上下边缘的方向:

    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();
    }