Advertisement
matthewrmata

Functions for Movement Programs

Jan 25th, 2017
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
R 85.67 KB | None | 0 0
  1. ##############################
  2. # PITCHf/x Movement Function #
  3. ##############################
  4.  
  5. PFX_Mvt <- function(PITCH,y_loc){
  6.     # Set gravity
  7.     g <- -32.174;
  8.     # Find the time for the pitch to reach y_loc feet
  9.     a <- 0.5*PITCH$ay;
  10.     b <- PITCH$vy0;
  11.     c_loc <- PITCH$y0 - y_loc;
  12.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  13.     # Find the time for the pitch to reach the front of the plate
  14.     c_plate <- PITCH$y0 - (17/12);
  15.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  16.     # Find the time from 40 feet to the front of the plate
  17.     t_diff <- t_plate - t_loc;
  18.     # Find the movement in the x- and z-directions (in inches)
  19.     pfx_x <- 6*PITCH$ax*t_diff^2;
  20.     pfx_z <- 6*(PITCH$az-g)*t_diff^2;
  21.     # Return the PITCHf/x movement as a vector
  22.     return(c(pfx_x,pfx_z));
  23. }
  24.  
  25. #######################################
  26. # PITCHf/x Movement with Drag Removed #
  27. #######################################
  28.  
  29. PFX_Mvt_Drag <- function(PITCH,y_loc){
  30.     # Set gravity
  31.     g <- -32.174;
  32.     G <- c(0,0,g);
  33.     # Find the time for the pitch to reach 40 feet
  34.     a <- 0.5*PITCH$ay;
  35.     b <- PITCH$vy0;
  36.     c_loc <- PITCH$y0 - y_loc;
  37.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  38.     # Find the time for the pitch to reach the front of the plate
  39.     c_plate <- PITCH$y0 - (17/12);
  40.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  41.     # Find the time from y_loc feet to the front of the plate
  42.     t_diff <- t_plate - t_loc;
  43.     # Find the velocity at 40 feet
  44.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  45.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  46.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  47.     # Find the velocity at the front of the plate
  48.     vx_plate <- PITCH$vx0 + PITCH$ax*t_plate;
  49.     vy_plate <- PITCH$vy0 + PITCH$ay*t_plate;
  50.     vz_plate <- PITCH$vz0 + PITCH$az*t_plate;
  51.     # Find the average velocity
  52.     vx_avg <- (vx_loc + vx_plate)/2;
  53.     vy_avg <- (vy_loc + vy_plate)/2;
  54.     vz_avg <- (vz_loc + vz_plate)/2;
  55.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  56.     # Set the average velocity and acceleration vectors
  57.     V <- c(vx_avg,vy_avg,vz_avg);
  58.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  59.     # Normalize the velocity vector
  60.     V_norm <- V/sqrt(V%*%V);
  61.     # Find the drag vector
  62.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  63.     # Find the acceleration with drag removed
  64.     ax_d <- PITCH$ax - Drag[1];
  65.     az_d <- PITCH$az - Drag[3];
  66.     # Find the movement without drag
  67.     m_x <- 6*ax_d*t_diff^2;
  68.     m_z <- 6*(az_d-g)*t_diff^2;
  69.     # Return the movement without drag as a vector
  70.     return(c(m_x,m_z));
  71. }
  72.  
  73. ##########################
  74. # Planar Movement (in w) #
  75. ##########################
  76.  
  77. W_Mvt <- function(PITCH,y_loc){
  78.     # Set gravity
  79.     G <- c(0,0,-32.174);
  80.     # Find the time for the pitch to reach y_loc feet in (x,y,z)-space
  81.     a <- 0.5*PITCH$ay;
  82.     b <- PITCH$vy0;
  83.     c_loc <- PITCH$y0 - y_loc;
  84.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  85.     # Find the time for the pitch to reach the front of the plate in (x,y,z)-space
  86.     c_plate <- PITCH$y0 - (17/12);
  87.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  88.     # Find the time from 40 feet to the front of the plate
  89.     t_diff <- t_plate - t_loc;
  90.     # Find the PITCHf/x basis
  91.     BV <- PFX_Basis(PITCH);
  92.     # Transpose the matrix
  93.     BV_T <- t(BV);
  94.     # Find the w-acceleration of the pitch
  95.     aw <- BV_T[3,] %*% c(PITCH$ax,PITCH$ay,PITCH$az);
  96.     # Find the contribution of gravity in the w-direction
  97.     gw <- BV_T[3,] %*% G;
  98.     # Return the in-plane movement
  99.     return((6*(aw-gw)*t_diff^2)*c(BV_T[3,1],BV_T[3,3]));
  100. }
  101.  
  102. ############################################
  103. # Planar Movement (in w) with Drag Removed #
  104. ############################################
  105.  
  106. W_Mvt_Drag <- function(PITCH,y_loc){
  107.     # Set gravity
  108.     G <- c(0,0,-32.174);
  109.     # Find the time for the pitch to reach y_loc feet in (x,y,z)-space
  110.     a <- 0.5*PITCH$ay;
  111.     b <- PITCH$vy0;
  112.     c_loc <- PITCH$y0 - y_loc;
  113.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  114.     # Find the time for the pitch to reach the front of the plate in (x,y,z)-space
  115.     c_plate <- PITCH$y0 - (17/12);
  116.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  117.     # Find the time from y_loc feet to the front of the plate
  118.     t_diff <- t_plate - t_loc;
  119.     # Find the velocity at 40 feet
  120.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  121.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  122.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  123.     # Find the velocity at the front of the plate
  124.     vx_plate <- PITCH$vx0 + PITCH$ax*t_plate;
  125.     vy_plate <- PITCH$vy0 + PITCH$ay*t_plate;
  126.     vz_plate <- PITCH$vz0 + PITCH$az*t_plate;
  127.     # Find the average velocity
  128.     vx_avg <- (vx_loc + vx_plate)/2;
  129.     vy_avg <- (vy_loc + vy_plate)/2;
  130.     vz_avg <- (vz_loc + vz_plate)/2;
  131.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  132.     # Set the average velocity and acceleration vectors
  133.     V <- c(vx_avg,vy_avg,vz_avg);
  134.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  135.     # Normalize the velocity vector
  136.     V_norm <- V/sqrt(V%*%V);
  137.     # Find the drag vector
  138.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  139.     # Find the PITCHf/x basis
  140.     BV <- PFX_Basis(PITCH);
  141.     # Transpose the matrix
  142.     BV_T <- t(BV);
  143.     # Find the w-acceleration of the pitch
  144.     aw <- BV_T[3,] %*% c(PITCH$ax,PITCH$ay,PITCH$az);
  145.     # Find the w-drag
  146.     drag_w <- BV_T[3,] %*% Drag;
  147.     # Find the contribution of gravity in the w-direction
  148.     gw <- BV_T[3,] %*% G;
  149.     # Find the w-acceleration without drag
  150.     aw_d <- aw - drag_w;
  151.     # Return the in-plane movement without drag
  152.     return((6*(aw_d-gw)*t_diff^2)*c(BV_T[3,1],BV_T[3,3]));
  153. }
  154.  
  155. ##########################
  156. # PITCHf/x Movement Norm #
  157. ##########################
  158.  
  159. PFX_Mvt_Norm <- function(PITCH,y_loc){
  160.     # Set gravity
  161.     g <- -32.174;
  162.     # Find the time for the pitch to reach y_loc feet
  163.     a <- 0.5*PITCH$ay;
  164.     b <- PITCH$vy0;
  165.     c_loc <- PITCH$y0 - y_loc;
  166.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  167.     # Find the time for the pitch to reach the front of the plate
  168.     c_plate <- PITCH$y0 - (17/12);
  169.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  170.     # Find the time from 40 feet to the front of the plate
  171.     t_diff <- t_plate - t_loc;
  172.     # Find the movement in the x- and z-directions (in inches)
  173.     pfx_x <- 6*PITCH$ax*t_diff^2;
  174.     pfx_z <- 6*(PITCH$az-g)*t_diff^2;
  175.     # Return the PITCHf/x movement as a vector
  176.     return(sqrt(pfx_x^2 + pfx_z^2));
  177. }
  178.  
  179. #############################################
  180. # PITCHf/x Movement Norm with Drag Removed  #
  181. #############################################
  182.  
  183. PFX_Mvt_Drag_Norm <- function(PITCH,y_loc){
  184.     # Set gravity
  185.     g <- -32.174;
  186.     G <- c(0,0,g);
  187.     # Find the time for the pitch to reach 40 feet
  188.     a <- 0.5*PITCH$ay;
  189.     b <- PITCH$vy0;
  190.     c_loc <- PITCH$y0 - y_loc;
  191.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  192.     # Find the time for the pitch to reach the front of the plate
  193.     c_plate <- PITCH$y0 - (17/12);
  194.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  195.     # Find the time from y_loc feet to the front of the plate
  196.     t_diff <- t_plate - t_loc;
  197.     # Find the velocity at 40 feet
  198.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  199.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  200.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  201.     # Find the velocity at the front of the plate
  202.     vx_plate <- PITCH$vx0 + PITCH$ax*t_plate;
  203.     vy_plate <- PITCH$vy0 + PITCH$ay*t_plate;
  204.     vz_plate <- PITCH$vz0 + PITCH$az*t_plate;
  205.     # Find the average velocity
  206.     vx_avg <- (vx_loc + vx_plate)/2;
  207.     vy_avg <- (vy_loc + vy_plate)/2;
  208.     vz_avg <- (vz_loc + vz_plate)/2;
  209.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  210.     # Set the average velocity and acceleration vectors
  211.     V <- c(vx_avg,vy_avg,vz_avg);
  212.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  213.     # Normalize the velocity vector
  214.     V_norm <- V/sqrt(V%*%V);
  215.     # Find the drag vector
  216.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  217.     # Find the acceleration with drag removed
  218.     ax_d <- PITCH$ax - Drag[1];
  219.     az_d <- PITCH$az - Drag[3];
  220.     # Find the movement without drag
  221.     m_x <- 6*ax_d*t_diff^2;
  222.     m_z <- 6*(az_d-g)*t_diff^2;
  223.     # Return the movement without drag as a vector
  224.     return(sqrt(m_x^2 + m_z^2));
  225. }
  226.  
  227. ###############################
  228. # Planar Movement Norm (in w) #
  229. ###############################
  230.  
  231. W_Mvt_Norm <- function(PITCH,y_loc){
  232.     # Set gravity
  233.     G <- c(0,0,-32.174);
  234.     # Find the time for the pitch to reach y_loc feet in (x,y,z)-space
  235.     a <- 0.5*PITCH$ay;
  236.     b <- PITCH$vy0;
  237.     c_loc <- PITCH$y0 - y_loc;
  238.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  239.     # Find the time for the pitch to reach the front of the plate in (x,y,z)-space
  240.     c_plate <- PITCH$y0 - (17/12);
  241.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  242.     # Find the time from 40 feet to the front of the plate
  243.     t_diff <- t_plate - t_loc;
  244.     # Find the PITCHf/x basis
  245.     BV <- PFX_Basis(PITCH);
  246.     # Transpose the matrix
  247.     BV_T <- t(BV);
  248.     # Find the w-acceleration of the pitch
  249.     aw <- BV_T[3,] %*% c(PITCH$ax,PITCH$ay,PITCH$az);
  250.     # Find the contribution of gravity in the w-direction
  251.     gw <- BV_T[3,] %*% G;
  252.     # Return the in-plane movement
  253.     return(6*(aw-gw)*t_diff^2);
  254. }
  255.  
  256. #################################################
  257. # Planar Movement Norm (in w) with Drag Removed #
  258. #################################################
  259.  
  260. W_Mvt_Drag_Norm <- function(PITCH,y_loc){
  261.     # Set gravity
  262.     G <- c(0,0,-32.174);
  263.     # Find the time for the pitch to reach y_loc feet in (x,y,z)-space
  264.     a <- 0.5*PITCH$ay;
  265.     b <- PITCH$vy0;
  266.     c_loc <- PITCH$y0 - y_loc;
  267.     t_loc <- (-b - sqrt(b^2 - 4*a*c_loc))/(2*a);
  268.     # Find the time for the pitch to reach the front of the plate in (x,y,z)-space
  269.     c_plate <- PITCH$y0 - (17/12);
  270.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  271.     # Find the time from y_loc feet to the front of the plate
  272.     t_diff <- t_plate - t_loc;
  273.     # Find the velocity at 40 feet
  274.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  275.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  276.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  277.     # Find the velocity at the front of the plate
  278.     vx_plate <- PITCH$vx0 + PITCH$ax*t_plate;
  279.     vy_plate <- PITCH$vy0 + PITCH$ay*t_plate;
  280.     vz_plate <- PITCH$vz0 + PITCH$az*t_plate;
  281.     # Find the average velocity
  282.     vx_avg <- (vx_loc + vx_plate)/2;
  283.     vy_avg <- (vy_loc + vy_plate)/2;
  284.     vz_avg <- (vz_loc + vz_plate)/2;
  285.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  286.     # Set the average velocity and acceleration vectors
  287.     V <- c(vx_avg,vy_avg,vz_avg);
  288.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  289.     # Normalize the velocity vector
  290.     V_norm <- V/sqrt(V%*%V);
  291.     # Find the drag vector
  292.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  293.     # Find the PITCHf/x basis
  294.     BV <- PFX_Basis(PITCH);
  295.     # Transpose the matrix
  296.     BV_T <- t(BV);
  297.     # Find the w-acceleration of the pitch
  298.     aw <- BV_T[3,] %*% c(PITCH$ax,PITCH$ay,PITCH$az);
  299.     # Find the w-drag
  300.     drag_w <- BV_T[3,] %*% Drag;
  301.     # Find the contribution of gravity in the w-direction
  302.     gw <- BV_T[3,] %*% G;
  303.     # Find the w-acceleration without drag
  304.     aw_d <- aw - drag_w;
  305.     # Return the in-plane movement without drag
  306.     return(6*(aw_d-gw)*t_diff^2);
  307. }
  308.  
  309. ###################
  310. # Binormal Vector #
  311. ###################
  312.  
  313. Binormal_Vector <- function(PITCH){
  314.     # Set the velocity vector
  315.     V <- c(PITCH$vx0,PITCH$vy0,PITCH$vz0);
  316.     # Set the acceleration vector
  317.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  318.     # Find the cross product of velocity and acceleration
  319.     V_x_A <- c(V[2]*A[3] - V[3]*A[2],V[3]*A[1] - V[1]*A[3],V[1]*A[2] - V[2]*A[1]);
  320.     # Find the magnitude of the cross product
  321.     V_x_A_norm <- sqrt(V_x_A[1]^2 + V_x_A[2]^2 + V_x_A[3]^2);
  322.     # Normalize the cross product to get the binormal vector
  323.     return(V_x_A/V_x_A_norm);
  324. }
  325.    
  326. ##################
  327. # PITCHf/x Basis #
  328. ##################
  329.  
  330. PFX_Basis <- function(PITCH){
  331.     # Find the binormal vector
  332.     V1 <- Binormal_Vector(PITCH);
  333.     # Find a unit vector in the general direction toward home plate
  334.     V2 <- sign(V1[1])*c(-V1[2],V1[1],0)/sqrt(V1[1]^2 + V1[2]^2);
  335.     # Find a unit vector perpendicular to both previous vectors
  336.     V3 <- sign(V1[1]*V2[2]-V1[2]*V2[1])*c(-V1[3]*V2[2],V1[3]*V2[1],V1[1]*V2[2]-V1[2]*V2[1]);
  337.     V3 <- V3/sqrt(V3[1]^2 + V3[2]^2 + V3[3]^2);
  338.     # Store the vectors in an array
  339.     V <- array(0,dim=c(3,3));
  340.     V[,1] <- V1;
  341.     V[,2] <- V2;
  342.     V[,3] <- V3;
  343.     return(V);
  344. }
  345.  
  346. ###################################################
  347. # Minimum Distance from a Point to a Line Segment #
  348. ###################################################
  349.  
  350. Dist_Seg <- function(P,P0,P1){
  351.     # Form a vector between the endpoints of the segments
  352.     v = P1 - P0;
  353.     # Form another vector between the point and one end of the segment
  354.     w = P - P0;
  355.     # Find the dot product between the two vectors
  356.     c1 = v[1]*w[1] + v[2]*w[2];
  357.     # Find the squared length of the line segment
  358.     c2 = v[1]*v[1] + v[2]*v[2];
  359.     # If c1 is less than or equal to zero, then the closest point on the line is the first endpoint
  360.     if ( c1 <= 0 ){
  361.     # Find the distance between the points
  362.         d <- Dist_Min(P,P0);
  363.         return(d);
  364.     # If c2 is less than or equal to c1, then the closest point on the line is the second endpoint
  365.     } else if( c2 <= c1 ){
  366.     # Find the distance between the points
  367.         d <- Dist_Min(P,P1);
  368.         return(d);
  369.     # Else, the closest point on the line is in the middle
  370.     } else {
  371.         b = c1/c2;
  372.         Pb = P0 + b*v;
  373.     # Find the distance between the points
  374.         d <- Dist_Min(P,Pb);
  375.         return(d);
  376.       }
  377. }
  378.  
  379. ##################################################
  380. # Location of a Pitch Relative to a Line Segment #
  381. ##################################################
  382.  
  383. Loc_Seg <- function(P,P0,P1){
  384.     # Form a vector between the endpoints of the segments
  385.     v = P1 - P0;
  386.     # Form another vector between the point and one end of the segment
  387.     w = P - P0;
  388.     # Find the dot product between the two vectors
  389.     c1 = v[1]*w[1] + v[2]*w[2];
  390.     # Find the squared length of the line segment
  391.     c2 = v[1]*v[1] + v[2]*v[2];
  392.     # If c1 is less than or equal to zero, then the closest point on the line is the first endpoint
  393.     if ( c1 <= 0 ){
  394.     # Find the distance between the points
  395.         d <- Dist_Min(P,P0);
  396.         return(list(d=d,Pc=P0));
  397.     # If c2 is less than or equal to c1, then the closest point on the line is the second endpoint
  398.     } else if( c2 <= c1 ){
  399.     # Find the distance between the points
  400.         d <- Dist_Min(P,P1);
  401.         return(list(d=d,Pc=P1));
  402.     # Else, the closest point on the line is in the middle
  403.     } else {
  404.         b = c1/c2;
  405.         Pb = P0 + b*v;
  406.     # Find the distance between the points
  407.         d <- Dist_Min(P,Pb);
  408.         return(list(d=d,Pc=Pb));
  409.       }
  410. }
  411.  
  412. ###############################
  413. # Distance Between Two Points #
  414. ###############################
  415.  
  416. Dist_Min <- function(P0,P1){
  417.     d <- sqrt((P1[1]-P0[1])^2 + (P1[2]-P0[2])^2);
  418.     return(d);
  419. }
  420.  
  421. #########################################################################
  422. # Minimum Distance Between and Point and the Outside of a Quadrilateral #
  423. #########################################################################
  424.  
  425. Min_Dist_Quad <- function(P,UL,UR,LL,LR){
  426.     # Distance from the top of the quadrilateral
  427.     d_top <- Dist_Seg(P,UL,UR);
  428.     m_top <- (UR[2]-UL[2])/(UR[1]-UL[1]);
  429.     b_top <- UR[2] - m_top*UR[1];
  430.     y_top <- m_top*P[1] + b_top;
  431.     sign_top <- sign(P[2]-y_top);
  432.     # Distance from the bottom of the quadrilateral
  433.     d_bottom <- Dist_Seg(P,LL,LR);
  434.     m_bottom <- (LR[2]-LL[2])/(LR[1]-LL[1]);
  435.     b_bottom <- LR[2] - m_bottom*LR[1];
  436.     y_bottom <- m_bottom*P[1] + b_bottom;
  437.     sign_bottom <- sign(y_bottom-P[2]);
  438.     # Distance from the left of the quadrilateral
  439.     d_left <- Dist_Seg(P,UL,LL);
  440.     m_left <- (UL[1]-LL[1])/(UL[2]-LL[2]);
  441.     b_left <- UL[1] - m_left*UL[2];
  442.     x_left <- m_left*P[2] + b_left;
  443.     sign_left <- sign(x_left-P[1]);
  444.     # Distance from the right of the quadrilateral
  445.     d_right <- Dist_Seg(P,UR,LR);
  446.     m_right <- (UR[1]-LR[1])/(UR[2]-LR[2]);
  447.     b_right <- UR[1] - m_right*UR[2];
  448.     x_right <- m_right*P[2] + b_right;
  449.     sign_right <- sign(P[1]-x_right);
  450.     # Find the minimum distance from the outside of the quadrilateral (Inside = 0)
  451.     if ( (sign_top < 0) && (sign_bottom < 0) && (sign_left < 0) && (sign_right < 0) ){
  452.         d_min <- 0;
  453.     } else {
  454.         d_min <- min(d_top,d_bottom,d_left,d_right);
  455.     }
  456.     return(d_min);
  457. }
  458.  
  459. ################################################################
  460. # Direction Between a Point and the Outside of a Quadrilateral #
  461. ################################################################
  462.  
  463. Dir_Quad <- function(P,UL,UR,LL,LR){
  464.     # Distance from the top of the quadrilateral
  465.     P_top <- Loc_Seg(P,UL,UR);
  466.     m_top <- (UR[2]-UL[2])/(UR[1]-UL[1]);
  467.     b_top <- UR[2] - m_top*UR[1];
  468.     y_top <- m_top*P[1] + b_top;
  469.     sign_top <- sign(P[2]-y_top);
  470.     P_dir <- P - P_top$Pc;
  471.     P_dist <- P_top$d;
  472.     # Distance from the bottom of the quadrilateral
  473.     P_bottom <- Loc_Seg(P,LL,LR);
  474.     m_bottom <- (LR[2]-LL[2])/(LR[1]-LL[1]);
  475.     b_bottom <- LR[2] - m_bottom*LR[1];
  476.     y_bottom <- m_bottom*P[1] + b_bottom;
  477.     sign_bottom <- sign(y_bottom-P[2]);
  478.     if (P_dist > P_bottom$d){
  479.         P_dir <- P - P_bottom$Pc;
  480.     }
  481.     # Distance from the left of the quadrilateral
  482.     P_left <- Loc_Seg(P,UL,LL);
  483.     m_left <- (UL[1]-LL[1])/(UL[2]-LL[2]);
  484.     b_left <- UL[1] - m_left*UL[2];
  485.     x_left <- m_left*P[2] + b_left;
  486.     sign_left <- sign(x_left-P[1]);
  487.     if (P_dist > P_left$d){
  488.         P_dir <- P - P_left$Pc;
  489.     }
  490.     # Distance from the right of the quadrilateral
  491.     P_right <- Loc_Seg(P,UR,LR);
  492.     m_right <- (UR[1]-LR[1])/(UR[2]-LR[2]);
  493.     b_right <- UR[1] - m_right*UR[2];
  494.     x_right <- m_right*P[2] + b_right;
  495.     sign_right <- sign(P[1]-x_right);
  496.     if (P_dist > P_right$d){
  497.         P_dir <- P - P_right$Pc;
  498.     }
  499.     # Find the minimum distance from the outside of the quadrilateral (Inside = 0)
  500.     if ( (sign_top < 0) && (sign_bottom < 0) && (sign_left < 0) && (sign_right < 0) ){
  501.         P_dir <- c(0,0);
  502.     }
  503.     return(P_dir);
  504. }
  505.  
  506. ######################################
  507. # Find the Zone Containing the Pitch #
  508. ######################################
  509.  
  510. Zone_Quad <- function(P,UL,UR,LL,LR){
  511.     # Distance from the top of the quadrilateral
  512.     d_top <- Dist_Seg(P,UL,UR);
  513.     m_top <- (UR[2]-UL[2])/(UR[1]-UL[1]);
  514.     b_top <- UR[2] - m_top*UR[1];
  515.     y_top <- m_top*P[1] + b_top;
  516.     sign_top <- sign(P[2]-y_top);
  517.     # Distance from the bottom of the quadrilateral
  518.     d_bottom <- Dist_Seg(P,LL,LR);
  519.     m_bottom <- (LR[2]-LL[2])/(LR[1]-LL[1]);
  520.     b_bottom <- LR[2] - m_bottom*LR[1];
  521.     y_bottom <- m_bottom*P[1] + b_bottom;
  522.     sign_bottom <- sign(y_bottom-P[2]);
  523.     # Distance from the left of the quadrilateral
  524.     d_left <- Dist_Seg(P,UL,LL);
  525.     m_left <- (UL[1]-LL[1])/(UL[2]-LL[2]);
  526.     b_left <- UL[1] - m_left*UL[2];
  527.     x_left <- m_left*P[2] + b_left;
  528.     sign_left <- sign(x_left-P[1]);
  529.     # Distance from the right of the quadrilateral
  530.     d_right <- Dist_Seg(P,UR,LR);
  531.     m_right <- (UR[1]-LR[1])/(UR[2]-LR[2]);
  532.     b_right <- UR[1] - m_right*UR[2];
  533.     x_right <- m_right*P[2] + b_right;
  534.     sign_right <- sign(P[1]-x_right);
  535.     # Find the minimum distance from the outside of the quadrilateral (Inside = 0)
  536.     if ( (sign_top < 0) && (sign_bottom < 0) && (sign_left < 0) && (sign_right < 0) ){
  537.         d_min <- 0;
  538.     } else {
  539.         d_min <- min(d_top,d_bottom,d_left,d_right);
  540.     }
  541.     if (d_min <= (log(2)/4)^(1/4)){
  542.         Zone <- 5;
  543.         return(Zone)
  544.     } else {
  545.         if (sign_top > 0){
  546.             Zone <- 0;
  547.         } else if (sign_bottom > 0){
  548.             Zone <- 6;
  549.         } else {
  550.             Zone <- 3;
  551.         }
  552.         if (sign_left > 0){
  553.             Zone <- Zone + 1;
  554.         } else if (sign_right > 0){
  555.             Zone <- Zone + 3;
  556.         } else {
  557.             Zone <- Zone + 2;
  558.         }
  559.         return(Zone);
  560.     }
  561. }
  562.  
  563. ##########################################
  564. # Angle (in Degrees) Between Two Vectors #
  565. ##########################################
  566.  
  567. Dot_Prod_Angle <- function(V1,V2){
  568.     # Find the dot product of the two vectors
  569.     V1dotV2 <- V1 %*% V2;
  570.     # Find the length of the two vectors
  571.     V1_norm <- sqrt(V1 %*% V1);
  572.     V2_norm <- sqrt(V2 %*% V2);
  573.     # Return the angle, in degrees, between the two vectors
  574.     return((180/pi)*acos(V1dotV2/(V1_norm*V2_norm)));
  575. }
  576.  
  577. ###################################################
  578. # Strike Zone Probability Based on Location (LHB) #
  579. ###################################################
  580.  
  581. Dist_LHB_Quad <- function(P){
  582.     # Define the four corners of the strike zone core (2016)
  583.     UL <- c(-0.47,2.85);
  584.     UR <- c(0.22,2.87);
  585.     LL <- c(-0.5,2.04);
  586.     LR <- c(0.24,2.16);
  587.     # Find the distance from the pitch location to the core
  588.     xz_dist <- Min_Dist_Quad(P,UL,UR,LL,LR);
  589.     # Find the strike probability
  590.     strike_prob <- exp(-4*xz_dist^4);
  591.     return(strike_prob);
  592. }
  593.  
  594. ###################################################
  595. # Strike Zone Probability Based on Location (RHB) #
  596. ###################################################
  597.  
  598. Dist_RHB_Quad <- function(P){
  599.     # Define the four corners of the strike zone core (2016)
  600.     UL <- c(-0.38,2.88);
  601.     UR <- c(0.35,2.81);
  602.     LL <- c(-0.46,2.1);
  603.     LR <- c(0.35,2.09);
  604.     # Find the distance from the pitch location to the core
  605.     xz_dist <- Min_Dist_Quad(P,UL,UR,LL,LR);
  606.     # Find the strike probability
  607.     strike_prob <- exp(-4*xz_dist^4);
  608.     return(strike_prob);
  609. }
  610.  
  611. ###################################################################################
  612. # Track the projected strike probability with remaining PITCHf/x movement removed #
  613. ###################################################################################
  614.  
  615. Pitch_Track_PFX <- function(PITCHES,Ny,stand){
  616.     g <- -32.174;
  617.     Np <- length(PITCHES$x0);
  618.     x0 <- PITCHES$x0;
  619.     y0 <- PITCHES$y0;
  620.     z0 <- PITCHES$z0;
  621.     vx0 <- PITCHES$vx0;
  622.     vy0 <- PITCHES$vy0;
  623.     vz0 <- PITCHES$vz0;
  624.     ax <- PITCHES$ax;
  625.     ay <- PITCHES$ay;
  626.     az <- PITCHES$az;
  627.     y_seq <- seq(55,17/12,length=Ny);
  628.     Proj_Prb <- array(0,dim=c(Np,Ny));
  629.     for (i in 1:Np){
  630.         # Find the time to the front of home plate
  631.         a <- 0.5*ay[i];
  632.         b <- vy0[i];
  633.         c_plate <- y0[i]-(17/12);
  634.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  635.         # Set a list for the 9 PITCHf/x parameters
  636.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  637.         # Loop over the y-slices
  638.         for (j in 1:Ny){
  639.             c_inc <- y0[i]-y_seq[j];
  640.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  641.             p_xz <- PFX_Calc(PITCH,t_inc,t_plate);
  642.             # Calculate the probability that the projected pitch is a strike
  643.             if (stand == 'L'){
  644.                 strike_prob <- Dist_LHB_Quad(p_xz);
  645.             }
  646.             else {
  647.                 strike_prob <- Dist_RHB_Quad(p_xz);
  648.             }
  649.             Proj_Prb[i,Ny-j+1] <- strike_prob;
  650.         }
  651.     }
  652.     return(Proj_Prb);
  653. }
  654.  
  655. #####################################################################################################
  656. # Track the projected strike probability with remaining PITCHf/x movement removed but drag added in #
  657. #####################################################################################################
  658.  
  659. Pitch_Track_PFX_Drag <- function(PITCHES,Ny,stand){
  660.     Np <- length(PITCHES$x0);
  661.     x0 <- PITCHES$x0;
  662.     y0 <- PITCHES$y0;
  663.     z0 <- PITCHES$z0;
  664.     vx0 <- PITCHES$vx0;
  665.     vy0 <- PITCHES$vy0;
  666.     vz0 <- PITCHES$vz0;
  667.     ax <- PITCHES$ax;
  668.     ay <- PITCHES$ay;
  669.     az <- PITCHES$az;
  670.     y_seq <- seq(55,17/12,length=Ny);
  671.     Proj_Prb <- array(0,dim=c(Np,Ny));
  672.     for (i in 1:Np){
  673.         # Find the time to the front of home plate
  674.         a <- 0.5*ay[i];
  675.         b <- vy0[i];
  676.         c_plate <- y0[i]-(17/12);
  677.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  678.         # Find the velocity at the front of the plate
  679.         vx_plate <- ax[i]*t_plate + vx0[i];
  680.         vy_plate <- ay[i]*t_plate + vy0[i];
  681.         vz_plate <- az[i]*t_plate + vz0[i];
  682.         v_plate <- list(x=vx_plate, y=vy_plate, z=vz_plate);
  683.         # Set a list for the 9 PITCHf/x parameters
  684.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  685.         # Loop over the y-slices
  686.         for (j in 1:Ny){
  687.             c_inc <- y0[i]-y_seq[j];
  688.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  689.             p_xz <- PFX_Drag_Calc(PITCH,t_inc,t_plate,v_plate);
  690.             # Calcuate the probability that the projected pitch is a strike
  691.             if (stand == 'L'){
  692.                 strike_prob <- Dist_LHB_Quad(p_xz);
  693.             }
  694.             else {
  695.                 strike_prob <- Dist_RHB_Quad(p_xz);
  696.             }
  697.             Proj_Prb[i,Ny-j+1] <- strike_prob;
  698.         }
  699.     }
  700.     return(Proj_Prb);
  701. }
  702.  
  703. ###################################################################################
  704. # Track the planar projected strike probability with remaining w-movement removed #
  705. ###################################################################################
  706.  
  707. Pitch_Track_W <- function(PITCHES,Ny,stand){
  708.     Np <- length(PITCHES$x0);
  709.     x0 <- PITCHES$x0;
  710.     y0 <- PITCHES$y0;
  711.     z0 <- PITCHES$z0;
  712.     vx0 <- PITCHES$vx0;
  713.     vy0 <- PITCHES$vy0;
  714.     vz0 <- PITCHES$vz0;
  715.     ax <- PITCHES$ax;
  716.     ay <- PITCHES$ay;
  717.     az <- PITCHES$az;
  718.     y_seq <- seq(55,17/12,length=Ny);
  719.     Proj_Prb <- array(0,dim=c(Np,Ny));
  720.     for (i in 1:Np){
  721.         # Find the time to the front of home plate
  722.         a <- 0.5*ay[i];
  723.         b <- vy0[i];
  724.         c_plate <- y0[i]-(17/12);
  725.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  726.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  727.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  728.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  729.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  730.         # Set up a list containing the parameters of the pitch
  731.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  732.         BV <- PFX_Basis(PITCH);
  733.         BV_T = t(BV);
  734.         # Find the u and b coordinates of the pitch at the front of the plate
  735.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  736.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  737.         # Loop over the y-slices
  738.         for (j in 1:Ny){
  739.             c_inc <- y0[i]-y_seq[j];
  740.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  741.             p_xz <- W_Calc(PITCH,BV_T,t_inc,t_plate,b_plate,u_plate);
  742.             if (stand == 'L'){
  743.                 strike_prob <- Dist_LHB_Quad(p_xz);
  744.             }
  745.             else {
  746.                 strike_prob <- Dist_RHB_Quad(p_xz);
  747.             }
  748.             Proj_Prb[i,Ny-j+1] <- strike_prob;
  749.         }
  750.     }
  751.     return(Proj_Prb);
  752. }
  753.  
  754. ##########################################################################################################
  755. # Track the planar projected strike probability with remaining planar movement removed but drag added in #
  756. ##########################################################################################################
  757.  
  758. Pitch_Track_W_Drag <- function(PITCHES,Ny,stand){
  759.     g <- -32.174;
  760.     G <- c(0,0,g);
  761.     Np <- length(PITCHES$x0);
  762.     x0 <- PITCHES$x0;
  763.     y0 <- PITCHES$y0;
  764.     z0 <- PITCHES$z0;
  765.     vx0 <- PITCHES$vx0;
  766.     vy0 <- PITCHES$vy0;
  767.     vz0 <- PITCHES$vz0;
  768.     ax <- PITCHES$ax;
  769.     ay <- PITCHES$ay;
  770.     az <- PITCHES$az;
  771.     y_seq <- seq(55,17/12,length=Ny);
  772.     Proj_Prb <- array(0,dim=c(Np,Ny));
  773.     for (i in 1:Np){
  774.         # Find the time to the front of home plate
  775.         a <- 0.5*ay[i];
  776.         b <- vy0[i];
  777.         c_plate <- y0[i]-(17/12);
  778.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  779.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  780.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  781.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  782.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  783.         plate_xz <- c(x_plate,z_plate);
  784.         # Find the velocity at the front of the plate
  785.         vx_plate <- ax[i]*t_plate + vx0[i];
  786.         vy_plate <- ay[i]*t_plate + vy0[i];
  787.         vz_plate <- az[i]*t_plate + vz0[i];
  788.         v_plate <- list(x=vx_plate, y=vy_plate, z=vz_plate);
  789.         # Set up a list containing the parameters of the pitch
  790.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  791.         BV <- PFX_Basis(PITCH);
  792.         BV_T = t(BV);
  793.         # Find the u and b coordinates of the pitch at the front of the plate
  794.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  795.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  796.         # Set the acceleration vector
  797.         A <- c(ax[i],ay[i],az[i]);
  798.         # Loop over the y-slices
  799.         for (j in 1:Ny){
  800.             c_inc <- y0[i]-y_seq[j];
  801.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  802.             p_xz <- W_Drag_Calc(PITCH,BV_T,t_inc,t_plate,v_plate,b_plate,u_plate);
  803.             if (stand == 'L'){
  804.                 strike_prob <- Dist_LHB_Quad(p_xz);
  805.             }
  806.             else {
  807.                 strike_prob <- Dist_RHB_Quad(p_xz);
  808.             }
  809.             Proj_Prb[i,Ny-j+1] <- strike_prob;
  810.         }
  811.     }
  812.     return(Proj_Prb);
  813. }
  814.  
  815. ###############################################################
  816. # Determine a ball or strike based on strike zone probability #
  817. ###############################################################
  818.  
  819. ball_strike_prob <- function(PITCHES,stand){
  820.     Np <- length(PITCHES$x0);
  821.     x0 <- PITCHES$x0;
  822.     y0 <- PITCHES$y0;
  823.     z0 <- PITCHES$z0;
  824.     vx0 <- PITCHES$vx0;
  825.     vy0 <- PITCHES$vy0;
  826.     vz0 <- PITCHES$vz0;
  827.     ax <- PITCHES$ax;
  828.     ay <- PITCHES$ay;
  829.     az <- PITCHES$az;
  830.     Str_Prb <- array(0,dim=Np);
  831.     for (i in 1:Np){
  832.         # Find the time to the front of home plate
  833.         a <- 0.5*ay[i];
  834.         b <- vy0[i];
  835.         c_plate <- y0[i]-(17/12);
  836.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  837.         # Find the x and z coordinates of the pitch at the front of the plate
  838.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  839.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  840.         plate_xz <- c(x_plate,z_plate);
  841.         if (stand == 'L'){
  842.             Str_Prb[i] <- Dist_LHB_Quad(plate_xz);
  843.         } else {
  844.             Str_Prb[i] <- Dist_RHB_Quad(plate_xz);
  845.         }
  846.         Str_Index <- which(Str_Prb >= 0.5);
  847.         Ball_Index <- which(Str_Prb < 0.5);
  848.         }
  849.     return(list(S = Str_Index, B = Ball_Index, Prb = Str_Prb));
  850. }
  851.  
  852. ##################################################################
  853. # Determine to xz-location of a pitch at the front of home plate #
  854. ##################################################################
  855.  
  856. xz_plate_loc <- function(PITCH){
  857.     x0 <- PITCH$x0;
  858.     y0 <- PITCH$y0;
  859.     z0 <- PITCH$z0;
  860.     vx0 <- PITCH$vx0;
  861.     vy0 <- PITCH$vy0;
  862.     vz0 <- PITCH$vz0;
  863.     ax <- PITCH$ax;
  864.     ay <- PITCH$ay;
  865.     az <- PITCH$az;
  866.     # Find the time to the front of home plate
  867.     a <- 0.5*ay;
  868.     b <- vy0;
  869.     c_plate <- y0-(17/12);
  870.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  871.     # Find the x and z coordinates of the pitch at the front of the plate
  872.     x_plate <- x0 + vx0*t_plate + 0.5*ax*t_plate^2;
  873.     z_plate <- z0 + vz0*t_plate + 0.5*az*t_plate^2;
  874.     return(c(x_plate,z_plate));
  875. }
  876.  
  877. #########################################################
  878. # Determine the mean angle from a collection of vectors #
  879. #########################################################
  880.  
  881. mean_angle <- function(x,z,N){
  882.     x_norm <- array(0,dim=N);
  883.     z_norm <- array(0,dim=N);
  884.     # Find the length of each vector and normalize
  885.     for (i in 1:N){
  886.         xz_norm <- sqrt(x[i]^2 + z[i]^2);
  887.         x_norm[i] <- x[i]/xz_norm;
  888.         z_norm[i] <- z[i]/xz_norm;
  889.     }
  890.     # Find the mean of each component
  891.     x_mean <- mean(x_norm);
  892.     z_mean <- mean(z_norm);
  893.     # Return the mean angle
  894.     theta <- atan2(z_mean,x_mean);
  895.     return(theta);
  896. }
  897.  
  898. ##############################################################################################
  899. # Display the perctange of angles in groups of 30 degrees and distances from the strike zone #
  900. ##############################################################################################
  901.  
  902. Angle_Pct_Dist <- function(Pitch_Angle,SZ_Distance){
  903.     # Find the number of pitches and indices for various ranges of angles from 0 to 180 degrees
  904.     N <- length(Pitch_Angle);
  905.     I_30 <- which(Pitch_Angle <= 30);
  906.     N_30 <- length(I_30);
  907.     I_60 <- which((Pitch_Angle > 30) & (Pitch_Angle <= 60));
  908.     N_60 <- length(I_60);
  909.     I_90 <- which((Pitch_Angle > 60) & (Pitch_Angle <= 90));
  910.     N_90 <- length(I_90);
  911.     I_120 <- which((Pitch_Angle > 90) & (Pitch_Angle <= 120));
  912.     N_120 <- length(I_120);
  913.     I_150 <- which((Pitch_Angle > 120) & (Pitch_Angle <= 150));
  914.     N_150 <- length(I_150);
  915.     I_180 <- which((Pitch_Angle > 150) & (Pitch_Angle <= 180));
  916.     N_180 <- length(I_180);
  917.     # Find the percentage of pitches in each range of angles
  918.     Pcts <- round(c(N_30/N,N_60/N,N_90/N,N_120/N,N_150/N,N_180/N)*100,digits=1);
  919.     # Find the average outside distance in each range of angles
  920.     Avg_Dist <- round(c(mean(SZ_Distance[I_30]),mean(SZ_Distance[I_60]),mean(SZ_Distance[I_90]),mean(SZ_Distance[I_120]),mean(SZ_Distance[I_150]),mean(SZ_Distance[I_180])),digits=2);
  921.     # Print the results
  922.     print(paste("0-30: ",Pcts[1],"% / 30-60: ",Pcts[2],"% / 60-90: ",Pcts[3],"%",sep=""));
  923.     print(paste("90-120: ",Pcts[4],"% / 120-150: ",Pcts[5],"% / 150-180: ",Pcts[6],"%",sep=""));
  924.     print(paste("0-30: ",Avg_Dist[1],"ft / 30-60: ",Avg_Dist[2],"ft / 60-90: ",Avg_Dist[3],"ft",sep=""));
  925.     print(paste("90-120: ",Avg_Dist[4],"ft / 120-150: ",Avg_Dist[5],"ft / 150-180: ",Avg_Dist[6],"ft",sep=""));
  926. }
  927.  
  928. ###########################################################################################
  929. # Find the perctange of angles in groups of 30 degrees and distances from the strike zone #
  930. ###########################################################################################
  931.  
  932. Angle_Pct_Dist_Store <- function(Pitch_Angle,SZ_Distance){
  933.     # Find the number of pitches and indices for various ranges of angles from 0 to 180 degrees
  934.     N <- length(Pitch_Angle);
  935.     I_30 <- which(Pitch_Angle <= 30);
  936.     N_30 <- length(I_30);
  937.     I_60 <- which((Pitch_Angle > 30) & (Pitch_Angle <= 60));
  938.     N_60 <- length(I_60);
  939.     I_90 <- which((Pitch_Angle > 60) & (Pitch_Angle <= 90));
  940.     N_90 <- length(I_90);
  941.     I_120 <- which((Pitch_Angle > 90) & (Pitch_Angle <= 120));
  942.     N_120 <- length(I_120);
  943.     I_150 <- which((Pitch_Angle > 120) & (Pitch_Angle <= 150));
  944.     N_150 <- length(I_150);
  945.     I_180 <- which((Pitch_Angle > 150) & (Pitch_Angle <= 180));
  946.     N_180 <- length(I_180);
  947.     # Find the percentage of pitches in each range of angles
  948.     Pcts <- round(c(N_30/N,N_60/N,N_90/N,N_120/N,N_150/N,N_180/N)*100,digits=1);
  949.     # Find the average outside distance in each range of angles
  950.     Avg_Dist <- array(0,dim=6);
  951.     if (N_30 != 0){
  952.         Avg_Dist[1] <- round(mean(SZ_Distance[I_30]),digits=2);
  953.     }
  954.     if (N_60 != 0){
  955.         Avg_Dist[2] <- round(mean(SZ_Distance[I_60]),digits=2);
  956.     }
  957.     if (N_90 != 0){
  958.         Avg_Dist[3] <- round(mean(SZ_Distance[I_90]),digits=2);
  959.     }
  960.     if (N_120 != 0){
  961.         Avg_Dist[4] <- round(mean(SZ_Distance[I_120]),digits=2);
  962.     }
  963.     if (N_150 != 0){
  964.         Avg_Dist[5] <- round(mean(SZ_Distance[I_150]),digits=2);
  965.     }
  966.     if (N_180 != 0){
  967.         Avg_Dist[6] <- round(mean(SZ_Distance[I_180]),digits=2);
  968.     }
  969.     # Store and return the data
  970.     return(c(Pcts,Avg_Dist));
  971. }
  972.  
  973. ########################################################
  974. # Find the perctange of angles in groups of 30 degrees #
  975. ########################################################
  976.  
  977. Angle_Pct_By_Case <- function(Pitch_Angle_C,Pitch_Angle_M,Pitch_Angle_T){
  978.     # Find the number of pitches with contact and indices for various ranges of angles from 0 to 180 degrees
  979.     IC_30 <- which(Pitch_Angle_C <= 30);
  980.     C_30 <- length(IC_30);
  981.     IC_60 <- which((Pitch_Angle_C > 30) & (Pitch_Angle_C <= 60));
  982.     C_60 <- length(IC_60);
  983.     IC_90 <- which((Pitch_Angle_C > 60) & (Pitch_Angle_C <= 90));
  984.     C_90 <- length(IC_90);
  985.     IC_120 <- which((Pitch_Angle_C > 90) & (Pitch_Angle_C <= 120));
  986.     C_120 <- length(IC_120);
  987.     IC_150 <- which((Pitch_Angle_C > 120) & (Pitch_Angle_C <= 150));
  988.     C_150 <- length(IC_150);
  989.     IC_180 <- which((Pitch_Angle_C > 150) & (Pitch_Angle_C <= 180));
  990.     C_180 <- length(IC_180);
  991.     # Find the number of pitches missed and indices for various ranges of angles from 0 to 180 degrees
  992.     IM_30 <- which(Pitch_Angle_M <= 30);
  993.     M_30 <- length(IM_30);
  994.     IM_60 <- which((Pitch_Angle_M > 30) & (Pitch_Angle_M <= 60));
  995.     M_60 <- length(IM_60);
  996.     IM_90 <- which((Pitch_Angle_M > 60) & (Pitch_Angle_M <= 90));
  997.     M_90 <- length(IM_90);
  998.     IM_120 <- which((Pitch_Angle_M > 90) & (Pitch_Angle_M <= 120));
  999.     M_120 <- length(IM_120);
  1000.     IM_150 <- which((Pitch_Angle_M > 120) & (Pitch_Angle_M <= 150));
  1001.     M_150 <- length(IM_150);
  1002.     IM_180 <- which((Pitch_Angle_M > 150) & (Pitch_Angle_M <= 180));
  1003.     M_180 <- length(IM_180);
  1004.     # Find the number of pitches taken and indices for various ranges of angles from 0 to 180 degrees
  1005.     IT_30 <- which(Pitch_Angle_T <= 30);
  1006.     T_30 <- length(IT_30);
  1007.     IT_60 <- which((Pitch_Angle_T > 30) & (Pitch_Angle_T <= 60));
  1008.     T_60 <- length(IT_60);
  1009.     IT_90 <- which((Pitch_Angle_T > 60) & (Pitch_Angle_T <= 90));
  1010.     T_90 <- length(IT_90);
  1011.     IT_120 <- which((Pitch_Angle_T > 90) & (Pitch_Angle_T <= 120));
  1012.     T_120 <- length(IT_120);
  1013.     IT_150 <- which((Pitch_Angle_T > 120) & (Pitch_Angle_T <= 150));
  1014.     T_150 <- length(IT_150);
  1015.     IT_180 <- which((Pitch_Angle_T > 150) & (Pitch_Angle_T <= 180));
  1016.     T_180 <- length(IT_180);
  1017.     # Sum the counts
  1018.     N_30 <- C_30 + M_30 + T_30;
  1019.     N_60 <- C_60 + M_60 + T_60;
  1020.     N_90 <- C_90 + M_90 + T_90;
  1021.     N_120 <- C_120 + M_120 + T_120;
  1022.     N_150 <- C_150 + M_150 + T_150;
  1023.     N_180 <- C_180 + M_180 + T_180;
  1024.     # Find the percentage of pitches in each range of angles
  1025.     C_Pcts <- round(c(C_30/N_30,C_60/N_60,C_90/N_90,C_120/N_120,C_150/N_150,C_180/N_180)*100,digits=1);
  1026.     M_Pcts <- round(c(M_30/N_30,M_60/N_60,M_90/N_90,M_120/N_120,M_150/N_150,M_180/N_180)*100,digits=1);
  1027.     T_Pcts <- round(c(T_30/N_30,T_60/N_60,T_90/N_90,T_120/N_120,T_150/N_150,T_180/N_180)*100,digits=1);
  1028.     return(list(C = C_Pcts, M = M_Pcts, T = T_Pcts));
  1029. }
  1030.  
  1031. ##############################################################################
  1032. # Find the angle between the movement and the direction from the strike zone #
  1033. ##############################################################################
  1034.  
  1035. Angle_Groupings <- function(PITCHES,QUAD,stand){
  1036.     # Find the indices of the pitches that are balls and are strikes
  1037.     Index <- ball_strike_prob(PITCHES,stand);
  1038.     # Set the indices of pitches outside the strike zone
  1039.     B_Ind <- Index$B;
  1040.     # Find the number of pitches outside the strike zone
  1041.     N_B <- length(B_Ind);
  1042.     # Set arrays for each set of angles for each type of movement
  1043.     Angle_PFX_B <- array(0,dim=N_B);
  1044.     Angle_PFX_Drag_B <- array(0,dim=N_B);
  1045.     Angle_W_B <- array(0,dim=N_B);
  1046.     Angle_W_Drag_B <- array(0,dim=N_B);
  1047.     # Loop over the pitches outside the zone and find the angle between the movement and direction of the pitch
  1048.     k <- 1;
  1049.     for (i in B_Ind){
  1050.         # Set the individual pitch data
  1051.         PITCH <- list(ax = PITCHES$ax[i], ay = PITCHES$ay[i], az = PITCHES$az[i], vx0 = PITCHES$vx0[i], vy0 = PITCHES$vy0[i], vz0 = PITCHES$vz0[i], x0 = PITCHES$x0[i], y0 = PITCHES$y0[i], z0 = PITCHES$z0[i]);
  1052.         # Set the location of the pitch at the front of home plate
  1053.         xz_loc <- xz_plate_loc(PITCH);
  1054.         # Find the four different types of movement
  1055.         PFX_B <- PFX_Mvt(PITCH,55);
  1056.         PFX_Drag_B <- PFX_Mvt_Drag(PITCH,55);
  1057.         W_B <- W_Mvt(PITCH,55);
  1058.         W_Drag_B <- W_Mvt_Drag(PITCH,55);
  1059.         # Find the direction of the pitch, relative to the strike zone
  1060.         xz_dir <- Dir_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1061.         # Find the angle between the direction of the pitch and the movement
  1062.         Angle_PFX_B[k] <- Dot_Prod_Angle(xz_dir,PFX_B);
  1063.         Angle_PFX_Drag_B[k] <- Dot_Prod_Angle(xz_dir,PFX_Drag_B);
  1064.         Angle_W_B[k] <- Dot_Prod_Angle(xz_dir,W_B);
  1065.         Angle_W_Drag_B[k] <- Dot_Prod_Angle(xz_dir,W_Drag_B);
  1066.         k <- k+1;
  1067.     }
  1068.     return(list(PFX = Angle_PFX_B, PFX_D = Angle_PFX_Drag_B, W = Angle_W_B, W_D = Angle_W_Drag_B));
  1069. }
  1070.  
  1071. ###################################################################################################
  1072. # Find the angle between the movement and the direction from the strike zone within some distance #
  1073. ###################################################################################################
  1074.  
  1075. Angle_Groupings_Dist <- function(PITCHES,QUAD,stand){
  1076.     # Find the indices of the pitches that are balls and are strikes
  1077.     Index <- ball_strike_prob(PITCHES,stand);
  1078.     # Set the indices of pitches outside the strike zone
  1079.     B_Ind <- Index$B;
  1080.     # Find the number of pitches outside the strike zone
  1081.     N_B <- length(B_Ind);
  1082.     # Set arrays for each set of angles for each type of movement
  1083.     Angle_PFX_B <- array(0,dim=N_B);
  1084.     Angle_PFX_Drag_B <- array(0,dim=N_B);
  1085.     Angle_W_B <- array(0,dim=N_B);
  1086.     Angle_W_Drag_B <- array(0,dim=N_B);
  1087.     # Set an array for the distances from the strike zone
  1088.     SZ_Dist_B <- array(0,dim=N_B);
  1089.     # Loop over the pitches outside the zone and find the angle between the movement and direction of the pitch
  1090.     k <- 1;
  1091.     for (i in B_Ind){
  1092.         # Set the individual pitch data
  1093.         PITCH <- list(ax = PITCHES$ax[i], ay = PITCHES$ay[i], az = PITCHES$az[i], vx0 = PITCHES$vx0[i], vy0 = PITCHES$vy0[i], vz0 = PITCHES$vz0[i], x0 = PITCHES$x0[i], y0 = PITCHES$y0[i], z0 = PITCHES$z0[i]);
  1094.         # Set the location of the pitch at the front of home plate
  1095.         xz_loc <- xz_plate_loc(PITCH);
  1096.         # Find the four different types of movement
  1097.         PFX_B <- PFX_Mvt(PITCH,55);
  1098.         PFX_Drag_B <- PFX_Mvt_Drag(PITCH,55);
  1099.         W_B <- W_Mvt(PITCH,55);
  1100.         W_Drag_B <- W_Mvt_Drag(PITCH,55);
  1101.         # Find the direction of the pitch, relative to the strike zone
  1102.         xz_dir <- Dir_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1103.         # Find the distance between the pitch and the core quadrilateral
  1104.         xz_sz_dist <- Min_Dist_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1105.         # Find the angle between the direction of the pitch and the movement
  1106.         Angle_PFX_B[k] <- Dot_Prod_Angle(xz_dir,PFX_B);
  1107.         Angle_PFX_Drag_B[k] <- Dot_Prod_Angle(xz_dir,PFX_Drag_B);
  1108.         Angle_W_B[k] <- Dot_Prod_Angle(xz_dir,W_B);
  1109.         Angle_W_Drag_B[k] <- Dot_Prod_Angle(xz_dir,W_Drag_B);
  1110.         # Set an array for the distances from the strike zone
  1111.         SZ_Dist_B[k] <- xz_sz_dist - (log(2)/4)^(1/4);
  1112.         k <- k+1;
  1113.     }
  1114.     # Find the indices of the array where the pitches are within d feet of the strike zone
  1115.     d <- 1;
  1116.     Index_d <- which(SZ_Dist_B <= 1);
  1117.     return(list(PFX = Angle_PFX_B[Index_d], PFX_D = Angle_PFX_Drag_B[Index_d], W = Angle_W_B[Index_d], W_D = Angle_W_Drag_B[Index_d]));
  1118. }
  1119.  
  1120. ##############################################
  1121. # Sort Percentages by Contact, Miss, or Take #
  1122. ##############################################
  1123.  
  1124. Ct_Ms_Tk_Table <- function(CONTACT,MISS,TAKE,QUAD,stand){
  1125.     Angle_C <- Angle_Groupings(CONTACT,QUAD,stand);
  1126.     Angle_M <- Angle_Groupings(MISS,QUAD,stand);
  1127.     Angle_T <- Angle_Groupings(TAKE,QUAD,stand);
  1128.     PFX_Pct <- Angle_Pct_By_Case(Angle_C$PFX,Angle_M$PFX,Angle_T$PFX);
  1129.     PFX_D_Pct <- Angle_Pct_By_Case(Angle_C$PFX_D,Angle_M$PFX_D,Angle_T$PFX_D);
  1130.     W_Pct <- Angle_Pct_By_Case(Angle_C$W,Angle_M$W,Angle_T$W);
  1131.     W_D_Pct <- Angle_Pct_By_Case(Angle_C$W_D,Angle_M$W_D,Angle_T$W_D);
  1132.     df_ct_ms_tk <- data.frame(PFX_Pct$C,PFX_Pct$M,PFX_Pct$T,PFX_D_Pct$C,PFX_D_Pct$M,PFX_D_Pct$T,
  1133.                               W_Pct$C,W_Pct$M,W_Pct$T,W_D_Pct$C,W_D_Pct$M,W_D_Pct$T);
  1134.     print(df_ct_ms_tk);
  1135. }
  1136.  
  1137. ###################################################################
  1138. # Sort Percentages by Contact, Miss, or Take For a Given Distance #
  1139. ###################################################################
  1140.  
  1141. Ct_Ms_Tk_Dist_Table <- function(CONTACT,MISS,TAKE,QUAD,stand){
  1142.     Angle_C <- Angle_Groupings_Dist(CONTACT,QUAD,stand);
  1143.     Angle_M <- Angle_Groupings_Dist(MISS,QUAD,stand);
  1144.     Angle_T <- Angle_Groupings_Dist(TAKE,QUAD,stand);
  1145.     PFX_Pct <- Angle_Pct_By_Case(Angle_C$PFX,Angle_M$PFX,Angle_T$PFX);
  1146.     PFX_D_Pct <- Angle_Pct_By_Case(Angle_C$PFX_D,Angle_M$PFX_D,Angle_T$PFX_D);
  1147.     W_Pct <- Angle_Pct_By_Case(Angle_C$W,Angle_M$W,Angle_T$W);
  1148.     W_D_Pct <- Angle_Pct_By_Case(Angle_C$W_D,Angle_M$W_D,Angle_T$W_D);
  1149.     df_ct_ms_tk <- data.frame(PFX_Pct$C,PFX_Pct$M,PFX_Pct$T,PFX_D_Pct$C,PFX_D_Pct$M,PFX_D_Pct$T,
  1150.                               W_Pct$C,W_Pct$M,W_Pct$T,W_D_Pct$C,W_D_Pct$M,W_D_Pct$T);
  1151.     print(df_ct_ms_tk);
  1152. }
  1153.  
  1154. ###################################################################################
  1155. # Track the projected strike probability with remaining PITCHf/x movement removed #
  1156. ###################################################################################
  1157.  
  1158. Pitch_Project_PFX <- function(PITCHES,Ny,stand){
  1159.     g <- -32.174;
  1160.     Np <- length(PITCHES$x0);
  1161.     x0 <- PITCHES$x0;
  1162.     y0 <- PITCHES$y0;
  1163.     z0 <- PITCHES$z0;
  1164.     vx0 <- PITCHES$vx0;
  1165.     vy0 <- PITCHES$vy0;
  1166.     vz0 <- PITCHES$vz0;
  1167.     ax <- PITCHES$ax;
  1168.     ay <- PITCHES$ay;
  1169.     az <- PITCHES$az;
  1170.     y_seq <- seq(55,17/12,length=Ny);
  1171.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1172.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1173.     for (i in 1:Np){
  1174.         # Find the time to the front of home plate
  1175.         a <- 0.5*ay[i];
  1176.         b <- vy0[i];
  1177.         c_plate <- y0[i]-(17/12);
  1178.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1179.         # Set a list for the PITCHf/x data
  1180.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  1181.         # Loop over the y-slices
  1182.         for (j in 1:Ny){
  1183.             c_inc <- y0[i]-y_seq[j];
  1184.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1185.             # Find the projected location at the front of the plate
  1186.             xz_PL <- PFX_Calc(PITCH,t_inc,t_plate);
  1187.             x_Proj_Loc[i,j] <- xz_PL[1];
  1188.             z_Proj_Loc[i,j] <- xz_PL[2];
  1189.         }
  1190.     }
  1191.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc));
  1192. }
  1193.  
  1194. #####################################################################################################
  1195. # Track the projected strike probability with remaining PITCHf/x movement removed but drag added in #
  1196. #####################################################################################################
  1197.  
  1198. Pitch_Project_PFX_Drag <- function(PITCHES,Ny,stand){
  1199.     g <- -32.174;
  1200.     G <- c(0,0,g);
  1201.     Np <- length(PITCHES$x0);
  1202.     x0 <- PITCHES$x0;
  1203.     y0 <- PITCHES$y0;
  1204.     z0 <- PITCHES$z0;
  1205.     vx0 <- PITCHES$vx0;
  1206.     vy0 <- PITCHES$vy0;
  1207.     vz0 <- PITCHES$vz0;
  1208.     ax <- PITCHES$ax;
  1209.     ay <- PITCHES$ay;
  1210.     az <- PITCHES$az;
  1211.     y_seq <- seq(55,17/12,length=Ny);
  1212.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1213.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1214.     for (i in 1:Np){
  1215.         # Find the time to the front of home plate
  1216.         a <- 0.5*ay[i];
  1217.         b <- vy0[i];
  1218.         c_plate <- y0[i]-(17/12);
  1219.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1220.         # Find the velocity at the front of the plate
  1221.         vx_plate <- ax[i]*t_plate + vx0[i];
  1222.         vy_plate <- ay[i]*t_plate + vy0[i];
  1223.         vz_plate <- az[i]*t_plate + vz0[i];
  1224.         v_plate <- list(x = vx_plate, y = vy_plate, z = vz_plate);
  1225.         # Set a list for the PITCHf/x data
  1226.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  1227.         # Loop over the y-slices
  1228.         for (j in 1:Ny){
  1229.             c_inc <- y0[i]-y_seq[j];
  1230.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1231.             # Find the projected location at the front of the plate
  1232.             xz_PL <- PFX_Drag_Calc(PITCH,t_inc,t_plate,v_plate);
  1233.             x_Proj_Loc[i,j] <- xz_PL[1];
  1234.             z_Proj_Loc[i,j] <- xz_PL[2];
  1235.  
  1236.         }
  1237.     }
  1238.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc));
  1239. }
  1240.  
  1241. #######################################################################################
  1242. # Track the planar projected strike probability with the remaining w-movement removed #
  1243. #######################################################################################
  1244.  
  1245. Pitch_Project_W <- function(PITCHES,Ny,stand){
  1246.     g <- -32.174;
  1247.     G <- c(0,0,g);
  1248.     Np <- length(PITCHES$x0);
  1249.     x0 <- PITCHES$x0;
  1250.     y0 <- PITCHES$y0;
  1251.     z0 <- PITCHES$z0;
  1252.     vx0 <- PITCHES$vx0;
  1253.     vy0 <- PITCHES$vy0;
  1254.     vz0 <- PITCHES$vz0;
  1255.     ax <- PITCHES$ax;
  1256.     ay <- PITCHES$ay;
  1257.     az <- PITCHES$az;
  1258.     y_seq <- seq(55,17/12,length=Ny);
  1259.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1260.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1261.     for (i in 1:Np){
  1262.         # Find the time to the front of home plate
  1263.         a <- 0.5*ay[i];
  1264.         b <- vy0[i];
  1265.         c_plate <- y0[i]-(17/12);
  1266.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1267.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  1268.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  1269.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  1270.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  1271.         # Set up a list containing the parameters of the pitch
  1272.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  1273.         BV <- PFX_Basis(PITCH);
  1274.         BV_T = t(BV);
  1275.         # Find the u and b coordinates of the pitch at the front of the plate
  1276.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  1277.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  1278.         # Loop over the y-slices
  1279.         for (j in 1:Ny){
  1280.             c_inc <- y0[i]-y_seq[j];
  1281.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1282.             # Find the projected location at the front of the plate
  1283.             xz_PL <- W_Calc(PITCH,BV_T,t_inc,t_plate,b_plate,u_plate);
  1284.             x_Proj_Loc[i,j] <- xz_PL[1];
  1285.             z_Proj_Loc[i,j] <- xz_PL[2];
  1286.         }
  1287.     }
  1288.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc));
  1289. }
  1290.  
  1291. #########################################################################################################
  1292. # Track the planar projected strike probability with the remaining w-movement removed but drag added in #
  1293. #########################################################################################################
  1294.  
  1295. Pitch_Project_W_Drag <- function(PITCHES,Ny,stand){
  1296.     g <- -32.174;
  1297.     G <- c(0,0,g);
  1298.     Np <- length(PITCHES$x0);
  1299.     x0 <- PITCHES$x0;
  1300.     y0 <- PITCHES$y0;
  1301.     z0 <- PITCHES$z0;
  1302.     vx0 <- PITCHES$vx0;
  1303.     vy0 <- PITCHES$vy0;
  1304.     vz0 <- PITCHES$vz0;
  1305.     ax <- PITCHES$ax;
  1306.     ay <- PITCHES$ay;
  1307.     az <- PITCHES$az;
  1308.     y_seq <- seq(55,17/12,length=Ny);
  1309.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1310.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1311.     for (i in 1:Np){
  1312.         # Find the time to the front of home plate
  1313.         a <- 0.5*ay[i];
  1314.         b <- vy0[i];
  1315.         c_plate <- y0[i]-(17/12);
  1316.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1317.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  1318.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  1319.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  1320.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  1321.         # Find the velocity at the front of the plate
  1322.         vx_plate <- ax[i]*t_plate + vx0[i];
  1323.         vy_plate <- ay[i]*t_plate + vy0[i];
  1324.         vz_plate <- az[i]*t_plate + vz0[i];
  1325.         v_plate <- list(x = vx_plate, y = vy_plate, z = vz_plate);
  1326.         # Set up a list containing the parameters of the pitch
  1327.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  1328.         BV <- PFX_Basis(PITCH);
  1329.         BV_T = t(BV);
  1330.         # Find the u and b coordinates of the pitch at the front of the plate
  1331.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  1332.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  1333.         # Loop over the y-slices
  1334.         for (j in 1:Ny){
  1335.             c_inc <- y0[i]-y_seq[j];
  1336.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1337.             # Find the projected location at the front of the plate
  1338.             xz_PL <- W_Drag_Calc(PITCH,BV_T,t_inc,t_plate,v_plate,b_plate,u_plate);
  1339.             x_Proj_Loc[i,j] <- xz_PL[1];
  1340.             z_Proj_Loc[i,j] <- xz_PL[2];
  1341.         }
  1342.     }
  1343.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc));
  1344. }
  1345.  
  1346. ################################################################################
  1347. # Track the projected pitches and movement direction with PFX movement removed #
  1348. ################################################################################
  1349.  
  1350. Pitch_Project_Dir_PFX <- function(PITCHES,QUAD,Ny,stand){
  1351.     # Set the arrays
  1352.     Np <- length(PITCHES$x0);
  1353.     x0 <- PITCHES$x0;
  1354.     y0 <- PITCHES$y0;
  1355.     z0 <- PITCHES$z0;
  1356.     vx0 <- PITCHES$vx0;
  1357.     vy0 <- PITCHES$vy0;
  1358.     vz0 <- PITCHES$vz0;
  1359.     ax <- PITCHES$ax;
  1360.     ay <- PITCHES$ay;
  1361.     az <- PITCHES$az;
  1362.     y_seq <- seq(55,17/12,length=Ny);
  1363.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1364.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1365.     Zone <- array(0,dim=Np);
  1366.     x_Dir <- array(0,dim=c(Np,Ny));
  1367.     z_Dir <- array(0,dim=c(Np,Ny));
  1368.     for (i in 1:Np){
  1369.         # Compute the time to the plate
  1370.         c_plate <- y0[i]-(17/12);
  1371.         b <- vy0[i];
  1372.         a <- 0.5*ay[i];
  1373.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1374.         # Find the location of the pitch at the plate
  1375.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  1376.         xz_loc <- xz_plate_loc(PITCH);
  1377.         # Find the zone (1-9) of the pitch at the plate
  1378.         Zone[i] <- Zone_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1379.         # Loop over the y-slices from release to the plate
  1380.         for (j in 1:Ny){
  1381.             c_inc <- y0[i]-y_seq[j];
  1382.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1383.             # Find the projected location at the front of the plate
  1384.             xz_PL <- PFX_Calc(PITCH,t_inc,t_plate);
  1385.             x_Proj_Loc[i,j] <- xz_PL[1];
  1386.             z_Proj_Loc[i,j] <- xz_PL[2];
  1387.             # Find where the pitch projects from one inch ahead of y_inc
  1388.             c_F <- y0[i]-y_seq[j] + (1/12);
  1389.             t_F <- (-b - sqrt(b^2 - 4*a*c_F))/(2*a);
  1390.             xz_F <- PFX_Calc(PITCH,t_F,t_plate);
  1391.             # Find where the pitch projects from one inch behind of y_inc
  1392.             c_B <- y0[i]-y_seq[j] - (1/12);
  1393.             t_B <- (-b - sqrt(b^2 - 4*a*c_B))/(2*a);
  1394.             xz_B <- PFX_Calc(PITCH,t_B,t_plate);
  1395.             x_Dir[i,j] <- (xz_F[1] - xz_B[1])/(1/6);
  1396.             z_Dir[i,j] <- (xz_F[2] - xz_B[2])/(1/6);
  1397.         }
  1398.         x_Dir[i,Ny] <- (x_Proj_Loc[i,Ny] - xz_B[1])/(1/12);
  1399.         z_Dir[i,Ny] <- (z_Proj_Loc[i,Ny] - xz_B[2])/(1/12);
  1400.     }
  1401.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc, x_Dir = x_Dir, z_Dir = z_Dir, Zone = Zone));
  1402. }
  1403.  
  1404. #####################################################################################################################
  1405. # Track the projected pitches and movement direction with the remaining PITCHf/x movement removed but drag added in #
  1406. #####################################################################################################################
  1407.  
  1408. Pitch_Project_Dir_PFX_Drag <- function(PITCHES,QUAD,Ny,stand){
  1409.     # Set the arrays
  1410.     Np <- length(PITCHES$x0);
  1411.     x0 <- PITCHES$x0;
  1412.     y0 <- PITCHES$y0;
  1413.     z0 <- PITCHES$z0;
  1414.     vx0 <- PITCHES$vx0;
  1415.     vy0 <- PITCHES$vy0;
  1416.     vz0 <- PITCHES$vz0;
  1417.     ax <- PITCHES$ax;
  1418.     ay <- PITCHES$ay;
  1419.     az <- PITCHES$az;
  1420.     y_seq <- seq(55,17/12,length=Ny);
  1421.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1422.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1423.     Zone <- array(0,dim=Np);
  1424.     x_Dir <- array(0,dim=c(Np,Ny));
  1425.     z_Dir <- array(0,dim=c(Np,Ny));
  1426.     for (i in 1:Np){
  1427.         # Compute the time to the plate
  1428.         c_plate <- y0[i]-(17/12);
  1429.         b <- vy0[i];
  1430.         a <- 0.5*ay[i];
  1431.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1432.         # Find the velocity at the front of the plate
  1433.         vx_plate <- ax[i]*t_plate + vx0[i];
  1434.         vy_plate <- ay[i]*t_plate + vy0[i];
  1435.         vz_plate <- az[i]*t_plate + vz0[i];
  1436.         v_plate <- list(x = vx_plate, y = vy_plate, z = vz_plate);
  1437.         # Find the location of the pitch at the plate
  1438.         PITCH <- list(ax = ax[i], ay = ay[i], az = az[i], vx0 = vx0[i], vy0 = vy0[i], vz0 = vz0[i], x0 = x0[i], y0 = y0[i], z0 = z0[i]);
  1439.         xz_loc <- xz_plate_loc(PITCH);
  1440.         # Find the zone (1-9) of the pitch at the plate
  1441.         Zone[i] <- Zone_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1442.         # Loop over the y-slices from release to the plate
  1443.         for (j in 1:Ny){
  1444.             c_inc <- y0[i]-y_seq[j];
  1445.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1446.             # Find the projected location at the front of the plate
  1447.             xz_PL <- PFX_Drag_Calc(PITCH,t_inc,t_plate,v_plate);
  1448.             x_Proj_Loc[i,j] <- xz_PL[1];
  1449.             z_Proj_Loc[i,j] <- xz_PL[2];
  1450.             # Find where the pitch projects from one inch ahead of y_inc
  1451.             c_F <- y0[i]-y_seq[j] + (1/12);
  1452.             t_F <- (-b - sqrt(b^2 - 4*a*c_F))/(2*a);
  1453.             xz_F <- PFX_Drag_Calc(PITCH,t_F,t_plate,v_plate);
  1454.             # Find where the pitch projects from one inch behind of y_inc
  1455.             c_B <- y0[i]-y_seq[j] - (1/12);
  1456.             t_B <- (-b - sqrt(b^2 - 4*a*c_B))/(2*a);
  1457.             xz_B <- PFX_Drag_Calc(PITCH,t_B,t_plate,v_plate);
  1458.             x_Dir[i,j] <- (xz_F[1] - xz_B[1])/(1/6);
  1459.             z_Dir[i,j] <- (xz_F[2] - xz_B[2])/(1/6);
  1460.         }
  1461.         x_Dir[i,Ny] <- (x_Proj_Loc[i,Ny] - xz_B[1])/(1/12);
  1462.         z_Dir[i,Ny] <- (z_Proj_Loc[i,Ny] - xz_B[2])/(1/12);
  1463.     }
  1464.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc, x_Dir = x_Dir, z_Dir = z_Dir, Zone = Zone));
  1465. }
  1466.  
  1467.  
  1468. #################################################################################################
  1469. # Track the projected pitches and movement direction with the remaining planar movement removed #
  1470. #################################################################################################
  1471.  
  1472. Pitch_Project_Dir_W <- function(PITCHES,QUAD,Ny,stand){
  1473.     g <- -32.174;
  1474.     G <- c(0,0,g);
  1475.     Np <- length(PITCHES$x0);
  1476.     x0 <- PITCHES$x0;
  1477.     y0 <- PITCHES$y0;
  1478.     z0 <- PITCHES$z0;
  1479.     vx0 <- PITCHES$vx0;
  1480.     vy0 <- PITCHES$vy0;
  1481.     vz0 <- PITCHES$vz0;
  1482.     ax <- PITCHES$ax;
  1483.     ay <- PITCHES$ay;
  1484.     az <- PITCHES$az;
  1485.     y_seq <- seq(55,17/12,length=Ny);
  1486.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1487.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1488.     Zone <- array(0,dim=Np);
  1489.     x_Dir <- array(0,dim=c(Np,Ny));
  1490.     z_Dir <- array(0,dim=c(Np,Ny));
  1491.     for (i in 1:Np){
  1492.         # Find the time to the front of home plate
  1493.         a <- 0.5*ay[i];
  1494.         b <- vy0[i];
  1495.         c_plate <- y0[i]-(17/12);
  1496.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1497.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  1498.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  1499.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  1500.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  1501.         # Set up a list containing the parameters of the pitch
  1502.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  1503.         # Find the location of the pitch at the plate
  1504.         xz_loc <- c(x_plate,z_plate);
  1505.         # Find the zone (1-9) of the pitch at the plate
  1506.         Zone[i] <- Zone_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1507.         # Find the coordinate transformation
  1508.         BV <- PFX_Basis(PITCH);
  1509.         BV_T = t(BV);
  1510.         # Find the u and b coordinates of the pitch at the front of the plate
  1511.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  1512.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  1513.         # Loop over the y-slices
  1514.         for (j in 1:Ny){
  1515.             c_inc <- y0[i]-y_seq[j];
  1516.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1517.             # Find the location at the front of the plate
  1518.             xz_PL <- W_Calc(PITCH,BV_T,t_inc,t_plate,b_plate,u_plate);
  1519.             x_Proj_Loc[i,j] <- xz_PL[1];
  1520.             z_Proj_Loc[i,j] <- xz_PL[2];
  1521.             # Find where the pitch projects from one inch ahead of y_inc
  1522.             c_F <- y0[i]-y_seq[j] + (1/12);
  1523.             t_F <- (-b - sqrt(b^2 - 4*a*c_F))/(2*a);
  1524.             xz_F <- W_Calc(PITCH,BV_T,t_F,t_plate,b_plate,u_plate);
  1525.             # Find where the pitch projects from one inch behind of y_inc
  1526.             c_B <- y0[i]-y_seq[j] - (1/12);
  1527.             t_B <- (-b - sqrt(b^2 - 4*a*c_B))/(2*a);
  1528.             xz_B <- W_Calc(PITCH,BV_T,t_B,t_plate,b_plate,u_plate);
  1529.             x_Dir[i,j] <- (xz_F[1] - xz_B[1])/(1/6);
  1530.             z_Dir[i,j] <- (xz_F[2] - xz_B[2])/(1/6);
  1531.         }
  1532.         x_Dir[i,Ny] <- (x_Proj_Loc[i,Ny] - xz_B[1])/(1/12);
  1533.         z_Dir[i,Ny] <- (z_Proj_Loc[i,Ny] - xz_B[2])/(1/12);
  1534.     }
  1535.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc, x_Dir = x_Dir, z_Dir = z_Dir, Zone = Zone));
  1536. }
  1537.  
  1538. #######################################################################################################################
  1539. # Track the planar projected location and movement direction with remaining planar movement removed but drag added in #
  1540. #######################################################################################################################
  1541.  
  1542. Pitch_Project_Dir_W_Drag <- function(PITCHES,QUAD,Ny,stand){
  1543.     g <- -32.174;
  1544.     G <- c(0,0,g);
  1545.     Np <- length(PITCHES$x0);
  1546.     x0 <- PITCHES$x0;
  1547.     y0 <- PITCHES$y0;
  1548.     z0 <- PITCHES$z0;
  1549.     vx0 <- PITCHES$vx0;
  1550.     vy0 <- PITCHES$vy0;
  1551.     vz0 <- PITCHES$vz0;
  1552.     ax <- PITCHES$ax;
  1553.     ay <- PITCHES$ay;
  1554.     az <- PITCHES$az;
  1555.     y_seq <- seq(55,17/12,length=Ny);
  1556.     x_Proj_Loc <- array(0,dim=c(Np,Ny));
  1557.     z_Proj_Loc <- array(0,dim=c(Np,Ny));
  1558.     Zone <- array(0,dim=Np);
  1559.     x_Dir <- array(0,dim=c(Np,Ny));
  1560.     z_Dir <- array(0,dim=c(Np,Ny));
  1561.     for (i in 1:Np){
  1562.         # Find the time to the front of home plate
  1563.         a <- 0.5*ay[i];
  1564.         b <- vy0[i];
  1565.         c_plate <- y0[i]-(17/12);
  1566.         t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  1567.         # Find the x, y, and z coordinates of the pitch at the front of the plate
  1568.         x_plate <- x0[i] + vx0[i]*t_plate + 0.5*ax[i]*t_plate^2;
  1569.         y_plate <- y0[i] + vy0[i]*t_plate + 0.5*ay[i]*t_plate^2;
  1570.         z_plate <- z0[i] + vz0[i]*t_plate + 0.5*az[i]*t_plate^2;
  1571.         # Find the velocity at the front of the plate
  1572.         vx_plate <- ax[i]*t_plate + vx0[i];
  1573.         vy_plate <- ay[i]*t_plate + vy0[i];
  1574.         vz_plate <- az[i]*t_plate + vz0[i];
  1575.         v_plate <- list(x = vx_plate, y = vy_plate, z = vz_plate);
  1576.         # Set up a list containing the parameters of the pitch
  1577.         PITCH <- list(ax=ax[i], ay=ay[i], az=az[i], vx0=vx0[i], vy0=vy0[i], vz0=vz0[i], x0=x0[i], y0=y0[i], z0=z0[i]);
  1578.         # Find the location of the pitch at the plate
  1579.         xz_loc <- c(x_plate,z_plate);
  1580.         # Find the zone (1-9) of the pitch at the plate
  1581.         Zone[i] <- Zone_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1582.         # Find the coordinate transformation
  1583.         BV <- PFX_Basis(PITCH);
  1584.         BV_T = t(BV);
  1585.         # Find the u and b coordinates of the pitch at the front of the plate
  1586.         b_plate <- BV_T[1,] %*% c(x_plate,y_plate,z_plate);
  1587.         u_plate <- BV_T[2,] %*% c(x_plate,y_plate,z_plate);
  1588.         # Loop over the y-slices
  1589.         for (j in 1:Ny){
  1590.             c_inc <- y0[i]-y_seq[j];
  1591.             t_inc <- (-b - sqrt(b^2 - 4*a*c_inc))/(2*a);
  1592.             # Find the projected location at the front of the plate
  1593.             xz_PL <- W_Drag_Calc(PITCH,BV_T,t_inc,t_plate,v_plate,b_plate,u_plate);
  1594.             x_Proj_Loc[i,j] <- xz_PL[1];
  1595.             z_Proj_Loc[i,j] <- xz_PL[2];
  1596.             # Find where the pitch projects from one inch ahead of y_inc
  1597.             c_F <- y0[i]-y_seq[j] + (1/12);
  1598.             t_F <- (-b - sqrt(b^2 - 4*a*c_F))/(2*a);
  1599.             xz_F <- W_Drag_Calc(PITCH,BV_T,t_F,t_plate,v_plate,b_plate,u_plate);
  1600.             # Find where the pitch projects from one inch behind of y_inc
  1601.             c_B <- y0[i]-y_seq[j] - (1/12);
  1602.             t_B <- (-b - sqrt(b^2 - 4*a*c_B))/(2*a);
  1603.             xz_B <- W_Drag_Calc(PITCH,BV_T,t_B,t_plate,v_plate,b_plate,u_plate);
  1604.             x_Dir[i,j] <- (xz_F[1] - xz_B[1])/(1/6);
  1605.             z_Dir[i,j] <- (xz_F[2] - xz_B[2])/(1/6);
  1606.         }
  1607.         x_Dir[i,Ny] <- (x_Proj_Loc[i,Ny] - xz_B[1])/(1/12);
  1608.         z_Dir[i,Ny] <- (z_Proj_Loc[i,Ny] - xz_B[2])/(1/12);
  1609.     }
  1610.     return(list(x_PL = x_Proj_Loc, z_PL = z_Proj_Loc, x_Dir = x_Dir, z_Dir = z_Dir, Zone = Zone));
  1611. }
  1612.  
  1613. #################################################
  1614. # Find the projection with PFX movement removed #
  1615. #################################################
  1616.  
  1617. PFX_Calc <- function(PITCH,t_loc,t_plate){
  1618.     # Set gravity
  1619.     g <- -32.174;
  1620.     # Compute x and z location in the quadratic part of the curve
  1621.     x_loc <- PITCH$x0 + PITCH$vx0*t_loc + 0.5*PITCH$ax*t_loc^2;
  1622.     z_loc <- PITCH$z0 + PITCH$vz0*t_loc + 0.5*PITCH$az*t_loc^2;
  1623.     # Find the velocity of the pitch in x and z at t_loc
  1624.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  1625.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  1626.     # Find the projected location of the pitch at the front of home plate
  1627.     x_PL <- x_loc + vx_loc*(t_plate - t_loc);
  1628.     z_PL <- z_loc + vz_loc*(t_plate - t_loc) + 0.5*g*(t_plate - t_loc)^2;
  1629.     return(c(x_PL,z_PL));
  1630. }
  1631.  
  1632. ###################################################################
  1633. # Find the projection with PFX movement removed and drag added in #
  1634. ###################################################################
  1635.  
  1636. PFX_Drag_Calc <- function(PITCH,t_loc,t_plate,v_plate){
  1637.     # Set gravity
  1638.     g <- -32.174;
  1639.     G <- c(0,0,g);
  1640.     # Compute x and z location in the quadratic part of the curve
  1641.     x_loc <- PITCH$x0 + PITCH$vx0*t_loc + 0.5*PITCH$ax*t_loc^2;
  1642.     z_loc <- PITCH$z0 + PITCH$vz0*t_loc + 0.5*PITCH$az*t_loc^2;
  1643.     # Find the velocity of the pitch in x and z at t_inc
  1644.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  1645.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  1646.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  1647.     # Find the average velocity over the remaining distance to the plate
  1648.     vx_avg <- (vx_loc + v_plate$x)/2;
  1649.     vy_avg <- (vy_loc + v_plate$y)/2;
  1650.     vz_avg <- (vz_loc + v_plate$z)/2;
  1651.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  1652.     # Set the average velocity and acceleration vectors
  1653.     V <- c(vx_avg,vy_avg,vz_avg);
  1654.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  1655.     # Normalize the velocity vector
  1656.     V_norm <- V/sqrt(V%*%V);
  1657.     # Find the drag vector
  1658.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  1659.     # Find the projected location at the front of the plate
  1660.     x_PL <- x_loc + vx_loc*(t_plate-t_loc) + 0.5*Drag[1]*(t_plate-t_loc)^2;
  1661.     z_PL <- z_loc + vz_loc*(t_plate-t_loc) + 0.5*(g + Drag[3])*(t_plate-t_loc)^2;
  1662.     return(c(x_PL,z_PL));
  1663. }
  1664.  
  1665. ####################################################
  1666. # Find the projection with planar movement removed #
  1667. ####################################################
  1668.  
  1669. W_Calc <- function(PITCH,BV_T,t_loc,t_plate,b_plate,u_plate){
  1670.     # Set gravity
  1671.     G <- c(0,0,-32.174);
  1672.     x_loc <- PITCH$x0 + PITCH$vx0*t_loc + 0.5*PITCH$ax*t_loc^2;
  1673.     y_loc <- PITCH$y0 + PITCH$vy0*t_loc + 0.5*PITCH$ay*t_loc^2;
  1674.     z_loc <- PITCH$z0 + PITCH$vz0*t_loc + 0.5*PITCH$az*t_loc^2;
  1675.     # Find the coordinates of the point in (u,w,b)-space
  1676.     w_loc <- BV_T[3,] %*% c(x_loc,y_loc,z_loc);
  1677.     # Find the velocity at y feet
  1678.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  1679.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  1680.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  1681.     # Find the velocity in (u,w,b)-space
  1682.     vw_loc <- BV_T[3,] %*% c(vx_loc,vy_loc,vz_loc);
  1683.     # Find the projection of gravity in the w direction
  1684.     gw <- BV_T[3,] %*% G;
  1685.     # Find the projected location of the pitch at the front of home plate
  1686.     pw <- w_loc + vw_loc*(t_plate-t_loc) + 0.5*gw*(t_plate - t_loc)^2;
  1687.     x_PL <- BV_T[,1] %*% c(b_plate,u_plate,pw);
  1688.     z_PL <- BV_T[,3] %*% c(b_plate,u_plate,pw);
  1689.     return(c(x_PL,z_PL));
  1690. }
  1691.  
  1692. ####################################################################
  1693. # Find the projection of planar movement removed and drag added in #
  1694. ####################################################################
  1695.  
  1696. W_Drag_Calc <- function(PITCH,BV_T,t_loc,t_plate,v_plate,b_plate,u_plate){
  1697.     # Set gravity
  1698.     G <- c(0,0,-32.174);
  1699.     x_loc <- PITCH$x0 + PITCH$vx0*t_loc + 0.5*PITCH$ax*t_loc^2;
  1700.     y_loc <- PITCH$y0 + PITCH$vy0*t_loc + 0.5*PITCH$ay*t_loc^2;
  1701.     z_loc <- PITCH$z0 + PITCH$vz0*t_loc + 0.5*PITCH$az*t_loc^2;
  1702.     # Find the coordinates of the point in (u,w,b)-space
  1703.     w_loc <- BV_T[3,] %*% c(x_loc,y_loc,z_loc);
  1704.     # Find the velocity at y feet
  1705.     vx_loc <- PITCH$vx0 + PITCH$ax*t_loc;
  1706.     vy_loc <- PITCH$vy0 + PITCH$ay*t_loc;
  1707.     vz_loc <- PITCH$vz0 + PITCH$az*t_loc;
  1708.     # Find the velocity in (u,w,b)-space
  1709.     vw_loc <- BV_T[3,] %*% c(vx_loc,vy_loc,vz_loc);
  1710.     # Find the average velocity over the remaining distance to the plate
  1711.     vx_avg <- (vx_loc + v_plate$x)/2;
  1712.     vy_avg <- (vy_loc + v_plate$y)/2;
  1713.     vz_avg <- (vz_loc + v_plate$z)/2;
  1714.     v_avg <- sqrt(vx_avg^2 + vy_avg^2 + vz_avg^2);
  1715.     # Set the average velocity and acceleration vectors
  1716.     V <- c(vx_avg,vy_avg,vz_avg);
  1717.     A <- c(PITCH$ax,PITCH$ay,PITCH$az);
  1718.     # Normalize the velocity vector
  1719.     V_norm <- V/sqrt(V%*%V);
  1720.     # Find the drag vector
  1721.     Drag <- -abs((A-G)%*%V_norm)*V_norm;
  1722.     # Find the drag in the w-direction
  1723.     Drag_w <- BV_T[3,] %*% Drag;
  1724.     # Find the projection of gravity in the w direction
  1725.     gw <- BV_T[3,] %*% G;
  1726.     # Find the point on the tangent line passing through the plane of home plate
  1727.     pw <- w_loc + vw_loc*(t_plate-t_loc) + 0.5*(gw + Drag_w)*(t_plate - t_loc)^2;
  1728.     x_PL <- BV_T[,1] %*% c(b_plate,u_plate,pw);
  1729.     z_PL <- BV_T[,3] %*% c(b_plate,u_plate,pw);
  1730.     return(c(x_PL,z_PL));
  1731. }
  1732.  
  1733. #########################################################################################
  1734. # Plot the pitches outside the strike zone based on angle vs. movement for all pitchers #
  1735. #########################################################################################
  1736.  
  1737. Angle_Dist_Table_Plot_All <- function(PITCHES,QUAD,throws,stand,pitch_type,result,res_color){
  1738.     # Find the indices of the pitches that are balls and are strikes
  1739.     Index <- ball_strike_prob(PITCHES,stand);
  1740.     # Set the indices of pitches outside the strike zone
  1741.     B_Ind <- Index$B;
  1742.     # Find the number of pitches outside the strike zone
  1743.     N_B <- length(B_Ind);
  1744.     # Set arrays for each set of angles for each type of movement
  1745.     Angle_PFX_B <- array(0,dim=N_B);
  1746.     Angle_PFX_Drag_B <- array(0,dim=N_B);
  1747.     Angle_W_B <- array(0,dim=N_B);
  1748.     Angle_W_Drag_B <- array(0,dim=N_B);
  1749.     # Set an array for the distances from the strike zone
  1750.     SZ_Dist_B <- array(0,dim=N_B);
  1751.     # Loop over the pitches outside the zone and find the angle between the movement and direction of the pitch
  1752.     k <- 1;
  1753.     for (i in B_Ind){
  1754.         # Set the individual pitch data
  1755.         PITCH <- list(ax = PITCHES$ax[i], ay = PITCHES$ay[i], az = PITCHES$az[i], vx0 = PITCHES$vx0[i], vy0 = PITCHES$vy0[i], vz0 = PITCHES$vz0[i], x0 = PITCHES$x0[i], y0 = PITCHES$y0[i], z0 = PITCHES$z0[i]);
  1756.         # Set the location of the pitch at the front of home plate
  1757.         xz_loc <- xz_plate_loc(PITCH);
  1758.         # Find the four different types of movement
  1759.         PFX_B <- PFX_Mvt(PITCH,55);
  1760.         PFX_Drag_B <- PFX_Mvt_Drag(PITCH,55);
  1761.         W_B <- W_Mvt(PITCH,55);
  1762.         W_Drag_B <- W_Mvt_Drag(PITCH,55);
  1763.         # Find the direction of the pitch, relative to the strike zone
  1764.         xz_dir <- Dir_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1765.         # Find the distance between the pitch and the core quadrilateral
  1766.         xz_sz_dist <- Min_Dist_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1767.         # Find the angle between the direction of the pitch and the movement
  1768.         Angle_PFX_B[k] <- Dot_Prod_Angle(xz_dir,PFX_B);
  1769.         Angle_PFX_Drag_B[k] <- Dot_Prod_Angle(xz_dir,PFX_Drag_B);
  1770.         Angle_W_B[k] <- Dot_Prod_Angle(xz_dir,W_B);
  1771.         Angle_W_Drag_B[k] <- Dot_Prod_Angle(xz_dir,W_Drag_B);
  1772.         # Set an array for the distances from the strike zone
  1773.         SZ_Dist_B[k] <- xz_sz_dist - (log(2)/4)^(1/4);
  1774.         k <- k+1;
  1775.     }
  1776.     Angle_Pct_Dist(Angle_PFX_B,SZ_Dist_B);
  1777.     Angle_Pct_Dist(Angle_PFX_Drag_B,SZ_Dist_B);
  1778.     Angle_Pct_Dist(Angle_W_B,SZ_Dist_B);
  1779.     Angle_Pct_Dist(Angle_W_Drag_B,SZ_Dist_B);
  1780.     # Plot the data for PITCHf/x movement
  1781.     windows();
  1782.     PFX_Title <- paste("2016: ",pitch_name," ",result," Outside (",throws,"HP v. ",stand,"HB) PFX",sep="");
  1783.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_PFX_B);
  1784.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1785.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1786.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1787.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1788.           scale_fill_gradient(low="white", high=res_color) + ggtitle(PFX_Title) +
  1789.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1790.     # Plot the data for PITCHf/x movement with drag removed
  1791.     windows();
  1792.     PFX_Drag_Title <- paste("2016: ",pitch_name," ",result," Outside (",throws,"HP v. ",stand,"HB) PFX D",sep="");
  1793.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_PFX_Drag_B);
  1794.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1795.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1796.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1797.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1798.           scale_fill_gradient(low="white", high=res_color) + ggtitle(PFX_Drag_Title) +
  1799.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1800.     # Plot the data for planar movement
  1801.     windows();
  1802.     W_Title <- paste("2016: ",pitch_name," ",result," Outside (",throws,"HP v. ",stand,"HB) W",sep="");
  1803.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_W_B);
  1804.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1805.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1806.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1807.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1808.           scale_fill_gradient(low="white", high=res_color) + ggtitle(W_Title) +
  1809.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1810.     # Plot the data for planar movement with drag removed
  1811.     windows();
  1812.     W_Drag_Title <- paste("2016: ",pitch_name," ",result," Outside (",throws,"HP v. ",stand,"HB) W D",sep="");
  1813.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_W_Drag_B);
  1814.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1815.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1816.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1817.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1818.           scale_fill_gradient(low="white", high=res_color) + ggtitle(W_Drag_Title) +
  1819.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1820. }
  1821.  
  1822. ######################################################################################
  1823. # Plot the pitches outside the strike zone based on angle vs. movement for a pitcher #
  1824. ######################################################################################
  1825.  
  1826. Angle_Dist_Table_Plot <- function(PITCHES,QUAD,first,last,stand,pitch_type,result,res_color){
  1827.     # Find the indices of the pitches that are balls and are strikes
  1828.     Index <- ball_strike_prob(PITCHES,stand);
  1829.     # Set the indices of pitches outside the strike zone
  1830.     B_Ind <- Index$B;
  1831.     # Find the number of pitches outside the strike zone
  1832.     N_B <- length(B_Ind);
  1833.     # Set arrays for each set of angles for each type of movement
  1834.     Angle_PFX_B <- array(0,dim=N_B);
  1835.     Angle_PFX_Drag_B <- array(0,dim=N_B);
  1836.     Angle_W_B <- array(0,dim=N_B);
  1837.     Angle_W_Drag_B <- array(0,dim=N_B);
  1838.     # Set an array for the distances from the strike zone
  1839.     SZ_Dist_B <- array(0,dim=N_B);
  1840.     # Loop over the pitches outside the zone and find the angle between the movement and direction of the pitch
  1841.     k <- 1;
  1842.     for (i in B_Ind){
  1843.         # Set the individual pitch data
  1844.         PITCH <- list(ax = PITCHES$ax[i], ay = PITCHES$ay[i], az = PITCHES$az[i], vx0 = PITCHES$vx0[i], vy0 = PITCHES$vy0[i], vz0 = PITCHES$vz0[i], x0 = PITCHES$x0[i], y0 = PITCHES$y0[i], z0 = PITCHES$z0[i]);
  1845.         # Set the location of the pitch at the front of home plate
  1846.         xz_loc <- xz_plate_loc(PITCH);
  1847.         # Find the four different types of movement
  1848.         PFX_B <- PFX_Mvt(PITCH,55);
  1849.         PFX_Drag_B <- PFX_Mvt_Drag(PITCH,55);
  1850.         W_B <- W_Mvt(PITCH,55);
  1851.         W_Drag_B <- W_Mvt_Drag(PITCH,55);
  1852.         # Find the direction of the pitch, relative to the strike zone
  1853.         xz_dir <- Dir_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1854.         # Find the distance between the pitch and the core quadrilateral
  1855.         xz_sz_dist <- Min_Dist_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1856.         # Find the angle between the direction of the pitch and the movement
  1857.         Angle_PFX_B[k] <- Dot_Prod_Angle(xz_dir,PFX_B);
  1858.         Angle_PFX_Drag_B[k] <- Dot_Prod_Angle(xz_dir,PFX_Drag_B);
  1859.         Angle_W_B[k] <- Dot_Prod_Angle(xz_dir,W_B);
  1860.         Angle_W_Drag_B[k] <- Dot_Prod_Angle(xz_dir,W_Drag_B);
  1861.         # Set an array for the distances from the strike zone
  1862.         SZ_Dist_B[k] <- xz_sz_dist - (log(2)/4)^(1/4);
  1863.         k <- k+1;
  1864.     }
  1865.     Angle_Pct_Dist(Angle_PFX_B,SZ_Dist_B);
  1866.     Angle_Pct_Dist(Angle_PFX_Drag_B,SZ_Dist_B);
  1867.     Angle_Pct_Dist(Angle_W_B,SZ_Dist_B);
  1868.     Angle_Pct_Dist(Angle_W_Drag_B,SZ_Dist_B);
  1869.     # Plot the data for PITCHf/x movement
  1870.     windows();
  1871.     PFX_Title <- paste("2016: ",pitch_name," ",result," Outside (",first," ",last," v. ",stand,"HB) PFX",sep="");
  1872.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_PFX_B);
  1873.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1874.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1875.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1876.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1877.           scale_fill_gradient(low="white", high=res_color) + ggtitle(PFX_Title) +
  1878.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1879.     # Plot the data for PITCHf/x movement with drag removed
  1880.     windows();
  1881.     PFX_Drag_Title <- paste("2016: ",pitch_name," ",result," Outside (",first," ",last," v. ",stand,"HB) PFX D",sep="");
  1882.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_PFX_Drag_B);
  1883.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1884.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1885.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1886.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1887.           scale_fill_gradient(low="white", high=res_color) + ggtitle(PFX_Drag_Title) +
  1888.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1889.     # Plot the data for planar movement
  1890.     windows();
  1891.     W_Title <- paste("2016: ",pitch_name," ",result," Outside (",first," ",last," v. ",stand,"HB) W",sep="");
  1892.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_W_B);
  1893.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1894.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1895.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1896.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1897.           scale_fill_gradient(low="white", high=res_color) + ggtitle(W_Title) +
  1898.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1899.     # Plot the data for planar movement with drag removed
  1900.     windows();
  1901.     W_Drag_Title <- paste("2016: ",pitch_name," ",result," Outside (",first," ",last," v. ",stand,"HB) W D",sep="");
  1902.     data.df <- data.frame(Dist = SZ_Dist_B,Angle = Angle_W_Drag_B);
  1903.     print(ggplot(data.df,aes(x=Dist,y=Angle)) + geom_hex(binwidth=c(0.25,15)) +
  1904.           scale_x_continuous(breaks=seq(0,3,0.5),limits=c(-0.125,3.125)) +
  1905.           scale_y_continuous(breaks=seq(0,180,30),limits=c(-7.5,187.5)) +
  1906.           xlab("Distance From Strike Zone (Feet)") + ylab("Angle (Degrees)") +
  1907.           scale_fill_gradient(low="white", high=res_color) + ggtitle(W_Drag_Title) +
  1908.       theme(panel.background = element_rect(fill = "black", color = "black", size = 1)));
  1909. }
  1910.  
  1911. #########################################################################################
  1912. # Calculate the angle of the pitches outside the strike zone vs. movement for a pitcher #
  1913. #########################################################################################
  1914.  
  1915. Angle_Dist_Store <- function(PITCHES,QUAD,stand,pitch_type){
  1916.     # Find the indices of the pitches that are balls and are strikes
  1917.     Index <- ball_strike_prob(PITCHES,stand);
  1918.     # Set the indices of pitches outside the strike zone
  1919.     B_Ind <- Index$B;
  1920.     # Find the number of pitches outside the strike zone
  1921.     N_B <- length(B_Ind);
  1922.     # Set arrays for each set of angles for each type of movement
  1923.     Angle_PFX_B <- array(0,dim=N_B);
  1924.     Angle_PFX_Drag_B <- array(0,dim=N_B);
  1925.     Angle_W_B <- array(0,dim=N_B);
  1926.     Angle_W_Drag_B <- array(0,dim=N_B);
  1927.     # Set an array for the distances from the strike zone
  1928.     SZ_Dist_B <- array(0,dim=N_B);
  1929.     # Loop over the pitches outside the zone and find the angle between the movement and direction of the pitch
  1930.     k <- 1;
  1931.     for (i in B_Ind){
  1932.         # Set the individual pitch data
  1933.         PITCH <- list(ax = PITCHES$ax[i], ay = PITCHES$ay[i], az = PITCHES$az[i], vx0 = PITCHES$vx0[i], vy0 = PITCHES$vy0[i], vz0 = PITCHES$vz0[i], x0 = PITCHES$x0[i], y0 = PITCHES$y0[i], z0 = PITCHES$z0[i]);
  1934.         # Set the location of the pitch at the front of home plate
  1935.         xz_loc <- xz_plate_loc(PITCH);
  1936.         # Find the four different types of movement
  1937.         PFX_B <- PFX_Mvt(PITCH,55);
  1938.         PFX_Drag_B <- PFX_Mvt_Drag(PITCH,55);
  1939.         W_B <- W_Mvt(PITCH,55);
  1940.         W_Drag_B <- W_Mvt_Drag(PITCH,55);
  1941.         # Find the direction of the pitch, relative to the strike zone
  1942.         xz_dir <- Dir_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1943.         # Find the distance between the pitch and the core quadrilateral
  1944.         xz_sz_dist <- Min_Dist_Quad(xz_loc,QUAD$UL,QUAD$UR,QUAD$LL,QUAD$LR);
  1945.         # Find the angle between the direction of the pitch and the movement
  1946.         Angle_PFX_B[k] <- Dot_Prod_Angle(xz_dir,PFX_B);
  1947.         Angle_PFX_Drag_B[k] <- Dot_Prod_Angle(xz_dir,PFX_Drag_B);
  1948.         Angle_W_B[k] <- Dot_Prod_Angle(xz_dir,W_B);
  1949.         Angle_W_Drag_B[k] <- Dot_Prod_Angle(xz_dir,W_Drag_B);
  1950.         # Set an array for the distances from the strike zone
  1951.         SZ_Dist_B[k] <- xz_sz_dist - (log(2)/4)^(1/4);
  1952.         k <- k+1;
  1953.     }
  1954.     PFX_Store <- Angle_Pct_Dist_Store(Angle_PFX_B,SZ_Dist_B);
  1955.     PFX_Drag_Store <- Angle_Pct_Dist_Store(Angle_PFX_Drag_B,SZ_Dist_B);
  1956.     W_Store <- Angle_Pct_Dist_Store(Angle_W_B,SZ_Dist_B);
  1957.     W_Drag_Store <- Angle_Pct_Dist_Store(Angle_W_Drag_B,SZ_Dist_B);
  1958.     return(c(PFX_Store,PFX_Drag_Store,W_Store,W_Drag_Store,N_B));
  1959. }
  1960.  
  1961. #####################################################
  1962. # Store the angle and distance data in a data frame #
  1963. #####################################################
  1964.  
  1965. Angle_Dist_to_DF <- function(First,Last,SR_Out,MR_Out,Angle_Dist){
  1966.     # Separate out the angles
  1967.     PFX_30_A <- Angle_Dist[,1];
  1968.     PFX_60_A <- Angle_Dist[,2];
  1969.     PFX_90_A <- Angle_Dist[,3];
  1970.     PFX_120_A <- Angle_Dist[,4];
  1971.     PFX_150_A <- Angle_Dist[,5];
  1972.     PFX_180_A <- Angle_Dist[,6];
  1973.     PFX_Drag_30_A <- Angle_Dist[,13];
  1974.     PFX_Drag_60_A <- Angle_Dist[,14];
  1975.     PFX_Drag_90_A <- Angle_Dist[,15];
  1976.     PFX_Drag_120_A <- Angle_Dist[,16];
  1977.     PFX_Drag_150_A <- Angle_Dist[,17];
  1978.     PFX_Drag_180_A <- Angle_Dist[,18];
  1979.     W_30_A <- Angle_Dist[,25];
  1980.     W_60_A <- Angle_Dist[,26];
  1981.     W_90_A <- Angle_Dist[,27];
  1982.     W_120_A <- Angle_Dist[,28];
  1983.     W_150_A <- Angle_Dist[,29];
  1984.     W_180_A <- Angle_Dist[,30];
  1985.     W_Drag_30_A <- Angle_Dist[,37];
  1986.     W_Drag_60_A <- Angle_Dist[,38];
  1987.     W_Drag_90_A <- Angle_Dist[,39];
  1988.     W_Drag_120_A <- Angle_Dist[,40];
  1989.     W_Drag_150_A <- Angle_Dist[,41];
  1990.     W_Drag_180_A <- Angle_Dist[,42];
  1991.     # Separate out the distances
  1992.     PFX_30_D <- Angle_Dist[,7];
  1993.     PFX_60_D <- Angle_Dist[,8];
  1994.     PFX_90_D <- Angle_Dist[,9];
  1995.     PFX_120_D <- Angle_Dist[,10];
  1996.     PFX_150_D <- Angle_Dist[,11];
  1997.     PFX_180_D <- Angle_Dist[,12];
  1998.     PFX_Drag_30_D <- Angle_Dist[,19];
  1999.     PFX_Drag_60_D <- Angle_Dist[,20];
  2000.     PFX_Drag_90_D <- Angle_Dist[,21];
  2001.     PFX_Drag_120_D <- Angle_Dist[,22];
  2002.     PFX_Drag_150_D <- Angle_Dist[,23];
  2003.     PFX_Drag_180_D <- Angle_Dist[,24];
  2004.     W_30_D <- Angle_Dist[,31];
  2005.     W_60_D <- Angle_Dist[,32];
  2006.     W_90_D <- Angle_Dist[,33];
  2007.     W_120_D <- Angle_Dist[,34];
  2008.     W_150_D <- Angle_Dist[,35];
  2009.     W_180_D <- Angle_Dist[,36];
  2010.     W_Drag_30_D <- Angle_Dist[,43];
  2011.     W_Drag_60_D <- Angle_Dist[,44];
  2012.     W_Drag_90_D <- Angle_Dist[,45];
  2013.     W_Drag_120_D <- Angle_Dist[,46];
  2014.     W_Drag_150_D <- Angle_Dist[,47];
  2015.     W_Drag_180_D <- Angle_Dist[,48];
  2016.     # Store the angles and distances in a data frame
  2017.     return(data.frame(First,Last,SR_Out,MR_Out,PFX_30_A,PFX_60_A,PFX_90_A,PFX_120_A,PFX_150_A,PFX_180_A,PFX_Drag_30_A,PFX_Drag_60_A,PFX_Drag_90_A,PFX_Drag_120_A,PFX_Drag_150_A,PFX_Drag_180_A,
  2018.                             W_30_A,W_60_A,W_90_A,W_120_A,W_150_A,W_180_A,W_Drag_30_A,W_Drag_60_A,W_Drag_90_A,W_Drag_120_A,W_Drag_150_A,W_Drag_180_A,
  2019.                             PFX_30_D,PFX_60_D,PFX_90_D,PFX_120_D,PFX_150_D,PFX_180_D,PFX_Drag_30_D,PFX_Drag_60_D,PFX_Drag_90_D,PFX_Drag_120_D,PFX_Drag_150_D,PFX_Drag_180_D,
  2020.                             W_30_D,W_60_D,W_90_D,W_120_D,W_150_D,W_180_D,W_Drag_30_D,W_Drag_60_D,W_Drag_90_D,W_Drag_120_D,W_Drag_150_D,W_Drag_180_D));
  2021. }
  2022.  
  2023. ##################################
  2024. # PITCHf/x Late Break (3 inches) #
  2025. ##################################
  2026.  
  2027. Late_Break_PFX <- function(PITCH){
  2028.     # Set gravity
  2029.     g <- -32.174;
  2030.     # Find the time for the pitch to reach the plate in y
  2031.     a <- 0.5*PITCH$ay;
  2032.     b <- PITCH$vy0;
  2033.     c_plate <- PITCH$y0 - (17/12);
  2034.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  2035.     # Find the PFX movement on the pitch
  2036.     pfx_loc <- PFX_Mvt_Norm(PITCH,677/24);
  2037.     if (pfx_loc >= 3){
  2038.         t_rem <- sqrt(0.5/sqrt(PITCH$ax^2 + (PITCH$az - g)^2));
  2039.         t_break <- t_plate - t_rem;
  2040.         a_arc <- (PITCH$ax)^2 + (PITCH$ay)^2 + (PITCH$az)^2;
  2041.         b_arc <- 2*(PITCH$ax*PITCH$vx0 + PITCH$ay*PITCH$vy0 + PITCH$az*PITCH$vz0);
  2042.         c_arc <- (PITCH$vx0)^2 + (PITCH$vy0)^2 + (PITCH$vz0)^2;
  2043.         arc_rem <- Arc_Length(a_arc,b_arc,c_arc,t_break,t_plate);
  2044.     } else {
  2045.         t_rem <- 0;
  2046.         arc_rem <- 0;
  2047.     }
  2048.     LB_PFX <- list(pfx_loc = pfx_loc, t_rem = t_rem, arc_rem = arc_rem);
  2049.     return(LB_PFX);
  2050. }
  2051.  
  2052. ####################################################
  2053. # PITCHf/x Late Break with Drag Removed (3 inches) #
  2054. ####################################################
  2055.  
  2056. Late_Break_PFX_Drag <- function(PITCH){
  2057.     # Set gravity
  2058.     g <- -32.174;
  2059.     # Find the time for the pitch to reach the plate in y
  2060.     a <- 0.5*PITCH$ay;
  2061.     b <- PITCH$vy0;
  2062.     c_plate <- PITCH$y0 - (17/12);
  2063.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  2064.     # Find the PFX movement with drag removed on the pitch
  2065.     pfx_drag_loc <- PFX_Mvt_Drag_Norm(PITCH,677/24);
  2066.     if (pfx_drag_loc >= 3){
  2067.         # Solve for the time of a 3-inch displacement iteratively
  2068.         t_break <- PFX_Drag_LB_IT(PITCH,677/24,17/12);
  2069.         t_rem <- t_plate - t_break;
  2070.         a_arc <- (PITCH$ax)^2 + (PITCH$ay)^2 + (PITCH$az)^2;
  2071.         b_arc <- 2*(PITCH$ax*PITCH$vx0 + PITCH$ay*PITCH$vy0 + PITCH$az*PITCH$vz0);
  2072.         c_arc <- (PITCH$vx0)^2 + (PITCH$vy0)^2 + (PITCH$vz0)^2;
  2073.         arc_rem <- Arc_Length(a_arc,b_arc,c_arc,t_break,t_plate);
  2074.     } else {
  2075.         t_rem <- 0;
  2076.         arc_rem <- 0;
  2077.     }
  2078.     LB_PFX_Drag <- list(pfx_drag_loc = pfx_drag_loc, t_rem = t_rem, arc_rem = arc_rem);
  2079.     return(LB_PFX_Drag);
  2080. }
  2081.  
  2082. #####################################
  2083. # w-Direction Late Break (3 inches) #
  2084. #####################################
  2085.  
  2086. Late_Break_W <- function(PITCH){
  2087.     # Find the time for the pitch to reach the plate in y
  2088.     a <- 0.5*PITCH$ay;
  2089.     b <- PITCH$vy0;
  2090.     c_plate <- PITCH$y0 - (17/12);
  2091.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  2092.     # Find the in-plane movement on the pitch
  2093.     w_loc <- abs(W_Mvt_Norm(PITCH,677/24));
  2094.     if (w_loc >= 3){
  2095.         # Find the PITCHf/x basis
  2096.         BV <- PFX_Basis(PITCH);
  2097.         BV_T <- t(BV);
  2098.         # Find the w-acceleration of the pitch
  2099.         aw <- BV_T[3,] %*% c(PITCH$ax,PITCH$ay,PITCH$az);
  2100.         gw <- BV_T[3,] %*% c(0,0,-32.174);
  2101.         # Solve for the time of a 3-inch displacement
  2102.         t_rem <- sqrt(0.5/abs(aw - gw));
  2103.         t_break <- t_plate - t_rem;
  2104.         a_arc <- (PITCH$ax)^2 + (PITCH$ay)^2 + (PITCH$az)^2;
  2105.         b_arc <- 2*(PITCH$ax*PITCH$vx0 + PITCH$ay*PITCH$vy0 + PITCH$az*PITCH$vz0);
  2106.         c_arc <- (PITCH$vx0)^2 + (PITCH$vy0)^2 + (PITCH$vz0)^2;
  2107.         arc_rem <- Arc_Length(a_arc,b_arc,c_arc,t_break,t_plate);
  2108.     } else {
  2109.         t_rem <- 0;
  2110.         arc_rem <- 0;
  2111.     }
  2112.     LB_W <- list(w_loc = w_loc, t_rem = t_rem, arc_rem = arc_rem);
  2113.     return(LB_W);
  2114. }
  2115.  
  2116. #######################################################
  2117. # w-Direction Late Break with Drag Removed (3 inches) #
  2118. #######################################################
  2119.  
  2120. Late_Break_W_Drag <- function(PITCH){
  2121.     # Find the time for the pitch to reach the plate in y
  2122.     a <- 0.5*PITCH$ay;
  2123.     b <- PITCH$vy0;
  2124.     c_plate <- PITCH$y0 - (17/12);
  2125.     t_plate <- (-b - sqrt(b^2 - 4*a*c_plate))/(2*a);
  2126.     # Find the in-plane movement without drag on the pitch
  2127.     w_drag_loc <- abs(W_Mvt_Drag_Norm(PITCH,677/24));
  2128.     if  (w_drag_loc >= 3){
  2129.         t_break <- W_Drag_LB_IT(PITCH,677/24,17/12);
  2130.         t_rem <- t_plate - t_break;
  2131.         a_arc <- (PITCH$ax)^2 + (PITCH$ay)^2 + (PITCH$az)^2;
  2132.         b_arc <- 2*(PITCH$ax*PITCH$vx0 + PITCH$ay*PITCH$vy0 + PITCH$az*PITCH$vz0);
  2133.         c_arc <- (PITCH$vx0)^2 + (PITCH$vy0)^2 + (PITCH$vz0)^2;
  2134.         arc_rem <- Arc_Length(a_arc,b_arc,c_arc,t_break,t_plate);
  2135.     } else {
  2136.         t_rem <- 0;
  2137.         arc_rem <- 0;
  2138.     }
  2139.     LB_W_Drag <- list(w_drag_loc = w_drag_loc, t_rem = t_rem, arc_rem = arc_rem);
  2140.     return(LB_W_Drag);
  2141. }
  2142.  
  2143. #######################
  2144. # Arc Length Function #
  2145. #######################
  2146.  
  2147. Arc_Func <- function(a,b,c,t){
  2148.     af <- (2*sqrt(a)*(b + 2*a*t)*sqrt(c+t*(b+a*t))-
  2149.           (b^2-4*a*c)*log(b+2*a*t+2*sqrt(a)*sqrt(c+t*(b+a*t))))/(8*a^(3/2));
  2150.     return(af);
  2151. }
  2152.  
  2153. ################################
  2154. # Arc Length Between Two Times #
  2155. ################################
  2156.  
  2157. Arc_Length <- function(a,b,c,t_0,t_1){
  2158.     arc_0 <- Arc_Func(a,b,c,t_0);
  2159.     arc_1 <- Arc_Func(a,b,c,t_1);
  2160.     arc <- arc_1 - arc_0;
  2161.     return(arc);
  2162. }
  2163.  
  2164. ########################################
  2165. # Three-Inch PFX Drag Iterative Solver #
  2166. ########################################
  2167.  
  2168. PFX_Drag_LB_IT <- function(PITCH,y_pitcher,y_plate){
  2169.     pfx_d <- PFX_Mvt_Drag_Norm(PITCH,y_pitcher);
  2170.     y_new <- y_pitcher;
  2171.     while(abs(pfx_d - 3) > 0.001){
  2172.         # Find the midpoint in y for the pitch
  2173.         y_new <- (y_pitcher + y_plate)/2;
  2174.         # Find the movement at this point
  2175.         pfx_d <- PFX_Mvt_Drag_Norm(PITCH,y_new);
  2176.         if (pfx_d > 3){
  2177.             y_pitcher <- y_new;
  2178.         } else {
  2179.             y_plate <- y_new;
  2180.         }
  2181.     }
  2182.     # Find the time associated with y
  2183.     a <- 0.5*PITCH$ay;
  2184.     b <- PITCH$vy0;
  2185.     c_loc <- PITCH$y0 - y_new;
  2186.     return((-b - sqrt(b^2 - 4*a*c_loc))/(2*a));
  2187. }
  2188.  
  2189. ######################################
  2190. # Three-Inch W Drag Iterative Solver #
  2191. ######################################
  2192.  
  2193. W_Drag_LB_IT <- function(PITCH,y_pitcher,y_plate){
  2194.     w_d <- abs(W_Mvt_Drag_Norm(PITCH,y_pitcher));
  2195.     y_new <- y_pitcher;
  2196.     while(abs(w_d - 3) > 0.001){
  2197.         # Find the midpoint in y for the pitch
  2198.         y_new <- (y_pitcher + y_plate)/2;
  2199.         # Find the movement at this point
  2200.         w_d <- abs(W_Mvt_Drag_Norm(PITCH,y_new));
  2201.         if (w_d > 3){
  2202.             y_pitcher <- y_new;
  2203.         } else {
  2204.             y_plate <- y_new;
  2205.         }
  2206.     }
  2207.     # Find the time associated with y
  2208.     a <- 0.5*PITCH$ay;
  2209.     b <- PITCH$vy0;
  2210.     c_loc <- PITCH$y0 - y_new;
  2211.     return((-b - sqrt(b^2 - 4*a*c_loc))/(2*a));
  2212. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement