Path.js 15.7 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 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 ];
G
gero3 已提交
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

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

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

146 147 148 149
 };

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

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

153
 };
Z
zz85 已提交
154

155
THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
156
									  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 ];

G
gero3 已提交
162
	this.absellipse( aX + x0, aY + y0, xRadius, yRadius,
163
		aStartAngle, aEndAngle, aClockwise, aRotation );
164

165
 };
Z
zz85 已提交
166

167 168

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

N
neko 已提交
171 172 173 174 175 176 177
	var args = [
		aX, aY,
		xRadius, yRadius,
		aStartAngle, aEndAngle,
		aClockwise,
		aRotation || 0 // aRotation is optional.
	];
178
	var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
179
									aStartAngle, aEndAngle, aClockwise, aRotation );
180 181
	this.curves.push( curve );

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

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

 };

190
THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
191

Z
zz85 已提交
192
	if ( ! divisions ) divisions = 40;
193

194 195
	var points = [];

196
	for ( var i = 0; i < divisions; i ++ ) {
197

198
		points.push( this.getPoint( i / divisions ) );
199

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

Z
zz85 已提交
202
	}
Z
zz85 已提交
203

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

	return points;
211 212

};
Z
zz85 已提交
213

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

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

G
gero3 已提交
218 219
	if ( this.useSpacedPoints ) {

220
		return this.getSpacedPoints( divisions, closedPath );
G
gero3 已提交
221

222 223
	}

Z
zz85 已提交
224 225
	divisions = divisions || 12;

226 227 228 229 230 231 232
	var points = [];

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

233
	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
234 235 236 237 238 239

		item = this.actions[ i ];

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

G
gero3 已提交
240
		switch ( action ) {
241 242 243

		case THREE.PathActions.MOVE_TO:

244
			points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
Z
zz85 已提交
245 246 247

			break;

248 249 250 251
		case THREE.PathActions.LINE_TO:

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

Z
zz85 已提交
252 253
			break;

254 255 256 257 258 259 260 261 262 263 264
		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 已提交
265 266 267

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

Z
zz85 已提交
269 270
			} else {

271 272 273 274
				laste = this.actions[ i - 1 ].args;

				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
275 276 277

			}

278 279 280 281
			for ( j = 1; j <= divisions; j ++ ) {

				t = j / divisions;

282 283
				tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
				ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
284 285 286

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

Z
zz85 已提交
287
			}
288

Z
zz85 已提交
289 290
			break;

291
		case THREE.PathActions.BEZIER_CURVE_TO:
Z
zz85 已提交
292

293 294
			cpx  = args[ 4 ];
			cpy  = args[ 5 ];
Z
zz85 已提交
295

296 297
			cpx1 = args[ 0 ];
			cpy1 = args[ 1 ];
Z
zz85 已提交
298

299 300
			cpx2 = args[ 2 ];
			cpy2 = args[ 3 ];
Z
zz85 已提交
301

302
			if ( points.length > 0 ) {
Z
zz85 已提交
303

304
				laste = points[ points.length - 1 ];
Z
zz85 已提交
305

306 307
				cpx0 = laste.x;
				cpy0 = laste.y;
Z
zz85 已提交
308

309
			} else {
Z
zz85 已提交
310

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

313 314
				cpx0 = laste[ laste.length - 2 ];
				cpy0 = laste[ laste.length - 1 ];
Z
zz85 已提交
315

316
			}
Z
zz85 已提交
317 318


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

321
				t = j / divisions;
Z
zz85 已提交
322

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

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

328
			}
Z
zz85 已提交
329

330
			break;
Z
zz85 已提交
331

Z
zz85 已提交
332
		case THREE.PathActions.CSPLINE_THRU:
333

334
			laste = this.actions[ i - 1 ].args;
335

336
			var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
337
			var spts = [ last ];
338

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

341
			spts = spts.concat( args[ 0 ] );
342

343
			var spline = new THREE.SplineCurve( spts );
344

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

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

349
			}
350

Z
zz85 已提交
351
			break;
Z
zz85 已提交
352

Z
zz85 已提交
353
		case THREE.PathActions.ARC:
Z
zz85 已提交
354

355 356 357
			var aX = args[ 0 ], aY = args[ 1 ],
				aRadius = args[ 2 ],
				aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
358
				aClockwise = !! args[ 5 ];
Z
zz85 已提交
359

Z
zz85 已提交
360 361
			var deltaAngle = aEndAngle - aStartAngle;
			var angle;
Z
zz85 已提交
362
			var tdivisions = divisions * 2;
363

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

366
				t = j / tdivisions;
367

Z
zz85 已提交
368
				if ( ! aClockwise ) {
369

Z
zz85 已提交
370
					t = 1 - t;
371

Z
zz85 已提交
372
				}
373

Z
zz85 已提交
374
				angle = aStartAngle + t * deltaAngle;
375

376 377
				tx = aX + aRadius * Math.cos( angle );
				ty = aY + aRadius * Math.sin( angle );
378

379
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
380

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

Z
zz85 已提交
383
			}
384

385
			//console.log(points);
Z
zz85 已提交
386

G
gero3 已提交
387
			break;
F
Fabian Lange 已提交
388

389 390 391 392
		case THREE.PathActions.ELLIPSE:

			var aX = args[ 0 ], aY = args[ 1 ],
				xRadius = args[ 2 ],
393
				yRadius = args[ 3 ],
394
				aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
395
				aClockwise = !! args[ 6 ],
N
neko 已提交
396
				aRotation = args[ 7 ];
397 398 399 400 401 402


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

403
			var cos, sin;
N
neko 已提交
404
			if ( aRotation !== 0 ) {
405 406 407 408 409 410
		
				cos = Math.cos( aRotation );
				sin = Math.sin( aRotation );

			}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
			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 );

N
neko 已提交
426
				if ( aRotation !== 0 ) {
427

N
neko 已提交
428 429
					var x = tx, y = ty;

430
					// Rotate the point about the center of the ellipse.
N
neko 已提交
431 432
					tx = ( x - aX ) * cos - ( y - aY ) * sin + aX;
					ty = ( x - aX ) * sin + ( y - aY ) * cos + aY;
433 434 435

				}

436
				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
437 438 439 440 441

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

			}

442
			//console.log(points);
443

G
gero3 已提交
444
			break;
Z
zz85 已提交
445 446

		} // end switch
Z
zz85 已提交
447

448 449
	}

450 451 452


	// Normalize to remove the closing point by default.
G
gero3 已提交
453
	var lastPoint = points[ points.length - 1 ];
454
	var EPSILON = 0.0000000001;
G
gero3 已提交
455 456 457
	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 已提交
458 459 460 461 462 463
	if ( closedPath ) {

		points.push( points[ 0 ] );

	}

464
	return points;
Z
zz85 已提交
465

466
};
Z
zz85 已提交
467

468
//
469
// Breaks path into shapes
470 471 472 473 474 475 476 477 478
//
//	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
//
479

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
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 已提交
495
			if ( action === THREE.PathActions.MOVE_TO ) {
496

F
Fabian Lange 已提交
497
				if ( lastPath.actions.length !== 0 ) {
498 499 500 501 502 503 504 505 506 507 508 509

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

				}

			}

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

		}

F
Fabian Lange 已提交
510
		if ( lastPath.actions.length !== 0 ) {
511 512 513 514 515

			subPaths.push( lastPath );

		}

516
		// console.log(subPaths);
517 518

		return	subPaths;
G
gero3 已提交
519

520 521 522 523 524 525
	}

	function toShapesNoHoles( inSubpaths ) {

		var shapes = [];

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

J
Juergen Ahting 已提交
528
			var tmpPath = inSubpaths[ i ];
529

J
Juergen Ahting 已提交
530
			var tmpShape = new THREE.Shape();
531 532 533 534
			tmpShape.actions = tmpPath.actions;
			tmpShape.curves = tmpPath.curves;

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

536 537
		}

538
		//console.log("shape", shapes);
539 540

		return shapes;
G
gero3 已提交
541

B
brason 已提交
542
	}
543

544
	function isPointInsidePolygon( inPt, inPolygon ) {
G
gero3 已提交
545

546 547 548 549 550 551 552 553 554
		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 已提交
555
		for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
G
gero3 已提交
556

557 558 559 560 561 562
			var edgeLowPt  = inPolygon[ p ];
			var edgeHighPt = inPolygon[ q ];

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

G
gero3 已提交
563 564 565
			if ( Math.abs( edgeDy ) > EPSILON ) {

				// not parallel
566
				if ( edgeDy < 0 ) {
G
gero3 已提交
567

568 569
					edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
					edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
G
gero3 已提交
570

571 572 573
				}
				if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;

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

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

579
				} else {
G
gero3 已提交
580 581

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

586
				}
G
gero3 已提交
587 588 589 590

			} else {

				// parallel or collinear
F
Fabian Lange 已提交
591
				if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
D
dubejf 已提交
592
				// edge lies on the same horizontal line as inPt
593 594 595
				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 已提交
596

597
			}
G
gero3 已提交
598

599 600 601
		}

		return	inside;
G
gero3 已提交
602

603 604
	}

605

606
	var subPaths = extractSubpaths( this.actions );
F
Fabian Lange 已提交
607
	if ( subPaths.length === 0 ) return [];
608

J
Juergen Ahting 已提交
609
	if ( noHoles === true )	return	toShapesNoHoles( subPaths );
610 611


Z
zz85 已提交
612
	var solid, tmpPath, tmpShape, shapes = [];
Z
zz85 已提交
613

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

G
gero3 已提交
616
		tmpPath = subPaths[ 0 ];
Z
zz85 已提交
617 618 619 620 621
		tmpShape = new THREE.Shape();
		tmpShape.actions = tmpPath.actions;
		tmpShape.curves = tmpPath.curves;
		shapes.push( tmpShape );
		return shapes;
622

Z
zz85 已提交
623
	}
624

625 626
	var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
	holesFirst = isCCW ? ! holesFirst : holesFirst;
627

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

630 631 632 633 634
	var betterShapeHoles = [];
	var newShapes = [];
	var newShapeHoles = [];
	var mainIdx = 0;
	var tmpPoints;
635

G
gero3 已提交
636 637
	newShapes[ mainIdx ] = undefined;
	newShapeHoles[ mainIdx ] = [];
638

639 640
	var i, il;

641
	for ( i = 0, il = subPaths.length; i < il; i ++ ) {
642

643 644 645
		tmpPath = subPaths[ i ];
		tmpPoints = tmpPath.getPoints();
		solid = THREE.Shape.Utils.isClockWise( tmpPoints );
646
		solid = isCCW ? ! solid : solid;
647

648
		if ( solid ) {
649

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

G
gero3 已提交
652 653 654
			newShapes[ mainIdx ] = { s: new THREE.Shape(), p: tmpPoints };
			newShapes[ mainIdx ].s.actions = tmpPath.actions;
			newShapes[ mainIdx ].s.curves = tmpPath.curves;
F
Fabian Lange 已提交
655

656
			if ( holesFirst )	mainIdx ++;
G
gero3 已提交
657
			newShapeHoles[ mainIdx ] = [];
658

659
			//console.log('cw', i);
660

661
		} else {
662

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

665
			//console.log('ccw', i);
666

Z
zz85 已提交
667
		}
668

669
	}
670

671
	// only Holes? -> probably all Shapes with wrong orientation
G
gero3 已提交
672
	if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
673 674


675
	if ( newShapes.length > 1 ) {
G
gero3 已提交
676

D
dubejf 已提交
677
		var ambiguous = false;
678
		var toChange = [];
679

G
gero3 已提交
680 681 682 683
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

			betterShapeHoles[ sIdx ] = [];

684
		}
G
gero3 已提交
685 686 687 688 689 690
		for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {

			var sho = newShapeHoles[ sIdx ];
			for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {

				var ho = sho[ hIdx ];
691
				var hole_unassigned = true;
G
gero3 已提交
692 693 694 695
				for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {

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

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

699
							hole_unassigned = false;
G
gero3 已提交
700 701
							betterShapeHoles[ s2Idx ].push( ho );

702
						} else {
G
gero3 已提交
703

D
dubejf 已提交
704
							ambiguous = true;
G
gero3 已提交
705

706
						}
G
gero3 已提交
707

708
					}
G
gero3 已提交
709

710
				}
G
gero3 已提交
711 712 713 714 715 716
				if ( hole_unassigned ) {

					betterShapeHoles[ sIdx ].push( ho );

				}

Z
zz85 已提交
717
			}
G
gero3 已提交
718

Z
zz85 已提交
719
		}
D
dubejf 已提交
720
		// console.log("ambiguous: ", ambiguous);
721
		if ( toChange.length > 0 ) {
G
gero3 已提交
722

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

726
		}
G
gero3 已提交
727

728
	}
Z
zz85 已提交
729

730 731
	var tmpHoles, j, jl;
	for ( i = 0, il = newShapes.length; i < il; i ++ ) {
G
gero3 已提交
732 733

		tmpShape = newShapes[ i ].s;
Z
zz85 已提交
734
		shapes.push( tmpShape );
G
gero3 已提交
735
		tmpHoles = newShapeHoles[ i ];
736
		for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
G
gero3 已提交
737 738 739

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

740
		}
G
gero3 已提交
741

Z
zz85 已提交
742
	}
743

744
	//console.log("shape", shapes);
745

Z
zz85 已提交
746
	return shapes;
747

Z
zz85 已提交
748
};