// Library for representing a range of angles // Author: Amit J Patel // License: MIT (see LICENSE file) // Url: http://www-cs-students.stanford.edu/~amitp/game-programming/game-ideas/radial-base/ package { public class AngularRange { public static var TWOPI:Number = Math.PI * 2; public var left:Number = 0.0; public var span:Number = 0.0; public function AngularRange(L:Number, R:Number) { left = normalize(L); span = normalize(R-L); } public function get right():Number { return normalize(left+span); } // Make sure angle a is in the normal range of 0 to TWOPI public static function normalize(a:Number):Number { // Note: this isn't efficient for large deviations form the normal range while (a < 0.0) { a += TWOPI; } while (a >= TWOPI) { a -= TWOPI; } // We could instead use a - TWOPI*Math.floor(a/TWOPI) return a; } // The angular distance from angle a, going left (counterclockwise), to b public static function distanceLeft(a:Number, b:Number):Number { return normalize(a - b); } // The angular distance from angle a, going right (clockwise), to angle b public static function distanceRight(a:Number, b:Number):Number { return normalize(b - a); } // The angular distance between angle a and angle b public static function distanceBetween(a:Number, b:Number):Number { return Math.min(distanceLeft(a, b), distanceRight(a, b)); } // Distance from the angular range to an angle a public function distanceTo(a:Number):Number { if (contains(a)) { return 0.0; } else { return Math.min(distanceBetween(left, a), distanceBetween(right, a)); } } // Does the range include angle a public function contains(a:Number):Boolean { return normalize(a - left) <= span; } // Extend the range to include angle a public function extend(a:Number):void { if (!contains(a)) { if (distanceLeft(left, a) < distanceRight(right, a)) { span += distanceLeft(left, a); left = a; } else { span = normalize(a - left); } } } // Some tests public static function runTests():void { var R:* = function (x:Number):Number { return Math.round(x*10.0)/10.0; }; var r1:AngularRange = new AngularRange(0, 0.5); if (!r1.contains(0.3)) throw new Error("r1.contains(0.3)"); if (!r1.contains(0.0)) throw new Error("r1.contains(0.0)"); if (!r1.contains(0.5)) throw new Error("r1.contains(0.5)"); if (r1.contains(0.6)) throw new Error("!r1.contains(0.6)"); if (R(distanceLeft(0.3, 0.2)) != 0.1) throw new Error("1.distance "); if (R(distanceLeft(0.3, 0.2)) != 0.1) throw new Error("2.distance"); if (R(distanceRight(0.3, 6.0)) != 5.7) throw new Error("3.distance"); if (R(distanceBetween(0.3, 0.2)) != 0.1) throw new Error("4.distance"); if (R(distanceBetween(0.2, 0.4)) != 0.2) throw new Error("5.distance"); r1.extend(0.7); if (!r1.contains(0.6)) throw new Error("r1.contains(0.6)"); } } }