Created
July 10, 2011 18:16
-
-
Save zz85/1074794 to your computer and use it in GitHub Desktop.
Prototype Path & Shape & Extrude Geometry Class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author zz85 / http://www.lab4games.net/zz85/blog | |
* Creates free form path. | |
**/ | |
THREE.Path = function (points) { | |
this.path = []; | |
if (points) { | |
this.fromPoints(points); | |
} | |
}; | |
var ACTIONS = { | |
MOVE_TO: 'moveTo', | |
LINE_TO: 'lineTo', | |
QUADRATIC_CURVE_TO: 'quadraticCurveTo', //BEZIER CURVE | |
CUBIC_CURVE_TO: 'bezierCurveTo', //BEZIER CURVE | |
CSPLINE_TO: 'cSplineTo' // TODO cardinal splines | |
}; | |
/* create path using straight lines to connect all points */ | |
THREE.Path.prototype.fromPoints = function(vectors) { | |
var v = 0, vlen = vectors.length; | |
this.moveTo(vectors[0].x, vectors[0].y); | |
for (v=1; v<vlen ;v++) { | |
this.lineTo(vectors[v].x, vectors[v].y); | |
}; | |
}; | |
THREE.Path.prototype.moveTo = function(x,y) { | |
var args = Array.prototype.slice.call(arguments); | |
this.path.push({action:ACTIONS.MOVE_TO, args:args}); | |
}; | |
THREE.Path.prototype.lineTo = function(x,y) { | |
var args = Array.prototype.slice.call(arguments); | |
this.path.push({action:ACTIONS.LINE_TO, args:args}); | |
}; | |
THREE.Path.prototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { | |
var args = Array.prototype.slice.call(arguments); | |
this.path.push({action:ACTIONS.QUADRATIC_CURVE_TO, args:args}); | |
}; | |
THREE.Path.prototype.bezierCurveTo = function(aCP1x, aCP1y, | |
aCP2x, aCP2y, | |
aX, aY) { | |
var args = Array.prototype.slice.call(arguments); | |
this.path.push({action:ACTIONS.CUBIC_CURVE_TO, args:args}); | |
}; | |
/* Return an array of vectors based on contour of the path */ | |
THREE.Path.prototype.getPoints = function(divisions) { | |
divisions = divisions || 2; | |
var pts = []; | |
var x,o, args; | |
for (x in this.path) { | |
o = this.path[x]; | |
args = o.args; | |
switch( action = o.action ) { | |
case ACTIONS.MOVE_TO: | |
//pts.push( new THREE.Vector2( args[0], args[1] ) ); | |
break; | |
case ACTIONS.LINE_TO: | |
pts.push( new THREE.Vector2( args[0], args[1] ) ); | |
break; | |
case ACTIONS.QUADRATIC_CURVE_TO: | |
var cpx, cpy, cpx1, cpy1, cpx0, cpy0; | |
cpx = args[2]; | |
cpy = args[3]; | |
cpx1 = args[0]; | |
cpy1 = args[1]; | |
laste = pts[ pts.length - 1 ]; | |
if ( laste ) { | |
cpx0 = laste.x; | |
cpy0 = laste.y; | |
for ( i2 = 1; i2 <= divisions; i2++ ) { | |
// TODO use LOD for divions | |
var t = i2 / divisions; | |
var tx = THREE.FontUtils.b2( t, cpx0, cpx1, cpx ); | |
var ty = THREE.FontUtils.b2( t, cpy0, cpy1, cpy ); | |
pts.push( new THREE.Vector2( tx, ty ) ); | |
} | |
} | |
break; | |
case CUBIC_CURVE_TO: | |
cpx = args[4]; | |
cpy = args[5]; | |
cpx1 = args[0]; | |
cpy1 = args[1]; | |
cpx2 = args[2]; | |
cpy2 = args[3]; | |
laste = pts[ pts.length - 1 ]; | |
if ( laste ) { | |
cpx0 = laste.x; | |
cpy0 = laste.y; | |
for ( i2 = 1; i2 <= divisions; i2++ ) { | |
var t = i2 / divisions; | |
var tx = THREE.FontUtils.b3( t, cpx0, cpx1, cpx2, cpx ); | |
var ty = THREE.FontUtils.b3( t, cpy0, cpy1, cpy2, cpy ); | |
pts.push( new THREE.Vector2( tx, ty ) ); | |
} | |
} | |
break; | |
} | |
} | |
return pts; | |
}; | |
// FutureTODO getMax/min Pts. | |
/* Draws this path onto a 2d canvas easily */ | |
THREE.Path.prototype.debug = function(canvas) { | |
// JUST A STUB | |
if (!canvas) { | |
canvas = document.createElement("canvas"); | |
canvas.setAttribute('width', 200); | |
canvas.setAttribute('height', 200); | |
document.body.appendChild(canvas); | |
} | |
var ctx = canvas.getContext("2d"); | |
ctx.fillStyle = "white"; | |
ctx.fillRect(0,0,200,200); | |
ctx.strokeStyle = "black"; | |
ctx.beginPath(); | |
var i,o, a; | |
// Debug Path | |
for (i in this.path) { | |
o = this.path[i]; | |
a = o.args; | |
// Short hand for now | |
ctx[o.action].apply(ctx, a); | |
/* | |
switch (o.action) { | |
case ACTIONS.MOVE_TO: | |
ctx[o.action](a[0],a[1]); | |
break; | |
case ACTIONS.LINE_TO: | |
ctx[o.action](a[0],a[1]); | |
break; | |
case ACTIONS.QUADRATIC_CURVE_TO: | |
ctx[o.action](a[0],a[1],a[2],a[3]); | |
break; | |
case ACTIONS.CUBIC_CURVE_TO: | |
ctx[o.action](a[0],a[1],a[2],a[3], a[4], a[5]); | |
break; | |
}*/ | |
} | |
ctx.stroke(); | |
ctx.closePath(); | |
// DebugPoints | |
ctx.strokeStyle = "red"; | |
var pts = this.getPoints(); | |
for (var p in pts) { | |
ctx.beginPath(); | |
ctx.arc(pts[p].x,pts[p].y, 1.5,0, Math.PI*2, false); | |
ctx.stroke(); | |
ctx.closePath(); | |
} | |
}; | |
// STEP 1 Create a path. | |
// STEP 2 Turn path into shape. | |
// STEP 3 Extrude Geometry takes in Shape/Shapes | |
// STEP 3a - Extract points from each shape, turn to Vertics | |
// STEP 3b - Triangulate Each Shape | |
/* Defines a 2d shape plane using paths */ | |
THREE.Shape = function ( ) { | |
THREE.Path.apply( this, arguments); | |
this.holes = []; | |
}; | |
THREE.Shape.prototype = new THREE.Path(); | |
THREE.Shape.prototype.constructor = THREE.Path; | |
/* Returns vertices of triangulated faces | get faces */ | |
THREE.Shape.prototype.triangulate = function() { | |
return THREE.FontUtils.Triangulate( this.getPoints(), true ); | |
}; | |
/* Convienence Method to return ExtrudeGeometry */ | |
THREE.Shape.prototype.extrude = function(options) { | |
var extruded = new THREE.ExtrudeGeometry(this, options); | |
return extruded; | |
}; | |
THREE.ExtrudeGeometry = function(shape, options) { | |
var amount; | |
if (!options.amount) { | |
amount = 100; | |
} else { | |
amount = options.amount; | |
} | |
THREE.Geometry.call( this ); | |
vertices = shape.getPoints(); | |
faces = shape.triangulate(); | |
contour = vertices; | |
bezelEnabled = false; | |
var scope = this; | |
var i, | |
vert, vlen = vertices.length, | |
face, flen = faces.length; | |
// Back facing vertices | |
for ( i = 0; i < vlen; i++ ) { | |
vert = vertices[ i ]; | |
v( vert.x, vert.y, 0 ); | |
} | |
// Front facing vertices | |
for ( i = 0; i < vlen; i++ ) { | |
vert = vertices[ i ]; | |
v( vert.x, vert.y, amount ); | |
} | |
if ( bezelEnabled ) { | |
for ( i = 0; i < blen; i++ ) { | |
bezelPt = bezelPoints[ i ]; | |
v( bezelPt.x, bezelPt.y, bezelThickness ); | |
} | |
for ( i = 0; i < blen; i++ ) { | |
bezelPt = bezelPoints[ i ]; | |
v( bezelPt.x, bezelPt.y, amount - bezelThickness ); | |
} | |
} | |
// Bottom faces | |
for ( i = 0; i < flen; i++ ) { | |
face = faces[ i ]; | |
f3( face[ 2 ], face[ 1 ], face[ 0 ] ); | |
} | |
// Top faces | |
for ( i = 0; i < flen; i++ ) { | |
face = faces[ i ]; | |
f3( face[ 0 ] + vlen, face[ 1 ] + vlen, face[ 2 ] + vlen ); | |
} | |
var lastV; | |
var j, k, l, m; | |
if ( bezelEnabled ) { | |
i = bezelPoints.length; | |
while ( --i > 0 ) { | |
if ( !lastV ) { | |
lastV = contour[ i ]; | |
} else if ( lastV.equals( contour[ i ] ) ) { | |
// We reached the last point of a closed loop | |
lastV = null; | |
continue; | |
} | |
l = vlen * 2 + i; | |
m = l - 1; | |
// Create faces for the z-sides of the text | |
f4( l, m, m + blen, l + blen ); | |
for ( j = 0; j < vlen; j++ ) { | |
if ( vertices[ j ].equals( contour[ i ] ) ) break; | |
} | |
for ( k = 0; k < vlen; k++ ) { | |
if ( vertices[ k ].equals( contour[ i - 1 ] ) ) break; | |
} | |
// Create faces for the z-sides of the text | |
f4( j, k, m, l ); | |
f4( l + blen, m + blen, k + vlen, j + vlen ); | |
} | |
} else { | |
i = contour.length; | |
while ( --i > 0 ) { | |
if ( !lastV ) { | |
lastV = contour[ i ]; | |
} else if ( lastV.equals( contour[ i ] ) ) { | |
// We reached the last point of a closed loop | |
lastV = null; | |
continue; | |
} | |
for ( j = 0; j < vlen; j++ ) { | |
if ( vertices[ j ].equals( contour[ i ] ) ) break; | |
} | |
for ( k = 0; k < vlen; k++ ) { | |
if ( vertices[ k ].equals( contour[ i - 1 ] ) ) break; | |
} | |
// Create faces for the z-sides of the text | |
f4( j, k, k + vlen, j + vlen ); | |
} | |
} | |
// UVs to be added | |
this.computeCentroids(); | |
this.computeFaceNormals(); | |
//this.computeVertexNormals(); | |
function v( x, y, z ) { | |
scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) ); | |
} | |
function f3( a, b, c ) { | |
scope.faces.push( new THREE.Face3( a, b, c) ); | |
} | |
function f4( a, b, c, d ) { | |
scope.faces.push( new THREE.Face4( a, b, c, d) ); | |
} | |
}; | |
THREE.ExtrudeGeometry.prototype = new THREE.Geometry(); | |
THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment