Last active
October 1, 2021 15:34
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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