Bezier Rendering Transformations

JavaScript performance comparison

Test case created by Ammar Hattab

Info

Compare performance of applying the transformation on bezier curve control points vs applying it on line segments approximation of the curve

Preparation code

<canvas id="canvas1" width="800" height="400"></canvas>
 
<script>
Benchmark.prototype.setup = function() {
                function CalculateMethod1(_preX, _preY, x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS)
                {
                    var step = NUM_STEPS;
                        var stepmu = 1/NUM_STEPS;
                        while(step--)
                        {
                           mu = 1-(stepmu* step);
                           var mum1,mum13,mu3;
                           mum1 = 1 - mu;
                           mum13 = mum1 * mum1 * mum1;
                           mu3 = mu * mu * mu;
                           px = mum13*x1 + 3*mu*mum1*mum1*x2 + 3*mu*mu*mum1*x3 + mu3*x4;
                           py = mum13*y1 + 3*mu*mum1*mum1*y2 + 3*mu*mu*mum1*y3 + mu3*y4;                       
                           _preX.push(px);
                           _preY.push(py);                     
                        }
                       
                }
               
                function DrawTransformedBezierCurve(canvasName, usePrecalculated, doTranslate, doRotate, doScale, dx, dy, theta, sx, sy, x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS)
                {
                        var _calculatedLineX = [];
                        var _calculatedLineY = [];
                       
                        var sint = 0;
                        var cost = 0;
                        if(doRotate){
                                 sint = Math.sin(theta);
                                 cost = Math.cos(theta);
                        }
                       
                        if(doTranslate){
                                 x1=x1+dx; y1=y1+dy; x4=x4+dx; y4=y4+dy;
                        }
                        if(doRotate){
                                 x1=x1*cost+y1*sint; y1=y1*cost-x1*sint; x4=x4*cost+y4*sint; y4=y4*cost-x4*sint;
                        }
                        if(doScale){
                                 x1=x1*sx; y1=y1*sy; x4=x4*sx; y4=y4*sy;
                        }
                       
                        if(usePrecalculated){                          
                                _calculatedLineX =_preCalculatedLineX;
                                _calculatedLineY =_preCalculatedLineY;
                                //Calculate then Apply Transformations
                                for(i=0; i<_calculatedLineX.length; i++) {
                                        if(doTranslate){
                                                 _calculatedLineX[i]=_calculatedLineX[i]+dx; _calculatedLineY[i]=_calculatedLineY[i]+dy;
                                        }
                                        if(doRotate){
                                                 _calculatedLineX[i]=_calculatedLineX[i]*cost+_calculatedLineY[i]*sint; _calculatedLineY[i]=_calculatedLineY[i]*cost-_calculatedLineX[i]*sint;
                                        }
                                        if(doScale){
                                                 _calculatedLineX[i]=_calculatedLineX[i]*sx; _calculatedLineY[i]=_calculatedLineY[i]*sy;
                                        }
                                }
                        }else{
                                //Apply Transformations and then calculate                             
                                if(doTranslate){
                                         x2=x2+dx; y2=y2+dy; x3=x3+dx; y3=y2+dy;
                                }
                                if(doRotate){
                                         x2=x2*cost+y2*sint; y2=y2*cost-x2*sint; x3=x3*cost+y3*sint; y3=y3*cost-x3*sint;
                                }
                                if(doScale){
                                        x2=x2*sx; y2=y2*sy; x3=x3*sx; y3=y2*sy;
                                }
                                //Calculate
                                CalculateMethod1(_calculatedLineX, _calculatedLineY, x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS)
                        }
                        //Canvas
                        //var canvas = document.getElementById(canvasName);
                  //  var context = canvas.getContext('2d');
                        //GeneralDraw(context, _calculatedLineX, _calculatedLineY, x1, y1, x2, y2, x3, y3, x4, y4);
                }
               
               
                function GeneralDraw(context, _calculatedLineX, _calculatedLineY, x1, y1, x2, y2, x3, y3, x4, y4)
                {
                        //Draw Green Line
                        /*context.lineWidth = 30;
                    context.strokeStyle = 'lightgreen';            
                        context.beginPath();
                        context.moveTo(x1, y1);
                        for(i=0; i<_calculatedLineX.length; i++) {
                                context.lineTo(_calculatedLineX[i], _calculatedLineY[i]);
                        }
                        context.lineTo(x4, y4);
                        context.stroke(); */

                       
                        //Draw thin blue lines
                        context.lineWidth = 1;
                    context.strokeStyle = 'darkblue';              
                        context.beginPath();
                        context.moveTo(x1, y1);
                        for(i=0; i<_calculatedLineX.length; i++) {
                                context.lineTo(_calculatedLineX[i], _calculatedLineY[i]);
                        }
                        context.lineTo(x4, y4);
                        context.stroke();
                       
                        //Draw points as circles
                        context.fillStyle = 'darkblue';
                        for(i=0; i<_calculatedLineX.length; i++) {
                                context.beginPath();                   
                                context.arc(_calculatedLineX[i], _calculatedLineY[i], 1, 0, Math.PI*2, true);
                                context.closePath();
                                context.fill();                        
                        }
                       
                        context.fillStyle = 'darkblue';
                        context.beginPath();                   
                        context.arc(x1, y1, 7, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();
                       
                        context.fillStyle = 'darkblue';
                        context.beginPath();                   
                        context.arc(x4, y4, 7, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();
                       
                        /*context.fillStyle = 'darkgreen';
                        context.beginPath();                   
                        context.arc(x2, y2, 5, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();
                       
                        context.fillStyle = 'darkgreen';
                        context.beginPath();                   
                        context.arc(x3, y3, 5, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();                 */

                }
       
                var _preCalculatedLineX = [];
                var _preCalculatedLineY = [];
                function PreCalculate(x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS){
                        CalculateMethod1(_preCalculatedLineX, _preCalculatedLineY, x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS)
                }
               
                function DrawAxeses(canvasName,w,h){
                        var canvas = document.getElementById(canvasName);
                    var context = canvas.getContext('2d');
                        context.lineWidth = 0.5;
                    context.strokeStyle = 'black';                 
                        context.beginPath();
                        //x-axis
                        context.moveTo(0, h/2);
                        context.lineTo(w, h/2);
                       
                        //y-axis
                        context.moveTo(w/2, 0);
                        context.lineTo(w/2, h);
                       
                        context.stroke();
                }
               
                function DrawReference(canvasName, x1, y1, x2, y2, x3, y3, x4, y4, NUM_STEPS){
                        _calculatedLineX =_preCalculatedLineX;
                        _calculatedLineY =_preCalculatedLineY;
                        var canvas = document.getElementById(canvasName);
                    var context = canvas.getContext('2d');
                       
                        //Draw thin blue lines
                        context.lineWidth = 1;
                    context.strokeStyle = 'darkblue';              
                        context.beginPath();
                        context.moveTo(x1, y1);
                        for(i=0; i<_calculatedLineX.length; i++) {
                                context.lineTo(_calculatedLineX[i], _calculatedLineY[i]);
                        }
                        context.lineTo(x4, y4);
                        context.stroke();
                       
                        //Draw points as circles
                        context.fillStyle = 'darkblue';
                        for(i=0; i<_calculatedLineX.length; i++) {
                                context.beginPath();                   
                                context.arc(_calculatedLineX[i], _calculatedLineY[i], 1, 0, Math.PI*2, true);
                                context.closePath();
                                context.fill();                        
                        }
                       
                        context.fillStyle = 'darkblue';
                        context.beginPath();                   
                        context.arc(x1, y1, 7, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();
                       
                        context.fillStyle = 'darkblue';
                        context.beginPath();                   
                        context.arc(x4, y4, 7, 0, Math.PI*2, true);
                        context.closePath();
                        context.fill();
                }
               
                PreCalculate(188, 130, 140, 10, 388, 10, 388, 170, 20);
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Translate Control Points
DrawTransformedBezierCurve('canvas1', false, true, false, false, 30, 0, 0, 0, 0, 188, 130, 140, 10, 388, 10, 388, 170, 20); 
pending…
Translate Lines
DrawTransformedBezierCurve('canvas1', true, true, false, false, -30, 0, 0, 0, 0, 188, 130, 140, 10, 388, 10, 388, 170, 20); 
 
pending…
Rotate Control Points
DrawTransformedBezierCurve('canvas1', false, false, true, false, 0, 0, -0.3, 0, 0, 188, 130, 140, 10, 388, 10, 388, 170, 20); 
pending…
Rotate Lines
DrawTransformedBezierCurve('canvas1', true, false, true, false, 0, 0, -0.3, 0, 0, 188, 130, 140, 10, 388, 10, 388, 170, 20);
pending…
Scale Control Points
DrawTransformedBezierCurve('canvas1', false, false, false, true, 0, 0, 0, 2, 2, 188, 130, 140, 10, 388, 10, 388, 170, 20);
pending…
Scale Lines
DrawTransformedBezierCurve('canvas1', true, false, false, true, 0, 0, 0, 1.5, 1.5, 188, 130, 140, 10, 388, 10, 388, 170, 20); 
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment