Skip to content

Instantly share code, notes, and snippets.

@gabrielflorit
Last active July 10, 2018 21:17
Show Gist options
  • Save gabrielflorit/a99f1bd5c7ca9d839970a40988ac0fe4 to your computer and use it in GitHub Desktop.
Save gabrielflorit/a99f1bd5c7ca9d839970a40988ac0fe4 to your computer and use it in GitHub Desktop.
SCRIPT-8
// title: Brute projectiles
// helper functions
const { sin, cos, exp, PI } = Math
const mphToMs = mph => mph * 1609.34 / 3600
const feetToMeters = feet => feet * 0.3048
// projectile constants
const v0 = mphToMs(102.846) // exit velocity (m/s)
const R = feetToMeters(368.786) // desired final distance
const ø = 34.93 // launch angle (degrees)
const y0 = feetToMeters(4)
const g = 9.8 // gravity (m/s2)
const ørad = ø * PI / 180 // launch angle (radians)
let C = 100
let minMax = [100, 100]
initialState = {
C: 100,
dC: 0.5
}
const calculateVt = () => C / 100 * R * g / (v0 * cos(ørad))
let vt = calculateVt()
// x(t) and y(t)
// these functions assume drag is a function of vt, terminal velocity
const xF = t => v0 * vt * cos(ørad) / g * (1 - exp(-g * t / vt))
const yF = t =>
y0 + vt / g * (v0 * sin(ørad) + vt) * (1 - exp(-g * t / vt)) - vt * t
const step = 0.1
const createPoints = () => {
// to create points:
// keep adding points until y is 0 or lower
const points = []
let found = false
let t = 0
let safety = 0
while (!found && ++safety < 1000) {
const point = [xF(t), yF(t)]
t += step
if (point[1] < 0) {
found = true
}
points.push(point)
}
return points
}
let points = createPoints()
// now we have our destination point.
// adjust C until the last point is at or past expected distance.
let found = false
let safety = 0
while (!found && ++safety < 1000) {
C++
vt = calculateVt()
points = createPoints()
if (points.slice(-1)[0][0] >= R) {
found = true
minMax[1] = C
}
}
// adjust coordinates so we can write conventional
// coordinate math (x goes left to right, y goes down to up)
const reproject = p => [p[0], 127 - 5 - p[1]]
const ease = x => {
const span = minMax[1] - minMax[0]
return (
cos((span - minMax[0]) * PI / span + x * PI / span) * span / 2 +
span / 2 +
minMax[0]
)
}
update = state => {
state.C += state.dC
if (state.C > minMax[1] || state.C < minMax[0]) {
state.dC *= -1
}
}
draw = state => {
clear()
// axes
line(0, 0, 0, 127 - 5, 6) // y-axis
line(0, 127 - 5, 127, 127 - 5, 6) // x-axis
// titles
print(2, 0, 'baseball path simulator', 2)
print(2, 30, `exit velocity: ${v0.toFixed(2)} m/s`, 3)
print(2, 40, `launch angle: ${ø.toFixed(2)} degrees`, 3)
print(2, 50, 'simulated distance', 2)
print(2, 70, `terminal velocity: ${vt.toFixed(2)} m/s`, 2)
circFill(78, 52, 3, 2)
print(2, 60, `target distance (${R.toFixed(2)} m)`, 2)
circStroke(78, 62, 5, 2)
C = ease(state.C)
vt = calculateVt()
points = createPoints()
print(2, 80, `simulated duration: ${(points.length*step).toFixed(2)} s`, 2)
// draw projectile:
points.forEach((p, i, a) => {
if (i < a.length - 1) {
// draw line
const next = a[i + 1]
line(...reproject(p), ...reproject(next), 4)
}
// if we're at the last point,
// draw a ball
if (i === a.length - 1) {
circFill(...reproject(p), 3, 2)
print(88, 50, `(${p[0].toFixed(2)} m)`, 2)
}
})
// draw ball at expected distance
circStroke(...reproject([R, 0]), 5, 2)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment