📄 geometry.as
字号:
package flare.util
{
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* Utility methods for computational geometry.
*/
public final class Geometry
{
/**
* Computes the co-efficients for a cubic Bezier curve.
* @param a the starting point of the curve
* @param b the first control point of the curve
* @param c the second control point of the curve
* @param d the ending point of the curve
* @param c1 point in which to store the zero-order co-efficients
* @param c2 point in which to store the first-order co-efficients
* @param c3 point in which to store the second-order co-efficients
*/
public static function cubicCoeff(a:Point, b:Point, c:Point, d:Point,
c1:Point, c2:Point, c3:Point) : void
{
c3.x = 3 * (b.x - a.x);
c2.x = 3 * (c.x - b.x) - c3.x;
c1.x = d.x - a.x - c3.x - c2.x;
c3.y = 3 * (b.y - a.y);
c2.y = 3 * (c.y - b.y) - c3.y;
c1.y = d.y - a.y - c3.y - c2.y;
}
/**
* Computes a point along a cubic Bezier curve.
* @param u the interpolation fraction along the curve (between 0 and 1)
* @param a the starting point of the curve
* @param c1 the zero-order Bezier co-efficients
* @param c2 the first-order Bezier co-efficients
* @param c3 the second-order Bezier co-efficients
* @param p point in which to store the calculated point on the curve
*/
public static function cubic(u:Number, a:Point,
c1:Point, c2:Point, c3:Point,
p:Point) : Point
{
p.x = u*(c3.x + u*(c2.x + u*c1.x)) + a.x;
p.y = u*(c3.y + u*(c2.y + u*c1.y)) + a.y;
return p;
}
/**
* Computes the co-efficients for a B-spline.
* @param p the control points of the spline as an array of x,y values
* @param a an array for storing the x-components of co-efficients
* @param b an array for storing the y-components of co-efficients
*/
public static function bsplineCoeff(p:Array, a:Array, b:Array):void
{
a[0] = (-p[0] + 3 * p[2] - 3 * p[4] + p[6]) / 6.0;
a[1] = (3 * p[0] - 6 * p[2] + 3 * p[4]) / 6.0;
a[2] = (-3 * p[0] + 3 * p[4]) / 6.0;
a[3] = (p[0] + 4 * p[3] + p[4]) / 6.0;
b[0] = (-p[1] + 3 * p[3] - 3 * p[5] + p[7]) / 6.0;
b[1] = (3 * p[1] - 6 * p[3] + 3 * p[5]) / 6.0;
b[2] = (-3 * p[1] + 3 * p[5]) / 6.0;
b[3] = (p[1] + 4 * p[4] + p[5]) / 6.0;
}
/**
* Computes a point along a B-spline.
* @param u the interpolation fraction along the curve (between 0 and 1)
* @param a an array of x-components of the B-spline co-efficients
* @param b an array of y-components of the B-spline co-efficients
* @param s point in which to store the calculated point on the curve
*/
public static function bspline(u:Number, a:Array, b:Array, s:Point) : Point
{
s.x = u*(a[2] + u*(a[1] + u*a[0])) + a[3];
s.y = u*(b[2] + u*(b[1] + u*b[0])) + b[3];
return s;
}
// --------------------------------------------------------------------
/** Indicates no intersection between shapes */
public static const NO_INTERSECTION:int = 0;
/** Indicates intersection between shapes */
public static const COINCIDENT:int = -1;
/** Indicates two lines are parallel */
public static const PARALLEL:int = -2;
/**
* Compute the intersection of two line segments.
* @param a1x the x-coordinate of the 1st endpoint of the 1st line
* @param a1y the y-coordinate of the 1st endpoint of the 1st line
* @param a2x the x-coordinate of the 2nd endpoint of the 1st line
* @param a2y the y-coordinate of the 2nd endpoint of the 1st line
* @param b1x the x-coordinate of the 1st endpoint of the 2nd line
* @param b1y the y-coordinate of the 1st endpoint of the 2nd line
* @param b2x the x-coordinate of the 2nd endpoint of the 2nd line
* @param b2y the y-coordinate of the 2nd endpoint of the 2nd line
* @param intersect a Point in which to store the intersection point
* @return the intersection code. This is either the number of
* intersections or one of {@link #NO_INTERSECTION},
* {@link #COINCIDENT}, or {@link #PARALLEL}.
*/
public static function intersectLines(a1x:Number, a1y:Number,
a2x:Number, a2y:Number, b1x:Number, b1y:Number, b2x:Number,
b2y:Number, intersect:Point):int
{
var ua_t:Number = (b2x-b1x)*(a1y-b1y)-(b2y-b1y)*(a1x-b1x);
var ub_t:Number = (a2x-a1x)*(a1y-b1y)-(a2y-a1y)*(a1x-b1x);
var u_b :Number = (b2y-b1y)*(a2x-a1x)-(b2x-b1x)*(a2y-a1y);
if (u_b != 0) {
var ua:Number = ua_t / u_b;
var ub:Number = ub_t / u_b;
if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
intersect.x = a1x+ua*(a2x-a1x);
intersect.y = a1y+ua*(a2y-a1y);
return 1;
} else {
return NO_INTERSECTION;
}
} else {
return (ua_t == 0 || ub_t == 0 ? COINCIDENT : PARALLEL);
}
}
/**
* Compute the intersection of a line and a rectangle.
* @param a1 the first endpoint of the line
* @param a2 the second endpoint of the line
* @param r the rectangle
* @param pts a length 2 or greater array of points in which to store
* the results
* @return the intersection code. This is either the number of
* intersections or one of {@link #NO_INTERSECTION},
* {@link #COINCIDENT}, or {@link #PARALLEL}.
*/
public static function intersectLineRect(a1x:Number, a1y:Number,
a2x:Number, a2y:Number, r:Rectangle, p0:Point, p1:Point):int
{
var xMax:Number = r.right, yMax:Number = r.bottom;
var xMin:Number = r.left, yMin:Number = r.top;
var i:int = 0, p:Point = p0;
if (intersectLines(xMin,yMin,xMax,yMin, a1x,a1y,a2x,a2y, p) > 0) {
++i; p = p1;
}
if (intersectLines(xMax,yMin,xMax,yMax, a1x,a1y,a2x,a2y, p) > 0) {
++i; p = p1;
}
if (i == 2) return i;
if (intersectLines(xMax,yMax,xMin,yMax, a1x,a1y,a2x,a2y, p) > 0) {
++i; p = p1;
}
if (i == 2) return i;
if (intersectLines(xMin,yMax,xMin,yMin, a1x,a1y,a2x,a2y, p) > 0) {
++i; p = p1;
}
return i;
}
/**
* Computes the convex hull for a set of points.
* @param p the input points, as a flat array of x,y values
* @param len the number of points to include in the hull
* @return the convex hull, as a flat array of x,y values
*/
public static function convexHull(p:Array, len:uint) : Array
{
// check arguments
if (len < 3)
throw new ArgumentError('Input must have at least 3 points');
var pts:Array = new Array(len-1);
var stack:Array = new Array(len);
var i:uint, j:uint, i0:uint = 0;
// find the starting ref point: leftmost point with the minimum y coord
for (i = 0; i < len; ++i)
{
if (p[i].Y < p[i0].Y) {
i0 = i;
} else if (p[i].Y == p[i0].Y) {
i0 = (p[i].X < p[i0].X ? i : i0);
}
}
// calculate polar angles from ref point and sort
for (i = 0, j = 0; i < len; ++i) {
if (i != i0) {
pts[j++] = {
angle: Math.atan2(p[i].Y-p[i0].Y, p[i].X-p[i0].X),
index: i
};
}
}
pts.sortOn('angle');
// toss out duplicated angles
var angle:Number = pts[0].angle;
var ti:uint = 0, tj:uint = pts[0].index;
for (i = 1; i < len-1; i++) {
j = pts[i].index;
if (angle == pts[i].angle)
{
// keep angle corresponding to point most distant from reference point
var d1:Number = Point.distance(p[i0], p[tj]);
var d2:Number = Point.distance(p[i0], p[j]);
if (d1 >= d2) {
pts[i].index = -1;
} else {
pts[ti].index = -1;
angle = pts[i].angle;
ti = i;
tj = j;
}
} else {
angle = pts[i].angle;
ti = i;
tj = j;
}
}
// initialize the stack
var sp:uint = 0;
stack[sp++] = i0;
var h:uint = 0;
for (var k:uint = 0; k < 2; h++) {
if (pts[h].index != -1) {
stack[sp++] = pts[h].index;
k++;
}
}
// do graham's scan
for (; h < len-1; h++)
{
if (pts[h].index == -1) continue; // skip tossed out points
while (isNonLeft(i0, stack[sp-2], stack[sp-1], pts[h].index, p))
sp--;
stack[sp++] = pts[h].index;
}
// construct the hull
var hull:Array = new Array(sp);
for (i = 0; i < sp; ++i) {
hull[i] = p[stack[i]];
}
return hull;
}
private static function isNonLeft(i0:uint, i1:uint, i2:uint, i3:uint, p:Array) : Boolean
{
var l1:Number, l2:Number, l4:Number, l5:Number, l6:Number, a:Number, b:Number;
a = p[i2].y - p[i1].y; b = p[i2].x - p[i1].y; l1 = Math.sqrt(a * a + b * b);
a = p[i3].y - p[i2].y; b = p[i3].x - p[i2].y; l2 = Math.sqrt(a * a + b * b);
a = p[i3].y - p[i0].y; b = p[i3].x - p[i0].y; l4 = Math.sqrt(a * a + b * b);
a = p[i1].y - p[i0].y; b = p[i1].x - p[i0].y; l5 = Math.sqrt(a * a + b * b);
a = p[i2].y - p[i0].y; b = p[i2].x - p[i0].y; l6 = Math.sqrt(a * a + b * b);
a = Math.acos((l2*l2 + l6*l6 - l4*l4) / (2*l2*l6));
b = Math.acos((l6*l6 + l1*l1 - l5*l5) / (2*l6*l1));
return (Math.PI - a - b < 0);
}
} // end of class Geometry
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -