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

Reply via email to