|
@@ -387,56 +387,64 @@ THREE.SVGLoader.prototype = {
|
|
|
* aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation
|
|
|
*/
|
|
|
|
|
|
- var vector = new THREE.Vector2();
|
|
|
-
|
|
|
function parseArcCommand( path, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, start, end ) {
|
|
|
|
|
|
x_axis_rotation = x_axis_rotation * Math.PI / 180;
|
|
|
|
|
|
// Ensure radii are positive
|
|
|
- var rX = Math.abs( rx );
|
|
|
- var rY = Math.abs( ry );
|
|
|
+ rx = Math.abs( rx );
|
|
|
+ ry = Math.abs( ry );
|
|
|
|
|
|
// Compute (x1′, y1′)
|
|
|
- var midDist = vector.subVectors( start, end ).multiplyScalar( 0.5 );
|
|
|
- var x1p = Math.cos( x_axis_rotation ) * midDist.x + Math.sin( x_axis_rotation ) * midDist.y;
|
|
|
- var y1p = - Math.sin( x_axis_rotation ) * midDist.x + Math.cos( x_axis_rotation ) * midDist.y;
|
|
|
+ var dx2 = ( start.x - end.x ) / 2.0;
|
|
|
+ var dy2 = ( start.y - end.y ) / 2.0;
|
|
|
+ var x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
|
|
|
+ var y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;
|
|
|
|
|
|
// Compute (cx′, cy′)
|
|
|
- var rxs = rX * rX;
|
|
|
- var rys = rY * rY;
|
|
|
+ var rxs = rx * rx;
|
|
|
+ var rys = ry * ry;
|
|
|
var x1ps = x1p * x1p;
|
|
|
var y1ps = y1p * y1p;
|
|
|
|
|
|
// Ensure radii are large enough
|
|
|
var cr = x1ps / rxs + y1ps / rys;
|
|
|
if ( cr > 1 ) {
|
|
|
- // scale up rX,rY equally so cr == 1
|
|
|
+ // scale up rx,ry equally so cr == 1
|
|
|
var s = Math.sqrt( cr );
|
|
|
- rX = s * rX;
|
|
|
- rY = s * rY;
|
|
|
- rxs = rX * rX;
|
|
|
- rys = rY * rY;
|
|
|
+ rx = s * rx;
|
|
|
+ ry = s * ry;
|
|
|
+ rxs = rx * rx;
|
|
|
+ rys = ry * ry;
|
|
|
}
|
|
|
|
|
|
var dq = ( rxs * y1ps + rys * x1ps );
|
|
|
var pq = ( rxs * rys - dq ) / dq;
|
|
|
- var q = Math.sqrt( pq );
|
|
|
+ var q = Math.sqrt( Math.max( 0, pq ) );
|
|
|
if ( large_arc_flag === sweep_flag ) q = - q;
|
|
|
- var cxp = q * rX * y1p / rY;
|
|
|
- var cyp = - q * rY * x1p / rX;
|
|
|
+ var cxp = q * rx * y1p / ry;
|
|
|
+ var cyp = - q * ry * x1p / rx;
|
|
|
|
|
|
// Step 3: Compute (cx, cy) from (cx′, cy′)
|
|
|
var cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
|
|
|
var cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;
|
|
|
|
|
|
// Step 4: Compute θ1 and Δθ
|
|
|
- var startAngle = vector.set( ( x1p - cxp ) / rX, ( y1p - cyp ) / rY ).angle();
|
|
|
- var endAngle = vector.set( ( - x1p - cxp ) / rX, ( - y1p - cyp ) / rY ).angle();
|
|
|
- if ( ! sweep_flag ) endAngle -= 2 * Math.PI;
|
|
|
+ var theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
|
|
|
+ var delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry );
|
|
|
+ delta = delta % ( Math.PI * 2 );
|
|
|
+ if ( ! sweep_flag ) delta -= 2 * Math.PI;
|
|
|
+
|
|
|
+ path.currentPath.absellipse( cx, cy, rx, ry, theta, theta + delta, theta + delta < theta, x_axis_rotation );
|
|
|
|
|
|
- path.currentPath.absellipse( cx, cy, rX, rY, startAngle, endAngle, endAngle > startAngle, x_axis_rotation );
|
|
|
+ }
|
|
|
|
|
|
+ function svgAngle( ux, uy, vx, vy ) {
|
|
|
+ var dot = ux * vx + uy * vy;
|
|
|
+ var len = Math.sqrt( ux * ux + uy * uy ) * Math.sqrt( vx * vx + vy * vy );
|
|
|
+ var ang = Math.acos( Math.max( -1, Math.min( 1, dot / len ) ) ); //floating point precision, slightly over values appear
|
|
|
+ if ( ( ux * vy - uy * vx ) < 0 ) ang = - ang;
|
|
|
+ return ang;
|
|
|
}
|
|
|
|
|
|
/*
|