# 回転砲台のアルゴリズム

* どっちに回したほうが近いか、やり方をよく忘れるのでメモ
by alumican_net 27 Apr 2010

## Tags

Embed
/**
* Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/t6u8
*/

/**
* 回転砲台のアルゴリズム
* どっちに回したほうが近いか、やり方をよく忘れるのでメモ
*/
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import com.bit101.components.*;

public class RotationPath extends Sprite
{
/**
* 右回りと左回りでどっちが近いか計算する
*
* @param startAngle  開始角度(rad)
* @param targetAngle 終了角度(rad)
* return 差分の角度
*/
public function calc(startAngle:Number, targetAngle:Number):Number
{
var angle0:Number = startAngle  % PI2;
var angle1:Number = targetAngle % PI2;
if (angle0 < 0) angle0 += PI2;
if (angle1 < 0) angle1 += PI2;

var d:Number = angle1　- angle0;
if (d < 0 ) d += PI2;
if (d > PI) d -= PI2;

return d;
}

private const PI:Number        = Math.PI;
private const PI2:Number       = PI * 2;
private const TO_DEGREE:Number = 180 / PI;
private const TO_RADIAN:Number = PI / 180;

private var _canvas:Sprite;
private var _center:Sprite;
private var _handle_0:Handle;
private var _handle_1:Handle;
private var _label:Label;
private var _title:String;

public function RotationPath():void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

_canvas = addChild( new Sprite() ) as Sprite;

//中心点
_center   = addChild( new Sprite() ) as Sprite;
_center.x = stage.stageWidth  * 0.5;
_center.y = stage.stageHeight * 0.5;
_center.graphics.beginFill(0x0);
_center.graphics.drawCircle(0, 0, 5);
_center.graphics.endFill();

//ハンドル
_handle_0 = addChild( new Handle(stage, update, 0xff0000) ) as Handle;
_handle_1 = addChild( new Handle(stage, update, 0x0000ff) ) as Handle;

_title = "SHORTEST ANGULAR PATH FROM RED POINT TO BLUE POINT";
_label = new Label(this, 10, 10, "");

update();
}

public function update():void
{
var g:Graphics = _canvas.graphics;

var cx:Number  = _center.x;
var cy:Number  = _center.y;

var x0:Number  = _handle_0.x;
var y0:Number  = _handle_0.y;

var x1:Number  = _handle_1.x;
var y1:Number  = _handle_1.y;

var angle0:Number = Math.atan2(y0 - cy, x0 - cx);
var angle1:Number = Math.atan2(y1 - cy, x1 - cx);

var angle:Number = calc(angle0, angle1);
_label.text = _title + "\n\n"
+ "START ANGLE : " + (angle0 * TO_DEGREE) + "\n"
+ "TARGET ANGLE : " + (angle1 * TO_DEGREE) + "\n\n"
+ "SHORTEST ANGULAR PATH : " + (angle  * TO_DEGREE);

g.clear();
g.lineStyle(0, 0xcccccc);
g.moveTo(cx, cy);
g.lineTo(x0, y0);
g.moveTo(cx, cy);
g.lineTo(x1, y1);
}
}
}

import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.geom.Rectangle;

internal class Handle extends Sprite
{
private var _stage:Stage;
private var _update:Function;

public function Handle(stage:Stage, update:Function, color:uint):void
{
_stage = stage;
_update = update;

graphics.beginFill(0x0, 0);
graphics.drawCircle(0, 0, 10);
graphics.endFill();
graphics.beginFill(color);
graphics.drawCircle(0, 0, 5);
graphics.endFill();

var margin:Number = 30;
x = margin + Math.random() * (stage.stageWidth  - margin * 2);
y = margin + Math.random() * (stage.stageHeight - margin * 2);

addEventListener(MouseEvent.MOUSE_DOWN, _mouseDownHandler);
buttonMode = true;
}

private function _mouseDownHandler(e:MouseEvent):void
{
startDrag(false, new Rectangle(0, 0, _stage.stageWidth, _stage.stageHeight));
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
}

private function _mouseUpHandler(e:MouseEvent):void
{
stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
}

private function _mouseMoveHandler(e:MouseEvent):void
{
_update();
}
}