Pinewood Derby Car Center-of-Gravity Visualization

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
}
3 Likes