staticpublicfloatangleBetween(PVectorv1, PVectorv2) {
// We get NaN if we pass in a zero vector which can cause problems// Zero seems like a reasonable angle between a (0,0,0) vector and something elseif (v1.x ==0&& v1.y ==0&& v1.z ==0 ) return0.0f;
if (v2.x ==0&& v2.y ==0&& v2.z ==0 ) return0.0f;
double dot = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
double v1mag =Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
double v2mag =Math.sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z);
// This should be a number between -1 and 1, since it's "normalized"double amt = dot / (v1mag * v2mag);
// But if it's not due to rounding error, then we need to fix it// http://code.google.com/p/processing/issues/detail?id=340// Otherwise if outside the range, acos() will return NaN// http://www.cppreference.com/wiki/c/math/acosif (amt <=-1) {
returnPConstants.PI;
} elseif (amt >=1) {
// http://code.google.com/p/processing/issues/detail?id=435return0;
}
return (float) Math.acos(amt);
}
No problem @kevinbarabash. But just to leave no trace of doubt that my _PVector_::angleBetween() implementation indeed fixes @lgto4's edgy case, paste this half-baked JavaScript Mode sample on http://ProcessingJS.org/tools/processing-helper.html:
finalPVector a =newPVector(1, 0, 0), b =newPVector(0, 1, 0);
float ang;
voidsetup() {
ang =PVector.angleBetween(a, b);
println(ang); // 1.5707963267948966
ang = angleBetween(a, b);
println(ang); // 1.5707963267948966
a.set(-1, 1, 0);
b.set(-1.5, 1.5, 0);
finalPVector c =newPVector(1.5, -1.5);
ang =PVector.angleBetween(b, c);
println(ang); // NaN
ang = angleBetween(b, c);
println(ang); // 3.141592653589793exit();
}
staticfinalfloatangleBetween(PVectorv1, PVectorv2) {
if (!v1.x &&!v1.y &&!v1.z ||!v2.x &&!v2.y &&!v2.z) return0;
const amt =PVector.dot(v1, v2) /Math.sqrt(v1.magSq() * v2.magSq());
return amt <=-1?Math.PI: amt >=1?0:Math.acos(amt);
}
It's funny that 1st ang = PVector.angleBetween(a, b); results 90 instead of 1.5707963267948966 O_o
var angleBetween =function (v1, v2) {
if (!v1.x &&!v1.y &&!v1.z ||!v2.x &&!v2.y &&!v2.z) { return0; }
var amt =PVector.dot(v1, v2) /Math.sqrt(v1.magSq() * v2.magSq());
return amt <=-1?Math.PI: amt >=1?0:Math.acos(amt);
};
var a =newPVector(1, 0, 0), b =newPVector(0, 1, 0);
var ang;
ang =PVector.angleBetween(a, b);
println(ang); // 90?!
ang = angleBetween(a, b);
println(ang); // 1.5707963267948966
a.set(-1, 1, 0);
b.set(-1.5, 1.5, 0);
var c =newPVector(1.5, -1.5);
ang =PVector.angleBetween(b, c);
println(ang); // NaN
ang = angleBetween(b, c);
println(ang); // 3.141592653589793exit();
Ah! I believe it's the same as p5.js' angleMode(): http://p5js.org/reference/#/p5/angleMode
I don't find it fully usable b/c although math functions return in degrees, we still need to pass values to them in radians, defeating its convenience.
We can't for example do something like this: cos(sin(PI)) while in degrees mode.
In the case above, sin() would return a degree value.
However cos() still demands a radian arg and can't use sin()'s returned degree value.
Another unintended consequence is that Khan's _PVector_ class becomes depended on the sketch's state due to angleMode. In Processing, Pjs & p5.js, _PVector_ is independent.
Activity
GoToLoop commented on Mar 4, 2016
Current _PVector_::angleBetween()'s implementation:
https://github.com/processing-js/processing-js/blob/master/src/Objects/PVector.js#L53
Proposed fix for it:
https://gist.github.com/GoToLoop/acbf106aa784820aff23#file-pvector-js-L64
GoToLoop commented on Mar 4, 2016
Indeed I haven't tested it yet. It is based off Processing's original _PVector_::angleBetween()'s: 😕
https://github.com/processing/processing/blob/master/core/src/processing/core/PVector.java#L987
k4b7 commented on Mar 4, 2016
Please disregard my previous message. I shouldn't post when I'm feeling under the weather.
GoToLoop commented on Mar 4, 2016
No problem @kevinbarabash. But just to leave no trace of doubt that my _PVector_::angleBetween() implementation indeed fixes @lgto4's edgy case, paste this half-baked JavaScript Mode sample on http://ProcessingJS.org/tools/processing-helper.html:
GoToLoop commented on Mar 4, 2016
Made a Khan version too at: https://www.KhanAcademy.org/computer-programming/spin-off-of-wat9-anglebetween/3127717618
It's funny that 1st ang = PVector.angleBetween(a, b); results 90 instead of 1.5707963267948966 O_o
k4b7 commented on Mar 4, 2016
@GoToLoop there's an angleMode setting that processing.js supports and we default to degrees on KA. See https://www.khanacademy.org/computer-programming/anglemode-processingjs/2350518561.
GoToLoop commented on Mar 4, 2016
Ah! I believe it's the same as p5.js' angleMode(): http://p5js.org/reference/#/p5/angleMode
I don't find it fully usable b/c although math functions return in degrees, we still need to pass values to them in radians, defeating its convenience.
We can't for example do something like this: cos(sin(PI)) while in degrees mode.
In the case above, sin() would return a degree value.
However cos() still demands a radian arg and can't use sin()'s returned degree value.
Another unintended consequence is that Khan's _PVector_ class becomes depended on the sketch's state due to angleMode. In Processing, Pjs & p5.js, _PVector_ is independent.