Permalink
Cannot retrieve contributors at this time
All your code in one place
GitHub makes it easy to scale back on context switching. Read rendered documentation, see the history of any file, and collaborate with contributors on projects across GitHub.
Sign up for free See pricing for teams and enterprises
Fetching contributors…

'use strict'; | |
if ( ! window.THREE ) throw new Error( 'ERROR: three.js not loaded' ); | |
THREE.Triangulation = ( function() { | |
var timer = false; | |
var library = 'original'; | |
/** | |
* Names of the supported libraries | |
* | |
* @type {{original: string, earcut: string, poly2tri: string, libtess: string}} | |
*/ | |
var libraries = { | |
original: 'original', | |
earcut: 'earcut', | |
poly2tri: 'poly2tri', | |
libtess: 'libtess' | |
}; | |
/** | |
* Container object for holding the different library adapters | |
* | |
* @type {{}} | |
*/ | |
var adapters = {}; | |
adapters[ libraries.original ] = { | |
triangulate: THREE.ShapeUtils.triangulate, | |
triangulateShape: THREE.ShapeUtils.triangulateShape | |
}; | |
adapters[ libraries.earcut ] = { | |
triangulateShape: function( contour, holes ) { | |
var i, il, dim = 2, array; | |
var holeIndices = []; | |
var points = []; | |
addPoints( contour ); | |
for ( i = 0, il = holes.length; i < il; i ++ ) { | |
holeIndices.push( points.length / dim ); | |
addPoints( holes[ i ] ); | |
} | |
array = earcut( points, holeIndices, dim ); | |
var result = []; | |
for ( i = 0, il = array.length; i < il; i += 3 ) { | |
result.push( array.slice( i, i + 3 ) ); | |
} | |
return result; | |
function addPoints( a ) { | |
var i, il = a.length; | |
for ( i = 0; i < il; i ++ ) { | |
points.push( a[ i ].x, a[ i ].y ); | |
} | |
} | |
} | |
}; | |
adapters[ libraries.poly2tri ] = { | |
triangulateShape: function( contour, holes ) { | |
var i, il, object, sweepContext, triangles; | |
var pointMap = {}, count = 0; | |
points = makePoints( contour ); | |
sweepContext = new poly2tri.SweepContext( points ); | |
for ( i = 0, il = holes.length; i < il; i ++ ) { | |
points = makePoints( holes[ i ] ); | |
sweepContext.addHole( points ); | |
points = points.concat( points ); | |
} | |
object = sweepContext.triangulate(); | |
triangles = object.triangles_; | |
var a, b, c, points, result = []; | |
for ( i = 0, il = triangles.length; i < il; i ++ ) { | |
points = triangles[ i ].points_; | |
a = pointMap[ points[ 0 ].x + ',' + points[ 0 ].y ]; | |
b = pointMap[ points[ 1 ].x + ',' + points[ 1 ].y ]; | |
c = pointMap[ points[ 2 ].x + ',' + points[ 2 ].y ]; | |
result.push( [ a, b, c ] ); | |
} | |
return result; | |
function makePoints( a ) { | |
var i, il = a.length, | |
points = []; | |
for ( i = 0; i < il; i ++ ) { | |
points.push( new poly2tri.Point( a[ i ].x, a[ i ].y ) ); | |
pointMap[ a[ i ].x + ',' + a[ i ].y ] = count; | |
count ++; | |
} | |
return points; | |
} | |
} | |
}; | |
adapters[ libraries.libtess ] = { | |
triangulateShape: function( contour, holes ) { | |
var i, il, triangles = []; | |
var pointMap = {}, count = 0; | |
// libtess will take 3d verts and flatten to a plane for tesselation | |
// since only doing 2d tesselation here, provide z=1 normal to skip | |
// iterating over verts only to get the same answer. | |
// comment out to test normal-generation code | |
tessy.gluTessNormal( 0, 0, 1 ); | |
tessy.gluTessBeginPolygon( triangles ); | |
points = makePoints( contour ); | |
for ( i = 0, il = holes.length; i < il; i ++ ) { | |
points = makePoints( holes[ i ] ); | |
} | |
tessy.gluTessEndPolygon(); | |
var a, b, c, points, result = []; | |
for ( i = 0, il = triangles.length; i < il; i += 6 ) { | |
a = pointMap[ triangles[ i ] + ',' + triangles[ i + 1 ]]; | |
b = pointMap[ triangles[ i + 2 ] + ',' + triangles[ i + 3 ]]; | |
c = pointMap[ triangles[ i + 4 ] + ',' + triangles[ i + 5 ]]; | |
result.push( [ a, b, c ] ); | |
} | |
return result; | |
function makePoints( a ) { | |
var i, il = a.length, | |
coordinates; | |
tessy.gluTessBeginContour(); | |
for ( i = 0; i < il; i ++ ) { | |
coordinates = [ a[ i ].x, a[ i ].y, 0 ]; | |
tessy.gluTessVertex( coordinates, coordinates ); | |
pointMap[ a[ i ].x + ',' + a[ i ].y ] = count; | |
count ++; | |
} | |
tessy.gluTessEndContour(); | |
return points; | |
} | |
} | |
}; | |
/** | |
* Initialize the library by attaching the triangulation methods to the three.js API | |
*/ | |
function init() { | |
checkDependencies( library ); | |
if ( timer ) { | |
THREE.ShapeUtils.triangulate = function() { | |
return adapters[ library ].triangulate.apply( this, arguments ); | |
}; | |
THREE.ShapeUtils.triangulateShape = function() { | |
console.time( library ); | |
var result = adapters[ library ].triangulateShape.apply( this, arguments ); | |
console.timeEnd( library ); | |
return result; | |
}; | |
} else { | |
THREE.ShapeUtils.triangulate = adapters[ library ].triangulate; | |
THREE.ShapeUtils.triangulateShape = adapters[ library ].triangulateShape; | |
} | |
} | |
/** | |
* Checks dependencies needed for the current library | |
* | |
* @param library | |
*/ | |
function checkDependencies( library ) { | |
switch ( library ) { | |
case libraries.earcut: | |
if ( ! window.earcut ) throw new Error( 'ERROR: earcut not loaded' ); | |
break; | |
case libraries.poly2tri: | |
if ( ! window.poly2tri ) throw new Error( 'ERROR: poly2tri not loaded' ); | |
break; | |
case libraries.libtess: | |
if ( ! window.tessy ) throw new Error( 'ERROR: libtess not loaded' ); | |
break; | |
} | |
} | |
/** | |
* Set the current triangulation library | |
* | |
* @param name | |
*/ | |
function setLibrary( name ) { | |
if ( ! libraries.hasOwnProperty( name ) ) throw new Error( 'ERROR: unknown library ' + name ); | |
library = name; | |
init(); | |
} | |
/** | |
* Set timer for triangulation on/off | |
* | |
* @param boolean | |
*/ | |
function setTimer( boolean ) { | |
timer = boolean; | |
init(); | |
} | |
init(); | |
return { | |
libraries: libraries, | |
setTimer: setTimer, | |
setLibrary: setLibrary | |
}; | |
} )(); |