Path.js 15.1 KB
Newer Older
Z
zz85 已提交
1 2
/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
Z
zz85 已提交
3 4
 * Creates free form 2d path using series of points, lines or curves.
 *
Z
zz85 已提交
5 6
 **/

7 8
THREE.Path = function ( points ) {

9
	THREE.CurvePath.call(this);
10 11 12 13 14 15 16

	this.actions = [];

	if ( points ) {

		this.fromPoints( points );

Z
zz85 已提交
17
	}
18

Z
zz85 已提交
19 20
};

21
THREE.Path.prototype = Object.create( THREE.CurvePath.prototype );
22
THREE.Path.prototype.constructor = THREE.Path;
23

24 25
THREE.PathActions = {

Z
zz85 已提交
26 27
	MOVE_TO: 'moveTo',
	LINE_TO: 'lineTo',
Z
zz85 已提交
28 29 30
	QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
	BEZIER_CURVE_TO: 'bezierCurveTo', 		// Bezier cubic curve
	CSPLINE_THRU: 'splineThru',				// Catmull-rom spline
31 32
	ARC: 'arc',								// Circle
	ELLIPSE: 'ellipse'
Z
zz85 已提交
33 34
};

35
// TODO Clean up PATH API
36

37 38
// Create path using straight lines to connect all points
// - vectors: array of Vector2
39

40
THREE.Path.prototype.fromPoints = function ( vectors ) {
41 42 43

	this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );

Z
zz85 已提交
44
	for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {
45 46 47

		this.lineTo( vectors[ v ].x, vectors[ v ].y );

B
brason 已提交
48
	}
49

Z
zz85 已提交
50 51
};

Z
zz85 已提交
52 53
// startPath() endPath()?

54
THREE.Path.prototype.moveTo = function ( x, y ) {
55 56 57 58

	var args = Array.prototype.slice.call( arguments );
	this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );

Z
zz85 已提交
59 60
};

61
THREE.Path.prototype.lineTo = function ( x, y ) {
62 63

	var args = Array.prototype.slice.call( arguments );
64

Z
curves  
zz85 已提交
65
	var lastargs = this.actions[ this.actions.length - 1 ].args;
66

Z
curves  
zz85 已提交
67 68
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
69

70
	var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
Z
zz85 已提交
71
	this.curves.push( curve );
72

73
	this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );
74

Z
zz85 已提交
75 76
};

77 78 79
THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {

	var args = Array.prototype.slice.call( arguments );
80

Z
curves  
zz85 已提交
81
	var lastargs = this.actions[ this.actions.length - 1 ].args;
82

Z
curves  
zz85 已提交
83 84
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
85

86 87 88
	var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
												new THREE.Vector2( aCPx, aCPy ),
												new THREE.Vector2( aX, aY ) );
Z
zz85 已提交
89
	this.curves.push( curve );
90

91
	this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );
92

Z
zz85 已提交
93 94
};

95
THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,
Z
zz85 已提交
96 97
											   aCP2x, aCP2y,
											   aX, aY ) {
98 99

	var args = Array.prototype.slice.call( arguments );
100

Z
curves  
zz85 已提交
101
	var lastargs = this.actions[ this.actions.length - 1 ].args;
102

Z
curves  
zz85 已提交
103 104 105
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

106 107 108 109
	var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),
											new THREE.Vector2( aCP1x, aCP1y ),
											new THREE.Vector2( aCP2x, aCP2y ),
											new THREE.Vector2( aX, aY ) );
Z
zz85 已提交
110
	this.curves.push( curve );
111

112
	this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );
113

Z
zz85 已提交
114 115
};

Z
zz85 已提交
116
THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {
117

Z
zz85 已提交
118
	var args = Array.prototype.slice.call( arguments );
Z
curves  
zz85 已提交
119
	var lastargs = this.actions[ this.actions.length - 1 ].args;
120

Z
curves  
zz85 已提交
121 122
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
Z
zz85 已提交
123
//---
124
	var npts = [ new THREE.Vector2( x0, y0 ) ];
125
	Array.prototype.push.apply( npts, pts );
126

Z
zz85 已提交
127 128
	var curve = new THREE.SplineCurve( npts );
	this.curves.push( curve );
129

130
	this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );
131

132
};
Z
zz85 已提交
133

Z
zz85 已提交
134
// FUTURE: Change the API or follow canvas API?
135

136
THREE.Path.prototype.arc = function ( aX, aY, aRadius,
137
									  aStartAngle, aEndAngle, aClockwise ) {
138

139 140 141 142 143 144
	var lastargs = this.actions[ this.actions.length - 1].args;
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

	this.absarc(aX + x0, aY + y0, aRadius,
		aStartAngle, aEndAngle, aClockwise );
Z
zz85 已提交
145

146 147 148 149 150
 };

 THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
									  aStartAngle, aEndAngle, aClockwise ) {
	this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
151
 };
Z
zz85 已提交
152

153
THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
154
									  aStartAngle, aEndAngle, aClockwise ) {
A
alteredq 已提交
155

156 157 158 159 160 161 162
	var lastargs = this.actions[ this.actions.length - 1].args;
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

	this.absellipse(aX + x0, aY + y0, xRadius, yRadius,
		aStartAngle, aEndAngle, aClockwise );

163
 };
Z
zz85 已提交
164

165 166 167 168 169 170

THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,
									  aStartAngle, aEndAngle, aClockwise ) {

	var args = Array.prototype.slice.call( arguments );
	var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
171 172 173
									aStartAngle, aEndAngle, aClockwise );
	this.curves.push( curve );

E
Emery 已提交
174
	var lastPoint = curve.getPoint(1);
175 176 177
	args.push(lastPoint.x);
	args.push(lastPoint.y);

178
	this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
179 180 181

 };

182
THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
183

Z
zz85 已提交
184
	if ( ! divisions ) divisions = 40;
185

186 187
	var points = [];

188
	for ( var i = 0; i < divisions; i ++ ) {
189

190
		points.push( this.getPoint( i / divisions ) );
191

192
		//if( !this.getPoint( i / divisions ) ) throw "DIE";
193

Z
zz85 已提交
194
	}
Z
zz85 已提交
195

196
	// if ( closedPath ) {
197
	//
198
	// 	points.push( points[ 0 ] );
199
	//
200
	// }
201 202

	return points;
203 204

};
Z
zz85 已提交
205

Z
zz85 已提交
206
/* Return an array of vectors based on contour of the path */
207

A
alteredq 已提交
208
THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
209

210
	if (this.useSpacedPoints) {
211
		THREE.log('tata');
212 213 214
		return this.getSpacedPoints( divisions, closedPath );
	}

Z
zz85 已提交
215 216
	divisions = divisions || 12;

217 218 219 220 221 222 223
	var points = [];

	var i, il, item, action, args;
	var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
		laste, j,
		t, tx, ty;

224
	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
225 226 227 228 229 230

		item = this.actions[ i ];

		action = item.action;
		args = item.args;

G
gero3 已提交
231
		switch ( action ) {
232 233 234

		case THREE.PathActions.MOVE_TO:

235
			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
Z
zz85 已提交
236 237 238

			break;

239 240 241 242
		case THREE.PathActions.LINE_TO:

			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );

Z
zz85 已提交
243 244
			break;

245 246 247 248 249 250 251 252 253 254 255
		case THREE.PathActions.QUADRATIC_CURVE_TO:

			cpx  = args[ 2 ];
			cpy  = args[ 3 ];

			cpx1 = args[ 0 ];
			cpy1 = args[ 1 ];

			if ( points.length > 0 ) {

				laste = points[ points.length - 1 ];
Z
zz85 已提交
256 257 258

				cpx0 = laste.x;
				cpy0 = laste.y;
259

Z
zz85 已提交
260 261
			} else {

262 263 264 265
				laste = this.actions[ i - 1 ].args;

				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
266 267 268

			}

269 270 271 272
			for ( j = 1; j <= divisions; j ++ ) {

				t = j / divisions;

273 274
				tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
				ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
275 276 277

				points.push( new THREE.Vector2( tx, ty ) );

Z
zz85 已提交
278
			}
279

Z
zz85 已提交
280 281
			break;

282
		case THREE.PathActions.BEZIER_CURVE_TO:
Z
zz85 已提交
283

284 285
			cpx  = args[ 4 ];
			cpy  = args[ 5 ];
Z
zz85 已提交
286

287 288
			cpx1 = args[ 0 ];
			cpy1 = args[ 1 ];
Z
zz85 已提交
289

290 291
			cpx2 = args[ 2 ];
			cpy2 = args[ 3 ];
Z
zz85 已提交
292

293
			if ( points.length > 0 ) {
Z
zz85 已提交
294

295
				laste = points[ points.length - 1 ];
Z
zz85 已提交
296

297 298
				cpx0 = laste.x;
				cpy0 = laste.y;
Z
zz85 已提交
299

300
			} else {
Z
zz85 已提交
301

302
				laste = this.actions[ i - 1 ].args;
Z
zz85 已提交
303

304 305
				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
306

307
			}
Z
zz85 已提交
308 309


310
			for ( j = 1; j <= divisions; j ++ ) {
Z
zz85 已提交
311

312
				t = j / divisions;
Z
zz85 已提交
313

314 315
				tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
				ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
Z
zz85 已提交
316

317
				points.push( new THREE.Vector2( tx, ty ) );
Z
zz85 已提交
318

319
			}
Z
zz85 已提交
320

321
			break;
Z
zz85 已提交
322

Z
zz85 已提交
323
		case THREE.PathActions.CSPLINE_THRU:
324

325
			laste = this.actions[ i - 1 ].args;
326

327
			var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
328
			var spts = [ last ];
329

Z
zz85 已提交
330
			var n = divisions * args[ 0 ].length;
331

332
			spts = spts.concat( args[ 0 ] );
333

334
			var spline = new THREE.SplineCurve( spts );
335

Z
zz85 已提交
336
			for ( j = 1; j <= n; j ++ ) {
337

Z
zz85 已提交
338
				points.push( spline.getPointAt( j / n ) ) ;
339

340
			}
341

Z
zz85 已提交
342
			break;
Z
zz85 已提交
343

Z
zz85 已提交
344
		case THREE.PathActions.ARC:
Z
zz85 已提交
345

346 347 348
			var aX = args[ 0 ], aY = args[ 1 ],
				aRadius = args[ 2 ],
				aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
349
				aClockwise = !! args[ 5 ];
Z
zz85 已提交
350

Z
zz85 已提交
351 352
			var deltaAngle = aEndAngle - aStartAngle;
			var angle;
Z
zz85 已提交
353
			var tdivisions = divisions * 2;
354

Z
zz85 已提交
355
			for ( j = 1; j <= tdivisions; j ++ ) {
356

357
				t = j / tdivisions;
358

Z
zz85 已提交
359
				if ( ! aClockwise ) {
360

Z
zz85 已提交
361
					t = 1 - t;
362

Z
zz85 已提交
363
				}
364

Z
zz85 已提交
365
				angle = aStartAngle + t * deltaAngle;
366

367 368
				tx = aX + aRadius * Math.cos( angle );
				ty = aY + aRadius * Math.sin( angle );
369

370
				//THREE.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
371

Z
zz85 已提交
372
				points.push( new THREE.Vector2( tx, ty ) );
373

Z
zz85 已提交
374
			}
375

376
			//THREE.log(points);
Z
zz85 已提交
377

G
gero3 已提交
378
			break;
379 380 381 382 383
		  
		case THREE.PathActions.ELLIPSE:

			var aX = args[ 0 ], aY = args[ 1 ],
				xRadius = args[ 2 ],
384
				yRadius = args[ 3 ],
385
				aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
386
				aClockwise = !! args[ 6 ];
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407


			var deltaAngle = aEndAngle - aStartAngle;
			var angle;
			var tdivisions = divisions * 2;

			for ( j = 1; j <= tdivisions; j ++ ) {

				t = j / tdivisions;

				if ( ! aClockwise ) {

					t = 1 - t;

				}

				angle = aStartAngle + t * deltaAngle;

				tx = aX + xRadius * Math.cos( angle );
				ty = aY + yRadius * Math.sin( angle );

408
				//THREE.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
409 410 411 412 413

				points.push( new THREE.Vector2( tx, ty ) );

			}

