# Translating horizontally inverted quads

**URL:** <https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364>\
**Category:** Coding Questions\
**Created:** [January 9, 2019, 6:00pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364 "2019-01-09T18:00:47Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [January 9, 2019, 6:00pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/1 "2019-01-09T18:00:47Z")

</div>

A week ago I asked a [question](https://discourse.processing.org/t/mirroring-pshape-objects-translation-rotation-issue/7099/8) about translations and rotations in Processing.

I wanted to:

- **translate** , **invert** and **rotate** a single quadrilateral (PShape object) multiple times
- then **change the height** of one of its 2 top vertices

so as the whole thing act as an articulated arm that can be bent either to the right or the left.

[![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/d791ff5ead3508a78be925219e1ddacc1780315b.png) ](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/d791ff5ead3508a78be925219e1ddacc1780315b.png)

I was able to achieve this effect but I am now facing another issue **when translating the last 5 top horizontally inverted quads**.

[![enter image description here](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2d3ca8f8a596dc0e5a9dfa9f094f6917dd268f00.png)](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2d3ca8f8a596dc0e5a9dfa9f094f6917dd268f00.png)

When bending the object, the first 3 quads get separated from the last 5. And the more the bending leg is curved, the farther they get apart.

I would really appreciate if someone could help me fix the **translation** part (from line 65 to 68) so as the quads stay attached to each other to matter how strong the bending is.

[![enter image description here](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2096baa0b037b0fc62d7c7f00b224f10cd8e873b.png)](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2096baa0b037b0fc62d7c7f00b224f10cd8e873b.png)

Any suggestion regarding that matter would be also greatly appreciated.

SCRIPT

```auto
int W = 40;
int H = 40;
int nQuads = 8;
int xOffset = 27;
    
float[] p0 = {-W/2 + xOffset, -H/2};
float[] p1 = {-W/2, H/2};
float[] p2 = {W/2, H/2};
float[] p3 = {W/2, -H/2};
    
PShape object;
    
    
void setup(){
    size(600, 600, P2D);
    smooth(8);
}
    
void draw(){
    
    background(255);
    
    // Bending to the left
    float bending = sin(frameCount*.05) * .1;
    p0[1] -= bending;
        
    pushMatrix();
    translate(width/2, height/2);
        
    
    float minX = min( min(p0[0], p3[0]), min(p2[0], p1[0]) );
    float maxX = max( max(p0[0], p3[0]), max(p2[0], p1[0]) );
        
    float cptX = (minX+maxX)/2;
        
    //Rotation Angle
    float angle = atan2(p3[1]-p0[1], p3[0]-p0[0]);
        
    //Pivot Height
    float PH = p0[1] + (p3[1]-p0[1]) * (cptX-p0[0])/(p3[0]-p0[0]);
        
    
    for (int i = 0; i < nQuads; i++){
    
         float PivotHeight = (i % 2 == 1) ? PH : H/2; 
    
        //Height translation
        if (i > 0){
          translate(0, PivotHeight);
        }
            
        //Rotate once every 2 quads
        if (i%2 == 1){
          rotate(angle*2);
        }
            
        //Height translation
        //Flip all quads except 1st one
        if (i > 0){
          translate(0, PivotHeight);
          scale(1, -1);
       }
              
         //NOT working --> Flipping horizontally the last 5 top QUADS
         if (i == 3){
           scale(-1, 1);
           translate(- xOffset, 0); //trying to align the quads on the X axis. Y translation is missing
           rotate(-angle*2);
         }
              
        object();
    }
    popMatrix();
}
     
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();
}

```

---

<div class="post-metadata">

**Author:** ![Kevin](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kevin/32/2297_2.png) [@Kevin](https://discourse.processing.org/u/Kevin)\
**Post date:** [January 9, 2019, 6:11pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/2 "2019-01-09T18:11:24Z")

</div>

Please link between crossposts. This question has also been asked here:

> <https://stackoverflow.com/questions/54114976/computing-pivot-height-in-processing>

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [January 9, 2019, 6:13pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/3 "2019-01-09T18:13:13Z")

</div>

Hi @Kevin,

Do you have an idea how I could possibly compute the pivot height ?

---

<div class="post-metadata">

**Author:** ![Architector\_4](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/architector_4/32/813_2.png) [@Architector\_4](https://discourse.processing.org/u/Architector_4)\
**Post date:** [January 9, 2019, 7:39pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/4 "2019-01-09T19:39:51Z")

</div>

Right, so I found some of my older functions that are useful for this that come in pairs and output only 1 number, while they should output `PVector` instead or something. In any case, I used them as is to create pretty horrific code that makes your final ideal output possible.  
Move mouse left/right to give the tower a tilt. Hold mouse to set the second tilt used more at the top parts of the tower. Move mouse up/down to set the steepness between the first and second tilt.

```auto
int sign(float in){
  //Tells the sign of the input number.
  if(in<0){return -1;}
  if(in>0){return 1;}
  return 0;
}

float mix(float in1,float in2,float mix){
  //Blends between 2 values - 0 mix equals in1, 1 mix equals in2, 0.5 mix equals half of both i.e. average.
 return in1+(in2-in1)*mix; 
}

float angle(float x, float y){
  //If you were to draw an arrow going from 0,0 to x,y coordinates in 2D space, considering up is 0 degrees and right is 90 degrees, this is the angle of that arrow.
  if(x==-0){x=0;}
  if(y==-0){y=0;}
return y!=0?(x<0?(180*sign(y)-(atan(y/abs(x))/(PI)*180)):atan(y/abs(x))/(PI)*180):sign(x)<0?(180):0;
//return y!=0?(-sign(x)*(180*sign(y)-(atan(y/abs(x))/(PI)*180))/(PI)*180):sign(x)<0?(180):0;
}
float rotX(float x, float y, float degrees){
  //Takes current x,y on 2D space, rotates them around the 0,0 pivot point at degrees degrees, and outputs X of the result.
  return sqrt(x*x+y*y)*cos((angle(x,y)+degrees)/180*PI);
}

float rotY(float x, float y, float degrees){
  //Takes current x,y on 2D space, rotates them around the 0,0 pivot point at degrees degrees, and outputs Y of the result.
  return sqrt(x*x+y*y)*sin((angle(x,y)+degrees)/180*PI);
}

float rotX(float originx, float originy, float x, float y, float degrees){
  //Takes current x,y on 2D space, rotates them around the originx, originy pivot point at degrees degrees, and outputs X of the result.
  return rotX(x-originx,y-originy,degrees)+originx;
}
float rotY(float originx, float originy, float x, float y, float degrees){
  //Takes current x,y on 2D space, rotates them around the originx, originy pivot point at degrees degrees, and outputs Y of the result.
  return rotY(x-originx,y-originy,degrees)+originy;
}

float offset=-50;
float sideSizeL = 25;
float sideSizeR = 25;
int count = 10;

float angle = 0;
float angle2 = 0;

float angleMixSteepness = 0.5;

int oddSegment = 5;
//At which shape it should change which side of the tower zigzags.

void setup(){size(480,640,P2D);}

void draw(){
  
  if(mousePressed) angle2 = (mouseX-width/2)*0.1;
              else angle = (mouseX-width/2)*0.1;
  angleMixSteepness = (float)mouseY*2/height;
  background(255);
  float currentX=width/2;
  float currentY=height-10;
  float currentAngle = 0;
// line(width/2,height-10,rotX(width/2,height-10,width/2,height-60,angle),rotY(width/2,height-10,width/2,height-60,angle));
  for(int i=0;i<count;i++){
    float nextAngle=currentAngle+mix(angle,angle2,pow((float)i/count,angleMixSteepness));
    float nextX=rotX(currentX,currentY,currentX,currentY+offset,nextAngle);
    float nextY=rotY(currentX,currentY,currentX,currentY+offset,nextAngle);
    
    //Current coordinates:
    //currentX currentY currentAngle - starting position and angle of this current segment.
    //nextX nextY nextAngle - ending position of this current segment - these values will be used for the start of the next segment.
    //All lines are based around these coordinates and rotating them around these angles.
    
      
      float sideSizeLeftCurrent = sideSizeL;
      float sideSizeLeftNext = sideSizeL;
      float sideSizeRightCurrent = sideSizeR;
      float sideSizeRightNext = sideSizeR;
      //sideSizeLeft/RightCurrent - Offsets from the starting point to the left/right to form the base of this segment. 
      //sideSizeLeft/RightCurrent - Offsets from the starting point to the left/right to form the roof of this segment or base of the next segment. 
      
      //Make them do the zig-zag thing.
            if(i<oddSegment){
        if(i%2==1) sideSizeLeftCurrent-=30;
              else sideSizeLeftNext-=30;
      }else if(i==oddSegment){
        sideSizeLeftCurrent-=30;
      }else if(i>oddSegment){
        if(i%2==1) sideSizeRightCurrent-=30;
              else sideSizeRightNext-=30;
      }
        
    
    line(rotX(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),
         rotX(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle));
    //Line going below the segment. Makes the base.
      //line(lastX,lastY,lastX1,lastY1);
      //Line going through the middle of the segment.
      beginShape(QUADS);
      vertex(rotX(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle));
      //Top left
      
      vertex(rotX(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle));
      //Top right
      
      vertex(rotX(nextX, nextY, nextX+sideSizeRightNext, nextY, nextAngle) ,rotY(nextX ,nextY ,nextX+sideSizeRightNext ,nextY ,nextAngle));
      //Bottom right
      
      vertex(rotX(nextX ,nextY ,nextX-sideSizeLeftNext ,nextY ,nextAngle) ,rotY(nextX ,nextY ,nextX-sideSizeLeftNext ,nextY ,nextAngle));
      //Bottom left
      endShape();
    
    currentAngle+=mix(angle,angle2,pow((float)i/count,angleMixSteepness));
    currentX = nextX; currentY = nextY;
    
  }
  
}

```

P.S. Forgive me for these long names - I named them like `X1` `Y4` and so on and it was pretty confusing. If you want to have a bit less horrific experience with my code, I suggest to right-click values, “Rename…”, and set them to something shorter… .\_.

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [January 10, 2019, 3:48pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/5 "2019-01-10T15:48:34Z")

</div>

Hi @Architector_4,

Thank you for the reply, I really appreciate you took the time to try to provide a solution. However, I’m afraid you haven’t understood the problem, and as result your answer is inconsistent with my question.

Your approach is not based on the original code I provided and the output is very (very) different from what I’m trying to achieve.

Regarding my issue, I’ve finally found the correct way to compute the pivot height but I still have to figure out how to compute the translation so as the array of quads stay connected no matter how strong the bending is.  
Question has been edited.

Thank you anyway.

---

<div class="post-metadata">

**Author:** ![Architector\_4](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/architector_4/32/813_2.png) [@Architector\_4](https://discourse.processing.org/u/Architector_4)\
**Post date:** [January 10, 2019, 9:40pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/6 "2019-01-10T21:40:55Z")

</div>

Oh. Yeah, what I remember when replying is that I didn’t read your text, saw “ideal output” and went on my adventures. Sorry!

Anyways, I think I solved your problem. I replaced:

```auto
        //Height translation
        //Flip all quads except 1st one
        if (i > 0){
          translate(0, PivotHeight);
          scale(1, -1);
       }
              
         //NOT working --> Flipping horizontally the last 5 top QUADS
         if (i == 3){
           scale(-1, 1);
           translate(- xOffset, 0); //trying to align the quads on the X axis. Y translation is missing
           rotate(-angle*2);
         }

```

With:

```auto
         //YES working --> Flipping horizontally the last 5 top QUADS
         if (i == 3){
           scale(-1, 1);
           rotate(angle*2);
           translate(-xOffset, xOffset*angle); //trying to align the quads on the X axis. Y translation is missing
           //Yes, angle is meant for rotation and not translation. I don't care! :D
         }
        //Height translation
        //Flip all quads except 1st one
        if (i > 0){
          translate(0, PivotHeight);
          scale(1, -1);
       }

```

And it produces the “ideal output” now.  
Basically I slammed an angle into a translate function and moved everything around, and it’s still almost your code and somehow now works.

Did I do it now? 😃

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [January 11, 2019, 2:25pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/7 "2019-01-11T14:25:52Z")

</div>

Almost !

If you increase the bending you’ll see that quad n°3 and quad n°4 get separated at some point.

![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/8/89d65f86793f1b30738c3da2a7b6db8a30369572.png)

Fortunately I just found a workaround. I don’t really get what I’m doing and it’s probably not the most efficient solution but it works.

```auto
if (i == 3) {
  scale(-1, 1);
  translate(0, PivotHeight); 
  rotate(-angle*2);
  translate(0, PivotHeight);
  translate(-xOffset , H/2 - p0[1]);
}

```

![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/7/73b6224c1c41f1334ecfc182e1482028ac1300ee.png)

Thank you for your time and suggestions !

---

<div class="post-metadata">

**Author:** ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)\
**Post date:** [January 12, 2019, 5:42am UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/8 "2019-01-12T05:42:14Z")

</div>

hi @solub  
i worry many of your problems from resent questions  
( that the QUADs got separated… and you had to solve it with??? )  
might have been avoided  
by a different structure:  
-a- use QUAD STRIP  
-b- make 2 start points ( like by pvector )  
-c- make a loop over…

- -d- make 2 more points to FINISH one QUAD each

 ![2019-01-12_12-33-04_snap](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/ed42b2cf65fc57650adcc3909ee441cfaccbf5c8.png)

now while i try with random distance ( startline to endline )  
you can use your moving math…

anyhow that strip can never be separated to your QUADs problem  
but i am not sure it fits for your application.  
still hope it helps.

```auto
int many = 8;
PVector[] points = new PVector[many];
void setup() {
  size(400, 400);
  points[0] = new PVector(0, 0);
  points[1] = new PVector(20, 0);  
  for ( int i = 2; i<many; i++) 
    points[i] = new PVector(points[i-2].x+int(random(10, 20)), points[i-2].y+int(random(20, 30)));
  printArray(points);
}
void make_shape() {
  beginShape(QUAD_STRIP); 
  fill(0, 200, 0);
  stroke(0, 0, 200);
  for ( int i = 0; i<many; i++) vertex(points[i].x, points[i].y);
  endShape();
}
void draw() { 
  background(200, 200, 0);
  translate(width/2, height/2);
  make_shape();
}

```

this does the same but using a named shape and regenerate at mouse click

```auto
int many = 8;
PVector[] points = new PVector[many];
PShape Qstrip;

void setup() {
  size(400, 400);
  make_points();
  make_shape();
}
void make_points() {  
  points[0] = new PVector(0, 0);
  points[1] = new PVector(20, 0);  
  for ( int i = 2; i<many; i++) 
    points[i] = new PVector(points[i-2].x+int(random(5, 30)), points[i-2].y+int(random(5, 30)));
  printArray(points);
}
void make_shape() {
  Qstrip = createShape();
  Qstrip.beginShape(QUAD_STRIP); 
  Qstrip.fill(0, 200, 0);
  Qstrip.stroke(0, 0, 200);
  for ( int i = 0; i<many; i++) Qstrip.vertex(points[i].x, points[i].y);
  Qstrip.endShape();
}
void draw() { 
  background(200, 200, 0);
  shape(Qstrip,width/2, height/2);
}

void mousePressed() {
  make_points();
  make_shape();  
}

```

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [January 12, 2019, 3:50pm UTC](https://discourse.processing.org/t/translating-horizontally-inverted-quads/7364/9 "2019-01-12T15:50:29Z")

</div>

@kll Many thanks for the kind suggestion. It doesn’t quite fit into my project ritgh now but could be interesting for future sketches. Thanks again.
