//
// L-SYSTEMによる自己相似図形の描画
//
// マウスクリックで成長
// カーソルキー上下で違う図形を描画
//
// 参考:http://www14.ocn.ne.jp/~kk62526/Lsys/index.html
// http://www.hl.pc.uec.ac.jp/hays/computer/turtle.htm
//
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
public class FlashTest extends Sprite {
public function FlashTest() {
Main = this;
initialize();
stage.addEventListener(Event.ENTER_FRAME,update);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyCheckDown);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
}
}
}
import flash.display.Sprite;
import flash.text.*;
import flash.events.*;
import flash.geom.*;
import flash.ui.Keyboard;
var SCREEN_W:Number = 465, SCREEN_H:Number = 465;
var Main:Sprite;
var Text:TextField;
var Text2:TextField;
var Ls:LSystem;
var Name:String = "";
var LsNo:int = 0;
var LsNoMax:int = 9;
function initialize():void{
Text = new TextField();
Text.text = "";
Text.autoSize = "left";
Main.addChild(Text);
Text2 = new TextField();
Text2.y = 16;
Text2.text = "";
Text2.autoSize = "left";
Main.addChild(Text2);
Ls = createLs( LsNo );
}
function createLs( type:int ):LSystem{
var l:LSystem;
switch( type ){
case 0:
Name = "コッホ曲線";
l = new LSystem( "F", 4, 60 );
l.CntMax = 5;
l.addRule( new Rule("F","F-F++F-F") );
l.draw();
break;
case 1:
Name = "シェルビンスキーのガスケット";
l = new LSystem( "F", 5, 120 );
l.addRule( new Rule("F","F-F-F-GG") );
l.addRule( new Rule("G","GG") );
l.draw();
break;
case 2:
Name = "シェルビンスキーの Arrowhead";
l = new LSystem( "LF", 5, 60 );
l.addRule( new Rule("L","-RF+LF+RF-") );
l.addRule( new Rule("R","+LF-RF-LF+") );
l.addRule( new Rule("F","") );
l.draw();
break;
case 3:
Name = "樹木1";
l = new LSystem( "F", 10, 15 );
l.XInit = 200;
l.RotInit = -90;
l.CntMax = 4;
l.addRule( new Rule("F","F[+F-F-F]F[--F+F+F]") );
l.draw();
break;
case 4:
Name = "樹木2";
l = new LSystem( "F", 2, 25 );
l.XInit = 200;
l.RotInit = -90;
l.CntMax = 5;
l.addRule( new Rule("F","F[-FF]F[++F]F") );
l.draw();
break;
case 5:
Name = "樹木3";
l = new LSystem( "F", 22, 21 );
l.XInit = 200;
l.RotInit = -90;
l.CntMax = 7;
l.addRule( new Rule("F","F[-F[F+++F]]") );
l.draw();
break;
case 6:
Name = "樹木4";
l = new LSystem( "F", 40, 17 );
l.XInit = 200;
l.RotInit = -90;
l.CntMax = 8;
l.addRule( new Rule("F","F[+F][-F]") );
l.draw();
break;
case 7:
Name = "ドラコン曲線";
l = new LSystem( "F+FA-F", 1, 45 );
l.XInit = 150;
l.YInit = 350;
l.CntMax = 14;
l.addRule( new Rule("A","A+F+FB") );
l.addRule( new Rule("B","A-F-FB") );
l.draw();
break;
case 8:
Name = "平面充填曲線";
l = new LSystem( "XF+F+XF+F+XF+F", 3, 60 );
l.XInit = 10;
l.YInit = 40;
l.CntMax = 5;
l.addRule( new Rule("X","XF+F+XF-F-F-XF-F+F+F-F+F+F-X") );
l.draw();
break;
}
Text.text = (type+1) +":"+ Name + " " + l.getRuleText();
Text2.text = l.Str;
return l;
}
function onClick(event:MouseEvent):void{
graphicClear();
Ls.update();
Ls.draw();
}
function keyCheckDown(event:KeyboardEvent):void {
switch (event.keyCode){
case Keyboard.UP: LsNo--; break;
case Keyboard.DOWN: LsNo++; break;
}
if( LsNo < 0 ) LsNo = LsNoMax-1;
if( LsNo >= LsNoMax ) LsNo = 0;
graphicClear();
Ls = createLs( LsNo );
Ls.draw();
}
function update(e :Event):void{
// graphicClear();
}
// 生成ルールクラス
class Rule {
public var Src:String;
public var Dst:String;
public function Rule( src:String, dst:String ){
Src = src;
Dst = dst;
}
}
// 描画用タートルグラフィッククラス
class Turtle {
public var X:Number, prevX:Number;
public var Y:Number, prevY:Number;
public var Rot:Number;
public var Speed:Number;
public var RotAdd:Number;
public var Stack:Array = new Array;
public var StackPos:int = 0;
public function Turtle( x:Number, y:Number, rot:Number, speed:Number, rotAdd:Number ){
X = prevX = x;
Y = prevY = y;
Rot = rot;
Speed = speed;
RotAdd = rotAdd;
}
public function update( c:String ):void{
switch( c ){
case "G": // 前進
moveForward();
break;
case "F": // 前進して線を引く
moveForward();
drawLine( prevX, prevY, X, Y, 1.0, 0xff0000 );
break;
case "+": // プラス方向に回転
Rot += RotAdd;
break;
case "-": // マイナス方向に回転
Rot -= RotAdd;
break;
case "[": // スタックに保存
var t:Turtle = new Turtle( X, Y, Rot, Speed, RotAdd );
Stack[StackPos] = t;
StackPos++;
break;
case "]": // スタックから復帰
StackPos--;
X = Stack[StackPos].X;
Y = Stack[StackPos].Y;
prevX = Stack[StackPos].prevX;
prevY = Stack[StackPos].prevY;
Rot = Stack[StackPos].Rot;
break;
}
}
// 前進
public function moveForward():void{
prevX = X;
prevY = Y;
X += Speed * Math.cos( Rot * 2.0*Math.PI / 360.0 );
Y += Speed * Math.sin( Rot * 2.0*Math.PI / 360.0 );
}
}
// L-SYSTEMクラス
class LSystem {
public var Str:String;
public var RuleAry:Vector.<Rule> = new Vector.<Rule>;
public var Speed:Number;
public var RotAdd:Number;
public var XInit:Number = 10;
public var YInit:Number = 400;
public var RotInit:Number = 0;
public var Cnt:int = 0;
public var CntMax:int = 8;
public function LSystem( s:String, speed:Number, rotAdd:Number ){
Str = s;
Speed = speed;
RotAdd = rotAdd;
}
public function update():Boolean{
if( ++Cnt > CntMax ) return false;
var out:String = "";
var len:int = Str.length;
for( var i:int=0; i<len; i++ ){
var c:String = Str.charAt(i);
var find:Boolean = false;
for each( var r:Rule in RuleAry ){
if( c == r.Src ){
out += r.Dst;
find = true;
}
}
if( find == false ) out += c;
}
Str = out;
Text2.text = Str;
return true;
}
public function addRule( r:Rule ):void{
RuleAry.push( r );
}
public function getRuleText():String{
var ret:String = "";
for each( var r:Rule in RuleAry ){
ret += "[" + r.Src + "→" + r.Dst + "]";
}
return ret;
}
public function draw():void{
var t:Turtle = new Turtle( XInit, YInit, RotInit, Speed, RotAdd );
var len:int = Str.length;
for( var i:int=0; i<len; i++ ){
var c:String = Str.charAt(i);
t.update( c );
}
}
}
function graphicClear():void{
Main.graphics.clear();
}
function drawLine( sx:Number, sy:Number, ex:Number, ey:Number, size:Number, col:int ):void{
Main.graphics.lineStyle(size,col);
Main.graphics.moveTo( sx, sy );
Main.graphics.lineTo( ex, ey);
}