This sketch was written to provide a visual aid to graphically demonstrate the effect on the center-of-gravity (CG) of a pinewood derby car by the car’s wheelbase (axle separation) and weight distribution between the front and rear axles of the car. The sketch uses some of the basic graphic features available in the Processing software sketchbook and demonstrates their use to create useful screens that display meaningful data and allow for user interaction. This sketch was originally written for use on an iPad using the iOS version of the Processing sketchbook. Some minor changes were required to the code to make it work with Processing3.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* PINEWOOD DERBY CAR CENTER-OF-GRAVITY 8/21/2021 *
* Created by: W. van Leeuwen (BillvsDerbyTimers.weebly.com) *
* *
* This sketch was written to provide a visual aid to graphically demonstrate the effect on the *
* center-of-gravity (CG) of a pinewood derby car by the car’s wheelbase (axle separation) and *
* weight distribution between the front and rear axles of the car. The sketch uses some of the *
* basic graphic features available in the Processing software sketchbook and demonstrates *
* their use to create useful screens that display meaningful data and allow for user *
* interaction. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Variables
int i, j, k, x, y; //Working integer variables
int Rx = 250; //Slider color Red value
int Gx = 250; //Slider color Green value
int Bx = 150; //Slider color Blue value
int Ry = 140; //Page Background color Red value
int Gy = 200; //Page Background color Green value
int By = 230; //Page Background color Blue value
int Axle1_Pos, Axle2_Pos; //Axle position in pixels (1" = 100 pixels)
int CG_Pos, ICG_Pos; //CG & Ideal CG pixel position
int S1pos = 600; //Slider1 position
int S2pos = 600; //Slider2 position
int S3pos = 600; //Slider3 position
boolean Updateflag = false; //True when page update is required
float Scale1_Wt, Scale2_Wt, Total_Wt; //Variables for scale weights in ounces
float Wheelbase, CG, Ideal_CG; //Wheelbase and CG lengths in inches
char[] top = {' ', '1', '1', '3', '1', '5', '3', '7'}; //Fraction display numerator array
char[] bot = {' ', '8', '4', '8', '2', '8', '4', '8'}; //Fraction display denominator array
String Str1; //String variable
//******************************************************************************************
void setup() {
size(1024, 750); //Set display area in pixels
Wheelbase = 4.375; //Set default wheelbase
CG = 0.75; //Set default CG
Ideal_CG = 0.75; //Set default ideal CG
Scale1_Wt = 4.15; //Set default rear axle weight
Scale2_Wt = 0.85; //Set default front axle weight
S1pos = int(map(Wheelbase, 2.0, 7.0, 600, 900)); //Get initial Slider1 position in pixels
S2pos = int(map(Scale1_Wt, 0.0, 9.0, 600, 900)); //Get initial Slider2 position in pixels
S3pos = int(map(Scale2_Wt, 0.0, 9.0, 600, 900)); //Get initial Slider3 position in pixels
Draw_Weight_Page(); //Call sub to draw weight page
Draw_Values(); //Call sub to draw values
Draw_Wheelbase_Slider(); //Call sub to draw wheelbase slider
Draw_Raxle_Wt_Slider(); //Call sub to draw rear axle slider
Draw_Faxle_Wt_Slider(); //Call sub to draw front axle slider
}
//******************************************************************************************
void draw() {
if (mousePressed == true) { //Do if mouse button is pressed
if (mouseX>S1pos-10 && mouseX<S1pos+10 && mouseY>523 && mouseY<543) { //Wheelbase slider?
S1pos = constrain(mouseX, 600, 900); //Get & limit horiz. mouse position
Draw_Wheelbase_Slider(); //Call sub to draw wheelbase slider
Wheelbase = map(S1pos, 600, 900, 2.0, 7.0); //Convert slider position to wheelbase value
Draw_Values(); //Call sub to draw values
}
if (mouseX>S2pos-10 && mouseX<S2pos+10 && mouseY>569 && mouseY<589) { //Rear axle slider?
S2pos = constrain(mouseX, 600, 900); //Get & limit horiz. mouse position
Draw_Raxle_Wt_Slider(); //Call sub to draw rear axle slider
Scale1_Wt = map(S2pos, 600, 900, 0.0, 9.0); //Convert slider position to weight value
Draw_Values(); //Call sub to draw values
}
if (mouseX>S3pos-10 && mouseX<S3pos+10 && mouseY>614 && mouseY<634) { //Front axle slider?
S3pos = constrain(mouseX, 600, 900); //Get & limit horiz. mouse position
Draw_Faxle_Wt_Slider(); //Call sub to draw front axle slider
Scale2_Wt = map(S3pos, 600, 900, 0.0, 9.0); //Convert slider position to weight value
Draw_Values(); //Call sub to draw values
}
}
if (Updateflag) { //Do an update when mouse button is released
Total_Wt = Scale1_Wt + Scale2_Wt; //Calc total weight
CG = Scale2_Wt/Total_Wt * Wheelbase; //Calc CG in inches fwd of rear axle
Draw_Weight_Page(); //Call sub to draw the weight page
Draw_Values(); //Call sub to draw the values
Draw_Wheelbase_Slider(); //Call sub to draw the wheelbase slider
Draw_Raxle_Wt_Slider(); //Call sub to draw the rear axle weight slider
Draw_Faxle_Wt_Slider(); //Call sub to draw the front axle weight slider
Updateflag = false; //Set to false so we don't continually redraw
}
}
//*********************************** SUBROUTINES ******************************************
void Draw_Weight_Page() { //Subroutine - Draw the Weight page
background(Ry, Gy, By); //Clear screen
fill(255, 0, 170); //Set Title color
textAlign(CENTER); //Set text alignment to center
textSize(40); //Set text size to 40 pixels
text("Pinewood Derby Car",512,40); //Display title line 1
textSize(80); //Set text size to 80 pixels
text("WEIGHT & CG",512,120); //Display title line 2
textSize(70); //Set text size to 70 pixels
fill(204, 102, 0); //Set color to burnt orange
quad(162, 150, 162, 275, 862, 275, 862, 250); //Draw car body
Axle1_Pos = 512 - int(Wheelbase/2.0 * 100); //Determine rear axle position in pixels
Axle2_Pos = 512 + int(Wheelbase/2.0 * 100); //Determine front axle position in pixels
Ideal_CG = 0.1714 * Wheelbase; //Calculate ideal CG in inches
ICG_Pos = int(Ideal_CG * 100) + Axle1_Pos; //Determine ideal CG position in pixels
CG_Pos = int(CG * 100) + Axle1_Pos; //Determine actual CG position in pixels
DrawArrow(CG_Pos-25, 300); //Call subroutine to draw arrow
Draw_CGbar(ICG_Pos-37, 280); //Call subroutine to draw ideal CG bar
fill(0,0,0,75); //Set color to black with transparency
ellipse(Axle1_Pos, 265, 118.75, 118.75); //Draw rear wheel at rear axle position
ellipse(Axle2_Pos, 265, 118.75, 118.75); //Draw front wheel at front axle position
fill(255); //Set color to white
ellipse(Axle1_Pos, 265, 20, 20); //Draw rear wheel center axle
ellipse(Axle2_Pos, 265, 20, 20); //Draw front wheel center axle
Draw_Pointer(ICG_Pos+45, 300); //Draw pointer to the CG bar
fill(0); //Set color to black
textSize(30); //Set text size to 30 pixels
textAlign(CENTER); //Set text alignment to center justify
text("Your Car's CG",CG_Pos,450); //Draw text
Str1 = "Position (" + nf(CG,1,3) + "\")"; //Format text string
text(Str1,CG_Pos,490); //Draw text string
textSize(40); //Set text size to 40 pixels
textAlign(LEFT); //Set text alignment to left justify
text("Ideal CG Position",650,400); //Draw text
text("Wheelbase:",5,545); //Draw text
text("Rear Axle Weight:",5,590); //Draw text
text("Front Axle Weight:",5,635); //Draw text
text("Total Weight:",5,680); //Draw text
textSize(20); //Set text size to 20 pixels
text("Note: CG position is in inches measured from rear axle",5,740); //Draw text
}
void Draw_Values() { //Subroutine - Draw values
fill(Ry, Gy, By); //Set background color
noStroke(); //Turn off outline
rect(360, 500, 200, 185); //Clear value draw area
stroke(0); //Restore outline to default
fill(0); //Set color to black
j = int((Wheelbase - int(Wheelbase)) * 1000); //Extract wheelbase fraction
k = int(map(j, 0, 999, 0, 8)); //Convert to a value 0 - 7
textSize(20); //Set text size to 20 pixels
textAlign(LEFT); //Set to left justify
if (k>0) { //Display the fraction?
text(top[k],423,530); //Draw fraction numerator
text(bot[k],440,545); //Draw fraction denominator
line(427, 540, 447, 520); //Draw fraction divisor line
}
textSize(40); //Set text size to 40 pixels
text(int(Wheelbase), 380,545); //Draw integer portion of wheelbase value
if (k>0) text("\"",460,540); //Draw inch symbol
else text("\"",410,540); //Draw alternate inch symbol
text(nf(Scale1_Wt,1,3),380,590); //Draw rear axle weight value
text("oz",500,590); //Draw weight suffix
text(nf(Scale2_Wt,1,3),380,635); //Draw front axle weight value
text("oz",500,635); //Draw weight suffix
fill(255,0,0); //Set color to red
Total_Wt = Scale1_Wt + Scale2_Wt; //Calc total weight
text(nf(Total_Wt,1,3),380,680); //Draw total weight value
text("oz",500,680); //Draw weight suffix
}
void Draw_Wheelbase_Slider() { //Subroutine - Draw wheelbase slider
fill(Ry, Gy, By); //Set slider box color
rect(575, 512, 360, 42); //Draw slider box
line(600, 533, 900, 533); //Draw slider line
fill(Rx, Gx, Bx); //Set slider touch area color
ellipse(S1pos, 533, 20, 20); //Draw horizontal slider touch area
}
void Draw_Raxle_Wt_Slider() { //Subroutine - Draw rear axle slider
fill(Ry, Gy, By); //Set slider box color
rect(575, 558, 360, 42); //Draw slider box
line(600, 579, 900, 579); //Draw slider line
fill(Rx, Gx, Bx); //Set slider touch area color
ellipse(S2pos, 579, 20, 20); //Draw horizontal slider touch area
}
void Draw_Faxle_Wt_Slider() { //Subroutine - Draw front axle slider
fill(Ry, Gy, By); //Set slider box color
rect(575, 603, 360, 42); //Draw slider box
line(600, 624, 900, 624); //Draw slider line
fill(Rx, Gx, Bx); //Set slider touch area color
ellipse(S3pos, 624, 20, 20); //Draw horizontal slider touch area
}
void Draw_CGbar(int x, int y) { //Subroutine - Draw CG color bar
fill(240, 255, 0); //Set color to yellow
rect(x, y, 25, 20); //Draw left rectangle
rect(x+50, y, 25, 20); //Draw right rectangle
fill(0, 255, 0); //Set color to green
rect(x+25, y, 25, 20); //Draw right rectangle
}
void Draw_Pointer(int x, int y) { //Subroutine - Draw pointer
strokeWeight(2); //Set line thickness to 2 pixels
line(x, y, 645, 390); //Draw lines
line(x, y, x+5, y+10);
line(x, y, x+10, y-5);
strokeWeight(1); //Reset line thickness to default
}
void DrawArrow(int x, int y) { //Subroutine - Draw arrow
fill(0, 0, 255); //Set color to blue
triangle(x+25, y, x, y+50, x+50, y+50); //draw arrowhead
rect(x+15, y+50, 20, 60); //draw arrow leg
}
void mouseReleased() { //Subroutine - Mouse Release
Updateflag = true; //Set to true when mouse is released
}