414
			//THREE.log(points);
415

G
gero3 已提交
416
			break;
Z
zz85 已提交
417 418

		} // end switch
Z
zz85 已提交
419

420 421
	}

422 423 424 425 426 427


	// Normalize to remove the closing point by default.
	var lastPoint = points[ points.length - 1];
	var EPSILON = 0.0000000001;
	if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&
Z
zz85 已提交
428
			 Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
429
		points.splice( points.length - 1, 1);
A
alteredq 已提交
430 431 432 433 434 435
	if ( closedPath ) {

		points.push( points[ 0 ] );

	}

436
	return points;
Z
zz85 已提交
437

438
};
Z
zz85 已提交
439

440
//
441
// Breaks path into shapes
442 443 444 445 446 447 448 449 450
//
//	Assumptions (if parameter isCCW==true the opposite holds):
//	- solid shapes are defined clockwise (CW)
//	- holes are defined counterclockwise (CCW)
//
//	If parameter noHoles==true:
//  - all subPaths are regarded as solid shapes
//  - definition order CW/CCW has no relevance
//
451

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {

	function extractSubpaths( inActions ) {

		var i, il, item, action, args;

		var subPaths = [], lastPath = new THREE.Path();

		for ( i = 0, il = inActions.length; i < il; i ++ ) {

			item = inActions[ i ];

			args = item.args;
			action = item.action;

			if ( action == THREE.PathActions.MOVE_TO ) {

				if ( lastPath.actions.length != 0 ) {

					subPaths.push( lastPath );
					lastPath = new THREE.Path();

				}

			}

			lastPath[ action ].apply( lastPath, args );

		}

		if ( lastPath.actions.length != 0 ) {

			subPaths.push( lastPath );

		}

488
		// THREE.log(subPaths);
489 490 491 492 493 494 495 496

		return	subPaths;
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

J
Juergen Ahting 已提交
497
		for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) {
498

J
Juergen Ahting 已提交
499
			var tmpPath = inSubpaths[ i ];
500

J
Juergen Ahting 已提交
501
			var tmpShape = new THREE.Shape();
502 503 504 505 506 507
			tmpShape.actions = tmpPath.actions;
			tmpShape.curves = tmpPath.curves;

			shapes.push( tmpShape );
		}

508
		//THREE.log("shape", shapes);
509 510

		return shapes;
B
brason 已提交
511
	}
512

513 514 515 516 517 518 519 520 521 522
	function isPointInsidePolygon( inPt, inPolygon ) {
		var EPSILON = 0.0000000001;

		var polyLen = inPolygon.length;

		// inPt on polygon contour => immediate success    or
		// toggling of inside/outside at every single! intersection point of an edge
		//  with the horizontal line through inPt, left of inPt
		//  not counting lowerY endpoints of edges and whole edges on that line
		var inside = false;
G
gero3 已提交
523
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
524 525 526 527 528 529 530 531
			var edgeLowPt  = inPolygon[ p ];
			var edgeHighPt = inPolygon[ q ];

			var edgeDx = edgeHighPt.x - edgeLowPt.x;
			var edgeDy = edgeHighPt.y - edgeLowPt.y;

			if ( Math.abs(edgeDy) > EPSILON ) {			// not parallel
				if ( edgeDy < 0 ) {
532 533
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
534 535 536 537 538 539 540 541 542 543
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

				if ( inPt.y == edgeLowPt.y ) {
					if ( inPt.x == edgeLowPt.x )		return	true;		// inPt is on contour ?
					// continue;				// no intersection or edgeLowPt => doesn't count !!!
				} else {
					var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
					if ( perpEdge == 0 )				return	true;		// inPt is on contour ?
					if ( perpEdge < 0 ) 				continue;
544
					inside = ! inside;		// true intersection left of inPt
545 546 547 548 549 550 551 552 553 554 555 556 557
				}
			} else {		// parallel or colinear
				if ( inPt.y != edgeLowPt.y ) 		continue;			// parallel
				// egde lies on the same horizontal line as inPt
				if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
					 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
				// continue;
			}
		}

		return	inside;
	}

