|
@@ -7,8 +7,7 @@
|
|
|
THREE.Path = function ( points ) {
|
|
|
|
|
|
THREE.CurvePath.call( this );
|
|
|
-
|
|
|
- this.actions = [];
|
|
|
+ this.currentPoint = new THREE.Vector2();
|
|
|
|
|
|
if ( points ) {
|
|
|
|
|
@@ -22,11 +21,8 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
constructor: THREE.Path,
|
|
|
|
|
|
- // TODO Clean up PATH API
|
|
|
-
|
|
|
// Create path using straight lines to connect all points
|
|
|
// - vectors: array of Vector2
|
|
|
-
|
|
|
fromPoints: function ( vectors ) {
|
|
|
|
|
|
this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
|
|
@@ -41,52 +37,37 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
moveTo: function ( x, y ) {
|
|
|
|
|
|
- this.actions.push( { action: 'moveTo', args: [ x, y ] } );
|
|
|
+ this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
|
|
|
|
|
|
},
|
|
|
|
|
|
lineTo: function ( x, y ) {
|
|
|
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
-
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
-
|
|
|
- var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
|
|
|
+ var curve = new THREE.LineCurve( this.currentPoint.clone(), new THREE.Vector2( x, y ) );
|
|
|
this.curves.push( curve );
|
|
|
|
|
|
- this.actions.push( { action: 'lineTo', args: [ x, y ] } );
|
|
|
+ this.currentPoint.set( x, y );
|
|
|
|
|
|
},
|
|
|
|
|
|
quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
|
|
|
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
-
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
-
|
|
|
var curve = new THREE.QuadraticBezierCurve(
|
|
|
- new THREE.Vector2( x0, y0 ),
|
|
|
+ this.currentPoint.clone(),
|
|
|
new THREE.Vector2( aCPx, aCPy ),
|
|
|
new THREE.Vector2( aX, aY )
|
|
|
);
|
|
|
|
|
|
this.curves.push( curve );
|
|
|
|
|
|
- this.actions.push( { action: 'quadraticCurveTo', args: [ aCPx, aCPy, aX, aY ] } );
|
|
|
+ this.currentPoint.set( aX, aY );
|
|
|
|
|
|
},
|
|
|
|
|
|
bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
|
|
|
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
-
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
-
|
|
|
var curve = new THREE.CubicBezierCurve(
|
|
|
- new THREE.Vector2( x0, y0 ),
|
|
|
+ this.currentPoint.clone(),
|
|
|
new THREE.Vector2( aCP1x, aCP1y ),
|
|
|
new THREE.Vector2( aCP2x, aCP2y ),
|
|
|
new THREE.Vector2( aX, aY )
|
|
@@ -94,38 +75,25 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
this.curves.push( curve );
|
|
|
|
|
|
- this.actions.push( { action: 'bezierCurveTo', args: [ aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ] } );
|
|
|
+ this.currentPoint.set( aX, aY );
|
|
|
|
|
|
},
|
|
|
|
|
|
splineThru: function ( pts /*Array of Vector*/ ) {
|
|
|
|
|
|
- var args = Array.prototype.slice.call( arguments );
|
|
|
-
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
-
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
-
|
|
|
- var npts = [ new THREE.Vector2( x0, y0 ) ];
|
|
|
- Array.prototype.push.apply( npts, pts );
|
|
|
+ var npts = [ this.currentPoint.clone() ].concat( pts );
|
|
|
|
|
|
var curve = new THREE.SplineCurve( npts );
|
|
|
this.curves.push( curve );
|
|
|
|
|
|
- var lastPoint = pts[ pts.length - 1 ];
|
|
|
- args.push( lastPoint.x );
|
|
|
- args.push( lastPoint.y );
|
|
|
-
|
|
|
- this.actions.push( { action: 'splineThru', args: args } );
|
|
|
+ this.currentPoint.copy( pts[ pts.length - 1 ] );
|
|
|
|
|
|
},
|
|
|
|
|
|
arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
|
|
|
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
+ var x0 = this.currentPoint.x;
|
|
|
+ var y0 = this.currentPoint.y;
|
|
|
|
|
|
this.absarc( aX + x0, aY + y0, aRadius,
|
|
|
aStartAngle, aEndAngle, aClockwise );
|
|
@@ -140,9 +108,8 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
|
|
|
|
|
|
- var lastargs = this.actions[ this.actions.length - 1 ].args;
|
|
|
- var x0 = lastargs[ lastargs.length - 2 ];
|
|
|
- var y0 = lastargs[ lastargs.length - 1 ];
|
|
|
+ var x0 = this.currentPoint.x;
|
|
|
+ var y0 = this.currentPoint.y;
|
|
|
|
|
|
this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
|
|
|
|
|
@@ -150,336 +117,58 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
|
|
|
|
|
|
- var args = [
|
|
|
- aX, aY,
|
|
|
- xRadius, yRadius,
|
|
|
- aStartAngle, aEndAngle,
|
|
|
- aClockwise,
|
|
|
- aRotation || 0 // aRotation is optional.
|
|
|
- ];
|
|
|
-
|
|
|
var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
|
|
|
- this.curves.push( curve );
|
|
|
-
|
|
|
- var lastPoint = curve.getPoint( 1 );
|
|
|
- args.push( lastPoint.x );
|
|
|
- args.push( lastPoint.y );
|
|
|
-
|
|
|
- this.actions.push( { action: 'ellipse', args: args } );
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- getSpacedPoints: function ( divisions ) {
|
|
|
-
|
|
|
- if ( ! divisions ) divisions = 40;
|
|
|
-
|
|
|
- var points = [];
|
|
|
-
|
|
|
- for ( var i = 0; i < divisions; i ++ ) {
|
|
|
-
|
|
|
- points.push( this.getPoint( i / divisions ) );
|
|
|
-
|
|
|
- //if ( !this.getPoint( i / divisions ) ) throw "DIE";
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( this.autoClose ) {
|
|
|
-
|
|
|
- points.push( points[ 0 ] );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return points;
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- getPoints: function ( divisions ) {
|
|
|
-
|
|
|
- divisions = divisions || 12;
|
|
|
-
|
|
|
- var b2 = THREE.ShapeUtils.b2;
|
|
|
- var b3 = THREE.ShapeUtils.b3;
|
|
|
-
|
|
|
- var points = [];
|
|
|
-
|
|
|
- var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
|
|
|
- laste, tx, ty;
|
|
|
-
|
|
|
- for ( var i = 0, l = this.actions.length; i < l; i ++ ) {
|
|
|
-
|
|
|
- var item = this.actions[ i ];
|
|
|
-
|
|
|
- var action = item.action;
|
|
|
- var args = item.args;
|
|
|
-
|
|
|
- switch ( action ) {
|
|
|
-
|
|
|
- case 'moveTo':
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'lineTo':
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'quadraticCurveTo':
|
|
|
-
|
|
|
- cpx = args[ 2 ];
|
|
|
- cpy = args[ 3 ];
|
|
|
-
|
|
|
- cpx1 = args[ 0 ];
|
|
|
- cpy1 = args[ 1 ];
|
|
|
-
|
|
|
- if ( points.length > 0 ) {
|
|
|
-
|
|
|
- laste = points[ points.length - 1 ];
|
|
|
-
|
|
|
- cpx0 = laste.x;
|
|
|
- cpy0 = laste.y;
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- laste = this.actions[ i - 1 ].args;
|
|
|
-
|
|
|
- cpx0 = laste[ laste.length - 2 ];
|
|
|
- cpy0 = laste[ laste.length - 1 ];
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- for ( var j = 1; j <= divisions; j ++ ) {
|
|
|
-
|
|
|
- var t = j / divisions;
|
|
|
-
|
|
|
- tx = b2( t, cpx0, cpx1, cpx );
|
|
|
- ty = b2( t, cpy0, cpy1, cpy );
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( tx, ty ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'bezierCurveTo':
|
|
|
-
|
|
|
- cpx = args[ 4 ];
|
|
|
- cpy = args[ 5 ];
|
|
|
-
|
|
|
- cpx1 = args[ 0 ];
|
|
|
- cpy1 = args[ 1 ];
|
|
|
-
|
|
|
- cpx2 = args[ 2 ];
|
|
|
- cpy2 = args[ 3 ];
|
|
|
-
|
|
|
- if ( points.length > 0 ) {
|
|
|
-
|
|
|
- laste = points[ points.length - 1 ];
|
|
|
-
|
|
|
- cpx0 = laste.x;
|
|
|
- cpy0 = laste.y;
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- laste = this.actions[ i - 1 ].args;
|
|
|
-
|
|
|
- cpx0 = laste[ laste.length - 2 ];
|
|
|
- cpy0 = laste[ laste.length - 1 ];
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- for ( var j = 1; j <= divisions; j ++ ) {
|
|
|
-
|
|
|
- var t = j / divisions;
|
|
|
-
|
|
|
- tx = b3( t, cpx0, cpx1, cpx2, cpx );
|
|
|
- ty = b3( t, cpy0, cpy1, cpy2, cpy );
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( tx, ty ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'splineThru':
|
|
|
|
|
|
- laste = this.actions[ i - 1 ].args;
|
|
|
+ if ( this.curves.length > 0 ) {
|
|
|
|
|
|
- var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
|
|
|
- var spts = [ last ];
|
|
|
+ // if a previous curve is present, attempt to join
|
|
|
+ var firstPoint = curve.getPoint( 0 );
|
|
|
|
|
|
- var n = divisions * args[ 0 ].length;
|
|
|
+ if ( ! firstPoint.equals( this.currentPoint ) ) {
|
|
|
|
|
|
- spts = spts.concat( args[ 0 ] );
|
|
|
+ this.lineTo( firstPoint.x, firstPoint.y );
|
|
|
|
|
|
- var spline = new THREE.SplineCurve( spts );
|
|
|
-
|
|
|
- for ( var j = 1; j <= n; j ++ ) {
|
|
|
-
|
|
|
- points.push( spline.getPointAt( j / n ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'arc':
|
|
|
-
|
|
|
- var aX = args[ 0 ], aY = args[ 1 ],
|
|
|
- aRadius = args[ 2 ],
|
|
|
- aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
|
|
|
- aClockwise = !! args[ 5 ];
|
|
|
-
|
|
|
- var deltaAngle = aEndAngle - aStartAngle;
|
|
|
- var angle;
|
|
|
- var tdivisions = divisions * 2;
|
|
|
-
|
|
|
- for ( var j = 1; j <= tdivisions; j ++ ) {
|
|
|
-
|
|
|
- var t = j / tdivisions;
|
|
|
-
|
|
|
- if ( ! aClockwise ) {
|
|
|
-
|
|
|
- t = 1 - t;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- angle = aStartAngle + t * deltaAngle;
|
|
|
-
|
|
|
- tx = aX + aRadius * Math.cos( angle );
|
|
|
- ty = aY + aRadius * Math.sin( angle );
|
|
|
-
|
|
|
- //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( tx, ty ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- //console.log(points);
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case 'ellipse':
|
|
|
-
|
|
|
- var aX = args[ 0 ], aY = args[ 1 ],
|
|
|
- xRadius = args[ 2 ],
|
|
|
- yRadius = args[ 3 ],
|
|
|
- aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
|
|
|
- aClockwise = !! args[ 6 ],
|
|
|
- aRotation = args[ 7 ];
|
|
|
-
|
|
|
-
|
|
|
- var deltaAngle = aEndAngle - aStartAngle;
|
|
|
- var angle;
|
|
|
- var tdivisions = divisions * 2;
|
|
|
-
|
|
|
- var cos, sin;
|
|
|
- if ( aRotation !== 0 ) {
|
|
|
-
|
|
|
- cos = Math.cos( aRotation );
|
|
|
- sin = Math.sin( aRotation );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- for ( var j = 1; j <= tdivisions; j ++ ) {
|
|
|
-
|
|
|
- var t = j / tdivisions;
|
|
|
-
|
|
|
- if ( ! aClockwise ) {
|
|
|
-
|
|
|
- t = 1 - t;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- angle = aStartAngle + t * deltaAngle;
|
|
|
-
|
|
|
- tx = aX + xRadius * Math.cos( angle );
|
|
|
- ty = aY + yRadius * Math.sin( angle );
|
|
|
-
|
|
|
- if ( aRotation !== 0 ) {
|
|
|
-
|
|
|
- var x = tx, y = ty;
|
|
|
-
|
|
|
- // Rotate the point about the center of the ellipse.
|
|
|
- tx = ( x - aX ) * cos - ( y - aY ) * sin + aX;
|
|
|
- ty = ( x - aX ) * sin + ( y - aY ) * cos + aY;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
|
|
|
-
|
|
|
- points.push( new THREE.Vector2( tx, ty ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- //console.log(points);
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- } // end switch
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
+ this.curves.push( curve );
|
|
|
|
|
|
+ var lastPoint = curve.getPoint( 1 );
|
|
|
+ this.currentPoint.copy( lastPoint );
|
|
|
|
|
|
- // Normalize to remove the closing point by default.
|
|
|
- var lastPoint = points[ points.length - 1 ];
|
|
|
- if ( Math.abs( lastPoint.x - points[ 0 ].x ) < Number.EPSILON &&
|
|
|
- Math.abs( lastPoint.y - points[ 0 ].y ) < Number.EPSILON )
|
|
|
- points.splice( points.length - 1, 1 );
|
|
|
-
|
|
|
- if ( this.autoClose ) {
|
|
|
+ }
|
|
|
|
|
|
- points.push( points[ 0 ] );
|
|
|
+} );
|
|
|
|
|
|
- }
|
|
|
|
|
|
- return points;
|
|
|
+// minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
|
|
|
+THREE.ShapePath = function() {
|
|
|
+ this.subPaths = [];
|
|
|
+ this.currentPath = null;
|
|
|
+}
|
|
|
|
|
|
+THREE.ShapePath.prototype = {
|
|
|
+ moveTo: function ( x, y ) {
|
|
|
+ this.currentPath = new THREE.Path();
|
|
|
+ this.subPaths.push(this.currentPath);
|
|
|
+ this.currentPath.moveTo( x, y );
|
|
|
+ },
|
|
|
+ lineTo: function ( x, y ) {
|
|
|
+ this.currentPath.lineTo( x, y );
|
|
|
+ },
|
|
|
+ quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
|
|
|
+ this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
|
|
|
+ },
|
|
|
+ bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
|
|
|
+ this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
|
|
|
+ },
|
|
|
+ splineThru: function ( pts ) {
|
|
|
+ this.currentPath.splineThru( pts );
|
|
|
},
|
|
|
|
|
|
toShapes: function ( isCCW, noHoles ) {
|
|
|
|
|
|
- function extractSubpaths( inActions ) {
|
|
|
-
|
|
|
- var subPaths = [], lastPath = new THREE.Path();
|
|
|
-
|
|
|
- for ( var i = 0, l = inActions.length; i < l; i ++ ) {
|
|
|
-
|
|
|
- var item = inActions[ i ];
|
|
|
-
|
|
|
- var args = item.args;
|
|
|
- var action = item.action;
|
|
|
-
|
|
|
- if ( action === 'moveTo' ) {
|
|
|
-
|
|
|
- if ( lastPath.actions.length !== 0 ) {
|
|
|
-
|
|
|
- subPaths.push( lastPath );
|
|
|
- lastPath = new THREE.Path();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- lastPath[ action ].apply( lastPath, args );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( lastPath.actions.length !== 0 ) {
|
|
|
-
|
|
|
- subPaths.push( lastPath );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // console.log(subPaths);
|
|
|
-
|
|
|
- return subPaths;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
function toShapesNoHoles( inSubpaths ) {
|
|
|
|
|
|
var shapes = [];
|
|
@@ -489,15 +178,12 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
var tmpPath = inSubpaths[ i ];
|
|
|
|
|
|
var tmpShape = new THREE.Shape();
|
|
|
- tmpShape.actions = tmpPath.actions;
|
|
|
tmpShape.curves = tmpPath.curves;
|
|
|
|
|
|
shapes.push( tmpShape );
|
|
|
|
|
|
}
|
|
|
|
|
|
- //console.log("shape", shapes);
|
|
|
-
|
|
|
return shapes;
|
|
|
|
|
|
}
|
|
@@ -563,7 +249,7 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
var isClockWise = THREE.ShapeUtils.isClockWise;
|
|
|
|
|
|
- var subPaths = extractSubpaths( this.actions );
|
|
|
+ var subPaths = this.subPaths;
|
|
|
if ( subPaths.length === 0 ) return [];
|
|
|
|
|
|
if ( noHoles === true ) return toShapesNoHoles( subPaths );
|
|
@@ -575,7 +261,6 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
|
|
|
tmpPath = subPaths[ 0 ];
|
|
|
tmpShape = new THREE.Shape();
|
|
|
- tmpShape.actions = tmpPath.actions;
|
|
|
tmpShape.curves = tmpPath.curves;
|
|
|
shapes.push( tmpShape );
|
|
|
return shapes;
|
|
@@ -608,7 +293,6 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
|
|
|
|
|
|
newShapes[ mainIdx ] = { s: new THREE.Shape(), p: tmpPoints };
|
|
|
- newShapes[ mainIdx ].s.actions = tmpPath.actions;
|
|
|
newShapes[ mainIdx ].s.curves = tmpPath.curves;
|
|
|
|
|
|
if ( holesFirst ) mainIdx ++;
|
|
@@ -709,5 +393,4 @@ THREE.Path.prototype = Object.assign( Object.create( THREE.CurvePath.prototype )
|
|
|
return shapes;
|
|
|
|
|
|
}
|
|
|
-
|
|
|
-} );
|
|
|
+}
|