
/* * 凸面の閉路 * * 立方体のシルエットだけ欲しいときがあって、 * でも、描画に負担をかけたくない時用。 * */ package { import flash.display.Sprite; import flash.events.Event; import flash.geom.Matrix3D; import flash.geom.Point; import flash.geom.Vector3D; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.easing.*; import org.libspark.betweenas3.tweens.ITween; [SWF(width = 465, height = 465, backgroundColor = 0x282222, frameRate = 30)] public class Main extends Sprite { private var _sps:Array; private var _sp:Sprite; private const DEGREE_FROM_RADIAN:Number = 180 / Math.PI; private var _canvas:Sprite = new Sprite(); private var _vector3Ds:Vector.<Vector3D> = new Vector.<Vector3D>(); public function Main():void { this.addChild(_canvas); _sp = new Sprite(); _sp.x = stage.stageWidth / 2; _sp.y = stage.stageHeight / 2; this.addChild(_sp); _sps = []; for (var i:int = 0; i < 24; i++) { _sps[i] = new Sprite(); _sps[i].graphics.beginFill(0xFF0000); _sps[i].graphics.drawCircle(0, 0, 5); this.addChild(_sps[i]); _vector3Ds[i] = new Vector3D(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); } this.addEventListener(Event.ENTER_FRAME, onEnter); } private function onEnter(event:Event):void { _sp.rotationX += (stage.mouseY-stage.stageHeight/2)/100; _sp.rotationY += Math.round((stage.mouseX-stage.stageWidth/2)/100); draw(); if (_sp.rotationY % 180 == 0) { var t_array:Array = []; var n:int = _sps.length; for (var i:int = 0; i < n; i++) { t_array.push(BetweenAS3.tween(_vector3Ds[i],{x:Math.random() * 360 - 180,z:Math.random() * 360 - 180},null,1,Cubic.easeOut)); t_array.push(BetweenAS3.tween(_vector3Ds[i],{y:Math.random() * 360 - 180},null,1,Cubic.easeIn)); } var t:ITween; t = BetweenAS3.parallel.apply(null, t_array); t.play(); } } private function draw():void { var _array:Array = []; var n:int = _sps.length; for (var i:int = 0; i < n; i++) { var poz:Vector3D = _sp.transform.matrix3D.transformVector(_vector3Ds[i]); _array.push(new Point(poz.x, poz.y)); _sps[i].x = poz.x; _sps[i].y = poz.y; } var points:Array = Geometry.getConvex.apply(null, Geometry.sortPosition.apply(null, _array)); _canvas.graphics.clear(); _canvas.graphics.lineStyle(0, 0x00FF00); _canvas.graphics.beginFill(0x001100); _canvas.graphics.moveTo(points[0].x, points[0].y); n = points.length; for (i = 1; i < n; i++) { _canvas.graphics.lineTo(points[i].x, points[i].y); } _canvas.graphics.lineTo(points[0].x, points[0].y); } } } import flash.geom.Point; //Geometry class Geometry { static public const DEGREE_FROM_RADIAN:Number = 180 / Math.PI; /* //参考:三角形の面積 //http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/SurfaceArea.htm static public function getTriSurfaceArea(a:Point, b:Point, c:Point):Number { return Math.abs((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2; } //多角形の面積。ただし、凹形によっては間違った面積が返る static public function getPolySurfaceArea(... rest):Number { var result:Number = 0; var n:int = rest.length; for (var i:int = 2; i < n; i++) { result += getTriSurfaceArea(rest[0], rest[i - 1], rest[i]); } return result; } */ //三点のなす角 static public function getTriRadian(a:Point, r:Point, b:Point):Number { var ra:Point = r.subtract(a); var rb:Point = r.subtract(b); return Math.atan2(ra.x * rb.y - ra.y * rb.x, ra.x * rb.x + ra.y * rb.y); } //角度の和による内外判定 //http://kone.vis.ne.jp/diary/diaryb09.html#040518_result static public function pointInPolygon(... rest):Boolean { var radian:Number = 0; var n:int = rest.length - 1; for (var i:int = 0; i < n; i++) { radian += getTriRadian(rest[i + 1], rest[0], rest[((i + 1) % n) + 1]); } return nearEquals(Math.abs(DEGREE_FROM_RADIAN * radian), 360, 0.1); } //だいたい同じ static public function nearEquals(a:Number, b:Number, tolerance:Number):Boolean { return ((b - tolerance) <= a && a <= (b + tolerance)); } //凸型にする。 //ある点が他の点からなる多角形の内側にあれば、それは凹点とみなす static public function getConvex(... rest):Array { var result:Array = []; var n:int = rest.length; for (var i:int = 0; i < n; i++) { var ar:Array = []; ar.push(rest[i]); for (var j:int = 0; j < n; j++) { if (j != i) { ar.push(rest[j]); } } if (!pointInPolygon.apply(null, ar)) { result.push(rest[i]); } } if (n > result.length) { result = getConvex.apply(null, result); } return result; } //閉路作成:http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/Heiro.htm static public function sortPosition(... rest):Array { var temp:Array = []; var sorted:Array = []; var sorted2:Array = []; var radians:Array = [0]; var result:Array = []; var n:int = rest.length; for (var i:int = 0; i < n; i++) { temp.push(rest[i].y); } sorted = temp.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); for (i = 1; i < n; i++) { var j:int = sorted[i]; radians.push(Math.atan2(rest[j].y - rest[sorted[0]].y, rest[j].x - rest[sorted[0]].x)); } sorted2 = radians.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); temp = []; for (i = 0; i < n; i++) { temp.push(sorted[sorted2[i]]); } for (i = 0; i < n; i++) { result.push(rest[temp[i]]); } return result; } }