diff --git a/examples/webgl_geometry_extrude_shapes2.html b/examples/webgl_geometry_extrude_shapes2.html index c5b14f58bc46d2f91f0b81c1dab4a54c6a936a96..514cdc974a6e7e3a045abff0992767515f2fef98 100644 --- a/examples/webgl_geometry_extrude_shapes2.html +++ b/examples/webgl_geometry_extrude_shapes2.html @@ -44,7 +44,7 @@ const DIGIT_0 = 48, DIGIT_9 = 57, COMMA = 44, SPACE = 32, PERIOD = 46, MINUS = 4 exports.transformSVGPath = function transformSVGPath(pathStr) { - var path = new THREE.Shape(); + var path = new THREE.ShapePath(); var idx = 1, len = pathStr.length, activeCmd, x = 0, y = 0, nx = 0, ny = 0, firstX = null, firstY = null, diff --git a/src/extras/ShapeUtils.js b/src/extras/ShapeUtils.js index cfaee11c39f5a9244d75be74701be167a383c126..d3e0b214351fad9d7929a387e8328df869436d73 100644 --- a/src/extras/ShapeUtils.js +++ b/src/extras/ShapeUtils.js @@ -628,7 +628,7 @@ THREE.ShapeUtils = { if ( allPointsMap[ key ] !== undefined ) { - console.warn( "THREE.Shape: Duplicate point", key ); + console.warn( "THREE.ShapeUtils: Duplicate point", key, i ); } diff --git a/src/extras/core/CurvePath.js b/src/extras/core/CurvePath.js index f6246c78998236af2f3f0a05b71467897642afba..e3b074ca680e90561c784382cbad151c923e45c9 100644 --- a/src/extras/core/CurvePath.js +++ b/src/extras/core/CurvePath.js @@ -28,8 +28,6 @@ THREE.CurvePath.prototype = Object.assign( Object.create( THREE.Curve.prototype closePath: function () { - // TODO Test - // and verify for vector3 (needs to implement equals) // Add a line curve if start and end of lines are not connected var startPoint = this.curves[ 0 ].getPoint( 0 ); var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); @@ -66,7 +64,8 @@ THREE.CurvePath.prototype = Object.assign( Object.create( THREE.Curve.prototype var diff = curveLengths[ i ] - d; var curve = this.curves[ i ]; - var u = 1 - diff / curve.getLength(); + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; return curve.getPointAt( u ); @@ -133,6 +132,66 @@ THREE.CurvePath.prototype = Object.assign( Object.create( THREE.Curve.prototype }, + getSpacedPoints: function ( divisions ) { + + if ( ! divisions ) divisions = 40; + + var points = []; + + for ( var i = 0; i <= divisions; i ++ ) { + + points.push( this.getPoint( i / divisions ) ); + + } + + if ( this.autoClose ) { + + points.push( points[ 0 ] ); + + } + + return points; + + }, + + getPoints: function ( divisions ) { + + divisions = divisions || 12; + + var points = [], tmp, last, curve; + + for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { + + curve = curves[i]; + var pts = curve.getPoints( curve instanceof THREE.LineCurve ? 1 : divisions ); + + for ( var j = 0; j < pts.length; j++ ) { + + var tmp = pts[ j ]; + if ( last && last.equals( tmp ) ) continue; // ensures no consecutive points are duplicates + points.push( tmp ); + last = tmp; + + } + + } + + if ( points[ points.length - 1 ].equals( points[ 0 ] ) ) { + + points.pop(); + + } + + if ( this.autoClose ) { + + points.push( points[ 0 ] ); + + } + + return points; + + }, + /************************************************************** * Create Geometries Helpers **************************************************************/ diff --git a/src/extras/core/Font.js b/src/extras/core/Font.js index 4705eff738040b841fab2652296e724b85c6127c..4f13af583d7e87c96fb1c66b05a90794a7dbf186 100644 --- a/src/extras/core/Font.js +++ b/src/extras/core/Font.js @@ -40,7 +40,7 @@ Object.assign( THREE.Font.prototype, { if ( ! glyph ) return; - var path = new THREE.Path(); + var path = new THREE.ShapePath(); var pts = [], b2 = THREE.ShapeUtils.b2, b3 = THREE.ShapeUtils.b3; var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste; diff --git a/src/extras/core/Path.js b/src/extras/core/Path.js index 3635d637857d1b61bb021c15af0d66ed7ec91931..c2246e3a7620ba0aa34f68ce7d2011152b6cd8f1 100644 --- a/src/extras/core/Path.js +++ b/src/extras/core/Path.js @@ -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; } - -} ); +} diff --git a/src/extras/curves/EllipseCurve.js b/src/extras/curves/EllipseCurve.js index 2ecbd59b539b58619d06d66e3fb5e94f77a9ddc1..463faf3f16b1bdb89eb19a5b6af8a8c21bfeec82 100644 --- a/src/extras/curves/EllipseCurve.js +++ b/src/extras/curves/EllipseCurve.js @@ -2,7 +2,7 @@ * Ellipse curve **************************************************************/ -THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { +THREE.EllipseCurve = function( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { this.aX = aX; this.aY = aY; @@ -14,7 +14,7 @@ THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle this.aEndAngle = aEndAngle; this.aClockwise = aClockwise; - + this.aRotation = aRotation || 0; }; @@ -22,25 +22,37 @@ THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; -THREE.EllipseCurve.prototype.getPoint = function ( t ) { +THREE.EllipseCurve.prototype.getPoint = function( t ) { + var twoPi = Math.PI * 2; var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; - if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; + if ( deltaAngle < Number.EPSILON ) { - var angle; + if ( samePoints ) { - if ( this.aClockwise === true ) { + deltaAngle = 0; - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + } else { - } else { + deltaAngle = twoPi; - angle = this.aStartAngle + t * deltaAngle; + } } - + + if ( this.aClockwise === true && deltaAngle != twoPi && ! samePoints ) { + + deltaAngle = deltaAngle - twoPi; + + } + + var angle = this.aStartAngle + t * deltaAngle; var x = this.aX + this.xRadius * Math.cos( angle ); var y = this.aY + this.yRadius * Math.sin( angle ); @@ -49,11 +61,12 @@ THREE.EllipseCurve.prototype.getPoint = function ( t ) { var cos = Math.cos( this.aRotation ); var sin = Math.sin( this.aRotation ); - var tx = x, ty = y; + var tx = x - this.aX; + var ty = y - this.aY; // Rotate the point about the center of the ellipse. - x = ( tx - this.aX ) * cos - ( ty - this.aY ) * sin + this.aX; - y = ( tx - this.aX ) * sin + ( ty - this.aY ) * cos + this.aY; + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; } diff --git a/src/extras/curves/LineCurve.js b/src/extras/curves/LineCurve.js index 2ae2bca9cbc82e66ec0cc97cf7d0d14e7a330ac9..e4326886d3606c5ae267372039778aacaf967db6 100644 --- a/src/extras/curves/LineCurve.js +++ b/src/extras/curves/LineCurve.js @@ -14,6 +14,12 @@ THREE.LineCurve.prototype.constructor = THREE.LineCurve; THREE.LineCurve.prototype.getPoint = function ( t ) { + if ( t === 1 ) { + + return this.v2.clone(); + + } + var point = this.v2.clone().sub( this.v1 ); point.multiplyScalar( t ).add( this.v1 ); diff --git a/src/extras/curves/LineCurve3.js b/src/extras/curves/LineCurve3.js index 16df3d18a3b3507e4f5b994a75c9f34a905ffcec..0f6fcd3b88f5770caa4c6abe60a47ca8692bf3ef 100644 --- a/src/extras/curves/LineCurve3.js +++ b/src/extras/curves/LineCurve3.js @@ -13,6 +13,12 @@ THREE.LineCurve3 = THREE.Curve.create( function ( t ) { + if ( t === 1 ) { + + return this.v2.clone(); + + } + var vector = new THREE.Vector3(); vector.subVectors( this.v2, this.v1 ); // diff