test_case08
forked from test (diff: 436)
ref Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編]
ActionScript3 source code
/**
* Copyright h_kamizono ( http://wonderfl.net/user/h_kamizono )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/oqA7
*/
// forked from h_kamizono's test
// ref
// Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編]
package {
import flash.trace.Trace;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.display.Bitmap;
import flash.display.BitmapData;
public class Pendulum extends MovieClip {
private var base:Sprite = new Sprite();
private var pt:Array = new Array();
private var pigment:Number = 0;
private var rotatePt:PhysicalPoint = new PhysicalPoint();
private var preAngle:Number;
private const minDotNum:Number = 3;
private var bitmapdata:BitmapData;
private var blackCover:Sprite = new Sprite();
private var pressed:Boolean = false;
private var curMouse:Point;
private var preMouse:Point;
public function Pendulum() {
// write as3 code here..
bitmapdata = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
addChild(new Bitmap(bitmapdata));
blackCover.graphics.lineStyle(0, 0, 0);
blackCover.graphics.beginFill(0, .05);
blackCover.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
blackCover.graphics.endFill();
rotatePt.kb = 0.98;
preAngle = rotatePt.angle;
curMouse = new Point(this.mouseX, this.mouseY);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
var delTimer:Timer = new Timer(10000);
delTimer.addEventListener(TimerEvent.TIMER, delLoop);
delTimer.start();
var timer:Timer = new Timer(33);
timer.addEventListener(TimerEvent.TIMER, loop);
timer.start();
}
private function onMDown(ev:MouseEvent) :void {
pressed = true;
pt.push(new Point(ev.target.mouseX, ev.target.mouseY));
var dire:Number = rotatePt.angle;
while (dire > Math.PI) dire -= Math.PI*2;
while (dire < -Math.PI) dire += Math.PI*2;
if (dire < Math.PI/2 && dire > -Math.PI/2)
rotatePt.setKakuKasokudo(-100);
else
rotatePt.setKakuKasokudo(100);
changeState();
}
private function onMUp(ev:MouseEvent) :void {
pressed = false;
}
private function delLoop(event:TimerEvent) :void {
if (pt.length > minDotNum) {
pt.shift();
changeState();
}
}
private function changeState() :void {
if (pt.length > 1) {
var ppt:Array = Functions.getPolygon(pt);
var jpt:Point = Functions.getCentroid(ppt);
if (jpt != null) {
var dire:Number = Math.atan2(jpt.y - pt[pt.length - 1].y,
jpt.x - pt[pt.length - 1].x);
rotatePt.angle = dire;
preAngle = dire;
}
}
}
private function loop(event:TimerEvent) :void {
preMouse = curMouse;
curMouse = new Point(this.mouseX, this.mouseY);
var ppt:Array = Functions.getPolygon(pt);
var jpt:Point = Functions.getCentroid(ppt);
// 個人的には必要ないかも
if (pressed) {
for (var i:Number = 0; i < pt.length; ++i) {
pt[i].x += curMouse.x - preMouse.x;
pt[i].y += curMouse.y - preMouse.y;
}
var mAngle:Number = Math.atan2(curMouse.y - preMouse.y,
curMouse.x - preMouse.x);
mAngle += Math.PI;
var par:Number = Point.distance(curMouse, jpt)*
Point.distance(preMouse, curMouse) * 0.01;
//rotatePt.setKakuKasokudo2(mAngle, par);
}
rotatePt.setKakuKasokudo2(Math.PI/2, 10);
for (var j:Number = 0; j < pt.length - 1; ++j) {
var p1x:Number = pt[j].x - pt[pt.length - 1].x;
var p1y:Number = pt[j].y - pt[pt.length - 1].y;
var p2x:Number = p1x * Math.cos(rotatePt.angle - preAngle) -
p1y * Math.sin(rotatePt.angle - preAngle);
var p2y:Number = p1x * Math.sin(rotatePt.angle - preAngle) +
p1y * Math.cos(rotatePt.angle - preAngle);
var p3x:Number = p2x + pt[pt.length - 1].x;
var p3y:Number = p2y + pt[pt.length - 1].y;
pt[j].x = p3x; pt[j].y = p3y;
}
pigment += 1;
var col:uint = Functions.hsbToRgb(pigment, 1, 1);
base.graphics.clear();
if (jpt != null) {
base.graphics.lineStyle(0, 0, 0);
base.graphics.beginFill(0x000000);
base.graphics.drawCircle(jpt.x, jpt.y, 3);
base.graphics.endFill();
}
if (ppt != null) {
base.graphics.lineStyle(1, col, 0.5);
base.graphics.moveTo(ppt[0].x, ppt[0].y);
base.graphics.beginFill(col, 0.1);
for (var k:Number = 1; k < ppt.length; ++k) {
base.graphics.lineTo(ppt[k].x, ppt[k].y);
}
base.graphics.lineTo(ppt[0].x, ppt[0].y);
base.graphics.endFill();
}
for (var m:Number = 0; m < pt.length; ++m) {
base.graphics.lineStyle(0, 0, 0);
base.graphics.beginFill(col, 0.5);
base.graphics.drawCircle(pt[m].x, pt[m].y, 4);
base.graphics.endFill();
}
bitmapdata.draw(blackCover);
bitmapdata.draw(base);
preAngle = rotatePt.angle;
}
}
}
class Functions {
public static function hsbToRgb(h:Number,
s:Number,
b:Number) :uint {
while (h < 0) {
h+=360;
}
while (h >= 360) {
h -= 360;
}
var h2:Number = Math.floor(h/60);
var f:Number = h/60 - h2;
var parFull:Number = 255;
var parEmp:Number = 0;
var parZoka:Number = 255*f;
var parGensho:Number = 255*(1-f);
var red:Number = 0;
var green:Number = 0;
var blue:Number = 0;
switch (h2) {
case 0:
red = parFull; green = parZoka; blue = parEmp;
break;
case 1:
red = parGensho; green = parFull; blue = parEmp;
break;
case 2:
red = parEmp; green = parFull; blue = parZoka;
break;
case 3:
red = parEmp; green = parGensho; blue = parFull;
break;
case 4:
red = parZoka; green = parEmp; blue = parFull;
break;
case 5:
red = parFull; green = parEmp; blue = parGensho;
break;
}
var max:Number = Math.max(Math.max(red, green), blue);
red = max - (max - red)*s;
green = max - (max - green)*s;
blue = max - (max - blue)*s;
red *= b; green *= b; blue *= b;
var ret:uint = int(red) << 16 | int(green) << 8 | int(blue);
return ret;
}
public static function getPolygon(pt:Array) :Array {
if (pt.length > 0) {
var maxPt:Point = null;
var minPt:Point = null;
var retPt:Array = new Array();
var minVal:Number = 100000;
var maxVal:Number = -100000;
for (var i:Number = 0; i < pt.length; ++i) {
if (minVal > pt[i].x) {
minVal = pt[i].x;
minPt = pt[i];
} else if (minVal == pt[i].x) {
if (minPt.y < pt[i].y) {
minPt = pt[i];
}
}
if (maxVal < pt[i].x) {
maxVal = pt[i].x;
maxPt = pt[i];
}
}
retPt.push(minPt);
var korePt:Point = null;
for (var j:Number = 0; j < pt.length; ++j) {
if (minPt == maxPt) break;
var maxK:Number = -100000;
for (var k:Number = 0; k < pt.length; ++k) {
if (minPt != pt[k]) {
if (pt[k].x > minPt.x) {
if (maxK < (pt[k].y - minPt.y) / (pt[k].x - minPt.x)) {
maxK = (pt[k].y - minPt.y) / (pt[k].x - minPt.x);
korePt = pt[k];
}
}
}
}
retPt.push(korePt);
minPt = korePt;
}
minVal = 100000;
maxVal = -100000;
for (var m:Number = 0; m < pt.length; ++m) {
if (minVal > pt[m].x) {
minVal = pt[m].x;
minPt = pt[m];
}
if (maxVal < pt[m].x) {
maxVal = pt[m].x;
maxPt = pt[m];
} else if (maxVal == pt[m].x) {
if (maxPt.y > pt[m].y) {
maxPt = pt[m];
}
}
}
if (retPt[retPt.length - 1] != maxPt) {
retPt.push(maxPt);
}
korePt = null;
for (var n:Number = 0 ; n < pt.length; ++n) {
if (minPt == maxPt) break;
maxK = -100000;
for (var q:Number = 0; q < pt.length; ++q) {
if (maxPt != pt[q]) {
if (pt[q].x < maxPt.x) {
if (maxK < (pt[q].y - maxPt.y) / (pt[q].x - maxPt.x)) {
maxK = (pt[q].y - maxPt.y) / (pt[q].x - maxPt.x);
korePt = pt[q];
}
}
}
}
retPt.push(korePt);
maxPt = korePt;
}
if (retPt.length > 1 &&
retPt[retPt.length - 1].x == retPt[0].x &&
retPt[retPt.length - 1].y == retPt[0].y) {
retPt.pop();
}
return retPt;
} else {
return null;
}
}
public static function getCentroid(pt:Array) :Point {
if (pt != null) {
if (pt.length == 0) {
return new Point(0, 0);
} else if (pt.length == 1) {
return new Point(pt[0].x, pt[0].y);
} else if (pt.length == 2) {
return new Point((pt[0].x + pt[1].x)/2, (pt[0].y + pt[1].y)/2);
} else {
var ptSize:Number = pt.length;
/*
var s:Number = 0;
for (var i:Number = 0; i < ptSize; ++i) {
s += (pt[i].x + pt[(i+1) % ptSize].x) * (pt[(i+1) % ptSize].y - pt[i].y);
}
*/
/*
for (var i:Number = 0; i < ptSize; ++i) {
s += (pt[i].x * pt[(i+1) % ptSize].y) - (pt[(i+1) % ptSize].x * pt[i].y);
}
*/
// area
var s:Number = pt[0].x * (pt[1].y - pt[ptSize-1].y);
// centroid
var gx:Number = pt[0].y * (pt[ptSize-1].x - pt[1].x) * (pt[ptSize-1].x + pt[0].x + pt[1].x);
var gy:Number = -pt[0].x * (pt[ptSize-1].y - pt[1].y) * (pt[ptSize-1].y + pt[0].y + pt[1].y);
for (var i:Number = 1; i < ptSize - 1; ++i) {
s += pt[i].x * (pt[i+1].y - pt[i-1].y);
gx += pt[i].y * (pt[i-1].x - pt[i+1].x) * (pt[i-1].x + pt[i].x + pt[i+1].x);
gy += -pt[i].x * (pt[i-1].y - pt[i+1].y) * (pt[i-1].y + pt[i].y + pt[i+1].y);
}
s += pt[ptSize - 1].x * (pt[0].y - pt[ptSize - 2].y);
s /= 2;
gx += pt[ptSize-1].y * (pt[ptSize-2].x - pt[0].x) * (pt[ptSize-2].x + pt[ptSize-1].x + pt[0].x);
gy += -pt[ptSize-1].x * (pt[ptSize-2].y - pt[0].y) * (pt[ptSize-2].y + pt[ptSize-1].y + pt[0].y);
/*
var gx:Number = 0; var gy:Number = 0;
for (var j:Number = 0; j < ptSize; ++j) {
// mul 4, add or sub 3, %op 4
gx += (pt[j].x * pt[j].x +
pt[j].x * pt[(j+1)%ptSize].x +
pt[(j+1)%ptSize].x * pt[(j+1)%ptSize].x) *
(pt[(j+1) % ptSize].y - pt[j].y);
gy += (pt[j].y * pt[j].y +
pt[j].y * pt[(j+1)%ptSize].y +
pt[(j+1)%ptSize].y * pt[(j+1)%ptSize].y) *
(-pt[(j+1) % ptSize].x + pt[j].x);
}*/
gx /= s*6; gy /= s*6;
return new Point(gx, gy);
}
} else {
return null;
}
}
}
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
class PhysicalPoint extends Point {
private var vx:Number, vy:Number;
private var ax:Number, ay:Number;
private var b:Number;
private var preTime:Number;
private var timer:Timer;
private var preX:Number, preY:Number;
public var kb:Number;
public var angle:Number;
public var preAngle:Number;
public var kakusokudo:Number;
public var kakukasokudo:Number;
private var limitter:Number = 0.3;
function PhysicalPoint(xx: Number = 0, yy:Number = 0, an:Number = 0) {
x = xx; y = yy;
preX = xx; preY = yy;
b = 0.9;
vx = 0; vy = 0;
ax = 0; ay = 0;
angle = an;
preAngle = an;
kb = 0.9;
kakusokudo = 0;
kakukasokudo = 0;
preTime = new Date().getTime();
timer = new Timer(33);
timer.addEventListener(TimerEvent.TIMER, loop);
timer.start();
}
public function loop(event:TimerEvent) :void {
var nowTime:Number = new Date().getTime();
var t:Number = (nowTime - preTime)/1000;
if (t > limitter) t = limitter;
preX = x;
preY = y;
x += (vx + 0.5*ax*t)*t;
y += (vy + 0.5*ay*t)*t;
vx += ax*t; vy += ay*t;
vx *= b; vy *= b;
ax = 0; ay = 0;
preAngle = angle;
angle += (kakusokudo + 0.5*kakukasokudo*t) *t;
kakusokudo += kakukasokudo*t;
kakusokudo *= kb;
kakukasokudo = 0;
preTime = nowTime;
}
public function setKasokudo(aax:Number = 0, aay:Number = 0) :void {
ax += aax;
ay += aay;
}
public function setKasokudoByPolar(r:Number=0, dire:Number = 0) :void {
ax += r*Math.cos(dire);
ay += r*Math.sin(dire);
}
public function setKakuKasokudo(aan:Number = 0) :void {
kakukasokudo += aan;
}
public function setKakuKasokudo2(dire:Number, val:Number) :void {
var aan:Number = val * Math.sin(dire - angle);
setKakuKasokudo(aan);
}
}
