†‡Paladin‡† |
25.04.2008 19:00 |
Ну и мои 5 копеек.
Код:
package {
import flash.display.*;
import flash.geom.*;
/**
* Based on Math2 class writed by Helen Triolo, with inclusions from Robert Penner, Tim Groleau
* @author Ilya (WYPaladin) Plotnikov
*
*/
public class QubicBezier {
/**
* @method getQuadBez_RP (Penner)
* @description Approximates a cubic bezier with as many quadratic bezier segments (n) as required
* to achieve a specified tolerance
* @param p1 (Object) endpoint
* @param c1 (Object) 1st control point
* @param c2 (Object) 2nd control point
* @param p2 (Object) endpoint
* @param k: tolerance (low number = most accurate result)
* @param qcurves (Array) will contain array of quadratic bezier curves, each element containing
* p1x, p1y, cx, cy, p2x, p2y
*/
public function getQuadBez_RP(p1:Point, c1:Point, c2:Point, p2:Point, k:Number, qcurves:Array):void {
// if something is wrong, abort function
try {
// find intersection between bezier arms
var s:Point = intersect2Lines(p1, c1, c2, p2);
// find distance between the midpoints
var dx:Number = (p1.x + p2.x + s.x * 4 - (c1.x + c2.x) * 3) * .125;
var dy:Number = (p1.y + p2.y + s.y * 4 - (c1.y + c2.y) * 3) * .125;
} catch (e:Error) {
return;
}
// split curve if the quadratic isn't close enough
if (dx*dx + dy*dy > k) {
var halves:Object = bezierSplit(p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
var b0:Object = halves.b0;
var b1:Object = halves.b1;
// recursive call to subdivide curve
getQuadBez_RP(p1, b0.c1, b0.c2, b0.p2, k, qcurves);
getQuadBez_RP(b1.p1, b1.c1, b1.c2, p2, k, qcurves);
} else {
// end recursion by saving points
qcurves.push({p1x:p1.x, p1y:p1.y, cx:s.x, cy:s.y, p2x:p2.x, p2y:p2.y});
}
}
/**
* @method intersect2Lines (Penner)
* @description Returns the point of intersection between two lines
* @param p1, p2 (Objects) points on line 1
* @param p3, p4 (Objects) points on line 2
* @returns Object (point of intersection)
*/
private function intersect2Lines (p1:Point, p2:Point, p3:Point, p4:Point):Point {
var x1:Number = p1.x;
var y1:Number = p1.y;
var x4:Number = p4.x;
var y4:Number = p4.y;
var dx1:Number = p2.x - x1;
var dx2:Number = p3.x - x4;
if (!(dx1 || dx2)) return undefined;
var m1:Number = (p2.y - y1) / dx1;
var m2:Number = (p3.y - y4) / dx2;
if (!dx1) {
return new Point(x1, m2 * (x1 - x4) + y4);
} else if (!dx2) {
return new Point(x4, m1 * (x4 - x1) + y1);
}
var xInt:Number = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
var yInt:Number = m1 * (xInt - x1) + y1;
return new Point(xInt, yInt);
}
/**
* @method bezierSplit (Penner)
* @description Divides a cubic bezier curve into two halves (each also cubic beziers)
* @param p1x (Number) pixels, endpoint 1
* @param p1y (Number) pixels
* @param c1x (Number) pixels, control point 1
* @param c1y (Number) pixels
* @param c2x (Number) pixels, control point 2
* @param c2y (Number) pixels
* @param p2x (Number) pixels, endpoint 2
* @param p2y (Number) pixels
* @returns Object (object with two cubic bezier definitions, b0 and b1)
*/
private function bezierSplit(p1x:Number, p1y:Number,
c1x:Number, c1y:Number,
c2x:Number, c2y:Number,
p2x:Number, p2y:Number):Object {
var p1:Point = new Point(p1x, p1y);
var p2:Point = new Point(p2x, p2y);
var p3:Point = new Point(c1x, c1y);
var p4:Point = new Point(c2x, c2y);
var p01:Point = getMiddle(p1, p3);
var p12:Point = getMiddle(p3, p4);
var p23:Point = getMiddle(p4, p2);
var p02:Point = getMiddle(p01, p12);
var p13:Point = getMiddle(p12, p23);
var p03:Point = getMiddle(p02, p13);
return { b0:{p1:p1, c1:p01, c2:p02, p2:p03}, b1:{p1:p03, c1:p13, c2:p23, p2:p2} };
}
/**
* @method getMiddle
* @description Returns the midpoint (x/y) of a line segment from p1x/p1y to p2x/p2y
* @param p1x (Number) pixels
* @param p1y (Number) pixels
* @param p2x (Number) pixels
* @param p2y (Number) pixels
* @returns Object (midpoint)
*/
private function getMiddle(pA:Point, pB:Point):Point {
return new Point((pA.x+pB.x)/2, (pA.y+pB.y)/2);
}
}
}
|