凸面の閉路

立方体のシルエットだけ欲しいときがあって、
でも、描画に負担をかけたくない時用。

▼参考
三角形の面積
http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/SurfaceArea.htm

閉路作成
http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/Heiro.htm

▼Wonderfl

凸面の閉路 – wonderfl build flash online

▼ActionScript AS3(FP10)
[sourcecode language=”as3″]
/*
* 凸面の閉路
*
* 立方体のシルエットだけ欲しいときがあって、
* でも、描画に負担をかけたくない時用。
* */

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);
for each(var point:Point in points) {
_canvas.graphics.lineTo(point.x, point.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;
}

}
[/sourcecode]