Path.js 14.8 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
// TODO Clean up PATH API
25

26 27
// Create path using straight lines to connect all points
// - vectors: array of Vector2
28

29
THREE.Path.prototype.fromPoints = function ( vectors ) {
30 31 32

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

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

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

B
brason 已提交
37
	}
38

Z
zz85 已提交
39 40
};

Z
zz85 已提交
41 42
// startPath() endPath()?

43
THREE.Path.prototype.moveTo = function ( x, y ) {
44

45
	this.actions.push( { action: 'moveTo', args: [ x, y ] } );
46

Z
zz85 已提交
47 48
};

49
THREE.Path.prototype.lineTo = function ( x, y ) {
50

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

Z
curves  
zz85 已提交
53 54
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
55

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

59
	this.actions.push( { action: 'lineTo', args: [ x, y ] } );
60

Z
zz85 已提交
61 62
};

63 64
THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {

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

M
Mr.doob 已提交
70 71 72 73 74 75
	var curve = new THREE.QuadraticBezierCurve(
		new THREE.Vector2( x0, y0 ),
		new THREE.Vector2( aCPx, aCPy ),
		new THREE.Vector2( aX, aY )
	);

Z
zz85 已提交
76
	this.curves.push( curve );
77

78
	this.actions.push( { action: 'quadraticCurveTo', args: [ aCPx, aCPy, aX, aY ] } );
79

Z
zz85 已提交
80 81
};

M
Mr.doob 已提交
82
THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
83

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

Z
curves  
zz85 已提交
86 87 88
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

M
Mr.doob 已提交
89 90 91 92 93 94 95
	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 已提交
96
	this.curves.push( curve );
97

98
	this.actions.push( { action: 'bezierCurveTo', args: [ aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ] } );
99

Z
zz85 已提交
100 101
};

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

Z
zz85 已提交
104
	var args = Array.prototype.slice.call( arguments );
105

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

Z
curves  
zz85 已提交
108 109
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];
M
Mr.doob 已提交
110

111
	var npts = [ new THREE.Vector2( x0, y0 ) ];
112
	Array.prototype.push.apply( npts, pts );
113

Z
zz85 已提交
114 115
	var curve = new THREE.SplineCurve( npts );
	this.curves.push( curve );
116

M
Mr.doob 已提交
117
	this.actions.push( { action: 'splineThru', args: args } );
118

119
};
Z
zz85 已提交
120

Z
zz85 已提交
121
// FUTURE: Change the API or follow canvas API?
122

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

G
gero3 已提交
125
	var lastargs = this.actions[ this.actions.length - 1 ].args;
126 127 128
	var x0 = lastargs[ lastargs.length - 2 ];
	var y0 = lastargs[ lastargs.length - 1 ];

G
gero3 已提交
129
	this.absarc( aX + x0, aY + y0, aRadius,
130
		aStartAngle, aEndAngle, aClockwise );
Z
zz85 已提交
131

132 133
 };

M
Mr.doob 已提交
134
 THREE.Path.prototype.absarc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
G
gero3 已提交
135 136 137

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

138
 };
Z
zz85 已提交
139

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

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

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

148
 };
Z
zz85 已提交
149

150

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

N
neko 已提交
153 154 155 156 157 158 159
	var args = [
		aX, aY,
		xRadius, yRadius,
		aStartAngle, aEndAngle,
		aClockwise,
		aRotation || 0 // aRotation is optional.
	];
M
Mr.doob 已提交
160 161

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

G
gero3 已提交
164 165 166
	var lastPoint = curve.getPoint( 1 );
	args.push( lastPoint.x );
	args.push( lastPoint.y );
167

M
Mr.doob 已提交
168
	this.actions.push( { action: 'ellipse', args: args } );
169 170 171

 };

W
WestLangley 已提交
172
THREE.Path.prototype.getSpacedPoints = function ( divisions ) {
173

Z
zz85 已提交
174
	if ( ! divisions ) divisions = 40;
175

176 177
	var points = [];

178
	for ( var i = 0; i < divisions; i ++ ) {
179

180
		points.push( this.getPoint( i / divisions ) );
181

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

Z
zz85 已提交
184
	}
Z
zz85 已提交
185

W
WestLangley 已提交
186 187 188 189 190
	if ( this.autoClose ) {

		points.push( points[ 0 ] );

	}
191 192

	return points;
193 194

};
Z
zz85 已提交
195

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

W
WestLangley 已提交
198
THREE.Path.prototype.getPoints = function( divisions ) {
199

Z
zz85 已提交
200 201
	divisions = divisions || 12;

M
Mr.doob 已提交
202 203 204
	var b2 = THREE.ShapeUtils.b2;
	var b3 = THREE.ShapeUtils.b3;

205 206 207
	var points = [];

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

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

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

M
Mr.doob 已提交
214 215
		var action = item.action;
		var args = item.args;
216

G
gero3 已提交
217
		switch ( action ) {
218

M
Mr.doob 已提交
219
		case 'moveTo':
220

221
			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
Z
zz85 已提交
222 223 224

			break;

M
Mr.doob 已提交
225
		case 'lineTo':
226 227 228

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

Z
zz85 已提交
229 230
			break;

M
Mr.doob 已提交
231
		case 'quadraticCurveTo':
232 233 234 235 236 237 238 239 240 241

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

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

			if ( points.length > 0 ) {

				laste = points[ points.length - 1 ];
Z
zz85 已提交
242 243 244

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

Z
zz85 已提交
246 247
			} else {

248 249 250 251
				laste = this.actions[ i - 1 ].args;

				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
252 253 254

			}

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

M
Mr.doob 已提交
257
				var t = j / divisions;
258

M
Mr.doob 已提交
259 260
				tx = b2( t, cpx0, cpx1, cpx );
				ty = b2( t, cpy0, cpy1, cpy );
261 262 263

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

Z
zz85 已提交
264
			}
265

Z
zz85 已提交
266 267
			break;

M
Mr.doob 已提交
268
		case 'bezierCurveTo':
Z
zz85 已提交
269

270 271
			cpx  = args[ 4 ];
			cpy  = args[ 5 ];
Z
zz85 已提交
272

273 274
			cpx1 = args[ 0 ];
			cpy1 = args[ 1 ];
Z
zz85 已提交
275

276 277
			cpx2 = args[ 2 ];
			cpy2 = args[ 3 ];
Z
zz85 已提交
278

279
			if ( points.length > 0 ) {
Z
zz85 已提交
280

281
				laste = points[ points.length - 1 ];
Z
zz85 已提交
282

283 284
				cpx0 = laste.x;
				cpy0 = laste.y;
Z
zz85 已提交
285

286
			} else {
Z
zz85 已提交
287

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

290 291
				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
292

293
			}
Z
zz85 已提交
294 295


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

M
Mr.doob 已提交
298
				var t = j / divisions;
Z
zz85 已提交
299

M
Mr.doob 已提交
300 301
				tx = b3( t, cpx0, cpx1, cpx2, cpx );
				ty = b3( t, cpy0, cpy1, cpy2, cpy );
Z
zz85 已提交
302

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

305
			}
Z
zz85 已提交
306

307
			break;
Z
zz85 已提交
308

M
Mr.doob 已提交
309
		case 'splineThru':
310

311
			laste = this.actions[ i - 1 ].args;
312

313
			var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
314
			var spts = [ last ];
315

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

318
			spts = spts.concat( args[ 0 ] );
319

320
			var spline = new THREE.SplineCurve( spts );
321

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

M
Mr.doob 已提交
324
				points.push( spline.getPointAt( j / n ) );
325

326
			}
327

Z
zz85 已提交
328
			break;
Z
zz85 已提交
329

M
Mr.doob 已提交
330
		case 'arc':
Z
zz85 已提交
331

332 333 334
			var aX = args[ 0 ], aY = args[ 1 ],
				aRadius = args[ 2 ],
				aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
335
				aClockwise = !! args[ 5 ];
Z
zz85 已提交
336

Z
zz85 已提交
337 338
			var deltaAngle = aEndAngle - aStartAngle;
			var angle;
Z
zz85 已提交
339
			var tdivisions = divisions * 2;
340

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

M
Mr.doob 已提交
343
				var t = j / tdivisions;
344

Z
zz85 已提交
345
				if ( ! aClockwise ) {
346

Z
zz85 已提交
347
					t = 1 - t;
348

Z
zz85 已提交
349
				}
350

Z
zz85 已提交
351
				angle = aStartAngle + t * deltaAngle;
352

353 354
				tx = aX + aRadius * Math.cos( angle );
				ty = aY + aRadius * Math.sin( angle );
355

356
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
357

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

Z
zz85 已提交
360
			}
361

362
			//console.log(points);
Z
zz85 已提交
363

G
gero3 已提交
364
			break;
F
Fabian Lange 已提交
365

M
Mr.doob 已提交
366
		case 'ellipse':
367 368 369

			var aX = args[ 0 ], aY = args[ 1 ],
				xRadius = args[ 2 ],
370
				yRadius = args[ 3 ],
371
				aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
372
				aClockwise = !! args[ 6 ],
N
neko 已提交
373
				aRotation = args[ 7 ];
374 375 376 377 378 379


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

380
			var cos, sin;
N
neko 已提交
381
			if ( aRotation !== 0 ) {
M
Mr.doob 已提交
382

383 384 385 386 387
				cos = Math.cos( aRotation );
				sin = Math.sin( aRotation );

			}

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

M
Mr.doob 已提交
390
				var t = j / tdivisions;
391 392 393 394 395 396 397 398 399 400 401 402

				if ( ! aClockwise ) {

					t = 1 - t;

				}

				angle = aStartAngle + t * deltaAngle;

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

N
neko 已提交
403
				if ( aRotation !== 0 ) {
404

N
neko 已提交
405 406
					var x = tx, y = ty;

407
					// Rotate the point about the center of the ellipse.
N
neko 已提交
408 409
					tx = ( x - aX ) * cos - ( y - aY ) * sin + aX;
					ty = ( x - aX ) * sin + ( y - aY ) * cos + aY;
410 411 412

				}

413
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
414 415 416 417 418

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

			}

419
			//console.log(points);
420

G
gero3 已提交
421
			break;
Z
zz85 已提交
422 423

		} // end switch
Z
zz85 已提交
424

425 426
	}

427 428 429


	// Normalize to remove the closing point by default.
G
gero3 已提交
430
	var lastPoint = points[ points.length - 1 ];
M
Mr.doob 已提交
431 432
	if ( Math.abs( lastPoint.x - points[ 0 ].x ) < Number.EPSILON &&
			 Math.abs( lastPoint.y - points[ 0 ].y ) < Number.EPSILON )
G
gero3 已提交
433
		points.splice( points.length - 1, 1 );
W
WestLangley 已提交
434 435

	if ( this.autoClose ) {
A
alteredq 已提交
436 437 438 439 440

		points.push( points[ 0 ] );

	}

441
	return points;
Z
zz85 已提交
442

443
};
Z
zz85 已提交
444

445
//
446
// Breaks path into shapes
447 448 449 450 451 452 453 454 455
//
//	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
//
456

457 458 459 460 461 462
THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {

	function extractSubpaths( inActions ) {

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

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

M
Mr.doob 已提交
465
			var item = inActions[ i ];
466

M
Mr.doob 已提交
467 468
			var args = item.args;
			var action = item.action;
469

M
Mr.doob 已提交
470
			if ( action === 'moveTo' ) {
471

F
Fabian Lange 已提交
472
				if ( lastPath.actions.length !== 0 ) {
473 474 475 476 477 478 479 480 481 482 483 484

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

				}

			}

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

		}

F
Fabian Lange 已提交
485
		if ( lastPath.actions.length !== 0 ) {
486 487 488 489 490

			subPaths.push( lastPath );

		}

491
		// console.log(subPaths);
492 493

		return	subPaths;
G
gero3 已提交
494

495 496 497 498 499 500
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

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

J
Juergen Ahting 已提交
503
			var tmpPath = inSubpaths[ i ];
504

J
Juergen Ahting 已提交
505
			var tmpShape = new THREE.Shape();
506 507 508 509
			tmpShape.actions = tmpPath.actions;
			tmpShape.curves = tmpPath.curves;

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

511 512
		}

513
		//console.log("shape", shapes);
514 515

		return shapes;
G
gero3 已提交
516

B
brason 已提交
517
	}
518

519
	function isPointInsidePolygon( inPt, inPolygon ) {
G
gero3 已提交
520

521 522 523 524 525 526 527
		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 已提交
528
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
G
gero3 已提交
529

530 531 532 533 534 535
			var edgeLowPt  = inPolygon[ p ];
			var edgeHighPt = inPolygon[ q ];

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

M
Mr.doob 已提交
536
			if ( Math.abs( edgeDy ) > Number.EPSILON ) {
G
gero3 已提交
537 538

				// not parallel
539
				if ( edgeDy < 0 ) {
G
gero3 已提交
540

541 542
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
G
gero3 已提交
543

544 545 546
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

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

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

552
				} else {
G
gero3 已提交
553 554

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

559
				}
G
gero3 已提交
560 561 562 563

			} else {

				// parallel or collinear
F
Fabian Lange 已提交
564
				if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
D
dubejf 已提交
565
				// edge lies on the same horizontal line as inPt
566 567 568
				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 已提交
569

570
			}
G
gero3 已提交
571

572 573 574
		}

		return	inside;
G
gero3 已提交
575

576 577
	}

M
Mr.doob 已提交
578
	var isClockWise = THREE.ShapeUtils.isClockWise;
579

580
	var subPaths = extractSubpaths( this.actions );
F
Fabian Lange 已提交
581
	if ( subPaths.length === 0 ) return [];
582

J
Juergen Ahting 已提交
583
	if ( noHoles === true )	return	toShapesNoHoles( subPaths );
584 585


Z
zz85 已提交
586
	var solid, tmpPath, tmpShape, shapes = [];
Z
zz85 已提交
587

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

G
gero3 已提交
590
		tmpPath = subPaths[ 0 ];
Z
zz85 已提交
591 592 593 594 595
		tmpShape = new THREE.Shape();
		tmpShape.actions = tmpPath.actions;
		tmpShape.curves = tmpPath.curves;
		shapes.push( tmpShape );
		return shapes;
596

Z
zz85 已提交
597
	}
598

M
Mr.doob 已提交
599
	var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
600
	holesFirst = isCCW ? ! holesFirst : holesFirst;
601

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

604 605 606 607 608
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;
609

G
gero3 已提交
610 611
	newShapes[ mainIdx ] = undefined;
	newShapeHoles[ mainIdx ] = [];
612

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

615 616
		tmpPath = subPaths[ i ];
		tmpPoints = tmpPath.getPoints();
M
Mr.doob 已提交
617
		solid = isClockWise( tmpPoints );
618
		solid = isCCW ? ! solid : solid;
619

620
		if ( solid ) {
621

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

G
gero3 已提交
624 625 626
			newShapes[ mainIdx ] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[ mainIdx ].s.actions = tmpPath.actions;
			newShapes[ mainIdx ].s.curves = tmpPath.curves;
F
Fabian Lange 已提交
627

628
			if ( holesFirst )	mainIdx ++;
G
gero3 已提交
629
			newShapeHoles[ mainIdx ] = [];
630

631
			//console.log('cw', i);
632

633
		} else {
634

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

637
			//console.log('ccw', i);
638

Z
zz85 已提交
639
		}
640

641
	}
642

643
	// only Holes? -> probably all Shapes with wrong orientation
G
gero3 已提交
644
	if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
645 646


647
	if ( newShapes.length > 1 ) {
G
gero3 已提交
648

D
dubejf 已提交
649
		var ambiguous = false;
650
		var toChange = [];
651

G
gero3 已提交
652 653 654 655
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

			betterShapeHoles[ sIdx ] = [];

656
		}
M
Mr.doob 已提交
657

G
gero3 已提交
658 659 660
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

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

G
gero3 已提交
662 663 664
			for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {

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

G
gero3 已提交
667 668 669 670
				for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {

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

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

674
							hole_unassigned = false;
G
gero3 已提交
675 676
							betterShapeHoles[ s2Idx ].push( ho );

677
						} else {
G
gero3 已提交
678

D
dubejf 已提交
679
							ambiguous = true;
G
gero3 已提交
680

681
						}
G
gero3 已提交
682

683
					}
G
gero3 已提交
684

685
				}
G
gero3 已提交
686 687 688 689 690 691
				if ( hole_unassigned ) {

					betterShapeHoles[ sIdx ].push( ho );

				}

Z
zz85 已提交
692
			}
G
gero3 已提交
693

Z
zz85 已提交
694
		}
D
dubejf 已提交
695
		// console.log("ambiguous: ", ambiguous);
696
		if ( toChange.length > 0 ) {
G
gero3 已提交
697

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

701
		}
G
gero3 已提交
702

703
	}
Z
zz85 已提交
704

M
Mr.doob 已提交
705 706 707
	var tmpHoles;

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

		tmpShape = newShapes[ i ].s;
Z
zz85 已提交
710
		shapes.push( tmpShape );
G
gero3 已提交
711
		tmpHoles = newShapeHoles[ i ];
M
Mr.doob 已提交
712 713

		for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
G
gero3 已提交
714 715 716

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

717
		}
G
gero3 已提交
718

Z
zz85 已提交
719
	}
720

721
	//console.log("shape", shapes);
722

Z
zz85 已提交
723
	return shapes;
724

Z
zz85 已提交
725
};