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
	QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
	BEZIER_CURVE_TO: 'bezierCurveTo', 		// Bezier cubic curve
D
dubejf 已提交
30
	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 211 212 213
	if (this.useSpacedPoints) {
		return this.getSpacedPoints( divisions, closedPath );
	}

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

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

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

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

		item = this.actions[ i ];

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

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

		case THREE.PathActions.MOVE_TO:

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

			break;

238 239 240 241
		case THREE.PathActions.LINE_TO:

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

Z
zz85 已提交
242 243
			break;

244 245 246 247 248 249 250 251 252 253 254
		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 已提交
255 256 257

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

Z
zz85 已提交
259 260
			} else {

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

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

			}

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

				t = j / divisions;

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

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

Z
zz85 已提交
277
			}
278

Z
zz85 已提交
279 280
			break;

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

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

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

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

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

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

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

299
			} else {
Z
zz85 已提交
300

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

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

306
			}
Z
zz85 已提交
307 308


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

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

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

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

318
			}
Z
zz85 已提交
319

320
			break;
Z
zz85 已提交
321

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

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

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

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

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

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

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

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

339
			}
340

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

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

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

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

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

356
				t = j / tdivisions;
357

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

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

Z
zz85 已提交
362
				}
363

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

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

369
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
370

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

Z
zz85 已提交
373
			}
374

375
			//console.log(points);
Z
zz85 已提交
376

G
gero3 已提交
377
			break;
F
Fabian Lange 已提交
378

379 380 381 382
		case THREE.PathActions.ELLIPSE:

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


			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 );

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

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

			}

413
			//console.log(points);
414

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

		} // end switch
Z
zz85 已提交
418

419 420
	}

421 422 423 424 425 426


	// 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 已提交
427
			 Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
428
		points.splice( points.length - 1, 1);
A
alteredq 已提交
429 430 431 432 433 434
	if ( closedPath ) {

		points.push( points[ 0 ] );

	}

435
	return points;
Z
zz85 已提交
436

437
};
Z
zz85 已提交
438

439
//
440
// Breaks path into shapes
441 442 443 444 445 446 447 448 449
//
//	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
//
450

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
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;

F
Fabian Lange 已提交
466
			if ( action === THREE.PathActions.MOVE_TO ) {
467

F
Fabian Lange 已提交
468
				if ( lastPath.actions.length !== 0 ) {
469 470 471 472 473 474 475 476 477 478 479 480

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

				}

			}

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

		}

F
Fabian Lange 已提交
481
		if ( lastPath.actions.length !== 0 ) {
482 483 484 485 486

			subPaths.push( lastPath );

		}

487
		// console.log(subPaths);
488 489 490 491 492 493 494 495

		return	subPaths;
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

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

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

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

			shapes.push( tmpShape );
		}

507
		//console.log("shape", shapes);
508 509

		return shapes;
B
brason 已提交
510
	}
511

512 513 514 515 516 517 518 519 520 521
	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 已提交
522
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
523 524 525 526 527 528 529 530
			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 ) {
531 532
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
533 534 535
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

F
Fabian Lange 已提交
536 537
				if ( inPt.y === edgeLowPt.y ) {
					if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
538 539 540
					// continue;				// no intersection or edgeLowPt => doesn't count !!!
				} else {
					var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
F
Fabian Lange 已提交
541
					if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
542
					if ( perpEdge < 0 ) 				continue;
543
					inside = ! inside;		// true intersection left of inPt
544
				}
D
dubejf 已提交
545
			} else {		// parallel or collinear
F
Fabian Lange 已提交
546
				if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
D
dubejf 已提交
547
				// edge lies on the same horizontal line as inPt
548 549 550 551 552 553 554 555 556
				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;
	}

557

558
	var subPaths = extractSubpaths( this.actions );
F
Fabian Lange 已提交
559
	if ( subPaths.length === 0 ) return [];
560

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


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

F
Fabian Lange 已提交
566
	if ( subPaths.length === 1) {
Z
zz85 已提交
567

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

Z
zz85 已提交
575
	}
576

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

580
	// console.log("Holes first", holesFirst);
F
Fabian Lange 已提交
581

582 583 584 585 586
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;
587

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

591 592
	var i, il;

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

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

600
		if ( solid ) {
601

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

604 605 606
			newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[mainIdx].s.actions = tmpPath.actions;
			newShapes[mainIdx].s.curves = tmpPath.curves;
F
Fabian Lange 已提交
607

608
			if ( holesFirst )	mainIdx ++;
609
			newShapeHoles[mainIdx] = [];
610

611
			//console.log('cw', i);
612

613
		} else {
614

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

617
			//console.log('ccw', i);
618

Z
zz85 已提交
619
		}
620

621
	}
622

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


627
	if ( newShapes.length > 1 ) {
D
dubejf 已提交
628
		var ambiguous = false;
629
		var toChange = [];
630

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

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

670
	//console.log("shape", shapes);
671

Z
zz85 已提交
672
	return shapes;
673

Z
zz85 已提交
674
};