フォードの円でパターンを描く(1)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/tWKI
*/
package {
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
/**
* フォードの円でパターンを描く(1)
* ステージをクリックしてください。
*/
public class Main2 extends Sprite {
// ファレイ数列から計算されたフォードの円の座標値を一次元配列で格納
private var data_:Vector.<Number>;
// 描画パターンの切り替え関連
private var switcher_:Switcher;
private var numOfPattern_:int;
private var currentPattern_:int;
// キャンバス
private var canvas_:Shape;
/**
* コンストラクタ
*/
public function Main2() {
setup();
stage.addEventListener(MouseEvent.CLICK, clickHandler);
clickHandler(null);
}
// セットアップ
private function setup():void {
// ファレイ数列生成
var farey0:Vector.<String> = Calculator.createFareySequence(6);
var fareyP1:Vector.<String> = Calculator.shift(farey0, 1);
var fareyP2:Vector.<String> = Calculator.shift(farey0, 2);
farey0.fixed = false;
fareyP1.fixed = false;
farey0.pop();
fareyP1.pop();
var farey:Vector.<String> = new Vector.<String>();
farey = farey.concat(farey0, fareyP1, fareyP2);
// フォードの円の座標値計算
data_ = Calculator.calcFordCircleCenter(farey);
// 描画パターンの切り替え
switcher_ = new Switcher();
numOfPattern_ = switcher_.patterns.length;
currentPattern_ = 0;
// キャンバス生成
canvas_ = new Shape();
addChild(canvas_);
}
// マウスハンドラ
private function clickHandler(e:MouseEvent):void {
switcher_.patterns[currentPattern_](data_, canvas_, stage.stageWidth);
currentPattern_++;
currentPattern_ %= numOfPattern_
}
}
}
//package {
/**
* ファレイ数列とフォードの円 Farey sequence & Ford circle
*/
/*public*/ class Calculator {
// F1 のファレイ数列
private static const FAREY1:Vector.<String> = Vector.<String>(["0/1", "1/1"]);
/**
* コンストラクタ
*/
public function Calculator() {
}
/**
* ファレイ数列の生成
* @param degree ファレイ数列が対応する整数
* @return ファレイ数列
*/
public static function createFareySequence(degree:uint):Vector.<String> {
var currentData:Vector.<String> = new Vector.<String>();
var nextData:Vector.<String> = new Vector.<String>();
var prevStr1:String = null;
currentData = FAREY1;
// ファレイ数列に対応する i をインクリメントする
for (var i:int = 2; i <= degree; i++) {
var len:int = currentData.length;
// i-1 に対応するファレイ数列から i に対応するファレイ数列を作るため、ファレイ数列の要素を爪弾く
for (var j:int = 1; j < len; j++) {
var str0:String = currentData[j - 1];
var str1:String = currentData[j];
var uints0:Vector.<int> = stringToInt(str0);
var uints1:Vector.<int> = stringToInt(str1);
var a:uint = uints0[0]; // 小さい分数の分子
var b:uint = uints0[1]; // 小さい分数の分母
var c:uint = uints1[0]; // 大きい分数の分子
var d:uint = uints1[1]; // 大きい分数の分母
// 前回の str1 の確認
if ((prevStr1) && (prevStr1 != str0)) nextData.push(prevStr1);
// 今回の str0 をデータとして登録
nextData.push(str0);
// 中間数の計算および評価
var mediant:String = null;
var denominator:uint = b + d;
if (denominator <= degree) mediant = String(a + c) + "/" + String(denominator);
if (mediant) nextData.push(mediant);
// ファレイ数列の要素爪弾く前の準備
prevStr1 = str1;
}
// ループを抜けた(i に対応するファレイ数列ができた)ので、最後の分数 str1(= "1/1")を登録
nextData.push(str1);
// ファレイ数列に対応する整数をインクリメントする前の準備
currentData = nextData;
nextData = new Vector.<String>();
prevStr1 = null;
}
currentData.fixed = true;
return currentData;
}
/**
* ファレイ数列のシフト
* 0 ~ 1の範囲から scale ~ scale+1 の範囲の値にシフトする
* @param farey 元データ
* @param scale シフト値
* @return シフト後のデータ
*/
public static function shift(farey:Vector.<String>, scale:int):Vector.<String> {
var ret:Vector.<String> = new Vector.<String>();
var len:int = farey.length;
for (var i:int = 0; i < len; i++) {
// String から Number に
var fraction:Vector.<int> = stringToInt(farey[i]);
var numerator:Number = Number(fraction[0]);
var denominator:Number = Number(fraction[1]);
// シフト計算
numerator += denominator * scale;
// 再び分数の形式にして置換
ret.push(String(numerator) + "/" + String(denominator));
}
ret.fixed = true;
return ret;
}
/**
* ファレイ数列からフォードの円の中心座標を計算
* @param farey ファレイ数列
* @return フォードの円の中心座標を一次元配列で格納した Vector
*/
public static function calcFordCircleCenter(farey:Vector.<String>):Vector.<Number> {
var data:Vector.<Number> = new Vector.<Number>();
var len:int = farey.length;
for (var i:int = 0; i < len; i++) {
// String から Number に
var fraction:Vector.<int> = stringToInt(farey[i]);
var numerator:Number = Number(fraction[0]);
var denominator:Number = Number(fraction[1]);
// 座標値
var posX:Number = numerator / denominator;
var posY:Number = 1 / (denominator * denominator * 2);
data.push(posX, posY);
}
data.fixed = true;
return data;
}
// ファレイ数列のひとつの要素を String から、分子・分母の二つの uint に変換
private static function stringToInt(data:String):Vector.<int> {
var d:Array = data.split("/");
return Vector.<int>([int(d[0]), int(d[1])]);
}
}
//}
//package {
//import aquioux.display.colorUtil.CycleRGB;
import flash.display.Graphics;
import flash.display.Shape;
/**
* ファレイ数列とフォードの円 Farey sequence & Ford circle
*/
/*public*/ class Switcher {
public function get patterns():Array { return _patterns; }
private var _patterns:Array;
/**
* コンストラクタ
*/
public function Switcher() {
_patterns = [pattern11, pattern12, pattern21, pattern22, pattern31, pattern32, pattern41, pattern42];
}
// 描画パターン
private function pattern11(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
//g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i];
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern12(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
//g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i];
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern21(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
//g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern22(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
//g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern31(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
//g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size / 2;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (posY + 1) * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posX * scale, (2 - posY) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((posY + 1) * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((2 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern32(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
//g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size / 2;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (posY + 1) * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posX * scale, (2 - posY) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((posY + 1) * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((2 - posY) * scale, posX * scale, posY * scale);
}
}
private function pattern41(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
//g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size / 2;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posX * scale, (posY + 1) * scale, posY * scale);
g.drawCircle(posX * scale, (2 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (0.5 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (posY + 0.5) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (1.5 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (posY + 1.5) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((posY + 1) * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((2 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((0.5 - posY) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((posY + 0.5) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((1.5 - posY) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((posY + 1.5) * scale, (posX - 0.5) * scale, posY * scale);
}
}
private function pattern42(data:Vector.<Number>, canvas:Shape, size:int):void {
var g:Graphics = canvas.graphics;
g.clear();
//g.lineStyle(0, CycleRGB.getColor(Math.random() * 360));
g.beginFill(CycleRGB.getColor(Math.random() * 360));
var scale:int = size / 2;
var len:int = data.length;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = data[i] - 0.5;
var posY:Number = data[i + 1];
g.drawCircle(posX * scale, posY * scale, posY * scale);
g.drawCircle(posX * scale, (1 - posY) * scale, posY * scale);
g.drawCircle(posX * scale, (posY + 1) * scale, posY * scale);
g.drawCircle(posX * scale, (2 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (0.5 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (posY + 0.5) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (1.5 - posY) * scale, posY * scale);
g.drawCircle((posX - 0.5) * scale, (posY + 1.5) * scale, posY * scale);
g.drawCircle(posY * scale, posX * scale, posY * scale);
g.drawCircle((posY + 1) * scale, posX * scale, posY * scale);
g.drawCircle((1 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((2 - posY) * scale, posX * scale, posY * scale);
g.drawCircle((0.5 - posY) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((posY + 0.5) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((1.5 - posY) * scale, (posX - 0.5) * scale, posY * scale);
g.drawCircle((posY + 1.5) * scale, (posX - 0.5) * scale, posY * scale);
}
}
}
//}
//package aquioux.display.colorUtil {
/**
* コサインカーブで色相環的な RGB を計算
* @author Aquioux(YOSHIDA, Akio)
*/
/*public*/ class CycleRGB {
/**
* 32bit カラーのためのアルファ値(0~255)
*/
static public function get alpha():uint { return _alpha; }
static public function set alpha(value:uint):void {
_alpha = (value > 0xFF) ? 0xFF : value;
}
private static var _alpha:uint = 0xFF;
private static const PI:Number = Math.PI; // 円周率
private static const DEGREE120:Number = PI * 2 / 3; // 120度(弧度法形式)
/**
* 角度に応じた RGB を得る
* @param angle HSV のように角度(度数法)を指定
* @return 色(0xNNNNNN)
*/
public static function getColor(angle:Number):uint {
var radian:Number = angle * PI / 180;
var r:uint = (Math.cos(radian) + 1) * 0xFF >> 1;
var g:uint = (Math.cos(radian + DEGREE120) + 1) * 0xFF >> 1;
var b:uint = (Math.cos(radian - DEGREE120) + 1) * 0xFF >> 1;
return r << 16 | g << 8 | b;
}
/**
* 角度に応じた RGB を得る(32bit カラー)
* @param angle HSV のように角度(度数法)を指定
* @return 色(0xNNNNNNNN)
*/
public static function getColor32(angle:Number):uint {
return _alpha << 24 | getColor(angle);
}
}
//}