forked from: 反転の「見える化」(シュタイナー・チェーン版)
円による「反転」の様子を見てみる(シュタイナー・チェーン版)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/bwce
*/
// forked from Aquioux's 反転の「見える化」
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
/**
* 反転の「見える化」(シュタイナー・チェーン版)
*
* 青:反転前図形
* 緑:反転対称軸としての円とその円の中心点を通る縦横の直線
* 赤:反転後座標
*
* ステージクリックで連なる円の数が変わる
*
* @see http://aquioux.net/blog/?p=557
*
* @author YOSHIDA, Akio (Aquioux)
*/
public class Main extends Sprite {
private const RADIUS:uint = 70; // 反転軸円の半径
private const RADIUS_SQUARE:uint = RADIUS * RADIUS; // 反転軸円の半径の2乗
private const N_PIXEL_COLOR:uint = 0xFF0000FF; // 反転前ピクセルの色
private const I_PIXEL_COLOR:uint = 0xFFFF0000; // 反転後ピクセルの色
private const BMD_FILL_COLOR:uint = 0x00000000; // ピクセルを描く BitmapData の fill 色
private const AXIS_COLOR:uint = 0x00FF00; // 反転軸円の色
private var nBmd_:BitmapData; // 反転前ピクセルを描く BitmapData;
private var iBmd_:BitmapData; // 反転後ピクセルを描く BitmapData;
private var axis_:Shape; // 反転軸円と中心交差線を描く表示物
// 反転前座標
private var nCoordinatesArray_:Array;
private var nCoordinates_:Vector.<int>;
// 反転後座標
private var iCoordinates_:Vector.<int>;
private var len_:int; // [n/i]Coordinates の length
private var toggle_:int = 0; // トグルスイッチ
private var toggleLen_:int = 10;
// コンストラクタ
public function Main() {
setup1();
setup2();
addEventListener(Event.ENTER_FRAME, update);
stage.addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(e:MouseEvent):void {
toggle_++;
toggle_ %= toggleLen_;
setup2();
}
// 表示物の生成と不動要素の描画
private function setup1():void {
var sw:Number = stage.stageWidth;
var sh:Number = stage.stageHeight;
var cx:Number = sw / 2;
var cy:Number = sh / 2;
// 表示物の生成
// BitmapData および Bitmap
nBmd_ = new BitmapData(sw, sh, true, BMD_FILL_COLOR);
iBmd_ = nBmd_.clone();
// 反転軸円と中心交差線を描く Shape
axis_ = new Shape();
addChild(axis_);
addChild(new Bitmap(nBmd_));
addChild(new Bitmap(iBmd_));
// 反転軸円と中心交差線を描く
var g_:Graphics = axis_.graphics;
g_.lineStyle(0, AXIS_COLOR);
g_.drawCircle(0, 0, RADIUS);
g_.moveTo(0, -sh);
g_.lineTo(0, sh);
g_.moveTo(-sw, 0);
g_.lineTo( sw, 0);
// 反転前座標の生成
nCoordinatesArray_ = [];
for (var j:int = 0; j < toggleLen_; j++) {
nCoordinates_ = new Vector.<int>();
// 内側の円
nCoordinates_ = nCoordinates_.concat(DataFactory.drawCircle(sw, sh, cx, cy, RADIUS));
// 取り巻く円
var numOfCircle:uint = 6 + j; // 取り巻く円の数
var radian:Number = Math.PI / numOfCircle; // 小円から見て、ひとつの円が占有するラジアンの半分
var radius:Number = RADIUS * Math.sin(radian) / (1 - Math.sin(radian)); // 半径
radian *= 2;
var dist:Number = RADIUS + radius; // 原点からひとつの円の中心までの距離
for (var i:int = 0; i < numOfCircle; i++) {
var p:Point = Point.polar(dist, radian * i);
nCoordinates_ = nCoordinates_.concat(DataFactory.drawCircle(sw, sh, p.x + cx, p.y + cy, radius));
}
// 外側の円
nCoordinates_ = nCoordinates_.concat(DataFactory.drawCircle(sw, sh, cx, cy, RADIUS + radius * 2));
nCoordinates_.fixed = true;
nCoordinatesArray_.push(nCoordinates_);
}
}
// 反転前座標の切り替えと描画
private function setup2():void {
nCoordinates_ = nCoordinatesArray_[toggle_];
len_ = nCoordinates_.length;
iCoordinates_ = new Vector.<int>(len_, true);
// 反転前座標の描画
nBmd_.lock();
nBmd_.fillRect(nBmd_.rect, BMD_FILL_COLOR);
for (var i:int = 0; i < len_; i += 2) {
var posX:Number = nCoordinates_[i];
var posY:Number = nCoordinates_[i + 1];
nBmd_.setPixel32(posX, posY, N_PIXEL_COLOR);
}
nBmd_.unlock();
}
// ループ処理
private function update(e:Event):void {
// マウスカーソル座標取得
var mx:Number = mouseX;
var my:Number = mouseY;
// マウスの移動に伴い対称軸円と中心交差線を動かす
axis_.x = mx;
axis_.y = my;
// 座標の反転計算
invert(mx, my, nCoordinates_, iCoordinates_);
// 反転座標の描画
iBmd_.lock();
iBmd_.fillRect(iBmd_.rect, BMD_FILL_COLOR);
for (var i:int = 0; i < len_; i += 2) {
var posX:Number = iCoordinates_[i];
var posY:Number = iCoordinates_[i + 1];
iBmd_.setPixel32(posX, posY, I_PIXEL_COLOR);
}
iBmd_.unlock();
}
// 座標の反転計算
private function invert(x0:Number, y0:Number, nCoordinate:Vector.<int>, iCoordinate:Vector.<int>):void {
for (var i:int = 0; i < len_; i += 2) {
// 円の中心O(x0, y0) -> マウスカーソルの座標
// 与えられた点P(x, y) -> nCoordinates_
// 求める点P'(x', y') -> iCoordinates_
// 反転計算式
// x' = r^2 * (x - x0) / ((x - x0)^2 + (y - y0)^2) + x0
// y' = r^2 * (y - y0) / ((x - x0)^2 + (y - y0)^2) + y0
var xp:Number = nCoordinates_[i];
var yp:Number = nCoordinates_[i + 1];
var distX:Number = xp - x0;
var distY:Number = yp - y0;
var distXY:Number = distX * distX + distY * distY;
iCoordinates_[i] = RADIUS_SQUARE * distX / distXY + x0;
iCoordinates_[i + 1] = RADIUS_SQUARE * distY / distXY + y0;
}
}
}
}
//package {
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
/**
* 指定図形を構成する座標値の取得
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class DataFactory {
public function DataFactory() {
}
/**
* 線の座標取得
* @param sw ステージサイズ幅
* @param sh ステージサイズ高
* @param x0 開始座標X
* @param y0 開始座標Y
* @param x1 終了座標X
* @param y1 終了座標Y
* @return 座標を1次元配列で格納した Vector
*/
public static function drawLine(sw:int, sh:int, x0:int, y0:int, x1:int, y1:int):Vector.<int> {
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(0, 0x000000);
g.moveTo(x0, y0);
g.lineTo(x1, y1);
return getVector(shape, sw, sh);
}
/**
* 円の座標取得
* @param sw ステージサイズ幅
* @param sh ステージサイズ高
* @param px 中心座標X
* @param py 中心座標Y
* @param radius 半径
* @return 座標を1次元配列で格納した Vector
*/
public static function drawCircle(sw:int, sh:int, px:int, py:int, radius:int):Vector.<int> {
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(0, 0x000000);
g.drawCircle(px, py, radius);
return getVector(shape, sw, sh);
}
static private function getVector(shape:Shape, sw:int, sh:int):Vector.<int> {
var transparent:int = 0x00000000;
var bmd:BitmapData = new BitmapData(sw, sh, true, transparent);
bmd.draw(shape);
var v:Vector.<int> = new Vector.<int>();
for (var y:int = 0; y < sh; y++) {
for (var x:int = 0; x < sw; x++) {
if (bmd.getPixel32(x, y) != transparent) v.push(x, y);
}
}
return v;
}
}
//}