Cow Pattern
package
{
import flash.display.Sprite;
import flash.display.Graphics;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.AntiAliasType;
[ SWF( width = "465" , height = "465" , backgroundColor = "0xFFFFFF" , frameRate = "60" ) ]
public class Main extends Sprite
{
var _sp : Sprite = new Sprite();
public function Main()
{
addChild( _sp );
var _txt:TextField = new TextField();
_txt.text = "2009\nHappy New Year";
_txt.autoSize = "left";
_txt.selectable = false;
var _tf:TextFormat = new TextFormat();
_tf.size = 60;
_tf.color = 0xFFFFFF;
_tf.font = "Arial";
_tf.bold = true;
_tf.letterSpacing = -2;
_tf.align = TextFormatAlign.CENTER;
_txt.setTextFormat( _tf );
_txt.x = stage.stageWidth / 2 - _txt.width / 2;
_txt.y = stage.stageHeight / 2 - _txt.height / 2;
stage.addChild( _txt );
stage.addEventListener( MouseEvent.CLICK , onClick );
}
private function onClick( event:MouseEvent ):void
{
var _cp : CowPattern = new CowPattern( _sp );
}
}
}
class CowPattern
{
import flash.display.Sprite;
import flash.display.Graphics;
import flash.display.Stage;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import flash.display.BlendMode;
private var _stage : Sprite;
private var _container : Sprite = new Sprite();
private var _pointArray : Array = new Array();
private var _anchorNum : int = 5; //アンカーポイントの数
private var _totalPointNum : int = _anchorNum * 3; //アンカーポイントとコントロールポイントの総数
private var _drewNum : int;
private var _controll_pointArray : Array = new Array();
private var _anchor_pointArray : Array = new Array();
private var _tempControll_pointArray : Array = new Array();
private var _tempAnchor_pointArray : Array = new Array();
private var _rateArray : Array = new Array();
public function CowPattern( stg:* )
{
_stage = stg;
_stage.addChild( _container );
_container.x = _stage.mouseX;
_container.y = _stage.mouseY;
_container.scaleX = _container.scaleY = ( Math.random() + 1 ) / 2;
create_pointArray()
drawLine();
}
private function create_pointArray():void
{
var array:Array = _pointArray;
var prevNum1:int;
var prevNum2:int;
array[ _totalPointNum - 1 ] = createPoint( _totalPointNum - 1 );
for ( var i : int = 0; i < _totalPointNum - 1; i ++ )
{
if ( i % 3 == 1 )
{
prevNum1 = i - 1;
prevNum2 = i - 2;
if (prevNum2 < 0 )
{
prevNum2 = _totalPointNum - 1;
}
array[i] = new Point( 2 * array[ prevNum1 ].x - array[ prevNum2 ].x , 2 * array[ prevNum1 ].y - array[ prevNum2 ].y );
} else {
array[ i ] = createPoint( i )
}
}
}
private function createPoint( num:int ):Point
{
var r : Number = 65;
var rad : Number = num * ( 2 * Math.PI ) / _totalPointNum;
var ran : Number = Math.random() * 0.8;
var point : Point = new Point( Math.sin( rad ) * r * ( 0.5 + ran ) , Math.cos( rad ) * r * ( 0.5 + ran ) );
return point;
}
private function drawLine():void
{
var array : Array = _pointArray;
var point1 : Number;
var point2 : Number;
var anchor1 : Number;
var anchor2 : Number;
for ( var i : int = 0; i < _totalPointNum - 1; i ++ )
{
point1 = i;
if ( i % 3 == 0 )
{
point2 = i + 3;
anchor1 = i + 1;
anchor2 = i + 2;
if ( point2 >= _totalPointNum )
{
point2 = 0;
}
createBezier( array[ point1 ] , array[ anchor1 ] , array[ anchor2 ] , array[ point2 ] );
}
}
for ( var j : int = 0; j <= _controll_pointArray.length; j ++ )
{
_tempControll_pointArray[ j ] = new Point( 0 , 0 );
_tempAnchor_pointArray[ j ] = new Point( 0 , 0 );
}
_container.addEventListener( Event.ENTER_FRAME , drawBezier );
}
public function createBezier( p0:Point , p1:Point , p2:Point , p3:Point ):void
{
var ancorPoint1 : Point
var ancorPoint2 : Point
var ancorPoint3 : Point
var controllPoint : Point;
var t : Number;
var separate : Number = 4; // ベジェの分割数
var sep : Number = 1.0 / separate;
var bezierSegment : BezierSegment = new BezierSegment( p0 , p1 , p2 , p3 );
for ( t = sep * 2; t <= 1.0; t += sep * 2 )
{
ancorPoint1 = bezierSegment.getValue( t-sep * 2 );
ancorPoint2 = bezierSegment.getValue( t-sep );
ancorPoint3 = bezierSegment.getValue( t );
//ancorPoint2を通るようにcontrollPointを設定
controllPoint = new Point( 2 * ancorPoint2.x - ( ancorPoint1.x + ancorPoint3.x ) * 0.5 , 2 * ancorPoint2.y - ( ancorPoint1.y + ancorPoint3.y ) * 0.5 );
_controll_pointArray.push( controllPoint );
_anchor_pointArray.push( ancorPoint3 );
}
}
public function drawBezier( e:Event ):void
{
_drewNum = 0;
_container.graphics.clear();
_container.graphics.lineStyle( 1 , 0xFF0000, 0 );
_container.graphics.beginFill( 0x000000 , 1 );
_container.graphics.moveTo( _tempAnchor_pointArray[0].x , _tempAnchor_pointArray[0].y );
for ( var i : int = 0; i < _controll_pointArray.length; i ++ )
{
var _controllX : Number = drawPoint( _tempControll_pointArray[i].x , _controll_pointArray[i].x );
var _controllY : Number = drawPoint( _tempControll_pointArray[i].y , _controll_pointArray[i].y );
var _anchorX : Number = drawPoint( _tempAnchor_pointArray[i].x , _anchor_pointArray[i].x );
var _anchorY : Number = drawPoint( _tempAnchor_pointArray[i].y , _anchor_pointArray[i].y );
_tempControll_pointArray[i] = new Point( _controllX , _controllY );
_tempAnchor_pointArray[i] = new Point( _anchorX , _anchorY );
_container.graphics.curveTo( _tempControll_pointArray[ i ].x , _tempControll_pointArray[ i ].y , _tempAnchor_pointArray[ i ].x , _tempAnchor_pointArray[ i ].y );
}
if ( _drewNum == _controll_pointArray.length * 4 )
{
_container.removeEventListener( Event.ENTER_FRAME , drawBezier );
}
_container.graphics.endFill();
}
public function drawPoint( _temp : Number , _end : Number ):Number
{
var _rate : int = 5;
var _value : Number;
if ( _end > 0 ) _value = ( _temp < _end ) ? _temp + _rate : _end;
else _value = ( _temp > _end ) ? _temp - _rate : _end;
if ( _temp == _end ) _drewNum ++;
return _value;
}
}
// Copyright © 2007. Adobe Systems Incorporated. All Rights Reserved.
/**
* A Bezier segment consists of four Point objects that define a single cubic Bezier curve.
* The BezierSegment class also contains methods to find coordinate values along the curve.
* @playerversion Flash 9.0.28.0
* @langversion 3.0
* @keyword BezierSegment, Copy Motion as ActionScript
* @see ../../motionXSD.html Motion XML Elements
*/
class BezierSegment
{
import flash.geom.Point;
public var a:Point;
public var b:Point;
public var c:Point;
public var d:Point;
function BezierSegment(a:Point, b:Point, c:Point, d:Point)
{
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
public function getValue(t:Number):Point
{
var ax:Number = this.a.x;
var x:Number = (t*t*(this.d.x-ax) + 3*(1-t)*(t*(this.c.x-ax) + (1-t)*(this.b.x-ax)))*t + ax;
var ay:Number = this.a.y;
var y:Number = (t*t*(this.d.y-ay) + 3*(1-t)*(t*(this.c.y-ay) + (1-t)*(this.b.y-ay)))*t + ay;
return new Point(x, y);
}
public static function getSingleValue(t:Number, a:Number=0, b:Number=0, c:Number=0, d:Number=0):Number
{
return (t*t*(d-a) + 3*(1-t)*(t*(c-a) + (1-t)*(b-a)))*t + a;
}
public function getYForX(x:Number, coefficients:Array=null):Number
{
if (this.a.x < this.d.x)
{
if (x <= this.a.x+0.0000000000000001) return this.a.y;
if (x >= this.d.x-0.0000000000000001) return this.d.y;
}
else
{
if (x >= this.a.x+0.0000000000000001) return this.a.y;
if (x <= this.d.x-0.0000000000000001) return this.d.y;
}
if (!coefficients)
{
coefficients = getCubicCoefficients(this.a.x, this.b.x, this.c.x, this.d.x);
}
// x(t) = a*t^3 + b*t^2 + c*t + d
var roots:Array = getCubicRoots(coefficients[0], coefficients[1], coefficients[2], coefficients[3]-x);
var time:Number = NaN;
if (roots.length == 0)
time = 0;
else if (roots.length == 1)
time = roots[0];
else
{
for each (var root:Number in roots)
{
if (0 <= root && root <= 1)
{
time = root;
break;
}
}
}
if (isNaN(time))
return NaN;
var y:Number = getSingleValue(time, this.a.y, this.b.y, this.c.y, this.d.y);
return y;
}
public static function getCubicCoefficients(a:Number, b:Number, c:Number, d:Number):Array
{
return [ -a + 3*b - 3*c + d,
3*a - 6*b + 3*c,
-3*a + 3*b,
a];
}
public static function getCubicRoots(a:Number=0, b:Number=0, c:Number=0, d:Number=0):Array
{
// make sure we really have a cubic
if (!a) return BezierSegment.getQuadraticRoots(b, c, d);
// normalize the coefficients so the cubed term is 1 and we can ignore it hereafter
if (a != 1)
{
b/=a;
c/=a;
d/=a;
}
var q:Number = (b*b - 3*c)/9; // won't change over course of curve
var qCubed:Number = q*q*q; // won't change over course of curve
var r:Number = (2*b*b*b - 9*b*c + 27*d)/54; // will change because d changes
// but parts with b and c won't change
// determine if there are 1 or 3 real roots using r and q
var diff:Number = qCubed - r*r; // will change
if (diff >= 0)
{
// avoid division by zero
if (!q) return [0];
// three real roots
var theta:Number = Math.acos(r/Math.sqrt(qCubed)); // will change because r changes
var qSqrt:Number = Math.sqrt(q); // won't change
var root1:Number = -2*qSqrt * Math.cos(theta/3) - b/3;
var root2:Number = -2*qSqrt * Math.cos((theta + 2*Math.PI)/3) - b/3;
var root3:Number = -2*qSqrt * Math.cos((theta + 4*Math.PI)/3) - b/3;
return [root1, root2, root3];
}
else
{
// one real root
var tmp:Number = Math.pow( Math.sqrt(-diff) + Math.abs(r), 1/3);
var rSign:int = (r > 0) ? 1 : r < 0 ? -1 : 0;
var root:Number = -rSign * (tmp + q/tmp) - b/3;
return [root];
}
return [];
}
public static function getQuadraticRoots(a:Number, b:Number, c:Number):Array
{
var roots:Array = [];
// make sure we have a quadratic
if (!a)
{
if (!b) return [];
roots[0] = -c/b;
return roots;
}
var q:Number = b*b - 4*a*c;
var signQ:int =
(q > 0) ? 1
: q < 0 ? -1
: 0;
if (signQ < 0)
{
return [];
}
else if (!signQ)
{
roots[0] = -b/(2*a);
}
else
{
roots[0] = roots[1] = -b/(2*a);
var tmp:Number = Math.sqrt(q)/(2*a);
roots[0] -= tmp;
roots[1] += tmp;
}
return roots;
}
}