123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Defines a 2d shape plane using paths.
- **/
- // STEP 1 Create a path.
- // STEP 2 Turn path into shape.
- // STEP 3 ExtrudeGeometry takes in Shape/Shapes
- // STEP 3a - Extract points from each shape, turn to vertices
- // STEP 3b - Triangulate each shape, add faces.
- THREE.Shape = function ( ) {
- THREE.Path.apply( this, arguments );
- this.holes = [];
- };
- THREE.Shape.prototype = new THREE.Path();
- THREE.Shape.prototype.constructor = THREE.Path;
- // Convenience method to return ExtrudeGeometry
- THREE.Shape.prototype.extrude = function ( options ) {
- var extruded = new THREE.ExtrudeGeometry( this, options );
- return extruded;
- };
- // Get points of holes
- THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
- var i, il = this.holes.length, holesPts = [];
- for ( i = 0; i < il; i ++ ) {
- holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );
- }
- return holesPts;
- };
- // Get points of holes (spaced by regular distance)
- THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
- var i, il = this.holes.length, holesPts = [];
- for ( i = 0; i < il; i ++ ) {
- holesPts[ i ] = this.holes[ i ].getSpacedPoints( divisions, this.bends );
- }
- return holesPts;
- };
- // Get points of shape and holes (keypoints based on segments parameter)
- THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
- return {
- shape: this.getTransformedPoints( divisions ),
- holes: this.getPointsHoles( divisions )
- };
- };
- //
- // THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
- //
- // return {
- //
- // shape: this.transform( bend, divisions ),
- // holes: this.getPointsHoles( divisions, bend )
- //
- // };
- //
- // };
- // Get points of shape and holes (spaced by regular distance)
- THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
- return {
- shape: this.getTransformedSpacedPoints( divisions ),
- holes: this.getSpacedPointsHoles( divisions )
- };
- };
- /**************************************************************
- * Utils
- **************************************************************/
- THREE.Shape.Utils = {
- /*
- contour - array of vector2 for contour
- holes - array of array of vector2
- */
- removeHoles: function ( contour, holes ) {
- var shape = contour.concat(); // work on this shape
- var allpoints = shape.concat();
- /* For each isolated shape, find the closest points and break to the hole to allow triangulation */
- var prevShapeVert, nextShapeVert,
- prevHoleVert, nextHoleVert,
- holeIndex, shapeIndex,
- shapeId, shapeGroup,
- h, h2,
- hole, shortest, d,
- p, pts1, pts2,
- tmpShape1, tmpShape2,
- tmpHole1, tmpHole2,
- verts = [];
- for ( h = 0; h < holes.length; h++ ) {
- hole = holes[ h ];
- /*
- shapeholes[ h ].concat(); // preserves original
- holes.push( hole );
- */
- allpoints = allpoints.concat( hole );
- shortest = Number.POSITIVE_INFINITY;
-
- // Find the shortest pair of pts between shape and hole
- // Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n)
- // Using distanceToSquared() intead of distanceTo() should speed a little
- // since running square roots operations are reduced.
-
- for ( h2 = 0; h2 < hole.length; h2 ++ ) {
- pts1 = hole[ h2 ];
- var dist = [];
- for ( p = 0; p < shape.length; p++ ) {
- pts2 = shape[ p ];
- d = pts1.distanceToSquared( pts2 );
- dist.push( d );
- if ( d < shortest ) {
- shortest = d;
- holeIndex = h2;
- shapeIndex = p;
- }
- }
- }
- //console.log("shortest", shortest, dist);
- prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
- prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
- var areaapts = [
- hole[ holeIndex ],
- shape[ shapeIndex ],
- shape[ prevShapeVert ]
- ];
- var areaa = THREE.FontUtils.Triangulate.area( areaapts );
- var areabpts = [
- hole[ holeIndex ],
- hole[ prevHoleVert ],
- shape[ shapeIndex ]
- ];
- var areab = THREE.FontUtils.Triangulate.area( areabpts );
- var shapeOffset = 1;
- var holeOffset = -1;
- var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex;
- shapeIndex += shapeOffset;
- holeIndex += holeOffset;
- if ( shapeIndex < 0 ) { shapeIndex += shape.length; }
- shapeIndex %= shape.length;
- if ( holeIndex < 0 ) { holeIndex += hole.length; }
- holeIndex %= hole.length;
- prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
- prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
- areaapts = [
- hole[ holeIndex ],
- shape[ shapeIndex ],
- shape[ prevShapeVert ]
- ];
- var areaa2 = THREE.FontUtils.Triangulate.area( areaapts );
- areabpts = [
- hole[ holeIndex ],
- hole[ prevHoleVert ],
- shape[ shapeIndex ]
- ];
- var areab2 = THREE.FontUtils.Triangulate.area( areabpts );
- //console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ), ( areaa2 + areab2 ));
- if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) {
- // In case areas are not correct.
- //console.log("USE THIS");
- shapeIndex = oldShapeIndex;
- holeIndex = oldHoleIndex ;
- if ( shapeIndex < 0 ) { shapeIndex += shape.length; }
- shapeIndex %= shape.length;
- if ( holeIndex < 0 ) { holeIndex += hole.length; }
- holeIndex %= hole.length;
- prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
- prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
- } else {
- //console.log("USE THAT ")
- }
- tmpShape1 = shape.slice( 0, shapeIndex );
- tmpShape2 = shape.slice( shapeIndex );
- tmpHole1 = hole.slice( holeIndex );
- tmpHole2 = hole.slice( 0, holeIndex );
- // Should check orders here again?
- var trianglea = [
- hole[ holeIndex ],
- shape[ shapeIndex ],
- shape[ prevShapeVert ]
- ];
- var triangleb = [
- hole[ holeIndex ] ,
- hole[ prevHoleVert ],
- shape[ shapeIndex ]
- ];
- verts.push( trianglea );
- verts.push( triangleb );
- shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
- }
- return {
- shape:shape, /* shape with no holes */
- isolatedPts: verts, /* isolated faces */
- allpoints: allpoints
- }
- },
- triangulateShape: function ( contour, holes ) {
- var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes );
- var shape = shapeWithoutHoles.shape,
- allpoints = shapeWithoutHoles.allpoints,
- isolatedPts = shapeWithoutHoles.isolatedPts;
- var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape
- // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
- //console.log( "triangles",triangles, triangles.length );
- //console.log( "allpoints",allpoints, allpoints.length );
- var i, il, f, face,
- key, index,
- allPointsMap = {},
- isolatedPointsMap = {};
- // prepare all points map
- for ( i = 0, il = allpoints.length; i < il; i ++ ) {
- key = allpoints[ i ].x + ":" + allpoints[ i ].y;
- if ( allPointsMap[ key ] !== undefined ) {
- console.log( "Duplicate point", key );
- }
- allPointsMap[ key ] = i;
- }
- // check all face vertices against all points map
- for ( i = 0, il = triangles.length; i < il; i ++ ) {
- face = triangles[ i ];
- for ( f = 0; f < 3; f ++ ) {
- key = face[ f ].x + ":" + face[ f ].y;
- index = allPointsMap[ key ];
- if ( index !== undefined ) {
- face[ f ] = index;
- }
- }
- }
- // check isolated points vertices against all points map
- for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {
- face = isolatedPts[ i ];
- for ( f = 0; f < 3; f ++ ) {
- key = face[ f ].x + ":" + face[ f ].y;
- index = allPointsMap[ key ];
- if ( index !== undefined ) {
- face[ f ] = index;
- }
- }
- }
- return triangles.concat( isolatedPts );
- }, // end triangulate shapes
- /*
- triangulate2 : function( pts, holes ) {
- // For use with Poly2Tri.js
- var allpts = pts.concat();
- var shape = [];
- for (var p in pts) {
- shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y));
- }
- var swctx = new js.poly2tri.SweepContext(shape);
- for (var h in holes) {
- var aHole = holes[h];
- var newHole = []
- for (i in aHole) {
- newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y));
- allpts.push(aHole[i]);
- }
- swctx.AddHole(newHole);
- }
- var find;
- var findIndexForPt = function (pt) {
- find = new THREE.Vector2(pt.x, pt.y);
- var p;
- for (p=0, pl = allpts.length; p<pl; p++) {
- if (allpts[p].equals(find)) return p;
- }
- return -1;
- };
- // triangulate
- js.poly2tri.sweep.Triangulate(swctx);
- var triangles = swctx.GetTriangles();
- var tr ;
- var facesPts = [];
- for (var t in triangles) {
- tr = triangles[t];
- facesPts.push([
- findIndexForPt(tr.GetPoint(0)),
- findIndexForPt(tr.GetPoint(1)),
- findIndexForPt(tr.GetPoint(2))
- ]);
- }
- // console.log(facesPts);
- // console.log("triangles", triangles.length, triangles);
- // Returns array of faces with 3 element each
- return facesPts;
- },
- */
- isClockWise: function ( pts ) {
- return THREE.FontUtils.Triangulate.area( pts ) < 0;
- },
- // Bezier Curves formulas obtained from
- // http://en.wikipedia.org/wiki/B%C3%A9zier_curve
- // Quad Bezier Functions
- b2p0: function ( t, p ) {
- var k = 1 - t;
- return k * k * p;
- },
- b2p1: function ( t, p ) {
- return 2 * ( 1 - t ) * t * p;
- },
- b2p2: function ( t, p ) {
- return t * t * p;
- },
- b2: function ( t, p0, p1, p2 ) {
- return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
- },
- // Cubic Bezier Functions
- b3p0: function ( t, p ) {
- var k = 1 - t;
- return k * k * k * p;
- },
- b3p1: function ( t, p ) {
- var k = 1 - t;
- return 3 * k * k * t * p;
- },
- b3p2: function ( t, p ) {
- var k = 1 - t;
- return 3 * k * t * t * p;
- },
- b3p3: function ( t, p ) {
- return t * t * t * p;
- },
- b3: function ( t, p0, p1, p2, p3 ) {
- return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );
- }
- };
|