Skip to content

Instantly share code, notes, and snippets.

@k0t0vich
Created October 22, 2013 19:18
Show Gist options
  • Select an option

  • Save k0t0vich/7106513 to your computer and use it in GitHub Desktop.

Select an option

Save k0t0vich/7106513 to your computer and use it in GitHub Desktop.
package ru.yandex.utils.math {
public class AngleRange {
private var _min:Number;
private var _max:Number;
/**
* Диапазон углов.
* <p>
* Этот класс не учитывает систему отсчета углов. Это может быть геометрическая
* система (углы отсчитываются от положительного направления оси Ox против часовой
* стрелки), либо географическая (углы отсчитываются от направления на север по
* часовой стрелке), либо любая другая.
* </p>
*
* @param minRadians Начальный угол в радианах.
* @param maxRadians Конечный угол в радианах.
*/
public function AngleRange(minRadians:Number, maxRadians:Number) {
_min = AngleUtil.normRadians(minRadians);
_max = AngleUtil.normRadians(maxRadians);
}
/**
* Проверка попадания значения угла в диапазон.
*
* @param radians Значение проверяемого угла в радианах.
*
* @return Если значение попадает в диапазон - <code>true</code>, в противном случае -
* <code>false</code>.
*/
public function containsValue(radians:Number):Boolean {
var normalized:Number = AngleUtil.normRadians(radians);
if (_min <= _max) {
return (_min <= normalized) && (normalized <= _max);
}
return (normalized <= _max) || (_min <= normalized);
}
/**
* @return Разница между начальным и конечным углом дианазона. Значение выдается в
* радианах, в дианазоне [0; 360).
*/
public function get size():Number {
var result:Number = AngleUtil.normRadians(_max - _min);
return (result >= 0) ? result : (result + AngleUtil.TWO_PI);
}
public function get bisector():Number {
return AngleUtil.normRadians(_min + size / 2);
}
public function get min():Number {
return _min;
}
public function get max():Number {
return _max;
}
}
}
package ru.yandex.utils.math {
public class AngleUtil {
public static const HALF_PI:Number = 0.5 * Math.PI;
public static const TWO_PI:Number = Math.PI + Math.PI;
public static const RAD_TO_DEG:Number = 180 / Math.PI;
public static const DEG_TO_RAD:Number = Math.PI / 180;
private static const RANGE_RAD:Number = 0x7FFFFFFF / Math.PI;
private static const RANGE_DEG:Number = 0x7FFFFFFF / 180;
/**
* Нормализация угла.
*
* @param angle Исходный угол в радианах.
*
* @return Значение в диапазоне [-PI, PI).
*
*/
public static function normRadians(angle:Number):Number {
return int(angle * RANGE_RAD) / RANGE_RAD;
}
public static function normRadiansTo2PI(angle:Number):Number {
var tmp:Number = normRadians(angle);
return tmp > 0 ? tmp : TWO_PI + tmp;
}
public static function degreesToRadians(angle:Number):Number {
return DEG_TO_RAD * angle;
}
public static function radiansToDegrees(angle:Number):Number {
return RAD_TO_DEG * angle;
}
/**
* Нормализация угла.
*
* @param angle Исходный угол в градусах.
*
* @return Значение в диапазоне [-180, 180).
*/
public static function normDegrees(angle:Number):Number {
return int(angle * RANGE_DEG) / RANGE_DEG;
}
/**
* Разница между двумя углами.
* <p>Определяет величину угла между двумя заданными углами</p>
* @param radians1
* @param radians2
* @return
*
*/
public static function diff(radians1:Number, radians2:Number):Number {
var diff:Number = (radians2 % TWO_PI) - (radians1 % TWO_PI);
return normRadians(diff);
}
public static function average(radians1:Number, ... radians):Number {
if (radians.length == 0) {
return normRadians(radians1);
}
var angles:Array = [normRadians(radians1)];
for (var i:int = 0; i < radians.length; i++) {
angles.push(normRadians(radians[i]));
}
var d:Number = diff(angles[0], angles[1]);
var maxDiff:Number = Math.abs(d);
var maxRange:AngleRange = (d >= 0) ? new AngleRange(angles[0], angles[1])
: new AngleRange(angles[1], angles[0]);
for (var j:int = 1; j < angles.length - 1; j++) {
d = diff(angles[j], angles[j + 1]);
if (Math.abs(d) > maxDiff) {
maxDiff = Math.abs(d);
maxRange = (d >= 0) ? new AngleRange(angles[j], angles[j + 1])
: new AngleRange(angles[j + 1], angles[j]);
}
}
var zeroAngle:Number = maxRange.bisector;
var sum:Number = 0;
for each (var angle:Number in angles) {
sum += normRadians(angle - zeroAngle);
}
return normRadians(sum / angles.length + zeroAngle);
}
}
}
package ru.yandex.utils.math {
import flash.geom.Point;
/**
* Возвращает точку p3 перпендикуляра,такую, что
* угол (p1p2, p2p3) = 90 и длина вектора p2p3 = length
* Используется подобие прямоугольных прямоугольников
* @param p1
* @param p2
* @param length
* @return
*/
public function getOrthogonalPoint(p1:Point, p2:Point, length:Number = 1):Point {
var dP:Point = p2.subtract(p1);
// коэффициент подобия
var k:Number = length / dP.length;
var dx:Number = k * dP.y;
var dy:Number = -k * dP.x;
var result:Point = new Point(dx, dy);
result = result.add(p2);
return result;
}
}
package ru.yandex.utils.math {
import flash.geom.Point;
public class IntersectUtil {
public static function getLinesIntersectionPoint(a1:Point, a2:Point, b1:Point, b2:Point):Point {
var d:Number = (a1.x - a2.x) * (b2.y - b1.y) - (a1.y - a2.y) * (b2.x - b1.x);
var da:Number = (a1.x - b1.x) * (b2.y - b1.y) - (a1.y - b1.y) * (b2.x - b1.x);
var db:Number = (a1.x - a2.x) * (a1.y - b1.y) - (a1.y - a2.y) * (a1.x - b1.x);
if (Math.abs(d) < 0.000001) {
return null;
} else {
var ta:Number = da / d;
var tb:Number = db / d;
if ((0 <= ta) && (ta <= 1) && (0 <= tb) && (tb <= 1)) {
var x:Number = a1.x + ta * (a2.x - a1.x);
var y:Number = a1.y + ta * (a2.y - a1.y);
return new Point(x, y);
}
}
return null;
}
public static function getPoligonsIntersectionPoints(polygone1:Array,
poligone2:Array):Array {
var len1:uint = polygone1.length;
var len2:uint = poligone2.length;
var result:Array = [];
for (var i:int = 0; i < len1; i++) {
var p1:Point = Point(polygone1[i]);
var p2:Point = Point(polygone1[(i + 1) % len1]);
for (var j:int = 0; j < len2; j++) {
var p3:Point = Point(poligone2[j]);
var p4:Point = Point(poligone2[(j + 1) % len2]);
var intersection:Point = getLinesIntersectionPoint(p1, p2, p3, p4);
if (intersection) {
result.push(intersection);
}
}
}
return result.length > 0 ? result : null;
}
}
}
package ru.yandex.utils.math {
public class NumberUtil {
public static function interpolate(amount:Number, begin:Number, end:Number):Number {
return begin + (end - begin) * amount;
}
}
}
package ru.yandex.utils.math {
public class Range {
private var _min:Number;
private var _max:Number;
public static function fromMinAndLength(min:Number, length:Number):Range {
return new Range(min, min + length);
}
public static function fromMiddleAndDiff(middle:Number, diff:Number):Range {
return new Range(middle - Math.abs(diff), middle + Math.abs(diff));
}
public function Range(min:Number = NaN, max:Number = NaN) {
if (!isNaN(min)) {
_min = min;
}
if (!isNaN(max)) {
_max = max;
}
validate();
}
public function interpolate(pos:Number):Number {
return _min + (_max - _min) * pos;
}
public function intersects(r:Range):Boolean {
return defined && r.defined && (_min <= r._max) && (_max >= r._min);
}
public function restrict(value:Number):Number {
if (value < _min) {
return _min;
}
if (value > _max) {
return _max;
}
return value;
}
/**
* Рассчитывает значения точек, полученных разбиением диапазона на
* <code>numParts</code> равных отрезков.
*
* <p>В результирующем массиве будет <code>numParts + 1</code> значений.</p>
*
* @param numParts Число отрезков, на которые нужно разбить диапазон.
*
* @return Набор значений.
*/
public function split(numParts:int):Array {
var result:Array = [_min];
var delta:Number = (_max - _min) / numParts;
var value:Number = _min;
for (var i:int = 1; i < numParts; i++) {
value += delta;
result.push(value);
}
result.push(_max);
return result;
}
public function equals(other:Range):Boolean {
return other && (_min == other._min) && (_max == other._max);
}
public function clone():Range {
return new Range(_min, _max);
}
public function toString():String {
return "{" + _min + ", " + _max + "}";
}
private function validate():void {
if (!isNaN(_min) && !isNaN(_max) && (_min > _max)) {
throw new RangeError("Invalid range: min = " + _min + ", max = " + _max);
}
}
public function get min():Number {
return _min;
}
public function set min(value:Number):void {
_min = value;
validate();
}
public function get max():Number {
return _max;
}
public function set max(value:Number):void {
_max = value;
if (_max < _min) {
_max = _min;
}
validate();
}
public function get size():Number {
return _max - _min;
}
private function get defined():Boolean {
return !(isNaN(_min) || isNaN(_max));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment