How to add a gradient in a Bezier curve? - processing

I have drawn curves that denote the customer country and the country where he is headed for a trip in a map.
But I could not add a gradient so that the lines would denote the said information and gives this random color between two colors at random. Here's what I tried.
int steps = 10;
noFill();
//stroke(#5A38FA, 50);
strokeWeight(1);
for(int i=0; i<steps; i++) {
strokeWeight(1);
noFill();
stroke(lerpColor(#31B5E8, #F0E62E, (float)i/steps));
bezier(locationX, locationY, locationX+random(15, 50), locationY+random(13,50), customerLocationX+random(15, 30), customerLocationY+random(15, 70), customerLocationX, customerLocationY);
}

You can decompose a bezier curve into points using the bezierPoint()method and then draw straight line segments between successive points, specifying the colour for each individual line segment (meanwhile gradually lerping the colour of course).
I've produced a method which can do that in the code example below.
Additionally, with the method, you can specify the curve's magnitude (curve) and the direction of the curve (dir); the method calculates the bezier control point using the point on a line perpendicular to the midpoint between the start point (head) and end point (tail).
void setup() {
size(500, 500);
smooth(4);
noLoop();
redraw();
strokeWeight(5);
noFill();
}
void draw() {
background(35);
drawCurve(new PVector(50, 50), new PVector(456, 490), #31B5E8, #F0E62E, 50, -1);
drawCurve(new PVector(150, 75), new PVector(340, 410), #B9FF00, #FF00C5, 150, 1);
drawCurve(new PVector(200, 480), new PVector(480, 30), #007CFF, #89CA7F, 100, 1);
}
void drawCurve(PVector head, PVector tail, color headCol, color tailCol, float curve, int curveDir) {
final float theta2 = angleBetween(tail, head);
final PVector midPoint = new PVector((head.x + tail.x) / 2,
(head.y + tail.y) / 2);
final PVector bezierCPoint = new PVector(midPoint.x + (sin(-theta2) * (curve * 2 * curveDir)),
midPoint.y + (cos(-theta2) * (curve * 2 * curveDir)));
PVector point = head.copy();
for (float t=0; t<=1; t+=0.025) {
float x1 = bezierPoint(head.x, bezierCPoint.x, bezierCPoint.x, tail.x, t);
float y1 = bezierPoint(head.y, bezierCPoint.y, bezierCPoint.y, tail.y, t);
PVector pointB = new PVector(x1, y1);
stroke(lerpColor(headCol, tailCol, t));
line(point.x, point.y, pointB.x, pointB.y);
point = pointB.copy();
}
}
static float angleBetween(PVector tail, PVector head) {
float a = PApplet.atan2(tail.y - head.y, tail.x - head.x);
if (a < 0) {
a += PConstants.TWO_PI;
}
return a;
}
Result:

Related

Why do the lines (muscles) not line up with part3 (blue)?

https://imgur.com/a/hDRx3SI
The lines (muscles) start out in the center as I want. (This video starts out a second or two into the sketch.) Why do the muscles not line up with the center of part3 (Blue circle)? Is it simply a trigonometric issue where I'm trying to force them into an impossible position given the constraints?
Part part1;
Part part2;
Part part3;
Muscle muscle1;
Muscle muscle2;
Muscle muscle3;
void setup() {
size (800, 800);
frameRate(1);
part1 = new Part(width/2, height/2, 50, color(255, 0, 0));
part2 = new Part(width/2 + 100, height/2, 50, color(0, 255, 0));
part3 = new Part(width/2 + 50, height/2 - 75, 50, color(0, 0, 255));
muscle1 = new Muscle(part1.x, part1.y, part2.x, part2.y, dist(part1.x, part1.y, part2.x,part2.y), color(0, 255, 0));
muscle2 = new Muscle(part1.x, part1.y, part3.x, part3.y, dist(part1.x, part1.y, part3.x, part3.y), color(0, 255, 0));
muscle3 = new Muscle(part2.x, part2.y, part3.x, part3.y, dist(part2.x, part2.y, part3.x, part3.y), color(0, 255, 0));
}
void draw() {
background(255);
part1.drawpart();
part2.drawpart();
part3.drawpart();
muscle1.drawmuscle(part1, part2);
muscle2.drawmuscle(part1, part3);
muscle3.drawmuscle(part2, part3);
part2.movepart();
}
class Muscle{
float leftx;
float lefty;
float rightx;
float righty;
float size = 100;
int musclecolor;
Muscle(float leftpositionx, float leftpositiony, float rightpositionx, float rightpositiony, float musclesize, int musclemusclecolor) {
leftx = leftpositionx;
lefty = leftpositiony;
rightx = rightpositionx;
righty = rightpositiony;
size = musclesize;
musclecolor = musclemusclecolor;
}
void drawmuscle(Part obj1, Part obj2) {
strokeWeight(5);
float dx = obj2.x - obj1.x;
float dy = obj2.y - obj1.y;
float angle = atan2(dy, dx);
obj2.x = obj1.x + cos(angle) * size;
obj2.y = obj1.y + sin(angle) * size;
line(obj1.x, obj1.y, obj2.x, obj2.y);
}
}
class Part{
float x;
float y;
float size;
int partcolor;
Part(float positionx, float positiony, float partsize, int partpartcolor) {
x = positionx;
y = positiony;
size = partsize;
partcolor = partpartcolor;
}
void drawpart() {
fill(partcolor);
strokeWeight(1);
ellipseMode(CENTER);
ellipse(x, y, size, size);
}
void movepart() {
y += 10;
}
}
There are two different problems here which interacts with one another, which is why this is hard to solve. You'll be happy to notice, though, that your math are irreproachable.
First issue is in the drawmuscle() method. You modify coordinates while drawing them, which isn't necessarily an issue. The problem is that you're doing this in cascade for 3 different parts, which depend on each other to be calculated. The variables all end up all right - so mathematically it works - but as you draw some parts before others have been calculated, they end up with unexpected coordinates that are neither the old ones nor the new ones.
To fix this, I modified the drawmuscle() method so it only draws the muscles, and I added a new method to update the muscles/parts coordinates. It's still all your code, just displaced into different containers. Then I modified the draw() method to reflect this change: the coordinates have to be calculated first, then the parts can be drawn.
Now, the blue circle was still misplaced. That's also because of a matter of order in the draw() method: as the circles were drawn before their coordinates were updated, they were subject to be misdrawn. Again, at the end of every frame, your calculations were correct, but in the way the operations to get there were applied and drawn they would appear off.
As a rule of thumb, I would say that you need to remember from this project the following rule: calculate first, draw last.
So here are the changes I made to your methods:
void draw() {
background(255);
// calculating new positions
muscle1.moveMuscle(part1, part2);
muscle2.moveMuscle(part1, part3);
muscle3.moveMuscle(part2, part3);
// drawing
part1.drawpart();
part2.drawpart();
part3.drawpart();
muscle1.drawmuscle(part1, part2);
muscle2.drawmuscle(part1, part3);
muscle3.drawmuscle(part2, part3);
muscle1.growmuscle(part1, part2);
}
void drawmuscle(Part obj1, Part obj2) {
// no calculations here
strokeWeight(5);
line(obj1.x, obj1.y, obj2.x, obj2.y);
}
void moveMuscle(Part obj1, Part obj2) {
// every calculations here
float dx = obj2.x - obj1.x;
float dy = obj2.y - obj1.y;
float angle = atan2(dy, dx);
obj2.x = obj1.x + cos(angle) * size;
obj2.y = obj1.y + sin(angle) * size;
rightx = obj2.x;
righty = obj2.y;
}
I hope this will help. Have fun!

Tangent to the curve

I’m new at coding and I have a problem, I would like to draw a program where there is a curve and but for now I just have the static drawing but I don’t know how to generate a tangent line on the curve thanks to his derivate, as the mouse move…
This is all I have for now
void draw(){
background(255);
noFill();
stroke(0);
beginShape();
for(float a=0; a < TWO_PI; a+=0.01) {
float r=78;
float x=sin (a);
float y=(pow(cos(a),2)/(2-cos(a)))
my idea was to make a cursor, that moved by the curve, and every tima generated is own tangent.
THANK YOU SO MUCH !!!!!
I recommend to use PVector for the computation.
Create a function which computes a point on the shape:
PVector fSahpe(float a) {
float r = 200;
float x = r * sin(a);
float y = -r *(pow(cos(a),2)/(2-cos(a)));
return new PVector(x, y);
}
You have to find the point on the shape which is closest to the mouse position. Find the nearest point while you draw the shape. Note, since the shape is translated, the mouse position which is used to compare the mouse position to a point on the shape has to be shifted in the opposite direction:
PVector m = new PVector(mouseX-width/2, mouseY-height/2);
dist() can be used to compute the Euclidean distance between 2 points:
float mindist = 1000;
float mina = 0;
for(float a=0; a < TWO_PI; a+=0.01) {
PVector p = fSahpe(a);
// [...]
float dist = PVector.dist(p, m);
if (dist < mindist) {
mindist = dist;
mina = a;
}
}
Define a threshold distance. If the distance of the mouse to the closest point on the curve falls below the distance, the draw the tangent:
if (mindist < 10) {
// [...] draw tangent
}
Compute 2 points on the curve, which are close to each another, where one point is the point which is closest to the mouse cursor:
PVector p0 = fSahpe(mina);
PVector p1 = fSahpe(mina+0.01);
This 2 points ar on the approximated tangent. Compute the vector from on point to the other and scale it to a certain length (the length is the half length of the tangent):
PVector dir = PVector.sub(p1, p0);
dir.normalize().mult(100);
Compute the start point and the end point of the tangent:
PVector l0 = PVector.add(p0, dir);
PVector l1 = PVector.sub(p0, dir);
See the complete example:
void setup() {
size(500, 500);
}
PVector fSahpe(float a) {
float r = 200;
float x = r * sin(a);
float y = -r *(pow(cos(a),2)/(2-cos(a)));
return new PVector(x, y);
}
void draw(){
background(0);
translate(width/2, height/2);
noFill();
strokeWeight(1);
stroke(255);
float mindist = 1000;
float mina = 0;
PVector m = new PVector(mouseX-width/2, mouseY-height/2);
beginShape();
for(float a=0; a < TWO_PI; a+=0.01) {
PVector p = fSahpe(a);
vertex(p.x, p.y);
float dist = PVector.dist(p, m);
if (dist < mindist) {
mindist = dist;
mina = a;
}
}
endShape();
if (mindist < 10) {
PVector p0 = fSahpe(mina);
PVector p1 = fSahpe(mina+0.01);
PVector dir = PVector.sub(p1, p0);
dir.normalize().mult(100);
PVector l0 = PVector.add(p0, dir);
PVector l1 = PVector.sub(p0, dir);
strokeWeight(3);
stroke(255, 0, 0);
line(l0.x, l0.y, l1.x, l1.y);
}
}

3D Baton Circles move around a Sun

How do I use translate and rotate to position spheres and lines on the canvas and also rotate the entire scene with Java Processing?
I need to be able to do this so that I can:
Create a class for a 3D baton which contains two equal size spheres and a line connecting the centers of the two spheres. The Baton class must have the following field variables:
float x, y, z; // the x, y, z coordinates of the center of one baton sphere
// the other baton sphere should be (-x, -y, -z)
float angle; // rotation angle
float speed; //rotational speed
float radius; //radius of the baton sphere
In the main tab of the sketch I need to create a scene that contains the following:
A yellow sphere with radius 50 at the center of the window. The yellow sphere doesn’t move.
6 batons rotating about the y axis passing through the yellow sphere.
Each baton rotates at a random speed between 0.01 and 0.04.
All batons have different distances from the center of the yellow sphere.
The radius of each baton sphere is a random number between 15 and 30.
3D Batons Picture
This is my code:
Baton[] batons;
void setup() {
size(600, 600);
batons = new Baton[4];
for(int i = 0; i < batons.length; i++)
batons[i] = new Baton(100, 100, 100, 45, 2, 25, 2);
}
void draw() {
background(255);
stroke(0);
translate(width/2, height/2);
fill(255, 200, 50);
sphere(50);
for(int i = 0; i < batons.length; i++) {
batons[i].update();
batons[i].display();
}
}
class Baton {
float x;
float y;
float z;
float angle;
float speed;
float radius;
float theta;
Baton(float x, float y, float z, float angle, float speed, float radius, float theta) {
this.x = x;
this.y = y;
this.z = y;
this.angle = angle;
this.speed = speed;
this.radius = radius;
theta = 0;
}
void update() {
theta = theta + speed;
}
void display() {
pushMatrix();
rotate(theta);
translate(radius/2, 0);
fill(51, 51, 51);
noStroke();
sphere(radius);
popMatrix();
line(x, y, -x, -y);
pushMatrix();
rotate(theta);
translate(radius/2, 0);
fill(51, 51, 51);
noStroke();
sphere(radius);
popMatrix();
}
}
The Baton has to go through the Sun that is in the middle. This means that the two circles and the line that connects it has to rotate around the Sun. To explain easier the line will go through the Sun and rotate with the two Circles. See the picture link above.
The main thing that makes your code render differently than the image you have attached is that the Baton objects are placed at the center of the canvas and end up being hidden by the sphere at the center.
Here I have moved the Baton spheres out away from the center and have slowed down the frameRate and speed so that it is easier to see how they are moving.
Baton[] batons;
void setup() {
size(600, 600, P3D);
batons = new Baton[4];
frameRate(1); // slowed down the frame rate to 1 frame per second
for(int i = 0; i < batons.length; i++){
// changed speed from 2 to 0.1 so that the batons move in smaller increments
batons[i] = new Baton(100, 100, 100, 45, 0.1, 25, 2);
}
}
void draw() {
background(255);
stroke(0);
translate(width/2, height/2);
fill(255, 200, 50);
sphere(50);
for(int i = 0; i < batons.length; i++) {
batons[i].update();
batons[i].display();
}
}
class Baton {
float x;
float y;
float z;
float angle;
float speed;
float radius;
float theta;
Baton(float x, float y, float z, float angle, float speed, float radius, float theta) {
this.x = x;
this.y = y;
this.z = y;
this.angle = angle;
this.speed = speed;
this.radius = radius;
theta = 0;
}
void update() {
theta = theta + speed;
}
void display() {
pushMatrix();
// since we want the entire configuration to rotate we will rotate the entire canvas
rotate(theta);
// for a more interesting rotation we could do this instead:
// rotateX(theta);
// rotateY(theta);
// rotateZ(theta);
float distanceBetweenBatonSpheres = radius + 300;
translate(distanceBetweenBatonSpheres/2, 0);
fill(0, 200, 200);
sphere(radius);
// now we undo the previous translate and also move back out to the other side of the central sphere
translate(distanceBetweenBatonSpheres/-1.0, 0);
sphere(radius);
// and finally.. draw a line to connect the two spheres
line(0,0,distanceBetweenBatonSpheres, 0);
popMatrix();
}
}
Notice how we rotate the entire canvas so that the configuration of spheres rotates as a body along with the line that connects the baton spheres.
Also see the comments about making the sketch more interesting by rotating in the x, y and z directions.

Translating horizontally inverted quads

A couple of days ago I asked a question 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.
Thanks to the help of #Rabbid76 I was able to achieve this effect but I am now facing another issue when translating the last 5 top horizontally inverted quads.
When bending the object, the first 3 quads get separated from the last 5 and. 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.
Any suggestion regarding that matter would be also greatly appreciated.
SCRIPT
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();
}
Just providing a workaround to my own question but won't accept it as a valid answer as I don't really understand what I'm doing and it's probably not the most efficient solution.
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) * .3;
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);
}
//Flipping horizontally the last 5 top QUADS
if (i == 3){
scale(-1, 1);
translate(0, PivotHeight);
rotate(-angle*2);
translate(0, PivotHeight);
translate(-xOffset , H/2 - p0[1]);
}
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();
}

"Mirroring" a PShape object (rotation / translation issue) with Processing

I would like to "mirror" a PShape object like in the picture below:
I know how to display multiple shapes and how to invert them (screenshot below) but things get complicated when I have to rotate them (and probably translating them) so as they "stick" to the preceding shapes (first picture).
I've been trying to compute an angle with the first 2 vertices of the original shape (irregular quadrilateral) and the atan2() function but to no avail.
I would really appreciate if someone could help figuring how to solve this problem.
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();
}
To do what you want you have to create a shape by 2 given angles for the top and the bottom of the shape angleT and `angleB´. The origin (0,0) is in the center of the shape. This causes that the pivots for the rotations are in the middle of the slopes of the shape :
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();
}
When you draw the parts, then you should distinguish between even and odd parts. The parts have to be flipped horizontal by inverting the y axis (scale(1, -1)). The even parts have to be rotated by the double of angleB and the odd parts have to be rotated by the doubled of angleT. For the rotation, the center of the slopes (pivots) have to be translated to the origin:
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);
}
}
The algorithm works for any angle, positive and negative including 0.
This algorithm can be further improved. Let's assume you have a quad, defined by 4 points (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();
}
Calculate the the minimum, maximum, centerpoint, pivots and angles:
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]);
Draw the shape like before:
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);
}
Another approach would be to stack the shape on both sides:
For this you have to know the heights of the pivots (HC1, HC2) and the angles (angleB, angleT). So this can be implemented based on both of the above approaches.
Define the pivot points and the directions of the top and bottom edge:
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)
Calculate the intersection point (X) of the both edges. Of course this will work only if the
edges are not parallel:
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) );
The stack algorithm works as follows:
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();
}

Resources