Skip to content

Instantly share code, notes, and snippets.

@Zearin
Last active October 1, 2021 15:34
Show Gist options
  • Save Zearin/a632965873644db1538fbd6ffb65ae63 to your computer and use it in GitHub Desktop.
Save Zearin/a632965873644db1538fbd6ffb65ae63 to your computer and use it in GitHub Desktop.
I enjoy programming, but I’m mathematically challenged. :) This gist is a request for help from the author of a fantastic answer on StackOverflow.
class Boid {
// ...
/**
* @param {Boid} other
* @returns {Boolean}
*/
canSee (other) {
// Adapted from
// https://stackoverflow.com/questions/65265444/flocking-boids-algorithm-field-of-view-specified-by-angle-in-3d
//
// (h−p) · (q−p)
// cos(φ) = ---------------
// ||h−p|| ||q−p||
//
// Translation of the above:
//
// p = this.position
// h = this.velocity
// q = other.position
//
// All of the above are vectors.
//
// -----------------------
// NOTE TO MATHEMATICIANS
//
// Here (and 2D computer graphics in general, AFAIK):
// * the origin (0, 0) is at the top-left of the screen; and,
// * the Y-axis is flipped (i.e. y-values increase downwards, and decrease upwards).
//
// I don’t think this comes into play here, but I am terrible at trigonometry, so I
// figured I’d mention it in case of some reason I’m not aware of. :)
// -----------------------
const velPosDiff = p5.Vector.sub(this.velocity, this.position) // (h-p)
const otherPosDiff = p5.Vector.sub(other.position, this.position) // (q-p)
const numerator = p5.Vector.dot(velPosDiff, otherPosDiff) // (h−p) · (q−p)
const denominator = velPosDiff.mag() * otherPosDiff.mag() // ||h−p|| ||q−p||
/*
* The StackOverflow post has me confused here.
*
* In the first equation (the big fraction), theta is shown on the left
* as `cos(φ)`:
*
* (h−p) · (q−p)
* cos(φ) = ---------------
* ||h−p|| ||q−p||
*
* But at the end of the Answer, it shows theta “naked” on the left,
* but within `cos()` on the right:
*
* φ > ρ if and only if cos(φ) < cos(ρ)
*
* So I’m not sure if I have this correct.
*
* (It’s not working, so I’m wrong *somewhere*...)
*/
const relTheta = numerator / denominator
const relCosTheta = p.cos(relTheta)
// half the field of vision (270° / 2 = 135)
const rho = p.radians(135)
const cosRho = p.cos(rho)
/* I had trouble parsing this sentence from the StackOverflow answer:
*
* Given some angle ρ (in whatever units your cosine function accepts, usually radians)
* past which the boid cannot see (putting the field of vision at 2ρ), we have
*
* φ > ρ if and only if cos(φ) < cos(ρ),
*
* ...So, I rewrote it (correctly, I hope?) as follows:
*/
// given ρ = rho
// when φ > ρ
// and cos(φ) < cos(ρ)
// then the `other` boid is unseen
const inView = cosRho > relCosTheta // ???
return inView
}
// ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment