soundSpectrumCity
shift: transparent buildings
space: change cityscape pattern
up arrow key: top view
left arrow key: white building
right arrow key: change traffic speed
down arrow key: change color mode
mouse click: regenerate buildings
update color
/**
* Copyright zob ( http://wonderfl.net/user/zob )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/o6k7
*/
package
{
import flash.display.*;
import flash.filters.*;
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import flash.geom.*;
import flash.text.*;
import flash.system.*;
import flash.ui.*;
import flash.media.*;
import net.hires.debug.Stats;
import frocessing.color.ColorHSV;
import com.bit101.components.PushButton;
import com.bit101.components.InputText;
[SWF(width=465,height=465,backgroundColor=0x000000,frameRate=30)]
public class therockcityMAX extends Sprite
{
private var SECTOR:int = 10;
private var LEVEL:int = 3;
private var LEVEL_HEIGHT:int = 20;
private var RADIUSX:int = 30;
private var RADIUSZ:int = 15;
private var edgeA:Array = new Array();
private var edgeB:Array = new Array();
private var D2R:Number = Math.PI/180;
private var R2D:Number = 180/Math.PI;
private var cPos:Dot = new Dot(0, 0);
private var points:Array = new Array();
//planning
private var regions:Array = new Array();
private var gCount:int = 300;
private var gwidth:int = 1000;//stage.stageWidth;
private var gheight:int = 1000;//stage.stageHeight;
//building
private var blength:Number = 100;
private var bwidth:Number = 200;
private var bheight:Number = 200;
private var offset:Dot = new Dot(-gwidth/2, -gheight/2);
private var autoAlign:Boolean = false;
//////////////////////////////////////////////////////////////////////////////////////////////////
// drawTriangles
//////////////////////////////////////////////////////////////////////////////////////////////////
private var viewport:Shape = new Shape();
private var world:Matrix3D = new Matrix3D();
private var vertices:Vector.<Number> = new Vector.<Number>(0, false);
private var projected:Vector.<Number> = new Vector.<Number>(0, false);
private var indices:Vector.<int> = new Vector.<int>(0, false);
private var uvtData:Vector.<Number> = new Vector.<Number>(0, false);
private var projection:PerspectiveProjection = new PerspectiveProjection();
private var sortedIndices:Vector.<int>;
private var faces:Array = [];
/**/
/////////////////////////////////////////////////////////////////////////////////////////////////
private var sort_count:int = 0;
private var rotate:Number = 0;
private var refrest_sort_at:int = 100;
/////////////////////////////////////////////////////////////////////////////////////////////////
private var snd:Sound;
private var bytes:ByteArray = new ByteArray();
private var bitmapData:BitmapData = new BitmapData(500,500, false, 0xFFFFFFFF);
private var colors:Array = [0xFFCC32,0x333333,0x333333];
private var alphas:Array = [1,0,0];
private var ratios:Array = [0,64,255];
private var m:Matrix = new Matrix();
private var light:Sprite = new Sprite();
private var lightRatio:Number = 48;
private var ct:ColorTransform = new ColorTransform(1,1,1,0.8);
private var transparent:Boolean = false;
////////////////////////////////////////////////////////////////////////////////////////////////
private var landVertices:Vector.<Number> = new Vector.<Number>(0, false);
private var landProjected:Vector.<Number> = new Vector.<Number>(0, false);
private var landIndices:Vector.<int> = new Vector.<int>(0, false);
private var landUvtData:Vector.<Number> = new Vector.<Number>(0, false);
////////////////////////////////////////////////////////////////////////////////////////////////
private var traffic:Array = new Array();
private var landResizing:Number = 0.3;
private var land_bmpd:BitmapData = new BitmapData(gwidth*landResizing, gheight*landResizing,false,0x0);
private var top_down_view:Boolean = false;
private var white_buildings:Boolean = false;
///////////////////////////////////////////////////////////////////
private var windowX:int = 32;
private var windowY:int = 16;
private var trafficTimer:Timer;
private var timerSpeed:int = 3;
private var timerCount:int = 0;
private var trafficSpeedLabel:TextField = new TextField();
private var buildingsTxt:String = "";
private var tf:TextFormat = new TextFormat();
private var vcolor:ColorHSV = new ColorHSV(0);
private var varyColor:int = 0;
private var staticColor:uint = 0xFFFFCC32;
// dynamic link to url
/////////////////////////////////////////////////////////////////////
private var url:String = "http://level0.kayac.com/images/murai/Digi_GAlessio_-_08_-_ekiti_son_feat_valeska_-_april_deegee_rmx.mp3";
private var inputText:InputText;
private var playButton:PushButton;
private var soundChannel:SoundChannel = new SoundChannel();
[SWF(width=465,height=465,backgroundColor=0x000011,frameRate=60)]
public function therockcityMAX()
{
addChild(new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000011)));
addChild(new Stats());
addChild(light);
trafficSpeedLabel.text = "traffic speed: 1";
tf.size = 10;
tf.font = "Arial"
trafficSpeedLabel.textColor = 0xFFFFFF;
trafficSpeedLabel.setTextFormat(tf);
trafficSpeedLabel.autoSize = "left";
addChild(trafficSpeedLabel);
trafficSpeedLabel.x = stage.stageWidth - trafficSpeedLabel.width -5;
var mc:MovieClip = new MovieClip();
with(mc.graphics)
{
beginFill(0x0);
drawRect(0,0, stage.stageWidth, 130);
endFill();
}
mc.y = stage.stageHeight - mc.height;
m.translate(stage.stageWidth/2, stage.stageHeight-130);
regions.push(new Region);
regions[0].vertices.push(new Dot(0 ,0));
regions[0].vertices.push(new Dot(gwidth, 0));
regions[0].vertices.push(new Dot(gwidth, gheight));
regions[0].vertices.push(new Dot(0, gheight));
init3D();
}
private function init3D(e:Event = null):void
{
viewport.x = stage.stageWidth / 2;
viewport.y = stage.stageHeight / 2;
addChild(viewport);
projection.fieldOfView = 45;
//add input mp3 url
var panel:Sprite = new Sprite();
inputText = new InputText(panel, stage.stageWidth - 250, 20, "http://level0.kayac.com/images/murai/Digi_GAlessio_-_08_-_ekiti_son_feat_valeska_-_april_deegee_rmx.mp3");
playButton = new PushButton(panel, stage.stageWidth - 45, 20, "play", onClickPlay);
inputText.setSize(200,20);
playButton.setSize(40,20);
addChild(panel);
//planning
generateCity();
constructLand();
snd = new Sound();
snd.load(new URLRequest("http://level0.kayac.com/images/murai/Digi_GAlessio_-_08_-_ekiti_son_feat_valeska_-_april_deegee_rmx.mp3"), new SoundLoaderContext(10,true));
soundChannel = snd.play(0, 9999);
trafficTimer = new Timer(10);
trafficTimer.addEventListener(TimerEvent.TIMER, updateTraffic);
trafficTimer.start();
stage.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown);
stage.addEventListener(Event.ENTER_FRAME, processing);
}
private function onClickPlay(...arg):void
{
soundChannel.stop();
snd = new Sound();
snd.load(new URLRequest(inputText.text), new SoundLoaderContext(10,true));
soundChannel = snd.play(0, 9999);
}
private function generateCity(m:* = null):void
{
var i:int = 0;
var j:int = 0;
var k:int = 0;
var randomlyPick:int = 0;
var randomlyRatio:Number = 0;
var rFactor:int = 1
var rFrom:int = 2;
var rTo:int = 3;
var limitLength:Number = 10;
var limitSize:Number = 3000;
var align:Boolean = true;
var detectLongest:Boolean = true;
var randomAlign:Boolean = autoAlign;
var aRFactor:int = 1;
while(i<gCount)
{
randomlyPick = int(multipleRandom(rFactor) * regions.length);
randomlyRatio = rFrom+Math.round(multipleRandom(rFactor) * (rTo - rFrom));
if(regions[randomlyPick].pass)
{
if(regions[randomlyPick].needPush2Region(regions, 1/randomlyRatio, limitLength, limitSize, align, detectLongest, randomAlign, aRFactor))
{
regions.splice(randomlyPick,1);
}
}
i++;
}
var tempvertices:Array = new Array();
for(i = 0; i < regions.length; i++)
{
regions[i].getResizedRegionVerticesByRatio(tempvertices, 0.7);
constructBuildingByVertices(tempvertices, m);
tempvertices.splice(0, tempvertices.length);
regions[i].getResizedRegionVerticesByRatio(tempvertices, 0.9);
if(area(tempvertices)>8000)
{
traffic.push(new Array());
for(j = 0; j < tempvertices.length; j++)
{
traffic[traffic.length-1].push(tempvertices[j]);
}
}
tempvertices.splice(0, tempvertices.length);
}
buildingsTxt = "total "+regions.length+" buildings";
updateLabel();
}
private function onmouseDown(e:MouseEvent):void
{
vertices.splice(0, vertices.length);
projected.splice(0, projected.length);
faces.splice(0, faces.length);
indices.splice(0, indices.length);
uvtData.splice(0, uvtData.length);
regions.splice(0, regions.length);
regions.push(new Region);
regions[0].vertices.push(new Dot(0 ,0));
regions[0].vertices.push(new Dot(gwidth, 0));
regions[0].vertices.push(new Dot(gwidth, gheight));
regions[0].vertices.push(new Dot(0, gheight));
traffic.splice(0, traffic.length);
generateCity();
}
private function onkeyDown(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case Keyboard.SPACE:
autoAlign = !autoAlign;
updateLabel();
break;
case Keyboard.SHIFT:
transparent = !transparent;
if(transparent)
bitmapData = new BitmapData(500,500, true, 0xFFFFFFFF);
else
bitmapData = new BitmapData(500,500, false, 0xFFFFFFFF);
break;
case Keyboard.UP:
top_down_view = !top_down_view;
break;
case Keyboard.LEFT:
white_buildings = !white_buildings;
if(white_buildings)
bitmapData = new BitmapData(500,500, true, 0xFFFFFFFF);
else
bitmapData = new BitmapData(500,500, false, 0xFFFFFFFF);
break;
case Keyboard.RIGHT:
if(++timerSpeed==4) timerSpeed = 0;
timerCount = 0;
updateLabel();
break;
case Keyboard.DOWN:
if(++varyColor>4) varyColor = 0;
updateLabel();
break;
}
}
private function processing(e:Event):void
{
update();
render();
}
private function render():void
{
world.identity();
rotate = getTimer() * -0.005;
world.appendRotation(getTimer() * -0.005, Vector3D.Y_AXIS);
if(top_down_view) world.appendRotation(90, Vector3D.X_AXIS);
world.appendTranslation(0, 220, 1000);
world.append(projection.toMatrix3D());
Utils3D.projectVectors(world, vertices, projected, uvtData);
if((rotate-180)/-180>sort_count)
{
resort();
sort_count++;
}
viewport.graphics.clear();
Utils3D.projectVectors(world, landVertices, landProjected, landUvtData);
viewport.graphics.beginBitmapFill(land_bmpd, null, false, false);
viewport.graphics.drawTriangles(landProjected, landIndices, landUvtData, TriangleCulling.NEGATIVE);
viewport.graphics.endFill();
if(white_buildings)
viewport.graphics.beginBitmapFill(new BitmapData(100, 100, true, 0x55FFFFFF), null, false, false);
else
viewport.graphics.beginBitmapFill(bitmapData, null, false, false);
viewport.graphics.drawTriangles(projected, sortedIndices, uvtData, TriangleCulling.NEGATIVE);
viewport.graphics.endFill();
/**/
}
private function resort():void
{
var face:Vector3D;
var inc:int = 0;
var i1:uint = 0x0;
var i2:uint = 0x0;
var i3:uint = 0x0;
var i4:int = 0;
for (var i:int = 0; i<indices.length; i+=3){
i1 = indices[ i+0 ];
i2 = indices[ i+1 ];
i3 = indices[ i+2 ];
face = faces[inc];
face.x = i1;
face.y = i2;
face.z = i3;
face.w = (uvtData[i1 * 3 + 2] + uvtData[i2 * 3 + 2] + uvtData[i3 * 3 + 2]) * 0.333333;
inc++;
}
faces.sortOn("w", Array.NUMERIC);
inc = 0;
for each (face in faces){
sortedIndices[inc++] = face.x;
sortedIndices[inc++] = face.y;
sortedIndices[inc++] = face.z;
}
sort_count = 0;
}
private function update():void
{
SoundMixer.computeSpectrum(bytes, false, 0);
var byteTotal:Number = 0;
var i:int = 0;
var byte:Number = 0;
bytes.position = 0;
var w:int = 20;
var h:int = 25;
bitmapData.colorTransform(bitmapData.rect, ct);
//bitmapData.fillRect(bitmapData.rect, 0x000000);
//bitmapData.applyFilter(bitmapData, bitmapData.rect, new Point(), blurEffect);
var size:Number = bitmapData.width*0.8;
var tcolor:uint = 0;
for(i = 0; i < 512; i++)
{
byte = Math.abs(bytes.readFloat());
byteTotal += byte;
if(byte>0.2)
{
switch(varyColor)
{
case 0:
tcolor = staticColor;
break;
case 1:
vcolor.h = getTimer()/5 + (i)*(360/512);
tcolor = vcolor.value32;
break;
case 2:
vcolor.h = getTimer()/5 + 10.5*i;
tcolor = vcolor.value32;
break;
case 3:
vcolor.h = getTimer()/5 + 100/1000*i;
tcolor = vcolor.value32;
break;
case 4:
vcolor.h = getTimer()/5 + getTimer()*i;
tcolor = vcolor.value32;
break;
}
bitmapData.fillRect(new Rectangle((i%windowX)*(size/windowX),int(i/windowX)*(size/windowY), (size/windowX)-8, (size/windowY)-8), tcolor);
}
}
byteTotal /= 512;
if(300 * byteTotal > lightRatio) lightRatio = 400 * byteTotal;
lightRatio -= (lightRatio-32) * 0.03333333;
ratios[1] = lightRatio;
with(light.graphics)
{
clear();
beginGradientFill(GradientType.RADIAL,colors,alphas,ratios,m);
drawRect(0,0,stage.stageWidth,stage.stageHeight);
endFill();
}
}
private function updateTraffic(e:TimerEvent):void
{
if(++timerCount==timerSpeed)
{
var i:int = 0;
var j:int = 0;
var k:int = 0;
var l:int = 0;
var vx:Number = 0;
var vy:Number = 0;
var vlen:Number = 0;
var tm:Number = 0;
var theRect:Rectangle = new Rectangle();
theRect.width = 2;
theRect.height = 2;
//land_bmpd.fillRect(land_bmpd.rect, 0x0);
land_bmpd.colorTransform(land_bmpd.rect, ct);
for(i = 0; i < traffic.length; i++)
{
for(j = 0; j < traffic[i].length; j++)
{
k = (j+1) % traffic[i].length;
vx = traffic[i][k].x*landResizing - traffic[i][j].x*landResizing;
vy = traffic[i][k].y*landResizing - traffic[i][j].y*landResizing;
vlen = Math.sqrt(vx*vx+vy*vy);
for(l = 0; l < 5; l++)
{
tm = (getTimer()/timerSpeed)%1000 * vlen/1000;
if(tm > vlen/5) tm %= vlen/5;
theRect.x = traffic[i][j].x*landResizing + vx/vlen * (vlen/5 * l + tm);
theRect.y = traffic[i][j].y*landResizing + vy/vlen * (vlen/5 * l + tm);
land_bmpd.fillRect(theRect, 0xFFFF0000);
theRect.x += vx/vlen * vlen/5*0.1;
theRect.y += vy/vlen * vlen/5*0.1;
land_bmpd.fillRect(theRect, 0xFFAA7732);
}
}
}
timerCount = 0;
}
}
private function updateLabel():void
{
var scolor:String = "";
switch(varyColor)
{
case 0:
scolor = "color: Yellow; ";
break;
case 1:
scolor = "color: HSV 1; ";
break;
case 2:
scolor = "color: HSV 2; ";
break;
case 3:
scolor = "color: HSV 3; ";
break;
case 4:
scolor = "color: HSV 4; ";
break;
}
if(autoAlign)
scolor += "align: gridless; ";
else
scolor += "align: by grid; ";
if(timerSpeed == 0)
trafficSpeedLabel.text = scolor + buildingsTxt + "; traffic pause!";
else
trafficSpeedLabel.text = scolor + buildingsTxt + "; traffic speed: "+(4 - timerSpeed);
trafficSpeedLabel.x = stage.stageWidth - trafficSpeedLabel.width;
trafficSpeedLabel.setTextFormat(tf);
}
private function constructBuildingByVertices(va:Array, m:* = null):void
{
var i:int = 0;
var j:int = 0;
var min:Number = bheight*0.20;
var max:Number = bheight*0.80;
var randomlyHeight:Number = min+multipleRandom(2)*max;
var i1:uint = 0;
var i2:uint = 0;
var i3:uint = 0;
var i4:uint = 0;
var indexer:int = 0;
var vratio:Number = 0.8;
for(i = 0; i < va.length; i++)
{
j = (i+1)%va.length;
indexer = vertices.length/3;
vertices.push(va[i].x+offset.x, -randomlyHeight, va[i].y+offset.y); //TL
vertices.push(va[j].x+offset.x, -randomlyHeight, va[j].y+offset.y); //TR
vertices.push(va[i].x+offset.x, 0, va[i].y+offset.y); //BL
vertices.push(va[j].x+offset.x, 0, va[j].y+offset.y); //BR
uvtData.push(0+i*vratio/4, 0, 0); //1
uvtData.push((i+1)*vratio/4, 0, 0); //2
uvtData.push(0+i*vratio/4, vratio, 0); //3
uvtData.push((i+1)*vratio/4, vratio, 0); //4
/**/
i1 = indexer;
i2 = indexer + 1;
i3 = indexer + 2;
i4 = indexer + 3;
indices.push(i1, i2, i3, i3, i2, i4);
faces.push(new Vector3D(), new Vector3D());
}
/**/
indexer = vertices.length/3;
// top
vertices.push(va[1].x+offset.x, -randomlyHeight, va[1].y+offset.y); //TL
vertices.push(va[0].x+offset.x, -randomlyHeight, va[0].y+offset.y); //TR
vertices.push(va[2].x+offset.x, -randomlyHeight, va[2].y+offset.y); //BL
vertices.push(va[3].x+offset.x, -randomlyHeight, va[3].y+offset.y); //BR
if(transparent)
{
uvtData.push(0, 0, 0); //1
uvtData.push(0, 0, 0); //2
uvtData.push(0, 0, 0); //3
uvtData.push(0, 0, 0); //4
} else {
uvtData.push(vratio, vratio, 0); //1
uvtData.push(1, vratio, 0); //2
uvtData.push(vratio, 1, 0); //3
uvtData.push(1, 1, 0); //4
}
i1 = indexer;
i2 = indexer + 1;
i3 = indexer + 2;
i4 = indexer + 3;
indices.push(i1, i2, i3, i3, i2, i4);
faces.push(new Vector3D(), new Vector3D());
/**/
//if(!sortedIndices)
sortedIndices= new Vector.<int>(indices.length, true);
}
private function constructLand():void
{
var i1:uint = 0;
var i2:uint = 1;
var i3:uint = 2;
var i4:uint = 3;
landVertices.push(gwidth-gwidth/2, 0, 0-gheight/2); //TR
landVertices.push(0-gwidth/2, 0, 0-gheight/2); //TL
landVertices.push(gwidth-gwidth/2, 0, gheight-gheight/2); //BL
landVertices.push(0-gwidth/2, 0, gheight-gheight/2); //BR
landUvtData.push(1, 0, 0); //2
landUvtData.push(0, 0, 0); //1
landUvtData.push(1, 1, 0); //4
landUvtData.push(0, 1, 0); //3
landIndices.push(i1, i2, i3, i3, i2, i4);
}
private function multipleRandom(factor:int):Number
{
var counter:int = 0;
var rand:Number = 1;
while(counter++<factor)
{
rand *= Math.random();
}
return rand;
}
private function area(p:Array):Number
{
var i:int = 0;
var j:int = 0;
var a:Number = 0;
i = 0;
while (i < p.length)
{
j = (i + 1) % p.length;
a = a + p[i].x * p[j].y;
a = a - p[i].y * p[j].x;
i++;
}
a = a / 2;
return a;
}
}
}
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.display.Sprite;
import flash.net.*;
import flash.filters.*;
import flash.geom.*;
import flash.ui.*;
class Region
{
public var vertices:Array = new Array();
public var pass:Boolean = true;
public function Region()
{
}
// right is always equal to edge index, so skip the right function
public function getVerticeAtEdgeLeft(index:int):int
{
return (index+1>3)?0:index+1;
}
public function getOppositeEdgeOfEdge(index:int):int
{
return (index+2>3)?(index+2)%4:index+2;
}
public function needPush2Region(origin:Array, ratio:Number, limitLength:Number = 0.0, limitSize:Number = 0.0, align:Boolean = true, detectLongest:Boolean = true, randomAlign:Boolean = false, aRFactor:int = 1):Boolean
{
var rIndex:int = int(Math.random() * 4);
if(detectLongest)
rIndex = getLongestEdgeStartFromEdge(rIndex);
var rLeft:int = getVerticeAtEdgeLeft(rIndex);
var rRight:int = rIndex;
var vx:Number = vertices[rLeft].x - vertices[rRight].x;
var vy:Number = vertices[rLeft].y - vertices[rRight].y;
var vlen:Number = Math.sqrt(vx*vx+vy*vy);
if(limitLength == 0.0 || vlen>limitLength)
{
var oIndex:int = getOppositeEdgeOfEdge(rIndex);
var oLeft:int = getVerticeAtEdgeLeft(oIndex);
var oRight:int = oIndex;
var rPoint:Dot;
rPoint = getPointAtEdgeByRatio(rIndex, ratio);
var oPoint:Dot;
//oPoint = getPointAtEdgeByPoint(oIndex, rPoint);
if(!randomAlign)
if(align)
oPoint = getPointAtEdgeByRatio(oIndex, 1-ratio);
else
oPoint = getPointAtEdgeByRatio(oIndex, ratio);
else {
if(multipleRandom(aRFactor)<0.5)
{
//oPoint = getPointAtEdgeByRatio(oIndex, 1-ratio);
oPoint = getPointAtEdgeByPoint(oIndex, rPoint);
if(oPoint == null)
{
oPoint = getPointAtEdgeByRatio(oIndex, Math.random()*(1-ratio));
}
} else
oPoint = getPointAtEdgeByRatio(oIndex, ratio);
}/**/
var regionLeft:Region = new Region();
var regionRight:Region = new Region();
regionLeft.vertices.push(vertices[oRight].clone());
regionLeft.vertices.push(oPoint);
regionLeft.vertices.push(rPoint);
regionLeft.vertices.push(vertices[rLeft].clone());
if(limitSize != 0.0 && regionLeft.area()<limitSize)
{
regionLeft.pass = false;
}
origin.push(regionLeft);
regionRight.vertices.push(oPoint);
regionRight.vertices.push(vertices[oLeft].clone());
regionRight.vertices.push(vertices[rRight].clone());
regionRight.vertices.push(rPoint);
if(limitSize != 0.0 && regionRight.area()<limitSize)
{
regionRight.pass = false;
}
origin.push(regionRight);
return true;
}
return false;
}
public function getPointAtEdgeByRatio(index:int, ratio:Number):Dot
{
var jndex:int = (index+1)%4;
var vx:Number = vertices[jndex].x - vertices[index].x;
var vy:Number = vertices[jndex].y - vertices[index].y;
return new Dot(vertices[index].x+vx*ratio, vertices[index].y+vy*ratio);
}
public function getPointAtEdgeByPoint(index:int, p:Dot):Dot
{
var jndex:int = (index+1)%4;
var avx:Number = vertices[jndex].x - vertices[index].x;
var avy:Number = vertices[jndex].y - vertices[index].y;
var vlena:Number = Math.sqrt(avx*avx+avy*avy);
var dist:Number = pdis(vertices[index], vertices[jndex], p);
var bvx:Number = p.x - vertices[index].x;
var bvy:Number = p.y - vertices[index].y;
var vlenb:Number = Math.sqrt(bvx*bvx+bvy*bvy);
var nvlena:Number = Math.sqrt(vlenb*vlenb - dist*dist);
if(nvlena<vlena)
return new Dot(vertices[index].x+nvlena*avx/vlena, vertices[index].y+nvlena*avy/vlena);
return null;
}
public function getLengthOfEdge(index:int):Number
{
var nextIndex:int = (index+1)%4;
var vx:Number = vertices[nextIndex].x - vertices[index].x;
var vy:Number = vertices[nextIndex].y - vertices[index].y;
return Math.sqrt(vx*vx+vy*vy);
}
public function getLongestEdgeStartFromEdge(index:int):int
{
var li:int = index;
var ci:int = index;
var startIndex:int = index;
var longestLength:Number = getLengthOfEdge(index);
var currLength:Number = 0;
do{
ci = (ci+1)%4;
currLength = getLengthOfEdge(ci);
if(currLength>longestLength)
{
longestLength = currLength;
li = ci;
}
} while(ci != startIndex);
return li;
}
public function area():Number
{
var i:int = 0;
var j:int = 0;
var a:Number = 0;
i = 0;
while (i < vertices.length)
{
j = (i + 1) % vertices.length;
a = a + vertices[i].x * vertices[j].y;
a = a - vertices[i].y * vertices[j].x;
i++;
}
a = a / 2;
return a;
}
public function multipleRandom(factor:int):Number
{
var counter:int = 0;
var rand:Number = 1;
while(counter++<factor)
{
rand *= Math.random();
}
return rand;
}
public function pdis(a:Dot, b:Dot, c:Dot):Number
{
var t:Dot = new Dot(b.x-a.x, b.y-a.y);// # Vector ab
var dd:Number = Math.sqrt(t.x*t.x+t.y*t.y);// # Length of ab
t.val_p_(t.x/dd, t.y/dd);// # unit vector of ab
var n:Dot = new Dot(-t.y, t.x);// # normal unit vector to ab
var ac:Dot = new Dot(c.x-a.x, c.y-a.y);// # vector ac
return Math.abs(ac.x*n.x+ac.y*n.y);
}
public function com() : Dot// centre of mass
{
var cm:Dot = new Dot(0, 0);
var tx:Number = 0;
var ty:Number = 0;
var a:Number = area();
var i:int = 0;
var j:int = 0;
var d:Number = 0;
i = 0;
while (i < vertices.length)
{
j = (i + 1) % vertices.length;
d = vertices[i].x * vertices[j].y - vertices[j].x * vertices[i].y;
tx = tx + (vertices[i].x + vertices[j].x) * d;
ty = ty + (vertices[i].y + vertices[j].y) * d;
i++;
}
a = a * 6;
d = 1 / a;
tx = tx * d;
ty = ty * d;
cm.x = tx;
cm.y = ty;
return cm;
}
public function getResizedRegionVerticesByRatio(target:Array, ratio:Number = 1.0):void
{
var centerOfMass:Dot = com();
var vx:Number = 0;
var vy:Number = 0;
var i:int = 0;
for(i = 0; i < vertices.length; i++)
{
vx = vertices[i].x - centerOfMass.x;
vy = vertices[i].y - centerOfMass.y;
target.push(new Dot(centerOfMass.x+vx*ratio, centerOfMass.y+vy*ratio));
}
}
}
class Dot
{
public var x:Number = 0;
public var y:Number = 0;
public var tx:Number = 0;
public var ty:Number = 0;
public var vx:Number = 0;
public var vy:Number = 0;
public var angle:Number = 0;
public var size:Number = 0;
public var speed:Number = 0;
public var m:Number = 0;
public var rad:Number = 0;
public function Dot(px:Number,py:Number)
{
x = px;
y = py;
tx = x;
ty = y;
}
public function clone():Dot
{
return new Dot(this.x, this.y);
}
public function val_(p:Dot):Dot
{
x = p.x;
y = p.y;
return this;
}
public function val_p_(px:Number, py:Number):Dot
{
x = px;
y = py;
return this;
}
public function add_(px:Number, py:Number):Dot
{
x += px;
y += py;
return this;
}
}