Permalink
Cannot retrieve contributors at this time
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 | |
}; | |
} )(); |