zz85 14 years ago
parent
commit
b287fd1d86
2 changed files with 274 additions and 88 deletions
  1. 221 0
      src/extras/geometries/Curve.js
  2. 53 88
      src/extras/geometries/Path.js

+ 221 - 0
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 (i<il) {
+		if (lengths[i]>distanceForU) 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)
+*/

+ 53 - 88
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 <d
 };
 
 // Compute Lengths and Cache Them
 THREE.Path.prototype.getLength = function() {
 	// Loop all actions/path
 	// Push sums into cached array
+	var lengths = [], sums = 0;
+	var i=0, il = this.actions.length, curve;
+	for (;i<il;i++) {
+		curve = this.actions[il].curve;
+		if (curve) {
+			sums += curve.getLength();
+			lengths.push(sums);
+		} else {
+			lengths.push(0);
+		}
+		
+	}
+	return sums;
+	
 };
 
-THREE.Line = function (x1, y1, x2, y2) {
-	this.x1 = x1;
-	this.y1 = y1;
-	this.x2 = x2;
-	this.y2 = y2;
-};
-
-THREE.Line.prototype.getPoints(divisions) {
-	if (!divisions) divisions = 200;
-	var d, pts = [];
-	for (d=0;d<divisions;d++) {
-		pts.push(this.getPoint(d/divisions));
-	};
-	return pts;
-};
-
-
-/*
-curve.getPoints();
-curve.getPoint(t);
-curve.getPointAtArcLength(t);
-curve.transform(params);
-curve.getTangentAt(t)
-*/
-
 // ALL THINGS BELOW TO BE REFACTORED
 // QN: Transform final pts or transform ACTIONS or add transform filters?
-THREE.Path.prototype.getPoint = function(t) {
-	var x0, y0, x1, y1, x2, y2;
-	x0 = this.actions[0].args[0];
-	y0 = this.actions[0].args[1];
-	x1 = this.actions[1].args[0];
-	y1 = this.actions[1].args[1];
-	x2 = this.actions[1].args[2];
-	y2 = this.actions[1].args[3];
-	
-	var tx, ty;
-	
-	tx = THREE.FontUtils.b2( t, x0, x1, x2 );
-	ty = THREE.FontUtils.b2( t, y0, y1, y2 );
-	
-	return new THREE.Vector2( tx, ty );
-};
 
 THREE.Path.prototype.getNormalVector = function(t) {
 	// iterate sub segments
@@ -454,48 +461,6 @@ THREE.Path.prototype.getNormalVector = function(t) {
 	
 };
 
-THREE.Path.prototype.cacheArcLengths = function() {
-	var divisions = 200;
-	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.arcLengthCache = cache;
-	return {sums: cache, sum:sum};
-	
-};
-
-/* Given u (0..1), get a t to find p. This gives you pt which are equi distance */
-
-THREE.Path.prototype.getUtoTmapping = function(u, distance) {
-	
-	//var arcs = this.cacheArcLengths();
-	var cache = this.arcLengthCache; 
-	var i = 0,il = cache.length;
-	
-	var distanceForU = u * cache[cache.length-1];
-	if (distance) distanceForU = distance;
-	
-	// Should do binary search + sub division + interpolation if needed
-	while (i<il) {
-		if (cache[i]>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 ) ;
 }