diff --git a/src/extras/geometries/Curve.js b/src/extras/geometries/Curve.js new file mode 100644 index 0000000000000000000000000000000000000000..f173242e483cc53ee7a1b3d3323671ce55b1484c --- /dev/null +++ b/src/extras/geometries/Curve.js @@ -0,0 +1,221 @@ +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible Curve Object + * + **/ + +THREE.Curve = function() { + +}; + +/* Basic function to overwrite and implement */ +THREE.Curve.prototype.getPoint = function ( t /* between 0 .. 1 */) { + console.log("Warning, getPoint() not implemented!"); + return null; +}; + +/* getPointAt returns as a porportion of arc length instead of formula */ +THREE.Curve.prototype.getPointAt = function ( u /* between 0 .. 1 */) { + var t = this.getUtoTmapping(u); + return this.getPoint(t); +}; + +/* Get Points using getPoint(t) */ +THREE.Curve.prototype.getPoints = function (divisions) { + if (!divisions) divisions = 5; + var d, pts = []; + for (d=0;d<=divisions;d++) { + pts.push(this.getPoint(d/divisions)); + }; + return pts; +}; + +/* Get Points using getPointAt(u) */ +THREE.Curve.prototype.getSpacedPoints = function (divisions) { + if (!divisions) divisions = 5; + var d, pts = []; + for (d=0;d<=divisions;d++) { + pts.push(this.getPointAt(d/divisions)); + }; + return pts; +}; + +THREE.Curve.prototype.getLength = function () { + var lengths = this.getLengths(); + return lengths[lengths.length-1]; +}; + +THREE.Curve.prototype.getLengths = function(divisions) { + if (!divisions) divisions = 200; + + if (this.cacheLengths && (this.cacheLengths.length==divisions)) { + console.log("catched",this.cacheLengths); + return this.cacheLengths; + } + + var cache = []; + var p=1; + var last = this.getPoint(0), current; + var sum = 0; + + for (; p <= divisions; p++) { + current = this.getPoint (p/divisions); + sum += current.distanceTo(last); + cache.push(sum); + last = current; + } + + this.cacheLengths = cache; + return cache; //{sums: cache, sum:sum}; Sum is in the last element. +}; + +/* Given u (0..1), get a t to find p. This gives you pt which are equi distance */ + +THREE.Curve.prototype.getUtoTmapping = function(u, distance) { + + var lengths = this.getLengths(); + var i = 0,il = lengths.length; + + var distanceForU; + if (distance) { + distanceForU = distance; + } else { + distanceForU = u * lengths[il-1]; + } + + // TODO Should do binary search + sub division + interpolation when needed + while (idistanceForU) break; + i++; + } + + var t= i/il; + return t; + +}; + + + +THREE.StraightCurve = function (x1, y1, x2, y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; +}; + +THREE.StraightCurve.prototype = new THREE.Curve(); +THREE.StraightCurve.prototype.constructor = THREE.StraightCurve; + +/* Basic function to overwrite and implement */ +THREE.StraightCurve.prototype.getPoint = function ( t /* between 0 .. 1 */) { + var dx = this.x2 - this.x1; + var dy = this.y2 - this.y1; + var tx = this.x1 + dx * t; + var ty = this.y1 + dy * t; + + return new THREE.Vector2( tx, ty ); +}; + +THREE.QuadraticBezierCurve = function ( x0, y0, x1, y1, x2, y2 ) { + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; +}; + +THREE.QuadraticBezierCurve.prototype = new THREE.Curve(); +THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; + +/* Basic function to overwrite and implement */ +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t /* between 0 .. 1 */) { + var tx, ty; + + tx = THREE.FontUtils.b2( t, this.x0, this.x1, this.x2 ); + ty = THREE.FontUtils.b2( t, this.y0, this.y1, this.y2 ); + + return new THREE.Vector2( tx, ty ); +}; + +THREE.CubicBezierCurve = function ( x0, y0, x1, y1, x2, y2, x3, y3 ) { + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + this.x3 = x3; + this.y3 = y3; +}; +THREE.CubicBezierCurve.prototype = new THREE.Curve(); +THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; + +/* Basic function to overwrite and implement */ +THREE.CubicBezierCurve.prototype.getPoint = function ( t /* between 0 .. 1 */) { + var tx, ty; + + tx = THREE.FontUtils.b2( t, this.x0, this.x1, this.x2 ); + ty = THREE.FontUtils.b2( t, this.y0, this.y1, this.y2 ); + + return new THREE.Vector2( tx, ty ); +}; + +THREE.SplineCurve = function ( points ) { + this.points = points; +}; + +THREE.SplineCurve.prototype = new THREE.Curve(); +THREE.SplineCurve.prototype.constructor = THREE.CubicBezierCurve; + + + +/* Basic function to overwrite and implement */ +THREE.SplineCurve.prototype.getPoint = function ( t /* between 0 .. 1 */) { + var v = new THREE.Vector2(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + + return v; + +} + +THREE.Curve.Utils = { + // Catmull-Rom + + interpolate: function( p0, p1, p2, p3, t ) { + + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + } +}; + + + + +/* +getPoint DONE +getLength DONE +getLengths DONE + +curve.getPoints(); DONE +curve.getPointAtArcLength(t); DONE +curve.transform(params); +curve.getTangentAt(t) +*/ \ No newline at end of file diff --git a/src/extras/geometries/Path.js b/src/extras/geometries/Path.js index 5abcea1424f89b504891a31a4acf6ff436c51041..5d95948810cf93313976f6937b9cb8a634cb5602 100644 --- a/src/extras/geometries/Path.js +++ b/src/extras/geometries/Path.js @@ -55,15 +55,29 @@ THREE.Path.prototype.moveTo = function( x, y ) { THREE.Path.prototype.lineTo = function( x, y ) { var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); - + + 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.StraightCurve( x0, y0, x, y ); + + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args, curve:curve } ); + }; THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args }); + + 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( x0, y0, aCPx, aCPy, aX, aY ); + + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args, curve:curve }); + //console.log(curve, curve.getPoints(), curve.getSpacedPoints()); + //console.log(curve.getPointAt(0), curve.getPointAt(0),curve.getUtoTmapping(0), curve.getSpacedPoints()); }; THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, @@ -71,14 +85,31 @@ THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, aX, aY) { var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + + 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( x0, y0, aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ); + + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args, curve:curve }); }; THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + var lastargs = this.actions[ this.actions.length - 1 ].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + pts.unshift(new THREE.Vector2(x0, y0)); + var curve = new THREE.SplineCurve( pts ); + + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args,curve:curve } ); + //console.log(curve, curve.getPoints(), curve.getSpacedPoints()); } @@ -378,57 +409,33 @@ THREE.Path.prototype.createPathGeometry = function(divisions, lineMaterial) { // 3. Get t for the curve // 4. Return curve.getPointAt(t') THREE.Path.prototype.getPoint = function(t) { + var d = t * this.getLength(); + + // loop where sum != 0, sum > d , sum+1 distanceForU) break; - i++; - } - - var t= i/il; - return t; - - -}; - - var tangentQuad = function (t, p0, p1, p2 ) { return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ) ; }