source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/extras/core/Shape.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 10.3 KB
Line 
1/**
2 * @author zz85 / http://www.lab4games.net/zz85/blog
3 * Defines a 2d shape plane using paths.
4 **/
5
6// STEP 1 Create a path.
7// STEP 2 Turn path into shape.
8// STEP 3 ExtrudeGeometry takes in Shape/Shapes
9// STEP 3a - Extract points from each shape, turn to vertices
10// STEP 3b - Triangulate each shape, add faces.
11
12THREE.Shape = function () {
13
14 THREE.Path.apply( this, arguments );
15 this.holes = [];
16
17};
18
19THREE.Shape.prototype = Object.create( THREE.Path.prototype );
20
21// Convenience method to return ExtrudeGeometry
22
23THREE.Shape.prototype.extrude = function ( options ) {
24
25 var extruded = new THREE.ExtrudeGeometry( this, options );
26 return extruded;
27
28};
29
30// Convenience method to return ShapeGeometry
31
32THREE.Shape.prototype.makeGeometry = function ( options ) {
33
34 var geometry = new THREE.ShapeGeometry( this, options );
35 return geometry;
36
37};
38
39// Get points of holes
40
41THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
42
43 var i, il = this.holes.length, holesPts = [];
44
45 for ( i = 0; i < il; i ++ ) {
46
47 holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );
48
49 }
50
51 return holesPts;
52
53};
54
55// Get points of holes (spaced by regular distance)
56
57THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
58
59 var i, il = this.holes.length, holesPts = [];
60
61 for ( i = 0; i < il; i ++ ) {
62
63 holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );
64
65 }
66
67 return holesPts;
68
69};
70
71
72// Get points of shape and holes (keypoints based on segments parameter)
73
74THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
75
76 return {
77
78 shape: this.getTransformedPoints( divisions ),
79 holes: this.getPointsHoles( divisions )
80
81 };
82
83};
84
85THREE.Shape.prototype.extractPoints = function ( divisions ) {
86
87 if (this.useSpacedPoints) {
88 return this.extractAllSpacedPoints(divisions);
89 }
90
91 return this.extractAllPoints(divisions);
92
93};
94
95//
96// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
97//
98// return {
99//
100// shape: this.transform( bend, divisions ),
101// holes: this.getPointsHoles( divisions, bend )
102//
103// };
104//
105// };
106
107// Get points of shape and holes (spaced by regular distance)
108
109THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
110
111 return {
112
113 shape: this.getTransformedSpacedPoints( divisions ),
114 holes: this.getSpacedPointsHoles( divisions )
115
116 };
117
118};
119
120/**************************************************************
121 * Utils
122 **************************************************************/
123
124THREE.Shape.Utils = {
125
126 /*
127 contour - array of vector2 for contour
128 holes - array of array of vector2
129 */
130
131 removeHoles: function ( contour, holes ) {
132
133 var shape = contour.concat(); // work on this shape
134 var allpoints = shape.concat();
135
136 /* For each isolated shape, find the closest points and break to the hole to allow triangulation */
137
138
139 var prevShapeVert, nextShapeVert,
140 prevHoleVert, nextHoleVert,
141 holeIndex, shapeIndex,
142 shapeId, shapeGroup,
143 h, h2,
144 hole, shortest, d,
145 p, pts1, pts2,
146 tmpShape1, tmpShape2,
147 tmpHole1, tmpHole2,
148 verts = [];
149
150 for ( h = 0; h < holes.length; h ++ ) {
151
152 hole = holes[ h ];
153
154 /*
155 shapeholes[ h ].concat(); // preserves original
156 holes.push( hole );
157 */
158
159 Array.prototype.push.apply( allpoints, hole );
160
161 shortest = Number.POSITIVE_INFINITY;
162
163
164 // Find the shortest pair of pts between shape and hole
165
166 // Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n)
167 // Using distanceToSquared() intead of distanceTo() should speed a little
168 // since running square roots operations are reduced.
169
170 for ( h2 = 0; h2 < hole.length; h2 ++ ) {
171
172 pts1 = hole[ h2 ];
173 var dist = [];
174
175 for ( p = 0; p < shape.length; p++ ) {
176
177 pts2 = shape[ p ];
178 d = pts1.distanceToSquared( pts2 );
179 dist.push( d );
180
181 if ( d < shortest ) {
182
183 shortest = d;
184 holeIndex = h2;
185 shapeIndex = p;
186
187 }
188
189 }
190
191 }
192
193 //console.log("shortest", shortest, dist);
194
195 prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
196 prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
197
198 var areaapts = [
199
200 hole[ holeIndex ],
201 shape[ shapeIndex ],
202 shape[ prevShapeVert ]
203
204 ];
205
206 var areaa = THREE.FontUtils.Triangulate.area( areaapts );
207
208 var areabpts = [
209
210 hole[ holeIndex ],
211 hole[ prevHoleVert ],
212 shape[ shapeIndex ]
213
214 ];
215
216 var areab = THREE.FontUtils.Triangulate.area( areabpts );
217
218 var shapeOffset = 1;
219 var holeOffset = -1;
220
221 var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex;
222 shapeIndex += shapeOffset;
223 holeIndex += holeOffset;
224
225 if ( shapeIndex < 0 ) { shapeIndex += shape.length; }
226 shapeIndex %= shape.length;
227
228 if ( holeIndex < 0 ) { holeIndex += hole.length; }
229 holeIndex %= hole.length;
230
231 prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
232 prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
233
234 areaapts = [
235
236 hole[ holeIndex ],
237 shape[ shapeIndex ],
238 shape[ prevShapeVert ]
239
240 ];
241
242 var areaa2 = THREE.FontUtils.Triangulate.area( areaapts );
243
244 areabpts = [
245
246 hole[ holeIndex ],
247 hole[ prevHoleVert ],
248 shape[ shapeIndex ]
249
250 ];
251
252 var areab2 = THREE.FontUtils.Triangulate.area( areabpts );
253 //console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ), ( areaa2 + areab2 ));
254
255 if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) {
256
257 // In case areas are not correct.
258 //console.log("USE THIS");
259
260 shapeIndex = oldShapeIndex;
261 holeIndex = oldHoleIndex ;
262
263 if ( shapeIndex < 0 ) { shapeIndex += shape.length; }
264 shapeIndex %= shape.length;
265
266 if ( holeIndex < 0 ) { holeIndex += hole.length; }
267 holeIndex %= hole.length;
268
269 prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
270 prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
271
272 } else {
273
274 //console.log("USE THAT ")
275
276 }
277
278 tmpShape1 = shape.slice( 0, shapeIndex );
279 tmpShape2 = shape.slice( shapeIndex );
280 tmpHole1 = hole.slice( holeIndex );
281 tmpHole2 = hole.slice( 0, holeIndex );
282
283 // Should check orders here again?
284
285 var trianglea = [
286
287 hole[ holeIndex ],
288 shape[ shapeIndex ],
289 shape[ prevShapeVert ]
290
291 ];
292
293 var triangleb = [
294
295 hole[ holeIndex ] ,
296 hole[ prevHoleVert ],
297 shape[ shapeIndex ]
298
299 ];
300
301 verts.push( trianglea );
302 verts.push( triangleb );
303
304 shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
305
306 }
307
308 return {
309
310 shape:shape, /* shape with no holes */
311 isolatedPts: verts, /* isolated faces */
312 allpoints: allpoints
313
314 }
315
316
317 },
318
319 triangulateShape: function ( contour, holes ) {
320
321 var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes );
322
323 var shape = shapeWithoutHoles.shape,
324 allpoints = shapeWithoutHoles.allpoints,
325 isolatedPts = shapeWithoutHoles.isolatedPts;
326
327 var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape
328
329 // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
330
331 //console.log( "triangles",triangles, triangles.length );
332 //console.log( "allpoints",allpoints, allpoints.length );
333
334 var i, il, f, face,
335 key, index,
336 allPointsMap = {},
337 isolatedPointsMap = {};
338
339 // prepare all points map
340
341 for ( i = 0, il = allpoints.length; i < il; i ++ ) {
342
343 key = allpoints[ i ].x + ":" + allpoints[ i ].y;
344
345 if ( allPointsMap[ key ] !== undefined ) {
346
347 console.log( "Duplicate point", key );
348
349 }
350
351 allPointsMap[ key ] = i;
352
353 }
354
355 // check all face vertices against all points map
356
357 for ( i = 0, il = triangles.length; i < il; i ++ ) {
358
359 face = triangles[ i ];
360
361 for ( f = 0; f < 3; f ++ ) {
362
363 key = face[ f ].x + ":" + face[ f ].y;
364
365 index = allPointsMap[ key ];
366
367 if ( index !== undefined ) {
368
369 face[ f ] = index;
370
371 }
372
373 }
374
375 }
376
377 // check isolated points vertices against all points map
378
379 for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {
380
381 face = isolatedPts[ i ];
382
383 for ( f = 0; f < 3; f ++ ) {
384
385 key = face[ f ].x + ":" + face[ f ].y;
386
387 index = allPointsMap[ key ];
388
389 if ( index !== undefined ) {
390
391 face[ f ] = index;
392
393 }
394
395 }
396
397 }
398
399 return triangles.concat( isolatedPts );
400
401 }, // end triangulate shapes
402
403 /*
404 triangulate2 : function( pts, holes ) {
405
406 // For use with Poly2Tri.js
407
408 var allpts = pts.concat();
409 var shape = [];
410 for (var p in pts) {
411 shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y));
412 }
413
414 var swctx = new js.poly2tri.SweepContext(shape);
415
416 for (var h in holes) {
417 var aHole = holes[h];
418 var newHole = []
419 for (i in aHole) {
420 newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y));
421 allpts.push(aHole[i]);
422 }
423 swctx.AddHole(newHole);
424 }
425
426 var find;
427 var findIndexForPt = function (pt) {
428 find = new THREE.Vector2(pt.x, pt.y);
429 var p;
430 for (p=0, pl = allpts.length; p<pl; p++) {
431 if (allpts[p].equals(find)) return p;
432 }
433 return -1;
434 };
435
436 // triangulate
437 js.poly2tri.sweep.Triangulate(swctx);
438
439 var triangles = swctx.GetTriangles();
440 var tr ;
441 var facesPts = [];
442 for (var t in triangles) {
443 tr = triangles[t];
444 facesPts.push([
445 findIndexForPt(tr.GetPoint(0)),
446 findIndexForPt(tr.GetPoint(1)),
447 findIndexForPt(tr.GetPoint(2))
448 ]);
449 }
450
451
452 // console.log(facesPts);
453 // console.log("triangles", triangles.length, triangles);
454
455 // Returns array of faces with 3 element each
456 return facesPts;
457 },
458*/
459
460 isClockWise: function ( pts ) {
461
462 return THREE.FontUtils.Triangulate.area( pts ) < 0;
463
464 },
465
466 // Bezier Curves formulas obtained from
467 // http://en.wikipedia.org/wiki/B%C3%A9zier_curve
468
469 // Quad Bezier Functions
470
471 b2p0: function ( t, p ) {
472
473 var k = 1 - t;
474 return k * k * p;
475
476 },
477
478 b2p1: function ( t, p ) {
479
480 return 2 * ( 1 - t ) * t * p;
481
482 },
483
484 b2p2: function ( t, p ) {
485
486 return t * t * p;
487
488 },
489
490 b2: function ( t, p0, p1, p2 ) {
491
492 return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
493
494 },
495
496 // Cubic Bezier Functions
497
498 b3p0: function ( t, p ) {
499
500 var k = 1 - t;
501 return k * k * k * p;
502
503 },
504
505 b3p1: function ( t, p ) {
506
507 var k = 1 - t;
508 return 3 * k * k * t * p;
509
510 },
511
512 b3p2: function ( t, p ) {
513
514 var k = 1 - t;
515 return 3 * k * t * t * p;
516
517 },
518
519 b3p3: function ( t, p ) {
520
521 return t * t * t * p;
522
523 },
524
525 b3: function ( t, p0, p1, p2, p3 ) {
526
527 return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );
528
529 }
530
531};
532
Note: See TracBrowser for help on using the repository browser.