source: Dev/trunk/src/client/dojox/gfx/bezierutils.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 4.3 KB
Line 
1define([
2        "./_base"
3], function(gfx){
4
5        var bu = gfx.bezierutils = {},
6                error = 0.1;
7
8        var tAtLength = bu.tAtLength = function(points, length){
9                // summary:
10                //              Returns the t corresponding to the given length for the specified bezier curve.
11                // points: Number[]
12                //              The bezier points. Should be [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y] for a cubic
13                //              bezier curve or [p1x, p1y, cx, cy, p2x, p2y] for a quadratic bezier curve.
14                // length: Number
15                //              The length.
16                var t = 0,
17                        quadratic = points.length == 6,
18                        currentLen = 0,
19                        splitCount = 0,
20                        splitFunc = quadratic ? splitQBezierAtT : splitBezierAtT;
21                var _compute = function(p, error){
22                        // control points polygon length
23                        var pLen = 0;
24                        for(var i = 0; i < p.length-2; i+=2)
25                                pLen += distance(p[i],p[i+1],p[i+2],p[i+3]);
26                        // chord length
27                        var chord = quadratic ?
28                                distance(points[0],points[1],points[4],points[5]) :
29                                distance(points[0],points[1],points[6],points[7]);
30                        // if needs more approx. or if currentLen is greater than the target length,
31                        // split the curve one more time
32                        if(pLen - chord > error || currentLen + pLen > length + error){
33                                ++splitCount;
34                                var newbezier = splitFunc(p, .5);
35                                // check 1st subpath
36                                _compute(newbezier[0], error);
37                                // the 1st subcurve was the good one, we stop
38                                if(Math.abs(currentLen - length) <= error){
39                                        return;
40                                }
41                                // need to continue with the 2nde subcurve
42                                _compute(newbezier[1], error);
43                                return ;
44                        }
45                        currentLen += pLen;
46                        t += 1.0 / (1 << splitCount);
47                };
48                if(length)
49                        _compute(points, 0.5);
50                return t;
51        };
52
53        var computeLength = bu.computeLength = function(/*Array*/points){
54                // summary:
55                //              Returns the length of the given bezier curve.
56                // points: Number[]
57                //              The bezier points. Should be [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y] for a cubic
58                //              bezier curve or [p1x, p1y, cx, cy, p2x, p2y] for a quadratic bezier curve.
59
60                var quadratic = points.length == 6, pLen=0;
61                // control points polygon length
62                for(var i = 0; i < points.length-2; i+=2)
63                        pLen += distance(points[i],points[i+1],points[i+2],points[i+3]);
64                // chord length
65                var chord = quadratic ?
66                        distance(points[0],points[1],points[4],points[5]) :
67                        distance(points[0],points[1],points[6],points[7]);
68                // split polygons until the polygon and the chord are "the same"
69                if(pLen-chord>error){
70                        var newBeziers = quadratic ? splitQBezierAtT(points,.5) : splitCBezierAtT(points,.5);
71                        var length = computeLength(newBeziers[0], quadratic);
72                        length += computeLength(newBeziers[1], quadratic);
73                        return length;
74                }
75                // pLen is close enough, done.
76                return pLen;
77        };
78
79        var distance = bu.distance = function(x1, y1, x2, y2){
80                // summary:
81                //              Returns the distance between the specified points.
82                return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
83        };
84
85        var splitQBezierAtT = function(points, t){
86                // summary:
87                //              Split a quadratic bezier curve into 2 sub-quadratic beziers at the specified t.
88
89                // de Casteljau
90                var r = 1-t,
91                        r2 = r*r,
92                        t2 = t*t,
93                        p1x = points[0],
94                        p1y = points[1],
95                        cx = points[2],
96                        cy = points[3],
97                        p2x = points[4],
98                        p2y = points[5],
99
100                        ax = r*p1x + t*cx,
101                        ay = r*p1y + t*cy,
102                        bx = r*cx + t*p2x,
103                        by = r*cy + t*p2y,
104                        px = r2*p1x + 2*r*t*cx + t2*p2x,
105                        py = r2*p1y + 2*r*t*cy + t2*p2y;
106
107                return [
108                        [
109                                p1x, p1y,
110                                ax, ay,
111                                px, py
112                        ],
113                        [
114                                px, py,
115                                bx, by,
116                                p2x, p2y
117                        ]
118                ];
119        };
120
121        var splitCBezierAtT = function(points, t){
122                // summary:
123                //              Split a cubic bezier curve into 2 sub-cubic beziers at the specified t.
124
125                // de Casteljau
126                var r = 1-t,
127                        r2 = r*r,
128                        r3 = r2*r,
129                        t2 = t*t,
130                        t3 = t2*t,
131                        p1x = points[0],
132                        p1y = points[1],
133                        c1x = points[2],
134                        c1y = points[3],
135                        c2x = points[4],
136                        c2y = points[5],
137                        p2x = points[6],
138                        p2y = points[7],
139
140                        ax = r*p1x + t*c1x,
141                        ay = r*p1y + t*c1y,
142                        cx = r*c2x + t*p2x,
143                        cy = r*c2y + t*p2y,
144                        mx = r2*p1x + 2*r*t*c1x + t2*c2x,
145                        my = r2*p1y + 2*r*t*c1y + t2*c2y,
146                        nx = r2*c1x + 2*r*t*c2x + t2*p2x,
147                        ny = r2*c1y + 2*r*t*c2y + t2*p2y,
148                        px = r3*p1x + 3*r2*t*c1x + 3*r*t2*c2x+t3*p2x,
149                        py = r3*p1y + 3*r2*t*c1y + 3*r*t2*c2y+t3*p2y;
150
151                return [
152                        [
153                                p1x, p1y,
154                                ax, ay,
155                                mx, my,
156                                px, py
157                        ],
158                        [
159                                px, py,
160                                nx, ny,
161                                cx, cy,
162                                p2x, p2y
163                        ]
164                ];
165        };
166
167        var splitBezierAtT = bu.splitBezierAtT = function(points, t){
168                return points.length == 6 ? splitQBezierAtT(points, t) : splitCBezierAtT(points, t);
169        };
170        return bu;
171});
Note: See TracBrowser for help on using the repository browser.