| 1 |
/* |
|---|
| 2 |
* Copyright(c) 2006-2008 the Spark project. |
|---|
| 3 |
* |
|---|
| 4 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 5 |
* you may not use this file except in compliance with the License. |
|---|
| 6 |
* You may obtain a copy of the License at |
|---|
| 7 |
* |
|---|
| 8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 9 |
* |
|---|
| 10 |
* Unless required by applicable law or agreed to in writing, software |
|---|
| 11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|---|
| 12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, |
|---|
| 13 |
* either express or implied. See the License for the specific language |
|---|
| 14 |
* governing permissions and limitations under the License. |
|---|
| 15 |
*/ |
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
package org.libspark.utils |
|---|
| 19 |
{ |
|---|
| 20 |
|
|---|
| 21 |
import flash.display.DisplayObject; |
|---|
| 22 |
import flash.errors.IllegalOperationError; |
|---|
| 23 |
import flash.geom.Matrix; |
|---|
| 24 |
import flash.geom.Point; |
|---|
| 25 |
import flash.geom.Rectangle; |
|---|
| 26 |
import flash.geom.ColorTransform; |
|---|
| 27 |
import flash.geom.Transform; |
|---|
| 28 |
|
|---|
| 29 |
/** |
|---|
| 30 |
* 図形計算のためのユーティリティクラスです |
|---|
| 31 |
*/ |
|---|
| 32 |
public class GeomUtil |
|---|
| 33 |
{ |
|---|
| 34 |
|
|---|
| 35 |
/** |
|---|
| 36 |
* @private |
|---|
| 37 |
*/ |
|---|
| 38 |
public function GeomUtil() |
|---|
| 39 |
{ |
|---|
| 40 |
throw new IllegalOperationError("Error #2012: GeomUtil class cannot be instantiated."); |
|---|
| 41 |
} |
|---|
| 42 |
|
|---|
| 43 |
/** |
|---|
| 44 |
* 2つのPoint間の角度を求めます |
|---|
| 45 |
* @param pt1 |
|---|
| 46 |
* @param pt2 |
|---|
| 47 |
* @return 2点間の角度 |
|---|
| 48 |
* @author michi at seyself.com |
|---|
| 49 |
*/ |
|---|
| 50 |
public static function angle( pt1:Point, pt2:Point ):Number |
|---|
| 51 |
{ |
|---|
| 52 |
return Math.atan2( pt2.y - pt1.y, pt2.x - pt1.x ); |
|---|
| 53 |
} |
|---|
| 54 |
|
|---|
| 55 |
/** |
|---|
| 56 |
* 極座標ペアを直交点座標に変換し、指定のポイント(座標)に加算した新しいポイントを作成します。 |
|---|
| 57 |
* |
|---|
| 58 |
* @param pt 追加するポイント |
|---|
| 59 |
* @param len 極座標ペアの長さ座標 |
|---|
| 60 |
* @param angle 極座標ペアの角度 (ラジアン単位) |
|---|
| 61 |
* @return 新しいポイント |
|---|
| 62 |
* @author michi at seyself.com |
|---|
| 63 |
*/ |
|---|
| 64 |
public static function addPolar( pt:Point, len:Number, angle:Number ):Point |
|---|
| 65 |
{ |
|---|
| 66 |
return pt.add( Point.polar( len, angle ) ); |
|---|
| 67 |
} |
|---|
| 68 |
|
|---|
| 69 |
/** |
|---|
| 70 |
* 3つ以上の直線によって構成された多角形の面積を求めます. |
|---|
| 71 |
* 引数には x, y の数値プロパティを持つオブジェクトを3つ以上渡す必要があります. |
|---|
| 72 |
* |
|---|
| 73 |
* @param arguments x, y の数値プロパティを持つオブジェクト |
|---|
| 74 |
* @return 面積 |
|---|
| 75 |
* @author michi at seyself.com |
|---|
| 76 |
*/ |
|---|
| 77 |
public static function polygonArea( ...points ):Number |
|---|
| 78 |
{ |
|---|
| 79 |
var leng:uint = points.length; |
|---|
| 80 |
var products:Number = 0; |
|---|
| 81 |
for(var i:uint=0;i<leng;i++){ |
|---|
| 82 |
var n:Number = (i==leng-1)? 0 : i+1; |
|---|
| 83 |
var p:Object = points[i]; |
|---|
| 84 |
var q:Object = points[n]; |
|---|
| 85 |
var product:Number = (p.x-q.x)*(p.y+q.y); |
|---|
| 86 |
products += product; |
|---|
| 87 |
} |
|---|
| 88 |
return products/2; |
|---|
| 89 |
} |
|---|
| 90 |
|
|---|
| 91 |
/** |
|---|
| 92 |
* 楕円形の面積を求めます. |
|---|
| 93 |
* 楕円を求めるには最短の直径と最長の直径が分かっていないといけません. |
|---|
| 94 |
* |
|---|
| 95 |
* @param width 楕円の最短の直径 |
|---|
| 96 |
* @param height 楕円の最長の直径 |
|---|
| 97 |
* @return 面積 |
|---|
| 98 |
* @author michi at seyself.com |
|---|
| 99 |
*/ |
|---|
| 100 |
public static function ellipseArea( width:Number , height:Number ):Number |
|---|
| 101 |
{ |
|---|
| 102 |
return (width/2)*(height/2)*Math.PI; |
|---|
| 103 |
} |
|---|
| 104 |
|
|---|
| 105 |
/** |
|---|
| 106 |
* 楕円形の円周の近似値を求めます(楕円積分). |
|---|
| 107 |
* 楕円を求めるには最短の直径と最長の直径が分かっていないといけません. |
|---|
| 108 |
* |
|---|
| 109 |
* @param width 楕円の最短の直径 |
|---|
| 110 |
* @param height 楕円の最長の直径 |
|---|
| 111 |
* @return 円周の近似値 |
|---|
| 112 |
* @author michi at seyself.com |
|---|
| 113 |
*/ |
|---|
| 114 |
public static function circumference( width:Number , height:Number ):Number |
|---|
| 115 |
{ |
|---|
| 116 |
var a:Number = Math.min( width , height ); |
|---|
| 117 |
var b:Number = Math.max( width , height ); |
|---|
| 118 |
var c:Number = (a-b)/(a+b); |
|---|
| 119 |
return Math.PI*(a+b)*( 1+1/4*Math.pow(c,2)+1/64*Math.pow(c,4)+1/256*Math.pow(c,6)); |
|---|
| 120 |
} |
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
/** |
|---|
| 124 |
* 直線AB と直線CD の交点を求めます. |
|---|
| 125 |
* 2つの直線が平行である場合は null を返します. |
|---|
| 126 |
* |
|---|
| 127 |
* @param a 直線AB の点Aの座標( x, y の数値プロパティを持つオブジェクト ) |
|---|
| 128 |
* @param b 直線AB の点Bの座標( x, y の数値プロパティを持つオブジェクト ) |
|---|
| 129 |
* @param c 直線CD の点Cの座標( x, y の数値プロパティを持つオブジェクト ) |
|---|
| 130 |
* @param d 直線CD の点Dの座標( x, y の数値プロパティを持つオブジェクト ) |
|---|
| 131 |
* @return 2直線の交点座標 |
|---|
| 132 |
* @author michi at seyself.com |
|---|
| 133 |
*/ |
|---|
| 134 |
public static function intersection( a:Object, b:Object, c:Object, d:Object ):Point |
|---|
| 135 |
{ |
|---|
| 136 |
var pos1:Number = (b.y-a.y)/(b.x-a.x); |
|---|
| 137 |
var pos2:Number = (d.y-c.y)/(d.x-c.x); |
|---|
| 138 |
var pi:Number = Number.POSITIVE_INFINITY; |
|---|
| 139 |
var ni:Number = Number.NEGATIVE_INFINITY; |
|---|
| 140 |
|
|---|
| 141 |
if(pos1==pos2) return null; |
|---|
| 142 |
if( pos1 == ni || pos1 == pi ) pos1 = b.y-a.y; |
|---|
| 143 |
if( pos2 == ni || pos2 == pi ) pos2 = d.y-c.y; |
|---|
| 144 |
|
|---|
| 145 |
var nx:Number = ( ( a.x*pos1 ) - a.y - ( c.x*pos2 ) + c.y )/( pos1-pos2 ); |
|---|
| 146 |
var ny:Number = pos1*( nx-a.x ) + a.y; |
|---|
| 147 |
|
|---|
| 148 |
return new Point( nx, ny ); |
|---|
| 149 |
} |
|---|
| 150 |
|
|---|
| 151 |
/** |
|---|
| 152 |
* 指定オブジェクトのプロパティ x, y から新しい Point インスタンスを作成します。 |
|---|
| 153 |
* |
|---|
| 154 |
* @param target 指定オブジェクト |
|---|
| 155 |
* @return 新しい Point インスタンス |
|---|
| 156 |
* @author michi at seyself.com |
|---|
| 157 |
*/ |
|---|
| 158 |
public static function getPoint( target:Object ):Point |
|---|
| 159 |
{ |
|---|
| 160 |
var pt:Point = new Point(); |
|---|
| 161 |
if ( target.hasOwnProperty("x") ) pt.x = target.x; |
|---|
| 162 |
if ( target.hasOwnProperty("y") ) pt.y = target.y; |
|---|
| 163 |
return pt; |
|---|
| 164 |
} |
|---|
| 165 |
|
|---|
| 166 |
/** |
|---|
| 167 |
* 指定オブジェクトのプロパティ x, y, width, height から新しい Rectangle インスタンスを作成します。 |
|---|
| 168 |
* |
|---|
| 169 |
* @param target 指定オブジェクト |
|---|
| 170 |
* @return 新しい Rectangle インスタンス |
|---|
| 171 |
* @author michi at seyself.com |
|---|
| 172 |
*/ |
|---|
| 173 |
public static function getRect( target:Object ):Rectangle |
|---|
| 174 |
{ |
|---|
| 175 |
var rect:Rectangle = new Rectangle(); |
|---|
| 176 |
if ( target.hasOwnProperty("x") ) rect.x = target.x; |
|---|
| 177 |
if ( target.hasOwnProperty("y") ) rect.y = target.y; |
|---|
| 178 |
if ( target.hasOwnProperty("width") ) rect.width = target.width; |
|---|
| 179 |
if ( target.hasOwnProperty("height") ) rect.height = target.height; |
|---|
| 180 |
return rect; |
|---|
| 181 |
} |
|---|
| 182 |
|
|---|
| 183 |
/** |
|---|
| 184 |
* 指定オブジェクトのプロパティ x, y に、それぞれポイントの値を代入します。 |
|---|
| 185 |
* |
|---|
| 186 |
* @param target 指定オブジェクト |
|---|
| 187 |
* @param pt 適応する Point オブジェクト |
|---|
| 188 |
* @author michi at seyself.com |
|---|
| 189 |
*/ |
|---|
| 190 |
public static function setPoint( target:Object, pt:Point ):void |
|---|
| 191 |
{ |
|---|
| 192 |
if ( target.hasOwnProperty("x") ) target.x = pt.x; |
|---|
| 193 |
if ( target.hasOwnProperty("y") ) target.y = pt.y; |
|---|
| 194 |
} |
|---|
| 195 |
|
|---|
| 196 |
/** |
|---|
| 197 |
* 指定オブジェクトのプロパティ x, y, width, height に、それぞれ Rectangle の値を代入します。 |
|---|
| 198 |
* |
|---|
| 199 |
* @param target 指定オブジェクト |
|---|
| 200 |
* @param rect 適応する Rectangle オブジェクト |
|---|
| 201 |
* @author michi at seyself.com |
|---|
| 202 |
*/ |
|---|
| 203 |
public static function setRect( target:Object, rect:Rectangle ):void |
|---|
| 204 |
{ |
|---|
| 205 |
if ( target.hasOwnProperty("x") ) target.x = rect.x; |
|---|
| 206 |
if ( target.hasOwnProperty("y") ) target.y = rect.y; |
|---|
| 207 |
if ( target.hasOwnProperty("width") ) target.width = rect.width; |
|---|
| 208 |
if ( target.hasOwnProperty("height") ) target.height = rect.height; |
|---|
| 209 |
} |
|---|
| 210 |
|
|---|
| 211 |
/** |
|---|
| 212 |
* 指定のマトリックスオブジェクトから回転値(ラジアン単位)を調べます。 |
|---|
| 213 |
* |
|---|
| 214 |
* @param mt 対象となるマトリックスオブジェクト |
|---|
| 215 |
* @return 回転値(ラジアン単位) |
|---|
| 216 |
* @author michi at seyself.com |
|---|
| 217 |
*/ |
|---|
| 218 |
public static function getRotateFromMatrix(mt:Matrix):Number |
|---|
| 219 |
{ |
|---|
| 220 |
var sx:Number = Math.sqrt(mt.a * mt.a + mt.b * mt.b); |
|---|
| 221 |
var angle:Number = Math.acos( mt.a / sx ); |
|---|
| 222 |
if (mt.b < 0) angle *= -1; |
|---|
| 223 |
return angle; |
|---|
| 224 |
} |
|---|
| 225 |
|
|---|
| 226 |
/** |
|---|
| 227 |
* 指定のマトリックスオブジェクトから拡大・縮小値を調べます。 |
|---|
| 228 |
* scaleX 、 scaleY は、それぞれ新たに作成されたポイントオブジェクトの x , y に代入されます。 |
|---|
| 229 |
* |
|---|
| 230 |
* @param mt 対象となるマトリックスオブジェクト |
|---|
| 231 |
* @return 拡大率の情報を持つポイントオブジェクト |
|---|
| 232 |
* @author michi at seyself.com |
|---|
| 233 |
*/ |
|---|
| 234 |
public static function getScaleFromMatrix(mt:Matrix):Point |
|---|
| 235 |
{ |
|---|
| 236 |
var sx:Number = Math.sqrt(mt.a * mt.a + mt.b * mt.b); |
|---|
| 237 |
var sy:Number = Math.sqrt(mt.c * mt.c + mt.d * mt.d); |
|---|
| 238 |
return new Point(sx, sy); |
|---|
| 239 |
} |
|---|
| 240 |
|
|---|
| 241 |
/** |
|---|
| 242 |
* 指定のマトリックスオブジェクトから位置情報を調べ、ポイントオブジェクトを作成します。 |
|---|
| 243 |
* |
|---|
| 244 |
* @param mt 対象となるマトリックスオブジェクト |
|---|
| 245 |
* @return 位置情報を持つポイントオブジェクト |
|---|
| 246 |
* @author michi at seyself.com |
|---|
| 247 |
*/ |
|---|
| 248 |
public static function getPositionFromMatrix(mt:Matrix):Point |
|---|
| 249 |
{ |
|---|
| 250 |
return new Point(mt.tx, mt.ty); |
|---|
| 251 |
} |
|---|
| 252 |
|
|---|
| 253 |
/** |
|---|
| 254 |
* 指定のマトリックスオブジェクトから Matrix.createBox の逆算を行います。 |
|---|
| 255 |
* getRotateFromMatrix や getScaleFromMatrix で得られる結果とは異なりますので注意してください。 |
|---|
| 256 |
* |
|---|
| 257 |
* @param mt 対象となるマトリックスオブジェクト |
|---|
| 258 |
* @return scaleX, scaleY, rotation, x, y のプロパティを持つオブジェクト |
|---|
| 259 |
* 得られた結果オブジェクトは toString() で内容を確認用の文字列に変換します。 |
|---|
| 260 |
*/ |
|---|
| 261 |
public static function degradeBox(mt:Matrix):Object |
|---|
| 262 |
{ |
|---|
| 263 |
var t:Number = mt.a * mt.d - mt.b * mt.c; |
|---|
| 264 |
var sx:Number = Math.sqrt(mt.a * mt.a + mt.c * mt.c); |
|---|
| 265 |
var sy:Number = t / sx; |
|---|
| 266 |
var angle:Number = Math.acos( mt.a / sx ); |
|---|
| 267 |
var obj:Object = { scaleX:sx , scaleY:sy, rotation:angle, x:mt.tx, y:mt.ty }; |
|---|
| 268 |
obj.toString = function():String { |
|---|
| 269 |
return "(scaleX="+this.scaleX+" , scaleY="+this.scaleY+ |
|---|
| 270 |
", rotation="+this.rotation+", x="+this.x+", y="+this.y+")"; |
|---|
| 271 |
} |
|---|
| 272 |
return obj; |
|---|
| 273 |
} |
|---|
| 274 |
|
|---|
| 275 |
/** |
|---|
| 276 |
* 3つの座標数値から2次ベジェ曲線のコントロールポイントの座標を取得します。 |
|---|
| 277 |
* |
|---|
| 278 |
* @param start 始点の座標数値 |
|---|
| 279 |
* @param passage 通過点の座標数値 |
|---|
| 280 |
* @param anchor 終点の座標数値 |
|---|
| 281 |
* @return コントロールポイントの座標数値 |
|---|
| 282 |
* @author michi at seyself.com |
|---|
| 283 |
*/ |
|---|
| 284 |
public static function getCurveControlPoint( start:Number, passage:Number, anchor:Number ):Number |
|---|
| 285 |
{ |
|---|
| 286 |
return ( passage * 4 - start - anchor ) * 0.5; |
|---|
| 287 |
} |
|---|
| 288 |
|
|---|
| 289 |
/** |
|---|
| 290 |
* 3つの座標数値から2次ベジェ曲線の中間座標を取得します。 |
|---|
| 291 |
* |
|---|
| 292 |
* @param a 始点の座標数値 |
|---|
| 293 |
* @param b コントロールポイントの座標数値 |
|---|
| 294 |
* @param c 終点の座標数値 |
|---|
| 295 |
* @param t 曲線の進度値。0 から 1 の小数値で指定します。 |
|---|
| 296 |
* @return 指定された時点におけるベジェ式の値。 |
|---|
| 297 |
* @author michi at seyself.com |
|---|
| 298 |
*/ |
|---|
| 299 |
public static function quadraticBezier( a:Number, b:Number, c:Number, t:Number ):Number |
|---|
| 300 |
{ |
|---|
| 301 |
var s:Number = 1-t; |
|---|
| 302 |
return s*s*a + 2*s*t*b + t*t*c; |
|---|
| 303 |
} |
|---|
| 304 |
|
|---|
| 305 |
/** |
|---|
| 306 |
* 4つの座標数値から3次ベジェ曲線の中間座標を取得します。 |
|---|
| 307 |
* |
|---|
| 308 |
* @param a 始点の座標数値 |
|---|
| 309 |
* @param b 点 a のコントロールポイントの座標数値 |
|---|
| 310 |
* @param c 点 b のコントロールポイントの座標数値 |
|---|
| 311 |
* @param d 終点の座標数値 |
|---|
| 312 |
* @param t 曲線の進度値。0 から 1 の小数値で指定します。 |
|---|
| 313 |
* @return 指定された時点におけるベジェ式の値。 |
|---|
| 314 |
* @author michi at seyself.com |
|---|
| 315 |
*/ |
|---|
| 316 |
public static function cubicBezier( a:Number, b:Number, c:Number, d:Number, t:Number ):Number |
|---|
| 317 |
{ |
|---|
| 318 |
var s:Number = 1-t; |
|---|
| 319 |
return s*s*s*a + 3*s*s*t*b + 3*s*t*t*c + t*t*t*d; |
|---|
| 320 |
} |
|---|
| 321 |
|
|---|
| 322 |
/** |
|---|
| 323 |
* 4つの座標数値からスプライン曲線の中間座標を取得します。 |
|---|
| 324 |
* |
|---|
| 325 |
* @param p0 始点座標数値 |
|---|
| 326 |
* @param p1 通過点座標数値(求められる曲線の始点) |
|---|
| 327 |
* @param p2 通過点座標数値(求められる曲線の終点) |
|---|
| 328 |
* @param p3 終点座標数値 |
|---|
| 329 |
* @param t 2 つの座標間の補間値。 0 から 1 までの数値 |
|---|
| 330 |
* @return p1 から p2 の間にある t の位置を示す座標値 |
|---|
| 331 |
* @author michi at seyself.com |
|---|
| 332 |
*/ |
|---|
| 333 |
public static function spline(p0:Number, p1:Number, p2:Number, p3:Number, t:Number):Number |
|---|
| 334 |
{ |
|---|
| 335 |
var v0:Number = (p2 - p0) * 0.5; |
|---|
| 336 |
var v1:Number = (p3 - p1) * 0.5; |
|---|
| 337 |
var t2:Number = t * t; |
|---|
| 338 |
var t3:Number = t2 * t; |
|---|
| 339 |
return (2 * p1 - 2 * p2 + v0 + v1) * t3 + |
|---|
| 340 |
( -3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; |
|---|
| 341 |
} |
|---|
| 342 |
|
|---|
| 343 |
/** |
|---|
| 344 |
* 指定されたオブジェクトのストリング表現を返します。 |
|---|
| 345 |
* |
|---|
| 346 |
* @param target 出力対象オブジェクト |
|---|
| 347 |
* @return オブジェクトのストリング表現 |
|---|
| 348 |
* @author michi at seyself.com |
|---|
| 349 |
*/ |
|---|
| 350 |
public static function toString(target:Object):String |
|---|
| 351 |
{ |
|---|
| 352 |
if (target is Rectangle) return target.toString(); |
|---|
| 353 |
if (target is Point) return target.toString(); |
|---|
| 354 |
if (target is ColorTransform) return target.toString(); |
|---|
| 355 |
if (target is Transform) { |
|---|
| 356 |
target = target.matrix; |
|---|
| 357 |
} |
|---|
| 358 |
|
|---|
| 359 |
if (target is Matrix) { |
|---|
| 360 |
var mt:Matrix = target as Matrix; |
|---|
| 361 |
return degradeBox(mt).toString(); |
|---|
| 362 |
} |
|---|
| 363 |
|
|---|
| 364 |
return getRect(target).toString(); |
|---|
| 365 |
} |
|---|
| 366 |
|
|---|
| 367 |
} |
|---|
| 368 |
|
|---|
| 369 |
} |
|---|