(WIP) Graphics - add ellipticalArc method #1544

Open
wants to merge 2 commits into
from

1 participant

@tripp

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
YUI Library member
ezequiel added a line comment Jan 13, 2014

Lines 321-322:

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
YUI Library member
ezequiel added a line comment Jan 13, 2014

Lines 340-343:

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
YUI Library member
ezequiel added a line comment Jan 13, 2014
((rxpow2 * rypow2) / (x1_pow2 * rypow2 + rxpow2 * y1_pow2)) - 1

Shorter by three operations. Check my work, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
YUI Library member
ezequiel added a line comment Jan 13, 2014
Math.PI / 360;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment