Path.js 15.5 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 ) {

G
gero3 已提交
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
THREE.PathActions = {
Z
zz85 已提交
25 26
	MOVE_TO: 'moveTo',
	LINE_TO: 'lineTo',
Z
zz85 已提交
27 28
	QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
	BEZIER_CURVE_TO: 'bezierCurveTo', 		// Bezier cubic curve
D
dubejf 已提交
29
	CSPLINE_THRU: 'splineThru',				// Catmull-Rom spline
30 31
	ARC: 'arc',								// Circle
	ELLIPSE: 'ellipse'
Z
zz85 已提交
32 33
};

34
// TODO Clean up PATH API
35

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

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

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

M
Mr.doob 已提交
43
	for ( var i = 1, l = vectors.length; i < l; i ++ ) {
44

M
Mr.doob 已提交
45
		this.lineTo( vectors[ i ].x, vectors[ i ].y );
46

B
brason 已提交
47
	}
48

Z
zz85 已提交
49 50
};

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

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

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

Z
zz85 已提交
58 59
};

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

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

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

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

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

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

Z
zz85 已提交
74 75
};

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

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

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

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

M
Mr.doob 已提交
85 86 87 88 89 90
	var curve = new THREE.QuadraticBezierCurve(
		new THREE.Vector2( x0, y0 ),
		new THREE.Vector2( aCPx, aCPy ),
		new THREE.Vector2( aX, aY )
	);

Z
zz85 已提交
91
	this.curves.push( curve );
92

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

Z
zz85 已提交
95 96
};

M
Mr.doob 已提交
97
THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, 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 ];

M
Mr.doob 已提交
106 107 108 109 110 111 112
	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 已提交
113
	this.curves.push( curve );
114

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

Z
zz85 已提交
117 118
};

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

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

Z
curves  
zz85 已提交
124 125
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
M
Mr.doob 已提交
126

127
	var npts = [ new THREE.Vector2( x0, y0 ) ];
128
	Array.prototype.push.apply( npts, pts );
129

Z
zz85 已提交
130 131
	var curve = new THREE.SplineCurve( npts );
	this.curves.push( curve );
132

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

135
};
Z
zz85 已提交
136

Z
zz85 已提交
137
// FUTURE: Change the API or follow canvas API?
138

M
Mr.doob 已提交
139
THREE.Path.prototype.arc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
140

G
gero3 已提交
141
	var lastargs = this.actions[ this.actions.length - 1 ].args;
142 143 144
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

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

148 149
 };

M
Mr.doob 已提交
150
 THREE.Path.prototype.absarc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
G
gero3 已提交
151 152 153

	this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );

154
 };
Z
zz85 已提交
155

M
Mr.doob 已提交
156
THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
A
alteredq 已提交
157

G
gero3 已提交
158
	var lastargs = this.actions[ this.actions.length - 1 ].args;
159 160 161
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

M
Mr.doob 已提交
162
	this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
163

164
 };
Z
zz85 已提交
165

166

M
Mr.doob 已提交
167
THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
168

N
neko 已提交
169 170 171 172 173 174 175
	var args = [
		aX, aY,
		xRadius, yRadius,
		aStartAngle, aEndAngle,
		aClockwise,
		aRotation || 0 // aRotation is optional.
	];
M
Mr.doob 已提交
176 177

	var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
178 179
	this.curves.push( curve );

G
gero3 已提交
180 181 182
	var lastPoint = curve.getPoint( 1 );
	args.push( lastPoint.x );
	args.push( lastPoint.y );
183

184
	this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
185 186 187

 };

188
THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
189

Z
zz85 已提交
190
	if ( ! divisions ) divisions = 40;
191

192 193
	var points = [];

194
	for ( var i = 0; i < divisions; i ++ ) {
195

196
		points.push( this.getPoint( i / divisions ) );
197

M
Mr.doob 已提交
198
		//if ( !this.getPoint( i / divisions ) ) throw "DIE";
199

Z
zz85 已提交
200
	}
Z
zz85 已提交
201

202
	// if ( closedPath ) {
203
	//
204
	// 	points.push( points[ 0 ] );
205
	//
206
	// }
207 208

	return points;
209 210

};
Z
zz85 已提交
211

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

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

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

218 219 220
	var points = [];

	var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
M
Mr.doob 已提交
221
		laste, tx, ty;
222

M
Mr.doob 已提交
223
	for ( var i = 0, l = this.actions.length; i < l; i ++ ) {
224

M
Mr.doob 已提交
225
		var item = this.actions[ i ];
226

M
Mr.doob 已提交
227 228
		var action = item.action;
		var args = item.args;
229

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

			}

M
Mr.doob 已提交
268
			for ( var j = 1; j <= divisions; j ++ ) {
269

M
Mr.doob 已提交
270
				var t = j / divisions;
271

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


M
Mr.doob 已提交
309
			for ( var j = 1; j <= divisions; j ++ ) {
Z
zz85 已提交
310

M
Mr.doob 已提交
311
				var 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

M
Mr.doob 已提交
335
			for ( var j = 1; j <= n; j ++ ) {
336

M
Mr.doob 已提交
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

M
Mr.doob 已提交
354
			for ( var j = 1; j <= tdivisions; j ++ ) {
355

M
Mr.doob 已提交
356
				var 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 ],
N
neko 已提交
386
				aRotation = args[ 7 ];
387 388 389 390 391 392


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

393
			var cos, sin;
N
neko 已提交
394
			if ( aRotation !== 0 ) {
M
Mr.doob 已提交
395

396 397 398 399 400
				cos = Math.cos( aRotation );
				sin = Math.sin( aRotation );

			}

M
Mr.doob 已提交
401
			for ( var j = 1; j <= tdivisions; j ++ ) {
402

M
Mr.doob 已提交
403
				var t = j / tdivisions;
404 405 406 407 408 409 410 411 412 413 414 415

				if ( ! aClockwise ) {

					t = 1 - t;

				}

				angle = aStartAngle + t * deltaAngle;

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

N
neko 已提交
416
				if ( aRotation !== 0 ) {
417

N
neko 已提交
418 419
					var x = tx, y = ty;

420
					// Rotate the point about the center of the ellipse.
N
neko 已提交
421 422
					tx = ( x - aX ) * cos - ( y - aY ) * sin + aX;
					ty = ( x - aX ) * sin + ( y - aY ) * cos + aY;
423 424 425

				}

426
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
427 428 429 430 431

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

			}

432
			//console.log(points);
433

G
gero3 已提交
434
			break;
Z
zz85 已提交
435 436

		} // end switch
Z
zz85 已提交
437

438 439
	}

440 441 442


	// Normalize to remove the closing point by default.
G
gero3 已提交
443
	var lastPoint = points[ points.length - 1 ];
444
	var EPSILON = 0.0000000001;
G
gero3 已提交
445 446 447
	if ( Math.abs( lastPoint.x - points[ 0 ].x ) < EPSILON &&
			 Math.abs( lastPoint.y - points[ 0 ].y ) < EPSILON )
		points.splice( points.length - 1, 1 );
A
alteredq 已提交
448 449 450 451 452 453
	if ( closedPath ) {

		points.push( points[ 0 ] );

	}

454
	return points;
Z
zz85 已提交
455

456
};
Z
zz85 已提交
457

458
//
459
// Breaks path into shapes
460 461 462 463 464 465 466 467 468
//
//	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
//
469

470 471 472 473 474 475
THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {

	function extractSubpaths( inActions ) {

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

M
Mr.doob 已提交
476
		for ( var i = 0, l = inActions.length; i < l; i ++ ) {
477

M
Mr.doob 已提交
478
			var item = inActions[ i ];
479

M
Mr.doob 已提交
480 481
			var args = item.args;
			var action = item.action;
482

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

F
Fabian Lange 已提交
485
				if ( lastPath.actions.length !== 0 ) {
486 487 488 489 490 491 492 493 494 495 496 497

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

				}

			}

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

		}

F
Fabian Lange 已提交
498
		if ( lastPath.actions.length !== 0 ) {
499 500 501 502 503

			subPaths.push( lastPath );

		}

504
		// console.log(subPaths);
505 506

		return	subPaths;
G
gero3 已提交
507

508 509 510 511 512 513
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

M
Mr.doob 已提交
514
		for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {
515

J
Juergen Ahting 已提交
516
			var tmpPath = inSubpaths[ i ];
517

J
Juergen Ahting 已提交
518
			var tmpShape = new THREE.Shape();
519 520 521 522
			tmpShape.actions = tmpPath.actions;
			tmpShape.curves = tmpPath.curves;

			shapes.push( tmpShape );
G
gero3 已提交
523

524 525
		}

526
		//console.log("shape", shapes);
527 528

		return shapes;
G
gero3 已提交
529

B
brason 已提交
530
	}
531

532
	function isPointInsidePolygon( inPt, inPolygon ) {
G
gero3 已提交
533

534 535 536 537 538 539 540 541 542
		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 已提交
543
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
G
gero3 已提交
544

545 546 547 548 549 550
			var edgeLowPt  = inPolygon[ p ];
			var edgeHighPt = inPolygon[ q ];

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

G
gero3 已提交
551 552 553
			if ( Math.abs( edgeDy ) > EPSILON ) {

				// not parallel
554
				if ( edgeDy < 0 ) {
G
gero3 已提交
555

556 557
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
G
gero3 已提交
558

559 560 561
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

F
Fabian Lange 已提交
562
				if ( inPt.y === edgeLowPt.y ) {
G
gero3 已提交
563

F
Fabian Lange 已提交
564
					if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
565
					// continue;				// no intersection or edgeLowPt => doesn't count !!!
G
gero3 已提交
566

567
				} else {
G
gero3 已提交
568 569

					var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
F
Fabian Lange 已提交
570
					if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
571
					if ( perpEdge < 0 ) 				continue;
572
					inside = ! inside;		// true intersection left of inPt
G
gero3 已提交
573

574
				}
G
gero3 已提交
575 576 577 578

			} else {

				// parallel or collinear
F
Fabian Lange 已提交
579
				if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
D
dubejf 已提交
580
				// edge lies on the same horizontal line as inPt
581 582 583
				if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
					 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
				// continue;
G
gero3 已提交
584

585
			}
G
gero3 已提交
586

587 588 589
		}

		return	inside;
G
gero3 已提交
590

591 592
	}

593

594
	var subPaths = extractSubpaths( this.actions );
F
Fabian Lange 已提交
595
	if ( subPaths.length === 0 ) return [];
596

J
Juergen Ahting 已提交
597
	if ( noHoles === true )	return	toShapesNoHoles( subPaths );
598 599


Z
zz85 已提交
600
	var solid, tmpPath, tmpShape, shapes = [];
Z
zz85 已提交
601

G
gero3 已提交
602
	if ( subPaths.length === 1 ) {
Z
zz85 已提交
603

G
gero3 已提交
604
		tmpPath = subPaths[ 0 ];
Z
zz85 已提交
605 606 607 608 609
		tmpShape = new THREE.Shape();
		tmpShape.actions = tmpPath.actions;
		tmpShape.curves = tmpPath.curves;
		shapes.push( tmpShape );
		return shapes;
610

Z
zz85 已提交
611
	}
612

613 614
	var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
	holesFirst = isCCW ? ! holesFirst : holesFirst;
615

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

618 619 620 621 622
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;
623

G
gero3 已提交
624 625
	newShapes[ mainIdx ] = undefined;
	newShapeHoles[ mainIdx ] = [];