558

559 560
	var subPaths = extractSubpaths( this.actions );
	if ( subPaths.length == 0 ) return [];
561

J
Juergen Ahting 已提交
562
	if ( noHoles === true )	return	toShapesNoHoles( subPaths );
563 564


Z
zz85 已提交
565
	var solid, tmpPath, tmpShape, shapes = [];
Z
zz85 已提交
566

Z
zz85 已提交
567
	if ( subPaths.length == 1) {
Z
zz85 已提交
568

Z
zz85 已提交
569 570 571 572 573 574
		tmpPath = subPaths[0];
		tmpShape = new THREE.Shape();
		tmpShape.actions = tmpPath.actions;
		tmpShape.curves = tmpPath.curves;
		shapes.push( tmpShape );
		return shapes;
575

Z
zz85 已提交
576
	}
577

578 579
	var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
	holesFirst = isCCW ? ! holesFirst : holesFirst;
580

581
	// THREE.log("Holes first", holesFirst);
582 583 584 585 586 587
	
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;
588

589 590
	newShapes[mainIdx] = undefined;
	newShapeHoles[mainIdx] = [];
591

592 593
	var i, il;

594
	for ( i = 0, il = subPaths.length; i < il; i ++ ) {
595

596 597 598
		tmpPath = subPaths[ i ];
		tmpPoints = tmpPath.getPoints();
		solid = THREE.Shape.Utils.isClockWise( tmpPoints );
599
		solid = isCCW ? ! solid : solid;
600

601
		if ( solid ) {
602

603
			if ( (! holesFirst ) && ( newShapes[mainIdx] ) )	mainIdx ++;
604

605 606 607 608
			newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[mainIdx].s.actions = tmpPath.actions;
			newShapes[mainIdx].s.curves = tmpPath.curves;
			
609
			if ( holesFirst )	mainIdx ++;
610
			newShapeHoles[mainIdx] = [];
611

612
			//THREE.log('cw', i);
613

614
		} else {
615

616
			newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } );
617

618
			//THREE.log('ccw', i);
619

Z
zz85 已提交
620
		}
621

622
	}
623

624
	// only Holes? -> probably all Shapes with wrong orientation
625
	if ( ! newShapes[0] )	return	toShapesNoHoles( subPaths );
626 627


628 629 630
	if ( newShapes.length > 1 ) {
		var ambigious = false;
		var toChange = [];
631

632
		for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
633 634
			betterShapeHoles[sIdx] = [];
		}
635
		for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
636
			var sho = newShapeHoles[sIdx];
637
			for (var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
638 639
				var ho = sho[hIdx];
				var hole_unassigned = true;
640
				for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
641 642 643 644 645 646 647 648 649 650 651
					if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) {
						if ( sIdx != s2Idx )		toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
						if ( hole_unassigned ) {
							hole_unassigned = false;
							betterShapeHoles[s2Idx].push( ho );
						} else {
							ambigious = true;
						}
					}
				}
				if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); }
Z
zz85 已提交
652 653
			}
		}
654
		// THREE.log("ambigious: ", ambigious);
655
		if ( toChange.length > 0 ) {
656
			// THREE.log("to change: ", toChange);
657 658 659
			if (! ambigious)	newShapeHoles = betterShapeHoles;
		}
	}
Z
zz85 已提交
660

661 662 663
	var tmpHoles, j, jl;
	for ( i = 0, il = newShapes.length; i < il; i ++ ) {
		tmpShape = newShapes[i].s;
Z
zz85 已提交
664
		shapes.push( tmpShape );
665 666 667 668
		tmpHoles = newShapeHoles[i];
		for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
			tmpShape.holes.push( tmpHoles[j].h );
		}
Z
zz85 已提交
669
	}
670

671
	//THREE.log("shape", shapes);
672

Z
zz85 已提交
673
	return shapes;
674

Z
zz85 已提交
675
};