/*
* Copyright 2007 Michiyasu Wada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import flash.geom.Point;
/**
* com.seyself.math.GeomMath
*
* 形状に関する計算処理もろもろ
* static関数のみで構成されています。
*
* @author Michiyasu Wada
*/
class com.seyself.math.GeomMath
{
private function GeomMath(){}
/**
* 3つ以上の直線によって構成された多角形の面積を求めます。
* 引数には x, y の数値プロパティを持つオブジェクトを3つ以上渡す必要があります。
*
* @param arguments : Point - x, y の数値プロパティを持つオブジェクト
* @return Number - 面積
* @usage
* import com.seyself.math.GeomMath;
* var a = { x:10 , y:50 };
* var b = { x:20 , y:30 };
* var c = { x:30 , y:50 };
* var d = { x:25 , y:80 };
* var e = { x:15 , y:80 };
* trace( GeomMath.polygonArea( a, b, c, d, e ) ); // 出力 : 650
*
*/
public static function polygonArea():Number
{
var leng = arguments.length;
var products = 0;
for(var i=0;i
* import com.seyself.math.GeomMath;
* trace( GeomMath.ellipseArea( 50 , 100 ) ); // 出力 : 3926.99081698724
*
*/
public static function ellipseArea( width:Number , height:Number ):Number
{
return (width/2)*(height/2)*Math.PI;
}
/**
* 楕円形の円周の近似値を求めます。(楕円積分)
* 楕円を求めるには最短の直径と最長の直径が分かっていないといけません。
*
* @param width : Number - 楕円の最短の直径
* @param height : Number - 楕円の最長の直径
* @return Number - 円周の近似値
* @usage
* import com.seyself.math.GeomMath;
* trace( GeomMath.circumference( 50 , 100 ) ); // 出力 : 3926.99081698724
*
*/
public static function circumference( width:Number , height:Number ):Number
{
var a = Math.min( width , height );
var b = Math.max( width , height );
var c = (a-b)/(a+b);
return Math.PI*(a+b)*( 1+1/4*Math.pow(c,2)+1/64*Math.pow(c,4)+1/256*Math.pow(c,6));
}
/**
* 直線AB と直線CD の交点を求めます。
* 2つの直線が平行である場合は null を返します。
*
* @param a : Point - 直線AB の点Aの座標( x, y の数値プロパティを持つオブジェクト )
* @param b : Point - 直線AB の点Bの座標( x, y の数値プロパティを持つオブジェクト )
* @param c : Point - 直線CD の点Cの座標( x, y の数値プロパティを持つオブジェクト )
* @param d : Point - 直線CD の点Dの座標( x, y の数値プロパティを持つオブジェクト )
* @return Point - 2直線の交点座標
* @usage
* import com.seyself.math.GeomMath;
* var a = { x:0 , y:0 };
* var b = { x:200 , y:200 };
* var c = { x:100 , y:0 };
* var d = { x:50 , y:200 };
* trace( GeomMath.intersection( a, b, c, d ) ); // 出力 : (x=80, y=80)
*
*/
public static function intersection( a:Object, b:Object, c:Object, d:Object ):Point
{
var pos1 = (b.y-a.y)/(b.x-a.x);
var pos2 = (d.y-c.y)/(d.x-c.x);
var pi = Number.POSITIVE_INFINITY;
var ni = Number.NEGATIVE_INFINITY;
if(pos1==pos2){
return null;
}
if( pos1 == ni || pos1 == pi ){
pos1 = b.y-a.y;
}
if( pos2 == ni || pos2 == pi ){
pos2 = d.y-c.y;
}
var nx = ( ( a.x*pos1 ) - a.y - ( c.x*pos2 ) + c.y )/( pos1-pos2 );
var ny = pos1*( nx-a.x ) + a.y;
return new Point( nx, ny );
}
/**
* 2次ベジェ曲線を描くための座標を求めます.
* 引数には x, y の数値プロパティを持つオブジェクトを3つと中間点の数を渡す必要があります.
*
* import flash.display.Sprite;
* import flash.geom.Point;
* import com.seyself.math.GeomMath;
*
* var t:Number = 0;
* var a:Point = new Point( 0, 0 );
* var b:Point = new Point( 20, 70 );
* var c:Point = new Point( 100, 100 );
*
* var sprite:Sprite = new Sprite();
* this.addChild( sprite );
* sprite.graphics.lineStyle( 1 , 0 , 1 );
* sprite.graphics.moveTo( a.x , a.y );
* for(t=0;t<=1;t+=0.05){
* var p:Point = GeomMath.quadraticBezier( a, b, c, t );
* sprite.graphics.lineTo( p.x , p.y );
* trace( p );
* }
*
*
* @param a : Point - 開始点( x, y の数値プロパティを持つオブジェクト )
* @param b : Point - アンカー( x, y の数値プロパティを持つオブジェクト )
* @param c : Point - 終了点( x, y の数値プロパティを持つオブジェクト )
* @param t : Number - 戻り値が持つ座標の数
* @return Array - 曲線の座標
*/
public static function quadraticBezier( a:Object, b:Object, c:Object, t:Number ):Point
{
var s:Number = 1-t;
var nx:Number = s*s*a.x + 2*s*t*b.x + t*t*c.x;
var ny:Number = s*s*a.y + 2*s*t*b.y + t*t*c.y;
return new Point( nx , ny );
}
/**
* 3次ベジェ曲線を描くための座標を求めます.
* 引数には x, y の数値プロパティを持つオブジェクトを4つと中間点の数を渡す必要があります.
*
* import flash.display.Sprite;
* import flash.geom.Point;
* import com.seyself.math.GeomMath;
*
* var t:Number = 0;
* var a:Point = new Point( 0, 0 );
* var b:Point = new Point( 12, 60 );
* var c:Point = new Point( 80, 20 );
* var d:Point = new Point( 100, 100 );
*
* var sprite:Sprite = new Sprite();
* this.addChild( sprite );
* sprite.graphics.lineStyle( 1 , 0 , 1 );
* sprite.graphics.moveTo( a.x , a.y );
* for(t=0;t<=1;t+=0.05){
* var p:Point = GeomMath.cubicBezier( a, b, c, d, t );
* sprite.graphics.lineTo( p.x , p.y );
* trace( p );
* }
*
*
* @param a 開始点( x, y の数値プロパティを持つオブジェクト )
* @param b 点 a のアンカー( x, y の数値プロパティを持つオブジェクト )
* @param c 点 b のアンカー( x, y の数値プロパティを持つオブジェクト )
* @param d 終了点( x, y の数値プロパティを持つオブジェクト )
* @param t 戻り値が持つ座標の数
* @return 曲線の座標
*/
public static function cubicBezier( a:Object, b:Object, c:Object, d:Object, t:Number ):Point
{
var s:Number = 1-t;
var nx:Number = s*s*s*a.x + 3*(s*s)*t*b.x + 3*s*(t*t)*c.x + t*t*t*d.x;
var ny:Number = s*s*s*a.y + 3*(s*s)*t*b.y + 3*s*(t*t)*c.y + t*t*t*d.y;
return new Point( nx , ny );
}
public static function toRadian( degrees:Number )
{
var r:Number = degrees % 360;
if( r<=-180 ) return ( 360+r )/ 180 * Math.PI;
if( r > 180 ) return -( 360-r )/ 180 * Math.PI;
return r / 180 * Math.PI;
}
public static function toDegrees( radian:Number )
{
var d:Number = ( radian % ( Math.PI*2 ) ) / Math.PI * 180;
if( d<0 ) return 360+d;
return d;
}
/**
* 指定したムービークリップのプロパティを、その位置、階層に関わらず、_root座標を基にした値に変換します。
* 対象となるプロパティは _x , _y , _xscale , _yscale , _width , _height , _rotation の7つです。
* 但し、 _xscale , _yscale はそれぞれ _width , _height に置き換えられます。
*
* @param target : MovieClip - 対象とするムービークリップ
* @param prop : Object - target の対象とするプロパティの値を示したオブジェクト
* @return Object - 変換後のプロパティ値を持ったオブジェクト
* @usage
* import com.seyself.math.GeomMath;
* var main = this.createEmptyMovieClip( "main" , 0 );
* var rect = main.createEmptyMovieClip( "rect" , 0 );
* rect.beginFill( 0 , 100 );
* rect.moveTo( 0, 0 );
* rect.lineTo( 0, 100 );
* rect.lineTo( 100, 100 );
* rect.lineTo( 100, 0 );
* rect.lineTo( 0, 0 );
* rect.endFill();
*
* main._x = 50;
* main._y = 50;
* main._width = 400;
* main._height = 350;
*
* var prop = {
* _x : 50 ,
* _y : 50 ,
* _width : 100 ,
* _yscale : 50
* }
* var changeProp = GeomMath.staticProp( rect , prop );
* trace( rect._x = changeProp._x ); // 出力 : 0
* trace( rect._y = changeProp._y ); // 出力 : 0
* trace( rect._width = changeProp._width ); // 出力 : 25
* trace( rect._height = changeProp._height ); // 出力 : 14.3
*
*/
public static function staticProp( target:MovieClip , prop:Object ):Object
{
var _result = {};
for(var val in prop){
if( typeof( prop[val] )=="number" || typeof( prop[val] )=="boolean" ){
_result[val] = prop[val];
}
}
if( prop._x != undefined || prop._y != undefined ){
var tmp = {
x:(( prop._x==undefined )?target._x:prop._x) ,
y:(( prop._y==undefined )?target._y:prop._y)
};
target._parent.globalToLocal( tmp );
if( prop._x != undefined ){
_result._x = tmp.x;
}
if( prop._y != undefined ){
_result._y = tmp.y;
}
}
if( prop._xscale != undefined || prop._yscale != undefined ){
if( prop._xscale != undefined ){
prop._width = prop._xscale/100*target._width;
delete prop._xscale;
}
if( prop._yscale != undefined ){
prop._height = prop._yscale/100*target._height;
delete prop._yscale;
}
}
if( prop._width != undefined || prop._height != undefined ){
var tmp = {
x:(( prop._width==undefined )?target._width : prop._width) ,
y:(( prop._height==undefined )?target._height : prop._height)
};
var tmp2 = { x:0 , y:0 };
target._parent.globalToLocal( tmp2 );
target._parent.globalToLocal( tmp );
if( prop._width != undefined ){
_result._width = tmp.x-tmp2.x;
}
if( prop._height != undefined ){
_result._height = tmp.y-tmp2.y;
}
}
if( prop._rotation != undefined ){
var _rot = 0;
var parentTarget = target._parent;
while( parentTarget!=_root ){
_rot += parentTarget._rotation;
parentTarget = parentTarget._parent;
}
_result._rotation = prop._rotation-_rot;
}
return _result;
}
}