Try running the code in a your browser's canvas implementation here:
http://developer.mozilla.org/samples/canvas-tutorial/2_6_canvas_beziercurveto.html
It should be a heart shape. I see the upper left and right corners
sheared off into a straight line when I user a drawview.
-Max
P T Withington wrote:
> I looked at the math in this 'till my head hurt. Googling tells me you
> are implementing de Casteljau's algorithm; perhaps a note to that effect
> would be good. AFAICT it is correct. What is the bug you see?
>
> (i.e., I approve this, but if there is someone out there with a better
> grasp on the math, feel free to chime in!)
>
> On 2006-03-13 16:19 EST, Max Carlson wrote:
>
>> Change 40515 by [EMAIL PROTECTED] on 2006/03/13 13:15:50 *pending*
>>
>> Summary: Add cubic bezier implementation. It works, but the
>> updated testcase (attached) shows a bug. Should we accept this patch
>> and file a separate bug?
>>
>> New Features:
>>
>> Bugs Fixed: LPP-1639
>>
>> Technical Reviewer: Tucker
>> QA Reviewer: (pending)
>> Doc Reviewer: (pending)
>>
>> Documentation:
>>
>> Release Notes:
>>
>> Details:
>>
>> Tests:
>>
>> Affected files ...
>>
>> ... //depot/lps-dev/WEB-INF/lps/lfc/views/LzDrawView.as#19 edit
>> ... //depot/lps-dev/test/drawing/drawing.lzx#5 edit
>>
>>
>> Differences ...
>>
>> ==== //depot/lps-dev/WEB-INF/lps/lfc/views/LzDrawView.as#19 -
>> c:\Laszlo\lps-dev\
>> WEB-INF\lps\lfc\views\LzDrawView.as ====
>> 521a522,639
>> >
>> //----------------------------------------------------------------------------
>>
>>
>> -
>> > // bezierCurveTo() adds the given coordinate (x, y) to the list of
>> points of
>> > // the subpath, and connects the two points with a bezier curve with
>> control
>> > // points (cp1x, cp1y) and (cp2x, cp2y). It then sets the current
>> position to
>>
>> > // the given coordinate (x, y). Approximates a cubic bezier with
>> quadratic
>> > // segments, to within a midpoint error of
>> > // LzDrawView.prototype.bezierCurveTo.error.
>> > //
>> > // @param Number cp1x: X value of control point 1
>> > // @param Number cp1y: Y value of control point 1
>> > // @param Number cp2x: X value of control point 2
>> > // @param Number cp2y: Y value of control point 2
>> > // @param Number x: X value of endpoint
>> > // @param Number y: Y value of endpoint
>> >
>> //----------------------------------------------------------------------------
>>
>>
>> -
>> > LzDrawView.prototype.bezierCurveTo = function(cp1x, cp1y, cp2x,
>> cp2y, x, y) {
>> > var error = arguments.callee.error;
>> >
>> > // These would be useful generally, but put them inside the
>> > // function so they don't pollute the general namespace.
>> > function distance(p0, p1) {
>> > var dx = p1.x - p0.x;
>> > var dy = p1.y - p0.y;
>> > return Math.sqrt(dx*dx+dy*dy);
>> > }
>> > // returns null if they're collinear
>> > function intersection(p0, p1, p2, p3) {
>> > var u = (p3.x-p2.x)*(p0.y-p2.y) - (p3.y-p2.y)*(p0.x-p2.x);
>> > var d = (p3.y-p2.y)*(p1.x-p0.x) - (p3.x-p2.x)*(p1.y-p0.y);
>> > _root.Debug.write('intersection', u, d);
>> > if (!d) return null;
>> > u /= d;
>> > return {x: p0.x + (p1.x-p0.x) * u,
>> > y: p0.y + (p1.y-p0.y) * u};
>> > }
>> > function midpoint(p0, p1) {
>> > return {x: (p0.x+p1.x)/2, y: (p0.y+p1.y)/2};
>> > }
>> >
>> > // Start from the cursor position, or (0, 0)
>> > var x0 = 0, y0 = 0;
>> > if (this.__path.length) {
>> > var instr = this.__path[this.__path.length - 1];
>> > x0 = instr[instr.length - 2];
>> > y0 = instr[instr.length - 1];
>> > }
>> > // The algorithm used is to recursively subdivide the cubic until
>> > // it's close enough to a quadratic, and then draw that.
>> > // The code below has the effect of
>> > // function draw_cubic(cubic) {
>> > // if (|midpoint(cubic)-midpoint(quadratic)| < error)
>> > // draw_quadratic(qudratic);
>> > // else
>> > // map(draw_cubic, subdivide(cubic));
>> > // }
>> > // where the recursion has been replaced by an explicit
>> > // work item queue.
>> >
>> > // To avoid recursion and undue temporary structure, the following
>> > // loop has a funny control flow. Each iteration either pops
>> > // the next work item from queue, or creates two new work items
>> > // and pushes one to the queue while setting +points+ to the
>> other one.
>> > // The loop effectively exits from the *middle*, when the next
>> > // work item is null. (This continues to the loop test,
>> > // which then exits.)
>> >
>> > // each item is a list of control points, with a sentinel of null
>> > var work_items = [null];
>> > // the current work item
>> > var points = [{x: x0, y: y0}, {x: cp1x, y: cp1y}, {x: cp2x, y:
>> cp2y}, {x:
>> x, y: y}];
>> > while (points) {
>> > // Compute the triangle, since the fringe is the subdivision
>> > // if we need that and the peak is the midpoint which we need
>> > // in any case
>> > var m = [points, [], [], []];
>> > for (var i = 1; i < 4; i++) {
>> > for (var j = 0; j < 4 - i; j++) {
>> > var c0 = m[i-1][j];
>> > var c1 = m[i-1][j+1];
>> > m[i][j] = {x: (c0.x + c1.x)/2,
>> > y: (c0.y + c1.y)/2};
>> > }
>> > }
>> > // Posit a quadratic. For C1 continuity, control point has to
>> > // be at the intersection of the tangents.
>> > var q1 = intersection.apply(null, points);
>> > var q0 = points[0];
>> > var q2 = points[3];
>> > if (!q1) {
>> > _root.Debug.write('a line');
>> > // It's really a line.
>> > this.lineTo(q2.x, q2.y);
>> > points = work_items.pop();
>> > continue;
>> > }
>> > var qa = midpoint(q0, q1);
>> > var qb = midpoint(q1, q2);
>> > var qm = midpoint(qa, qb);
>> > // Is the midpoint of the quadratic close to the midpoint of
>> > // the cubic? If so, use it as the approximation.
>> > if (distance(qm, m[3][0]) < error) {
>> > this.quadraticCurveTo(q1.x, q1.y, q2.x, q2.y);
>> > points = work_items.pop();
>> > continue;
>> > }
>> > // Otherwise subdivide the cubic. The first division is the
>> > // next work item, and the second goes on the work queue.
>> > var left = new Array(4), right = new Array(4);
>> > for (i = 0; i < 4; i++) {
>> > left[i] = m[i][0];
>> > right[i] = m[3-i][i];
>> > }
>> > points = left;
>> > work_items.push(right);
>> > }
>> > };
>> > LzDrawView.prototype.bezierCurveTo.error = 10;
>> >
>> ==== //depot/lps-dev/test/drawing/drawing.lzx#5 -
>> c:\Laszlo\lps-dev\test\drawing
>> \drawing.lzx ====
>> 87a88,101
>> > <!-- test new bezierCurveTo method - from
>> http://developer.mozilla.org/sample
>> s/canvas-tutorial/2_6_canvas_beziercurveto.html -->
>> > <drawview>
>> > <method event="oninit">
>> > this.beginPath();
>> > this.moveTo(75,40);
>> > this.bezierCurveTo(75,37,70,25,50,25);
>> > this.bezierCurveTo(20,25,20,62.5,20,62.5);
>> > this.bezierCurveTo(20,80,40,102,75,120);
>> > this.bezierCurveTo(110,102,130,80,130,62.5);
>> > this.bezierCurveTo(130,62.5,130,25,100,25);
>> > this.bezierCurveTo(85,25,75,37,75,40);
>> > this.fill();
>> > </method>
>> > </drawview>
>> <changeset-40515.zip>
>
>
--
Regards,
Max Carlson
OpenLaszlo.org
_______________________________________________
Laszlo-dev mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-dev