AS3で流体解析テスト
動作重いです。要注意 ***
*
* AS3で数値流体力学テスト
*
* 解析 :二次元浅水流方程式(ただし、拡散項を省略)
* 解析方法 :非構造格子有限体積法・流束差分離法(FDS)
* 解析データ :水工学委員会基礎水理部会 河床変動計算法研究グループ
* (http://www.civil.hokudai.ac.jp/yasu/hendou/index.htm)
* で公開されている計算用テストデータを使用
* 初期条件 :適当
* 境界条件 :上流端=流入0.1m3/s 下流端=水位-0.1448m 閉境界=ノンスリップ
* 結果表示 :流速のみ(カラーコンターで表示)
* 結果出力 :未実装。
*
/**
* Copyright termat ( http://wonderfl.net/user/termat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/zQXz
*/
/*** 動作重いです。要注意 ***
*
* AS3で数値流体力学テスト
*
* 解析 :二次元浅水流方程式(ただし、拡散項を省略)
* 解析方法 :非構造格子有限体積法・流束差分離法(FDS)
* 解析データ :水工学委員会基礎水理部会 河床変動計算法研究グループ
* (http://www.civil.hokudai.ac.jp/yasu/hendou/index.htm)
* で公開されている計算用テストデータを使用
* 初期条件 :適当
* 境界条件 :上流端=流入0.1m3/s 下流端=水位-0.1448m 閉境界=ノンスリップ
* 結果表示 :流速のみ(カラーコンターで表示)
* 結果出力 :未実装。
*
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.Security;
import flash.events.MouseEvent;
import flash.text.engine.JustificationStyle;
import flash.text.TextField;
[SWF(framerate="60",width="500",height="500",backgroundColor="0xffffff")]
public class Flow2d extends Sprite{
private static const G:Number = 9.80665;//重力加速度
private static const H:int = 0;
private static const UH:int = 1;
private static const VH:int = 2;
private static const NONE:int = 0;
private static const NONSLIP:int = 1;
private static const FLOW:int = 2;
private static const LEVEL:int = 3;
private static const H_MIN:Number = 0.005;
private var cells:Vector.<Cell>;
private var map:Vector.<Array>;
private var iter:int = 0;
private var time:Number = 0.0;
private var dt:Number = 0.5;
private var loader:URLLoader;
private var rect:Rectangle;
private var canvas:MeshCanvas;
private var pos:Point = null;
private var cpos:Point = null;
private var flowQ:Number;
private var level:Number;
private var preF:Vector.<Array>;
private var text:TextField;
private var start:Boolean = false;
private var calc:Boolean = true;
private var bt:Button;
public function Flow2d():void {
cells = new Vector.<Cell>();
/*5iVESTAR.ORGさん(http://5ivestar.org/blog/)のプロキシを利用させていただいている。*/
load("http://5ivestar.org/proxy/http://termat.sakura.ne.jp/air/mesh.csv",
"http://5ivestar.org/proxy/crossdomain.xml");
addEventListener(Event.EXIT_FRAME, update);
text = new TextField();
text.x = 10;
text.y = 25;
text.width = text.textWidth + 10;
addChild(text);
bt = new Button(30, 20, 5, "Start", 11);
bt.addEventListener(MouseEvent.MOUSE_DOWN, buttonDown);
addChild(bt);
Wonderfl.capture_delay(900);
}
private function buttonDown(e:MouseEvent):void {
start = (!start);
if (start) {
bt.setLabelText("Stop", 11);
} else {
bt.setLabelText("Start", 11);
}
}
private function load(url:String, sec:String = null):void {
loader = new URLLoader();
if (sec != null) Security.loadPolicyFile(sec);
loader.addEventListener(Event.COMPLETE,onCompleted);
loader.load(new URLRequest(url));
}
private function onCompleted(e:Event):void {
var mesh:MeshData = new MeshData(loader.data);
flowQ = mesh.flowQ;
level = mesh.level;
dt = mesh.dt;
iter = 0;
var node:Array = mesh.node;
var elem:Vector.<Array> = mesh.elem;
for (var i:int = 0; i < elem.length; i++) {
cells[i] = new Cell(node[elem[i][0]], node[elem[i][1]], node[elem[i][2]]);
cells[i].boundType = mesh.boundary[i];
}
map = mesh.map;
rect = mesh.rect;
preF = new Vector.<Array>(elem.length);
canvas = new MeshCanvas(cells,rect);
addChild(canvas);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onWheel);
}
private function update(e:Event):void {
if (canvas != null) canvas.update();
if (start) {
text.text = "計算中:time=" + time.toString() + " iter=" + iter.toString();
text.width = text.textWidth + 10;
if (iter == 0) {
if(calc)this.calc1d();
}else {
if(calc)this.calc2d();
}
}else {
text.text = "停止中:time=" + time.toString()+" iter="+iter.toString();
text.width = text.textWidth + 10;
}
}
private function mouseDown(e:MouseEvent):void {
pos = new Point(e.stageX, e.stageY);
cpos = new Point(canvas.x, canvas.y);
}
private function mouseUp(e:MouseEvent):void {
mouseMove(e);
pos = null;
cpos = null;
}
private function mouseMove(e:MouseEvent):void {
if (pos != null) {
canvas.x = cpos.x + (e.stageX - pos.x);
canvas.y = cpos.y + (e.stageY - pos.y);
}
}
private function onWheel(e:MouseEvent):void {
if (canvas == null) return;
var n:Number = e.delta;
if (n > 0) {
canvas.scale /= 1.2;
}else {
canvas.scale *= 1.2;
}
}
// Array処理関数 -------------------------------------------------
private function add(a:Array,b:Array):Array {
for (var i:int = 0; i < a.length; i++) a[i] += b[i];
return a;
}
private function sub(a:Array,b:Array):Array{
for (var i:int = 0; i < a.length; i++) a[i] -= b[i];
return a;
}
public function mul(a:Array,b:Number):Array{
for (var i:int = 0; i < a.length; i++) a[i] *= b;
return a;
}
private function copy(a:Array):Array {
var ret:Array = new Array();
for (var i:int = 0; i < a.length; i++) ret[i] = a[i];
return ret;
}
// 計算用関数 -------------------------------------------------
// Roe平均の計算
private function getRoe(Ul:Array,Ur:Array):Array{
var hl:Number=Ul[H];
var hr:Number=Ur[H];
var ul:Number=Ul[UH]/hl;
var ur:Number=Ur[UH]/hr;
var vl:Number=Ul[VH]/hl;
var vr:Number=Ur[VH]/hr;
var hh:Number=(Math.sqrt(hl)+Math.sqrt(hr));
var _u:Number=(Math.sqrt(hl)*ul+Math.sqrt(hr)*ur)/hh;
var _v:Number=(Math.sqrt(hl)*vl+Math.sqrt(hr)*vr)/hh;
var _h:Number=(hl+hr)/2.0;
var _c:Number=Math.sqrt(G*_h);
return [_u, _v, _c, _h];
}
// 流束の計算
public function getFN(nx:Number,ny:Number,Ex:Array,Fx:Array):Array{
var e:Array = mul(copy(Ex), nx);
var f:Array = mul(copy(Fx), ny);
return add(e, f);
}
// 流束 第二項の計算
public function getEDA3d(uvch:Array,nx:Number,ny:Number,Ul:Array,Ur:Array):Array{
var e:Array=getRoeE3d(uvch, nx, ny);
var d:Array=getRoeAbsDn3d(Ul,Ur,uvch,nx,ny);
var a:Array=getRoeAlpha3d(uvch,nx,ny,Ul,Ur);
e[0]=mul(e[0],a[0]*d[0]);
e[1]=mul(e[1],a[1]*d[1]);
e[2]=mul(e[2],a[2]*d[2]);
return add(add(e[0], e[1]), e[2]);
}
// 近似ヤコビアンの右固有行列
public function getRoeE3d(uvch:Array,nx:Number,ny:Number):Array{
var m0:Array = [1.0, uvch[0] + uvch[2] * nx, uvch[1] + uvch[2] * ny];
var m1:Array = [0.0, -uvch[2] * ny, uvch[2] * nx];
var m2:Array = [1.0, uvch[0] - uvch[2] * nx, uvch[1] - uvch[2] * ny];
return [m0, m1, m2];
}
// 近似ヤコビアンの固有値
private function getRoeAbsDn3d(Ul:Array,Ur:Array,uvch:Array,nx:Number,ny:Number):Array{
var ck:Array=getRoeDelta3d(Ul,Ur,nx,ny);
var a0:Number = Math.abs(uvch[0] * nx + uvch[1] * ny + uvch[2]);
var a1:Number = Math.abs(uvch[0] * nx + uvch[1] * ny);
var a2:Number = Math.abs(uvch[0] * nx + uvch[1] * ny - uvch[2]);
if(a0<ck[0])a0=ck[0];
if(a1<ck[1])a1=ck[1];
if(a2<ck[2])a2=ck[2];
return [a0, a1, a2];
}
private function getRoeDelta3d(Ul:Array,Ur:Array,nx:Number,ny:Number):Array{
var hl:Number = Ul[H];
var ul:Number = Ul[UH] / hl;
var vl:Number = Ul[VH] / hl;
var cl:Number = Math.sqrt(G * hl);
var hr:Number = Ur[H];
var ur:Number = Ur[UH] / hr;
var vr:Number = Ur[VH] / hr;
var cr:Number = Math.sqrt(G * hr);
var ff:Array = getRoeDn3d(getRoe(Ul, Ur), nx, ny);
var fl:Array = getRoeDn3d(new Array(ul, vl, cl, hl), nx, ny);
var fr:Array=getRoeDn3d(new Array(ur,vr,cr,hr),nx,ny);
return [
Math.max(0.0, ff[0] - fl[0], fr[0] - ff[0]),
Math.max(0.0, ff[1] - fl[1], fr[1] - ff[1]),
Math.max(0.0, ff[2] - fl[2], fr[2] - ff[2])];
}
// 近似ヤコビアンの固有値
private function getRoeDn3d(uvch:Array,nx:Number,ny:Number):Array{
return [
uvch[0] * nx + uvch[1] * ny + uvch[2],
uvch[0] * nx + uvch[1] * ny,
uvch[0] * nx + uvch[1] * ny - uvch[2]];
}
// 波の強さaの計算
private function getRoeAlpha3d(uvch:Array,nx:Number,ny:Number,Ul:Array,Ur:Array):Array{
var c:Number = uvch[2];
var r:Number = (1.0 / (2.0 * c));
var dh:Number = (Ur[H] - Ul[H]);
var duh:Number = (Ur[UH] - Ul[UH]);
var dvh:Number = (Ur[VH] - Ul[VH]);
var m0:Number = 0.5 * dh + r * (duh * nx + dvh * ny - (uvch[0] * nx + uvch[1] * ny) * dh)
var m1:Number = (1.0 / c) * ((dvh - uvch[1] * dh) * nx - (duh - uvch[0] * dh) * ny);
var m2:Number = 0.5 * dh - r * (duh * nx + dvh * ny - (uvch[0] * nx + uvch[1] * ny) * dh);
return [m0, m1, m2];
}
// 生成・消滅項の計算(1)
private function getSxSy3d(h:Number,u:Number,v:Number,n:Number):Array{
var uv:Number = Math.sqrt(u * u + v * v);
var h43:Number = Math.pow(h, 4.0 / 3.0);
var sx:Number = n * n * u * uv / h43;
var sy:Number = n * n * v * uv / h43;
return [0.0, sx, sy];
}
// 生成・消滅項の計算(2)
private function getSk3d(db:Number,l:Number,nx:Number,ny:Number,uvch:Array):Array{
var ret:Array = getBarSk3d(db, l, nx, ny, uvch);
var f0:Array = getAbsFByFMatrix3d(uvch, nx, ny);
var e:Array = getRoeE3d(uvch, nx, ny);
var beta:Array = getBeta3d(ret, uvch, nx, ny);
e[0] = mul(e[0], f0[0] * beta[0]);
e[1] = mul(e[1], f0[1] * beta[1]);
e[2] = mul(e[2], f0[2] * beta[2]);
e[0] = add(add(e[0], e[1]), e[2]);
return mul(sub(ret, e[0]), 0.5);
}
// 生成・消滅項の計算(3)
private function getBarSk3d(db:Number,l:Number,nx:Number,ny:Number,uvch:Array):Array{
var s2:Number = G * uvch[3] * (l * db * nx);
var s3:Number = G * uvch[3] * (l * db * ny);
return [0.0, s2, s3];
}
// 生成・消滅項の計算(4)
private function getBeta3d(barSk:Array,uvch:Array,nx:Number,ny:Number):Array{
var r:Number=(1.0/(2.0*uvch[2]));
var b0:Number = r * (barSk[1] * nx + barSk[2] * ny);
var b2:Number = -r * (barSk[1] * nx + barSk[2] * ny);
return [b0, 0.0, b2];
}
// |f|/fを取得
private function getAbsFByFMatrix3d(uvch:Array,nx:Number,ny:Number):Array{
var f0:Number=uvch[0]*nx+uvch[1]*ny+uvch[2];
var f1:Number=uvch[0]*nx+uvch[1]*ny;
var f2:Number=uvch[0]*nx+uvch[1]*ny-uvch[2];
var a:Number;
var b:Number;
var c:Number;
if(f0!=0.0){a=Math.abs(f0)/f0;}else{a=1;}
if(f1!=0.0){b=Math.abs(f1)/f1;}else{b=1;}
if(f2!=0.0){c=Math.abs(f2)/f2;}else{c=1;}
return [a, b, c];
}
// 計算 有限体積法 -----------------------------------------------------
private function updateCell():void {
for (var i:int = 0; i < cells.length; i++) cells[i].updateData();
}
//時間積分(一次)
private function calc1d():void {
calc = false;
iter++;
time += dt;
for (var i:int = 0; i < cells.length; i++) {
var tmp:Array = calcFVM(i);
var ans0:Array = add(tmp[0], tmp[1]);
var sxsy:Array = getSxSy3d(cells[i].h, cells[i].u, cells[i].v, cells[i].n);
ans0 = add(ans0, mul(sxsy, G * cells[i].h * cells[i].area));
ans0 = mul(ans0, 1.0 / cells[i].area);
preF[i] = copy(ans0);
ans0 = mul(ans0, dt);
cells[i].U1[H] = cells[i].U[H] - ans0[H];
cells[i].U1[UH] = cells[i].U[UH] - ans0[UH];
cells[i].U1[VH] = cells[i].U[VH] - ans0[VH];
}
updateCell();
calc = true;
}
//時間積分(二次)
private function calc2d():void {
calc = false;
iter++;
time += dt;
var ans:Array=calc2df();
for(var i:int=0;i<cells.length;i++){
var ans0:Array = ans[i];
var tp0:Number = ans0[H];
var tp1:Number = ans0[UH];
var tp2:Number = ans0[VH];
ans0 = mul(ans0, 3.0);
ans0 = sub(ans0, preF[i]);
ans0 = mul(ans0, dt / 2.0);
cells[i].U1[H] = cells[i].U[H] - ans0[H];
cells[i].U1[UH] = cells[i].U[UH] - ans0[UH];
cells[i].U1[VH] = cells[i].U[VH] - ans0[VH];
preF[i] = [tp0, tp1, tp2];
}
updateCell();
calc = true;
}
private function calc2df():Array{
var ret:Array = new Array();
for(var i:int=0;i<cells.length;i++){
var tmp:Array = calcFVM(i);
var ans0:Array = add(tmp[0], tmp[1]);
var sxsy:Array = getSxSy3d(cells[i].h, cells[i].u, cells[i].v, cells[i].n);
ans0 = add(ans0, mul(sxsy, G * cells[i].h * cells[i].area));
ans0 = mul(ans0, 1.0 / cells[i].area);
ret[i] = ans0;
}
return ret;
}
private function calcFVM(id:int):Array {
var ans0:Array = [0.0, 0.0, 0.0];
var ans1:Array = [0.0, 0.0, 0.0];
for(var i:int=0;i<map[id].length;i++){
if (cells[id].isWet()) {
var tmp:Array = calcFVM_Wet(id, i);
ans0 = add(ans0, tmp[0]);
ans1 = add(ans1, tmp[1]);
}else {
tmp = calcFVM_Dry(id, i);
ans0 = add(ans0, tmp[0]);
ans1 = add(ans1, tmp[1]);
}
}
return [ans0, ans1];
}
//陸地セルの計算
private function calcFVM_Dry(id:int,i:int):Array {
var an:Array = null;
if(cells[id].boundType[i]==NONE){
if (!cells[map[id][i]].isWet() || (cells[map[id][i]].wl < cells[id].b)) return new Array([0.0, 0.0, 0.0], [0.0, 0.0, 0.0]);
an=calcNone(cells[id].U,cells[id].E,cells[id].F,cells[map[id][i]].U,cells[map[id][i]].E,cells[map[id][i]].F,
cells[id].edgesLength[i], cells[id].n, cells[id].b, cells[map[id][i]].b, cells[id].nolm[i]);
}else if(cells[id].boundType[i]==NONSLIP){
return new Array([0.0, 0.0, 0.0], [0.0, 0.0, 0.0]);
}else if (cells[id].boundType[i]==FLOW) {
an = calcFlow(cells[id].U, cells[id].E, cells[id].F, flowQ, cells[id].edgesLength[i], cells[id].n, cells[id].nolm[i]);
}else if(cells[id].boundType[i]==LEVEL){
if(cells[id].b>level)return new Array([0.0, 0.0, 0.0], [0.0, 0.0, 0.0]);
an=calcLevel(cells[id].U,cells[id].E,cells[id].F,level,cells[id].b,cells[id].edgesLength[i],cells[id].n,cells[id].nolm[i]);
}
return an;
}
//水面セルの計算
private function calcFVM_Wet(id:int,i:int):Array {
var an:Array = null;
if(cells[id].boundType[i]==NONE){
if (!cells[map[id][i]].isWet() && (cells[id].wl < cells[map[id][i]].b)) {
an=calcNonSlip(
cells[id].U, cells[id].E, cells[id].F, cells[id].edgesLength[i], cells[id].n, cells[id].nolm[i]);
}else{
an = calcNone(cells[id].U, cells[id].E, cells[id].F, cells[map[id][i]].U, cells[map[id][i]].E, cells[map[id][i]].F,
cells[id].edgesLength[i], cells[id].n, cells[id].b, cells[map[id][i]].b, cells[id].nolm[i]);
}
}else if(cells[id].boundType[i]==NONSLIP){
an=calcNonSlip(
cells[id].U, cells[id].E, cells[id].F, cells[id].edgesLength[i], cells[id].n, cells[id].nolm[i]);
}else if(cells[id].boundType[i]==FLOW){
an = calcFlow(cells[id].U, cells[id].E, cells[id].F, flowQ, cells[id].edgesLength[i], cells[id].n, cells[id].nolm[i]);
}else if (cells[id].boundType[i] == LEVEL) {
if (cells[id].b > level) return new Array([0.0, 0.0, 0.0], [0.0, 0.0, 0.0]);
an = calcLevel(cells[id].U, cells[id].E, cells[id].F, level, cells[id].b, cells[id].edgesLength[i], cells[id].n, cells[id].nolm[i]);
}
return an;
}
// 境界別 流束の計算----------------------------------------------------
private function calcNone(Ul:Array,El:Array,Fl:Array,
Ur:Array, Er:Array, Fr:Array, L:Number, n:Number, bl:Number, br:Number, nolm:Point):Array {
var uvch:Array=getRoe(Ul,Ur);
var fr:Array = getFN(nolm.x, nolm.y, Er, Fr);
var fl:Array = getFN(nolm.x, nolm.y, El, Fl);
fr=add(fr,fl);
var eda:Array = getEDA3d(uvch, nolm.x, nolm.y, Ul, Ur);
fr=sub(fr,eda);
fr=mul(fr,0.5);
fr=mul(fr,L);
var sk:Array = getSk3d((br - bl), L, nolm.x, nolm.y, uvch);
return [fr, sk];
}
private function calcNonSlip(Ul:Array, El:Array, Fl:Array, L:Number, n:Number, nolm:Point):Array {
var Ur:Array=copy(Ul);
var Er:Array=copy(El);
var Fr:Array=copy(Fl);
Ur[1]=Ur[1]*-1.0; Ur[2]=Ur[2]*-1.0;
Er[0]=Er[0]*-1.0; Fr[0]=Fr[0]*-1.0;
var uvch:Array = getRoe(Ul, Ur);
var fr:Array = getFN(nolm.x, nolm.y, Er, Fr);
var fl:Array = getFN(nolm.x, nolm.y, El, Fl);
fr = add(fr, fl);
var eda:Array = getEDA3d(uvch, nolm.x, nolm.y, Ul, Ur);
fr = sub(fr, eda);
fr = mul(fr, 0.5);
fr = mul(fr, L);
var sk:Array = getSk3d(0, L, nolm.x, nolm.y, uvch);
return [fr, sk];
}
private function calcFlow(Ul:Array, El:Array, Fl:Array, Q:Number, L:Number, n:Number, nolm:Point):Array {
var hr:Number = Ul[0];
var ur:Number = Q / hr * -nolm.x;
var vr:Number = Q / hr * -nolm.y;
var Ur:Array = [hr, hr * ur, hr * vr];
var Er:Array = [ur * hr, ur * ur * hr + 0.5 * G * hr * hr, ur * vr * hr];
var Fr:Array = [vr * hr, ur * vr * hr, vr * vr * hr + 0.5 * G * hr * hr];
var uvch:Array = [ur, vr, Math.sqrt(G * hr), hr];
var fr:Array = getFN(nolm.x, nolm.y, Er, Fr);
var fl:Array = getFN(nolm.x, nolm.y, El, Fl);
fr = add(fr, fl);
var eda:Array = getEDA3d(uvch, nolm.x, nolm.y, Ul, Ur);
fr = sub(fr, eda);
fr = mul(fr, 0.5);
fr = mul(fr, L);
return [fr, [0.0, 0.0, 0.0]];
}
private function calcLevel(Ul:Array,El:Array,Fl:Array,WL:Number,gl:Number,L:Number,n:Number,nolm:Point):Array{
var hl:Number = Ul[0];
var ul:Number = Ul[1] / hl;
var vl:Number = Ul[2] / hl;
var _h:Number = WL - gl;
var hr:Number = 2.0 * _h - hl;
var ur:Number = ul + 2.0 * (Math.sqrt(G * hl) - Math.sqrt(G * hr)) * nolm.x;
var vr:Number = vl + 2.0 * (Math.sqrt(G * hl) - Math.sqrt(G * hr)) * nolm.y;
var Ur:Array = [hr, hr * ur, hr * vr];
var Er:Array = [ur * hr, ur * ur * hr + 0.5 * G * hr * hr, ur * vr * hr];
var Fr:Array = [vr * hr, ur * vr * hr, vr * vr * hr + 0.5 * G * hr * hr];
var fr:Array = getFN(nolm.x, nolm.y, Er, Fr);
var fl:Array = getFN(nolm.x, nolm.y, El, Fl);
fr = add(fr, fl);
var uvch:Array = getRoe(Ul, Ur);
var eda:Array = getEDA3d(uvch, nolm.x, nolm.y, Ul, Ur);
fr = sub(fr, eda);
fr = mul(fr, 0.5);
fr = mul(fr, L);
var sk:Array = getSk3d(0.0, L, nolm.x, nolm.y, uvch);
return [fr, sk];
}
}
}
import flash.display.Sprite;
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.filters.ColorMatrixFilter;
import flash.geom.Matrix;
import flash.filters.GlowFilter;
import flash.text.TextField;
class MeshCanvas extends MovieClip {
private var cells:Vector.<Cell>;
private var rect:Rectangle;
public var scale:Number = 1.0;
private var hh:Array;
public function MeshCanvas(v:Vector.<Cell>,r:Rectangle):void {
cells = v;
rect = r;
scale = Math.max(scale, 500/rect.width);
scale = Math.min(scale, 500/rect.height);
this.x = 250-scale*(rect.x+rect.width/2);
this.y = 250+scale*(rect.y+rect.height/2);
}
public function update():void {
this.scaleX = scale;
this.scaleY = scale;
var min:Number = 99999999;
var max:Number = -99999999;
for (var i:int = 0; i < cells.length; i++) {
if (isNaN(cells[i].velocity)) continue;
if (min > cells[i].velocity) min = cells[i].velocity;
if (max < cells[i].velocity) max = cells[i].velocity;
}
hh =[];
for (i = 0; i < cells.length; i++) {
hh[i] = (cells[i].velocity - min) / (max - min);
}
graphics.clear();
for (i = 0; i < cells.length;i++) {
graphics.beginFill(getColor(hh[i]));
cells[i].draw(graphics);
graphics.endFill();
}
}
private function getColor(v:Number):Number {
var r:Number = Math.cos(Math.PI * ((v - 0.81) * 1.1)) * 255;
var g:Number = Math.cos(Math.PI * ((v - 0.50) * 1.0)) * 255;
var b:Number = Math.cos(Math.PI * ((v - 0.19) * 1.1)) * 255;
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
return (r<<16)+(g<<8)+b;
}
}
// 要素(非構造格子)
class Cell {
public var node:Vector.<Point>;
public var pos:Point;
public var b:Number;
public var n:Number;
public var h:Number;
public var u:Number;
public var v:Number;
public var wl:Number;
public var velocity:Number;
public var boundType:Array;
public var edgesLength:Vector.<Number>;
public var area:Number;
public var nolm:Vector.<Point>;
public var U0:Array;
public var U:Array;
public var U1:Array;
public var E:Array;
public var F:Array;
private var vertex:Vector.<Number>;
private static const H_MIN:Number = 0.005;
private static const G:Number = 9.80665;
public function Cell(p0:Array, p1:Array, p2:Array):void {
node = new Vector.<Point>();
node[0]=new Point(p0[0], p0[1]);
node[1]=new Point(p1[0], p1[1]);
node[2]=new Point(p2[0], p2[1]);
pos = new Point((p0[0] + p1[0] + p2[0]) / 3.0, (p0[1] + p1[1] + p2[1]) / 3.0);
b = (p0[2] + p1[2] + p2[2]) / 3.0;
h = (p0[3] + p1[3] + p2[3]) / 3.0;
n = (p0[4] + p1[4] + p2[4]) / 3.0;
u = (p0[5] + p1[5] + p2[5]) / 3.0;
v = (p0[6] + p1[6] + p2[6]) / 3.0;
wl = b + h;
velocity = Math.sqrt(u * u + v * v);
edgesLength = new Vector.<Number>();
edgesLength[0] = dist(p0, p1);
edgesLength[1] = dist(p1, p2);
edgesLength[2] = dist(p2, p0);
area = getTriArea(p0, p1, p2);
nolm = new Vector.<Point>();
nolm[0]=createNolm(p0, p1);
nolm[1]=createNolm(p1, p2);
nolm[2]=createNolm(p2, p0);
U0 = [0.0, 0.0, 0.0];
U = [0.0, 0.0, 0.0];
U[0] = h;
U[1] = h * u;
U[2] = h * v;
U1 = [0.0, 0.0, 0.0];
E = calcE(U);
F = calcF(U);
vertex = new Vector.<Number>();
vertex.push(node[0].x); vertex.push(node[0].y);
vertex.push(node[1].x); vertex.push(node[1].y);
vertex.push(node[2].x); vertex.push(node[2].y);
}
public function draw(g:Graphics):void {
g.drawTriangles(vertex);
}
private function calcE(u:Array):Array {
var ret:Array = new Array();
ret[0]=u[1];
ret[1]=getU2hGh2(u);
ret[2]=getUVH(u);
return ret;
}
private function getU2hGh2(u:Array):Number{
if (u[0] <= H_MIN) return 0.0;
var uu:Number=u[1]/u[0];
return uu*u[1]+0.5*G*u[0]*u[0];
}
private function getUVH(u:Array):Number{
if (u[0] <= H_MIN) return 0.0;
var uu:Number=u[1]/u[0];
return uu*u[2];
}
private function getV2hGh2(u:Array):Number{
if (u[0] <= H_MIN) return 0.0;
var vv:Number=u[2]/u[0];
return vv*u[2]+0.5*G*u[0]*u[0];
}
private function calcF(u:Array):Array{
var ret:Array = new Array();
ret[0]=u[2];
ret[1]=getUVH(u);
ret[2]=getV2hGh2(u);
return ret;
}
public function isWet():Boolean {
return (U[0] > H_MIN);
}
private function dist(p0:Array, p1:Array):Number {
var x0:Number = p0[0] - p1[0];
var y0:Number = p0[1] - p1[1];
return Math.sqrt(x0 * x0 + y0 * y0);
}
private function getTriArea(p0:Array, p1:Array, p2:Array):Number{
var aa:Number = p0[0] * p1[1];
var bb:Number = p1[0] * p2[1];
var cc:Number = p2[0] * p0[1];
var dd:Number = p0[0] * p2[1];
var ee:Number = p1[0] * p0[1];
var ff:Number = p2[0] * p1[1];
return 0.5 * (aa + bb + cc - dd - ee - ff);
}
public function createNolm(p0:Array, p1:Array):Point {
var x:Number = p1[0] - p0[0];
var y:Number = p1[1] - p0[1];
var vc:Point = rotatePos(x, y);
var ll:Number = Math.sqrt(vc.x * vc.x + vc.y * vc.y);
vc.x /= ll; vc.y /= ll;
return vc;
}
private static const ROTATE:Number = -Math.PI / 2.0;
private function rotatePos(x:Number, y:Number):Point {
var p:Point = new Point();
p.x = Math.cos(ROTATE) * x - Math.sin(ROTATE) * y;
p.y = Math.sin(ROTATE) * x + Math.cos(ROTATE) * y;
return p;
}
public function updateData():void {
var i:int;
if (U1[0] <= H_MIN) {
U0[0] = U[0];
U0[1] = U[1];
U0[2] = U[2];
U[0] = H_MIN;
U[1] = 0.0;
U[2] = 0.0;
E = [0.0,0.0,0.0];
F = [0.0, 0.0, 0.0];
}else {
U0[0] = U[0];
U0[1] = U[1];
U0[2] = U[2];
U[0] = U1[0];
U[1] = U1[1];
U[2] = U1[2];
E = calcE(U);
F = calcF(U);
}
this.h = U[0];
this.u = U[1] / U[0];
this.v = U[2] / U[0];
this.wl = this.b + this.h;
velocity = Math.sqrt(u * u + v * v);
}
}
class MeshData {
public var node:Array;
public var elem:Vector.<Array>;
public var map:Vector.<Array>;
public var boundary:Vector.<Array>;
public var cell:Vector.<Array>;
public var rect:Rectangle;
public var flowQ:Number;
public var level:Number;
public var dt:Number;
public function MeshData(str:String):void {
var data:Array = parseCSV(str);
node = new Array();
var n:Number = parseInt((data.shift() as Array)[0] as String);
var minX:Number = 9999999999;
var maxX:Number = -9999999999;
var minY:Number = 9999999999;
var maxY:Number = -9999999999;
for (var i:Number = 0; i < n; i++) {
var tmp:Array = data.shift() as Array;
var p:Array = new Array();
for (var j:Number = 1; j < 8; j++) {
p.push(parseFloat(tmp[j] as String));
}
node.push(p);
minX = Math.min(minX, p[0] as Number);
maxX = Math.max(maxX, p[0] as Number);
minY = Math.min(minY, p[1] as Number);
maxY = Math.max(maxY, p[1] as Number);
}
rect = new Rectangle(minX,minY,maxX-minX,maxY-minY);
elem = new Vector.<Array>();
map = new Vector.<Array>();
boundary = new Vector.<Array>();
n = parseInt((data.shift() as Array)[0] as String);
for (i = 0; i < n; i++) {
tmp = data.shift() as Array;
elem.push(new Array(parseInt(tmp[1] as String), parseInt(tmp[2] as String), parseInt(tmp[3] as String)));
map.push(new Array(parseInt(tmp[4] as String), parseInt(tmp[5] as String), parseInt(tmp[6] as String)));
boundary.push(new Array(parseInt(tmp[7] as String), parseInt(tmp[8] as String), parseInt(tmp[9] as String)));
}
flowQ = parseFloat((data.shift() as Array)[0] as String);
level = parseFloat((data.shift() as Array)[0] as String);
dt = parseFloat((data.shift() as Array)[0] as String);
}
private function parseCSV(str:String):Array {
str = (str.split("\r\n")).join("\n");
str = (str.split("\r")).join("\n");
var data:Array = new Array();
var tmp:Array = str.split("\n");
var l:Number = tmp.length;
for(var i:Number=0; i<l; i++){
data.push(tmp[i].split(","));
}
if(data[data.length-1].length == 1 && data[data.length-1][0] == ""){data.pop();}
return data;
}
}
class Button extends Sprite{
private static const mono:ColorMatrixFilter = new ColorMatrixFilter([
1 / 3, 1 / 3, 1 / 3, 0, 10, 1 / 3, 1 / 3, 1 / 3, 0, 10,
1 / 3, 1 / 3, 1 / 3, 0, 10, 0,0,0, 1, 0]);
private var _hover:Boolean = false;
private var textField:TextField;
public function get hover():Boolean{
return _hover;
}
public function set hover(value:Boolean):void{
if(_hover != value){
_hover = value;
filters = (_hover ? null : [mono]);
}
}
public function Button(W:Number, H:Number, R:Number, label:String = "", size:int = 11){
var matrix:Matrix = new Matrix();
matrix.createGradientBox(W, H, Math.PI / 2);
var bg:Sprite = new Sprite();
bg.graphics.beginGradientFill("linear", [0xDDE9F4, 0xD5E4F1, 0xBAD2E8], [1, 1, 1],[0, 120, 136], matrix);
bg.graphics.drawRoundRect(0, 0, W, H, R, R);
bg.graphics.endFill();
bg.filters = [new GlowFilter(0xFFFFBE, .5, 10, 10, 2, 1, true)];
addChild(bg);
var line:Sprite = new Sprite();
line.graphics.lineStyle(3, 0xBAD2E8);
line.graphics.drawRoundRect(0, 0, W, H, R, R);
addChild(line);
filters = [mono];
buttonMode = true;
mouseChildren = false;
if (label != ""){
textField= new TextField();
textField.selectable = false;
textField.autoSize = "left";
textField.htmlText = <font size={size} color="#6B8399">{label}</font>.toXMLString();
textField.x = (W - textField.width) / 2;
textField.y = (H - textField.height) / 2;
addChild(textField);
}
addEventListener("rollOver", buttonRollOver);
addEventListener("rollOut", buttonRollOut);
addEventListener("removed", function(event:Event):void{
removeEventListener("rollOver", buttonRollOver);
removeEventListener("rollOut", buttonRollOut);
removeEventListener("removed", arguments.callee);
});
}
public function setLabelText(str:String,size:int):void {
textField.htmlText = <font size={size} color="#6B8399">{str}</font>.toXMLString();
}
protected function buttonRollOver(event:Event):void{
hover = true;
}
protected function buttonRollOut(event:Event):void{
hover = false;
}
}