626

M
Mr.doob 已提交
627
	for ( var i = 0, l = subPaths.length; i < l; i ++ ) {
628

629 630 631
		tmpPath = subPaths[ i ];
		tmpPoints = tmpPath.getPoints();
		solid = THREE.Shape.Utils.isClockWise( tmpPoints );
632
		solid = isCCW ? ! solid : solid;
633

634
		if ( solid ) {
635

G
gero3 已提交
636
			if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )	mainIdx ++;
637

G
gero3 已提交
638 639 640
			newShapes[ mainIdx ] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[ mainIdx ].s.actions = tmpPath.actions;
			newShapes[ mainIdx ].s.curves = tmpPath.curves;
F
Fabian Lange 已提交
641

642
			if ( holesFirst )	mainIdx ++;
G
gero3 已提交
643
			newShapeHoles[ mainIdx ] = [];
644

645
			//console.log('cw', i);
646

647
		} else {
648

G
gero3 已提交
649
			newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
650

651
			//console.log('ccw', i);
652

Z
zz85 已提交
653
		}
654

655
	}
656

657
	// only Holes? -> probably all Shapes with wrong orientation
G
gero3 已提交
658
	if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
659 660


661
	if ( newShapes.length > 1 ) {
G
gero3 已提交
662

D
dubejf 已提交
663
		var ambiguous = false;
664
		var toChange = [];
665

G
gero3 已提交
666 667 668 669
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

			betterShapeHoles[ sIdx ] = [];

670
		}
M
Mr.doob 已提交
671

G
gero3 已提交
672 673 674
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

			var sho = newShapeHoles[ sIdx ];
M
Mr.doob 已提交
675

G
gero3 已提交
676 677 678
			for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {

				var ho = sho[ hIdx ];
679
				var hole_unassigned = true;
M
Mr.doob 已提交
680

G
gero3 已提交
681 682 683 684
				for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {

					if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {

F
Fabian Lange 已提交
685
						if ( sIdx !== s2Idx )	toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
686
						if ( hole_unassigned ) {
G
gero3 已提交
687

688
							hole_unassigned = false;
G
gero3 已提交
689 690
							betterShapeHoles[ s2Idx ].push( ho );

691
						} else {
G
gero3 已提交
692

D
dubejf 已提交
693
							ambiguous = true;
G
gero3 已提交
694

695
						}
G
gero3 已提交
696

697
					}
G
gero3 已提交
698

699
				}
G
gero3 已提交
700 701 702 703 704 705
				if ( hole_unassigned ) {

					betterShapeHoles[ sIdx ].push( ho );

				}

Z
zz85 已提交
706
			}
G
gero3 已提交
707

Z
zz85 已提交
708
		}
D
dubejf 已提交
709
		// console.log("ambiguous: ", ambiguous);
710
		if ( toChange.length > 0 ) {
G
gero3 已提交
711

712
			// console.log("to change: ", toChange);
G
gero3 已提交
713 714
			if ( ! ambiguous )	newShapeHoles = betterShapeHoles;

715
		}
G
gero3 已提交
716

717
	}
Z
zz85 已提交
718

M
Mr.doob 已提交
719 720 721
	var tmpHoles;

	for ( var i = 0, il = newShapes.length; i < il; i ++ ) {
G
gero3 已提交
722 723

		tmpShape = newShapes[ i ].s;
Z
zz85 已提交
724
		shapes.push( tmpShape );
G
gero3 已提交
725
		tmpHoles = newShapeHoles[ i ];
M
Mr.doob 已提交
726 727

		for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
G
gero3 已提交
728 729 730

			tmpShape.holes.push( tmpHoles[ j ].h );

731
		}
G
gero3 已提交
732

Z
zz85 已提交
733
	}
734

735
	//console.log("shape", shapes);
736

Z
zz85 已提交
737
	return shapes;
738

Z
zz85 已提交
739
};