(WIP) Graphics - add ellipticalArc method #1544

Open
wants to merge 2 commits into
from

Projects

None yet

2 participants

Contributor
tripp commented Jan 11, 2014

First pass at fixing #1443.
Created ellipticalArc method based on w3c elliptical arc implementation notes.

Added manual example based on this example in the path spec.

Currently, VML/Canvas implementations are drawing arcs by point. May consider using cubic bezier approximations depending on performance.

  • Add unit tests.
  • Cross browser/platform testing
  • Perf testing.
  • Update based on any feedback.
tripp added some commits Jan 11, 2014
@tripp tripp First pass at adding elliptical arc to graphics.
	modified:   js/CanvasDrawing.js
	modified:   js/SVGDrawing.js
	modified:   js/VMLDrawing.js
fadae84
@tripp tripp Add manual test for arc method. 97401e8
@ezequiel ezequiel commented on the diff Jan 13, 2014
src/graphics/js/CanvasDrawing.js
+ rx = Math.abs(rx);
+ ry = Math.abs(ry);
+ //flags are true unless explicitly set to zero per spec
+ largeArcFlag = parseFloat(largeArcFlag) !== 0;
+ sweepFlag = parseFloat(sweepFlag) !== 0;
+ //ensure its between -360 and 360
+ xAxisRotation = xAxisRotation % 360;
+ //convert to radians
+ xAxisRotation = xAxisRotation/180 * Math.PI;
+ //cache sin and cos of angle
+ sinTheta = Math.sin(xAxisRotation);
+ cosTheta = Math.cos(xAxisRotation);
+
+ //step 1: compute x and y derivatives
+ x1_ = (cosTheta * (x1 - x2)/2) + (sinTheta * (y1 - y2)/2);
+ y1_ = (-sinTheta * (x1 - x2)/2) + (cosTheta * (y1 - y2)/2);
ezequiel
ezequiel Jan 13, 2014 Contributor

Lines 321-322:

You don't have to divide by 2 twice. Factor it out.

@ezequiel ezequiel commented on the diff Jan 13, 2014
src/graphics/js/CanvasDrawing.js
+ y1_pow2 = Math.pow(y1_, 2);
+ lambda = x1_pow2/rxpow2 + y1_pow2/rypow2;
+
+ if(lambda > 1) {
+ //correct rx and ry and resquare
+ lambda = Math.sqrt(lambda);
+ rx = lambda * rx;
+ ry = lambda * ry;
+ rxpow2 = Math.pow(rx, 2);
+ rypow2 = Math.pow(ry, 2);
+ }
+
+ x1_pow2 = Math.round(x1_pow2 * 10)/10;
+ y1_pow2 = Math.round(y1_pow2 * 10)/10;
+ rxpow2 = Math.round(rxpow2 * 10)/10;
+ rypow2 = Math.round(rypow2 * 10)/10;
ezequiel
ezequiel Jan 13, 2014 Contributor

Lines 340-343:

Are you simply trying to round and truncate? 12345.6789 => 12345.7? If so, use toFixed(1).

@ezequiel ezequiel commented on the diff Jan 13, 2014
src/graphics/js/CanvasDrawing.js
+ //correct rx and ry and resquare
+ lambda = Math.sqrt(lambda);
+ rx = lambda * rx;
+ ry = lambda * ry;
+ rxpow2 = Math.pow(rx, 2);
+ rypow2 = Math.pow(ry, 2);
+ }
+
+ x1_pow2 = Math.round(x1_pow2 * 10)/10;
+ y1_pow2 = Math.round(y1_pow2 * 10)/10;
+ rxpow2 = Math.round(rxpow2 * 10)/10;
+ rypow2 = Math.round(rypow2 * 10)/10;
+
+ //compute cx/cy derivatives
+ //cache the scalr value for use in getting both derivatives
+ scalarMultiplier = ((rxpow2 * rypow2) - (rxpow2 * y1_pow2) - (rypow2 * x1_pow2)) / ((rxpow2 * y1_pow2) + (rypow2 * x1_pow2));
ezequiel
ezequiel Jan 13, 2014 Contributor
((rxpow2 * rypow2) / (x1_pow2 * rypow2 + rxpow2 * y1_pow2)) - 1

Shorter by three operations. Check my work, though.

@ezequiel ezequiel commented on the diff Jan 13, 2014
src/graphics/js/CanvasDrawing.js
+ //set the vectors for deltaTheta
+ ux = (x1_ - cx_)/rx;
+ uy = (y1_ - cy_)/ry;
+ vx = (-x1_ - cx_)/rx;
+ vy = (-y1_ - cy_)/ry;
+ sign = (ux * vy - uy * vx) < 0 ? -1 : 1;
+ //sign = sign < 0 ? -1 : 1;
+ //get the angle between the two vectors
+ deltaTheta = sign * Math.acos((ux * vx + uy * vy) / (Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy))) % radian360;
+
+ if(!sweepFlag && deltaTheta > 0) {
+ deltaTheta = deltaTheta - radian360;
+ } else if(sweepFlag && deltaTheta < 0) {
+ deltaTheta = deltaTheta + radian360;
+ }
+ segments = Math.ceil(Math.abs(deltaTheta) / (1/360 * Math.PI));
ezequiel
ezequiel Jan 13, 2014 Contributor
Math.PI / 360;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment