RSS

(root)/iphone/common : 61 : Jigs/source/Triangulation.m

« back to all changes in this revision

Viewing changes to Jigs/source/Triangulation.m

Dömötör Gulyás
2010-01-18 09:03:51
Revision ID: dognotdog@gmail.com-20100118080351-ib2knxvk4w8ssw3h
made common a nested tree

Show diffs side-by-side

added added

removed removed

1
 
//
2
 
//  Triangulation.m
3
 
//  Jigs
4
 
//
5
 
//  Created by döme on 05.08.2009.
6
 
//  Copyright 2009 __MyCompanyName__. All rights reserved.
7
 
//
8
 
 
9
 
#import "Triangulation.h"
10
 
 
11
 
#import "geometry.h"
12
 
#import "VertexArray.h"
13
 
 
14
 
//#define SHOW_LINES 1
15
 
 
16
 
struct _bezierElementExtractorRec
17
 
{
18
 
        CGPoint*        points;
19
 
        size_t          numPoints;
20
 
        float           targetResolution;
21
 
};
22
 
 
23
 
void _bezierPathElementExtractor(void *info,
24
 
    const CGPathElement *element)
25
 
{
26
 
        struct _bezierElementExtractorRec* rec = info;
27
 
        switch(element->type)
28
 
        {
29
 
                case kCGPathElementMoveToPoint:
30
 
                        if (rec->numPoints && CGPointEqualToPoint(element->points[0], rec->points[rec->numPoints-1]))
31
 
                                break;
32
 
                        rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+1));
33
 
                        rec->points[rec->numPoints++] = element->points[0];
34
 
                        break;
35
 
                case kCGPathElementAddLineToPoint:
36
 
                {
37
 
                        CGPoint c0 = element->points[0];
38
 
                        //CGPoint c1 = element->points[1];
39
 
 
40
 
                        //if (rec->numPoints && CGPointEqualToPoint(c1, lastPoint))
41
 
                        //      break;
42
 
                        rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+1));
43
 
                        rec->points[rec->numPoints++] = c0;
44
 
                        break;
45
 
                }
46
 
                case kCGPathElementAddQuadCurveToPoint:
47
 
                {
48
 
                        CGPoint c0 = rec->points[rec->numPoints-1];
49
 
                        CGPoint c1 = element->points[0];
50
 
                        CGPoint c2 = element->points[1];
51
 
                        float approxLength = sqrtf(CGPointDoubleDot(CGPointSub(c1,c0)) + CGPointDoubleDot(CGPointSub(c2,c1)));
52
 
 
53
 
                        int numSegments = 2 + (int)(approxLength/rec->targetResolution);
54
 
                        
55
 
                        rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+numSegments));
56
 
 
57
 
                        for (int i = 0; i < numSegments; ++i)
58
 
                        {
59
 
                                float t = (i+1)/(float)numSegments;
60
 
                                rec->points[rec->numPoints+i] = quadraticPointAtT(c0, c1, c2, t);
61
 
                        }
62
 
 
63
 
                        rec->numPoints += numSegments;
64
 
                        
65
 
                        break;
66
 
                }
67
 
                case kCGPathElementAddCurveToPoint:
68
 
                {
69
 
                        CGPoint c0 = rec->points[rec->numPoints-1];
70
 
                        CGPoint c1 = element->points[0];
71
 
                        CGPoint c2 = element->points[1];
72
 
                        CGPoint c3 = element->points[2];
73
 
                        //CGPoint c3 = element->points[3];
74
 
                        float approxLength = sqrtf(CGPointDoubleDot(CGPointSub(c1, c0)) + CGPointDoubleDot(CGPointSub(c2, c1)) + CGPointDoubleDot(CGPointSub(c3, c2)));
75
 
 
76
 
                        int numSegments = 3 + (int)(approxLength/rec->targetResolution);
77
 
                        
78
 
                        rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+numSegments));
79
 
 
80
 
                        for (int i = 0; i < numSegments; ++i)
81
 
                        {
82
 
                                float t = (i+1)/(float)numSegments;
83
 
                                CGPoint p = cubicPointAtT(c0, c1, c2, c3, t);
84
 
                                rec->points[rec->numPoints+i] = p;
85
 
                        }
86
 
 
87
 
                        rec->numPoints += numSegments;
88
 
                        
89
 
                        break;
90
 
                }
91
 
                case kCGPathElementCloseSubpath:
92
 
                {
93
 
                        break;
94
 
                }
95
 
        };
96
 
}
97
 
 
98
 
void SimpleBezierPathToPolyline(CGPathRef cpath, CGPoint** outPoints, size_t* numOutPoints)
99
 
{
100
 
        struct _bezierElementExtractorRec lineRec = {NULL, 0, 5.0f};
101
 
        CGPathApply(cpath, &lineRec, _bezierPathElementExtractor);
102
 
        
103
 
//      NSLog(@"points:");
104
 
//      for (size_t i = 0; i < lineRec.numPoints; ++i)
105
 
//              NSLog(@"%f %f", lineRec.points[i].x, lineRec.points[i].y);
106
 
        
107
 
        *outPoints = lineRec.points;
108
 
        *numOutPoints = lineRec.numPoints;
109
 
}
110
 
 
111
 
struct _vertex;
112
 
typedef struct _vertex _vertex;
113
 
 
114
 
struct _edge;
115
 
typedef struct _edge _edge;
116
 
 
117
 
typedef struct _polygon
118
 
{
119
 
        _edge*          firstEdge;
120
 
        size_t          numEdges;
121
 
} _polygon;
122
 
 
123
 
struct _vertex
124
 
{
125
 
        CGPoint         pos;
126
 
        _edge**         edges;
127
 
        size_t          numEdges;
128
 
};
129
 
 
130
 
struct _edge
131
 
{
132
 
        _edge*          dual;
133
 
        _edge*          prevEdge;
134
 
        _edge*          nextEdge;
135
 
        _polygon*       polygon;
136
 
        size_t          vertices[2];
137
 
};
138
 
 
139
 
void _vertexAddEdge(_vertex* self, _edge* edge)
140
 
{
141
 
        self->edges = realloc(self->edges, sizeof(*self->edges)*(self->numEdges+1));
142
 
        self->edges[self->numEdges++] = edge;
143
 
};
144
 
 
145
 
_edge* _edgeCreate(size_t v0, size_t v1, _edge* dual, _vertex* vertices)
146
 
{
147
 
        _edge* self = calloc(1, sizeof(*self));
148
 
        
149
 
        assert(v0 != v1);
150
 
        
151
 
        self->vertices[0] = v0;
152
 
        self->vertices[1] = v1;
153
 
        self->dual = dual;
154
 
        if (dual)
155
 
                dual->dual = self;
156
 
        
157
 
        _vertexAddEdge(&vertices[v0], self);
158
 
        _vertexAddEdge(&vertices[v1], self);
159
 
 
160
 
        return self;
161
 
}
162
 
 
163
 
 
164
 
_polygon* _polyCreate(void)
165
 
{
166
 
        _polygon* self = calloc(1, sizeof(*self));
167
 
        
168
 
        return self;
169
 
}
170
 
 
171
 
void _polyRemoveEdge(_polygon* self, _edge* edge)
172
 
{
173
 
        if (edge == self->firstEdge)
174
 
                self->firstEdge = edge->nextEdge;
175
 
        
176
 
        if (edge->prevEdge)
177
 
                edge->prevEdge->nextEdge = edge->nextEdge;
178
 
        if (edge->nextEdge)
179
 
                edge->nextEdge->prevEdge = edge->prevEdge;
180
 
        edge->prevEdge = NULL;
181
 
        edge->nextEdge = NULL;
182
 
        edge->polygon = NULL;
183
 
        
184
 
        self->numEdges--;
185
 
}
186
 
 
187
 
void _polyDelete(_polygon* self)
188
 
{
189
 
        while (self->numEdges)
190
 
        {
191
 
                _edge* edge = self->firstEdge;
192
 
                _polyRemoveEdge(self, edge);
193
 
                free(edge);
194
 
        }
195
 
 
196
 
        free(self);
197
 
}
198
 
 
199
 
 
200
 
void _polyReplaceEdgesWithEdge(_polygon* self, _edge* e0, _edge* e1, _edge* replacement)
201
 
{
202
 
        if (e0->polygon == self)
203
 
                e0->polygon = NULL;
204
 
        if (e1->polygon == self)
205
 
                e1->polygon = NULL;
206
 
                
207
 
        replacement->prevEdge = e0->prevEdge;
208
 
        replacement->nextEdge = e1->nextEdge;
209
 
        if (replacement->prevEdge)
210
 
                replacement->prevEdge->nextEdge = replacement;
211
 
        if (replacement->nextEdge)
212
 
                replacement->nextEdge->prevEdge = replacement;
213
 
        
214
 
        if ((self->firstEdge == e0) || (self->firstEdge == e1))
215
 
                self->firstEdge = replacement;
216
 
 
217
 
        replacement->polygon = self;
218
 
        
219
 
        self->numEdges--;
220
 
}
221
 
 
222
 
void _polyAddEdge(_polygon* self, _edge* edge)
223
 
{
224
 
        edge->polygon = self;
225
 
        
226
 
        if (self->numEdges)
227
 
        {
228
 
                edge->nextEdge = self->firstEdge;
229
 
                edge->prevEdge = self->firstEdge->prevEdge;
230
 
                
231
 
                edge->nextEdge->prevEdge = edge;
232
 
                edge->prevEdge->nextEdge = edge;
233
 
        }
234
 
        else
235
 
        {
236
 
                self->firstEdge = edge;
237
 
                edge->nextEdge = edge;
238
 
                edge->prevEdge = edge;
239
 
        }
240
 
                
241
 
        self->numEdges++;
242
 
}
243
 
 
244
 
void polygonRobustnessCheck(_polygon* polygon, _vertex* vertices)
245
 
{
246
 
        _edge* edge0 = polygon->firstEdge;
247
 
        for (size_t i = 0; i < polygon->numEdges; ++i, edge0 = edge0->nextEdge)
248
 
        {
249
 
                CGPoint a0 = vertices[edge0->vertices[0]].pos;
250
 
                CGPoint a1 = vertices[edge0->vertices[1]].pos;
251
 
                
252
 
                assert(!CGPointEqualToPoint(a0, a1));
253
 
                
254
 
                _edge* edge1 = edge0->nextEdge->nextEdge;
255
 
                for (size_t j = i+2; j < polygon->numEdges; ++j, edge1 = edge1->nextEdge)
256
 
                {
257
 
                        CGPoint b0 = vertices[edge1->vertices[0]].pos;
258
 
                        CGPoint b1 = vertices[edge1->vertices[1]].pos;
259
 
                        
260
 
                        if (CGLineSegmentsIntersect(a0,a1,b0,b1))
261
 
                        {
262
 
                                NSLog(@"oops, found a baddie");
263
 
                        }
264
 
                        
265
 
                }
266
 
        }
267
 
}
268
 
 
269
 
_polygon* triangulatePolygon(_polygon* polygon, _vertex* vertices)
270
 
{
271
 
        if (polygon->numEdges < 4)
272
 
                return NULL;
273
 
 
274
 
        
275
 
        //NSMutableArray* rejectionList = [NSMutableArray array];;
276
 
        
277
 
        _edge* edge0 = polygon->firstEdge;
278
 
        for (size_t i = 0; i < polygon->numEdges; ++i, edge0 = edge0->nextEdge)
279
 
        {
280
 
                _edge* edge1 = edge0->nextEdge;
281
 
 
282
 
                assert(edge0->vertices[1] == edge1->vertices[0]);
283
 
 
284
 
                CGPoint p0 = vertices[edge0->vertices[0]].pos;
285
 
                CGPoint p1 = vertices[edge0->vertices[1]].pos;
286
 
                CGPoint p2 = vertices[edge1->vertices[1]].pos;
287
 
                CGPoint e01 = CGPointSub(p1, p0);
288
 
                CGPoint e12 = CGPointSub(p2, p1);
289
 
                
290
 
                float ecross = CGPointCross(e01, e12);
291
 
                
292
 
                if (ecross < 0.0f)
293
 
                {       
294
 
                        //[rejectionList addObject: [NSString stringWithFormat: @"wrong winding %zu %zu, %f", i0,i1, ecross]];
295
 
                        continue;
296
 
                }
297
 
                        
298
 
                // if the third edge would be in correct winding order, we need to make sure it's also
299
 
                //      1) within the adjacent edges
300
 
                //      2) not intersecting non-adjacent edges
301
 
                
302
 
 
303
 
                size_t numNonEdges = polygon->numEdges - 3;
304
 
                
305
 
                int intersectFound = 0;
306
 
                
307
 
                _edge* nonEdge = edge1->nextEdge;
308
 
                for (size_t j = 0; j < numNonEdges; ++j, nonEdge = nonEdge->nextEdge)
309
 
                {
310
 
                        CGPoint x = vertices[nonEdge->vertices[1]].pos;
311
 
                        
312
 
                        
313
 
                        if (CGPointInTriangle(x, p0, p1, p2))
314
 
                        {
315
 
                                intersectFound = 1;
316
 
                                //[rejectionList addObject: [NSString stringWithFormat: @"vertex in triangle %zu %zu X %zu", i0,i1, nonEdge->vertices[0]]];
317
 
                                break;
318
 
                        }
319
 
                }
320
 
                
321
 
                if (intersectFound)
322
 
                {
323
 
                        continue;
324
 
                }
325
 
        
326
 
                // the new edge doesn't intersect anything, so we can go on and create the new triangle
327
 
                
328
 
                _edge* edge2 = _edgeCreate(edge1->vertices[1], edge0->vertices[0], NULL, vertices);
329
 
                _edge* edgeRedux = _edgeCreate(edge0->vertices[0], edge1->vertices[1], edge2, vertices);
330
 
 
331
 
                _polyReplaceEdgesWithEdge(polygon, edge0, edge1, edgeRedux); // important to replace first, due to edge prev/next pointers
332
 
 
333
 
                _polygon* reducedPoly = _polyCreate();
334
 
                _polyAddEdge(reducedPoly, edge0);
335
 
                _polyAddEdge(reducedPoly, edge1);
336
 
                _polyAddEdge(reducedPoly, edge2);
337
 
                
338
 
                assert(edge0->vertices[1] == edge1->vertices[0]);
339
 
                assert(edge1->vertices[1] == edge2->vertices[0]);
340
 
                assert(edge2->vertices[1] == edge0->vertices[0]);
341
 
                
342
 
                assert(edge0->vertices[0] == edgeRedux->vertices[0]);
343
 
                assert(edgeRedux->vertices[1] == edge1->vertices[1]);
344
 
 
345
 
 
346
 
                
347
 
                return reducedPoly;
348
 
        }
349
 
        
350
 
        polygonRobustnessCheck(polygon, vertices);
351
 
        
352
 
        //NSLog(@"%@", rejectionList);
353
 
        
354
 
        return NULL;
355
 
}
356
 
 
357
 
long edgeCanBeFlipped(_edge* edge, _vertex* vertices)
358
 
{
359
 
        if (!edge->dual)
360
 
                return 0;
361
 
        if (edge->polygon->numEdges != 3)
362
 
                return 0;
363
 
        if (edge->dual->polygon->numEdges != 3)
364
 
                return 0;
365
 
        
366
 
        return 1;
367
 
}
368
 
 
369
 
long edgeShouldBeFlipped(_edge* edge, _vertex* vertices)
370
 
{       
371
 
        CGPoint d0 = vertices[edge->dual->nextEdge->vertices[1]].pos;
372
 
        CGPoint a0 = vertices[edge->vertices[0]].pos;
373
 
        CGPoint b0 = vertices[edge->vertices[1]].pos;
374
 
        CGPoint c0 = vertices[edge->nextEdge->vertices[1]].pos;
375
 
        
376
 
        if (CGPointInCircumCircule(d0, a0, b0, c0))
377
 
                return 1;
378
 
 
379
 
        CGPoint d1 = vertices[edge->nextEdge->vertices[1]].pos;
380
 
        CGPoint a1 = vertices[edge->dual->vertices[0]].pos;
381
 
        CGPoint b1 = vertices[edge->dual->vertices[1]].pos;
382
 
        CGPoint c1 = vertices[edge->dual->nextEdge->vertices[1]].pos;
383
 
        
384
 
        if (CGPointInCircumCircule(d1, a1, b1, c1))
385
 
                return 1;
386
 
        
387
 
        return 0;
388
 
}
389
 
 
390
 
void flipEdge(_edge* edge)
391
 
{
392
 
        _polygon* p0 = edge->polygon;
393
 
        _polygon* p1 = edge->dual->polygon;
394
 
        _edge* a0 = edge;
395
 
        _edge* b0 = a0->nextEdge;
396
 
        _edge* c0 = b0->nextEdge;
397
 
        _edge* a1 = edge->dual;
398
 
        _edge* b1 = a1->nextEdge;
399
 
        _edge* c1 = b1->nextEdge;
400
 
        
401
 
        a0->nextEdge = c0;
402
 
        a0->prevEdge = b1;
403
 
        b0->nextEdge = a1;
404
 
        b0->prevEdge = c1;
405
 
        c0->nextEdge = b1;
406
 
        c0->prevEdge = a0;
407
 
        a1->nextEdge = c1;
408
 
        a1->prevEdge = b0;
409
 
        b1->nextEdge = a0;
410
 
        b1->prevEdge = c0;
411
 
        c1->nextEdge = b0;
412
 
        c1->prevEdge = a1;
413
 
 
414
 
        if (b0 == p0->firstEdge)
415
 
                p0->firstEdge = a0;
416
 
        if (b1 == p1->firstEdge)
417
 
                p1->firstEdge = a1;
418
 
 
419
 
        b0->polygon = p1;
420
 
        b1->polygon = p0;
421
 
}
422
 
 
423
 
void flipEdgesNextToNewPolygon(_polygon* polygon, _vertex* vertices)
424
 
{
425
 
        if (polygon->numEdges != 3)
426
 
                return;
427
 
        
428
 
        _edge* edge = polygon->firstEdge;
429
 
        for (size_t i = 0; i < 3; ++i, edge = edge->nextEdge)
430
 
        {
431
 
                if (edgeCanBeFlipped(edge, vertices) && edgeShouldBeFlipped(edge, vertices))
432
 
                {
433
 
                        //NSLog(@"flipping edge");
434
 
                        flipEdge(edge);
435
 
                }
436
 
        }
437
 
}
438
 
 
439
 
_polygon** triangulatePolygons(_polygon** polygons, size_t* numPolygonsPtr, _vertex* vertices, size_t numVertices)
440
 
{
441
 
        // starting at the last polygon on the list, we try to create a correctly winded triangle out of it
442
 
        
443
 
        size_t numPolygons = *numPolygonsPtr;
444
 
        
445
 
        for (size_t i = 0; i < numPolygons; ++i)
446
 
        {
447
 
                _polygon* reducedPoly = triangulatePolygon(polygons[i], vertices);
448
 
                
449
 
                if (reducedPoly)
450
 
                {
451
 
                        polygons = realloc(polygons, sizeof(*polygons)*(numPolygons+1));
452
 
                        polygons[numPolygons++] = reducedPoly;
453
 
                        --i;
454
 
                        
455
 
                        //flipEdgesNextToNewPolygon(reducedPoly, vertices);
456
 
                        
457
 
                //      NSLog(@"reduced to: %d %d %d", reducedPoly->edges[0]->vertices[0], reducedPoly->edges[1]->vertices[0], reducedPoly->edges[2]->vertices[0]);
458
 
                //      NSLog(@"reduced to: %d %d %d", reducedPoly->edges[1]->vertices[1], reducedPoly->edges[2]->vertices[1], reducedPoly->edges[0]->vertices[1]);
459
 
                }
460
 
                else if (polygons[i]->numEdges > 3)
461
 
                {
462
 
                        NSLog(@"Badunka, why no triangle, instead we got a %zd-angle (%zd)", polygons[i]->numEdges, numVertices);
463
 
                        _edge* edge = polygons[i]->firstEdge;
464
 
                        for (size_t j = 0; j < polygons[i]->numEdges; ++j, edge = edge->nextEdge)
465
 
                                NSLog(@"  %u,%u", edge->vertices[0], edge->vertices[1]);
466
 
                }
467
 
                
468
 
        }
469
 
        
470
 
        *numPolygonsPtr = numPolygons;
471
 
        return polygons;
472
 
}
473
 
 
474
 
VertexArray* TriangulateOutline(CGPoint* inPoints, size_t numInPoints)
475
 
{
476
 
        _polygon* initialPoly = _polyCreate();
477
 
        
478
 
        _vertex* vertices = calloc(numInPoints, sizeof(*vertices));
479
 
        
480
 
        for (size_t i = 0; i < numInPoints; ++i)
481
 
        {
482
 
                vertices[i].pos = inPoints[i];
483
 
                if (i > 0)
484
 
                        assert(!CGPointEqualToPoint(vertices[i-1].pos, vertices[i].pos));
485
 
        }
486
 
        
487
 
        if (CGPointEqualToPoint(vertices[numInPoints-1].pos, vertices[0].pos))
488
 
                numInPoints--;
489
 
        
490
 
        for (size_t i = 0; i+1 < numInPoints; ++i)
491
 
        {
492
 
                _polyAddEdge(initialPoly, _edgeCreate(i, i+1, NULL, vertices));
493
 
        }
494
 
        _polyAddEdge(initialPoly, _edgeCreate(numInPoints-1, 0, NULL, vertices));
495
 
        
496
 
        polygonRobustnessCheck(initialPoly, vertices);
497
 
 
498
 
        _polygon** polygons = calloc(1, sizeof(*polygons));
499
 
        polygons[0] = initialPoly;
500
 
        size_t numPolygons = 1;
501
 
        
502
 
        polygons = triangulatePolygons(polygons, &numPolygons, vertices, numInPoints);
503
 
        
504
 
        
505
 
        VertexArray* var = [[[VertexArray alloc] init] autorelease];
506
 
        
507
 
#ifdef SHOW_LINES
508
 
        var->mode = GL_LINES;
509
 
#else
510
 
        var->mode = GL_TRIANGLES;
511
 
#endif  
512
 
 
513
 
        var->vertices = calloc(numInPoints, sizeof(*var->vertices));
514
 
        var->numVertices = numInPoints;
515
 
        
516
 
        for (size_t i = 0; i < numInPoints; ++i)
517
 
        {
518
 
                PositionNormalTex3f3f2f* vertex = var->vertices+i;
519
 
                
520
 
                vertex->pos[0] = vertices[i].pos.x;
521
 
                vertex->pos[1] = vertices[i].pos.y;
522
 
                vertex->pos[2] = 0.0f;
523
 
                vertex->normal[0] = 0.0f;
524
 
                vertex->normal[1] = 0.0f;
525
 
                vertex->normal[2] = 1.0f;
526
 
                vertex->texcoord[0] = vertices[i].pos.x;
527
 
                vertex->texcoord[1] = vertices[i].pos.y;
528
 
        }
529
 
 
530
 
        
531
 
        size_t numIndices = 0;
532
 
#ifdef SHOW_LINES
533
 
        for (size_t i = 0; i < numPolygons; ++i)
534
 
                numIndices += 2*polygons[i]->numEdges;
535
 
        uint16_t* indices = calloc(numIndices, sizeof(*indices));
536
 
        numIndices = 0;
537
 
#else
538
 
        uint16_t* indices = calloc(3*numPolygons, sizeof(*indices));
539
 
#endif
540
 
        for (size_t i = 0; i < numPolygons; ++i)
541
 
        {
542
 
                _polygon* polygon = polygons[i];
543
 
                if (polygon->numEdges != 3)
544
 
                {
545
 
                        NSLog(@"whoops, polygon with %d sides instead of 3, skipping.", polygon->numEdges);
546
 
                #ifndef SHOW_LINES
547
 
                        continue;
548
 
                #endif
549
 
                }
550
 
                _edge* edge = polygon->firstEdge;
551
 
/*
552
 
                assert(polygon->edges[0]->vertices[0] != polygon->edges[1]->vertices[0]);
553
 
                assert(polygon->edges[1]->vertices[0] != polygon->edges[2]->vertices[0]);
554
 
                assert(polygon->edges[2]->vertices[0] != polygon->edges[0]->vertices[0]);
555
 
                assert(polygon->edges[0]->vertices[0] < numInPoints);
556
 
                assert(polygon->edges[1]->vertices[0] < numInPoints);
557
 
                assert(polygon->edges[2]->vertices[0] < numInPoints);
558
 
                assert(polygon->edges[0]->vertices[1] < numInPoints);
559
 
                assert(polygon->edges[1]->vertices[1] < numInPoints);
560
 
                assert(polygon->edges[2]->vertices[1] < numInPoints);
561
 
*/
562
 
        #ifdef SHOW_LINES
563
 
                //if (polygon->numEdges != 3)
564
 
                        for (size_t j = 0; j < polygon->numEdges; ++j, edge = edge->nextEdge)
565
 
                        {
566
 
                                indices[numIndices++] = edge->vertices[0];
567
 
                                indices[numIndices++] = edge->vertices[1];
568
 
                        }
569
 
        #else
570
 
                indices[numIndices++] = edge->vertices[0];
571
 
                edge = edge->nextEdge;
572
 
                indices[numIndices++] = edge->vertices[0];
573
 
                edge = edge->nextEdge;
574
 
                indices[numIndices++] = edge->vertices[0];
575
 
        #endif
576
 
 
577
 
        }
578
 
        
579
 
#ifdef SHOW_LINES
580
 
        if (!numIndices)
581
 
                numIndices++;
582
 
#endif
583
 
 
584
 
        var->numIndices = numIndices;
585
 
        var->indices = indices;
586
 
        
587
 
        
588
 
        for (size_t i = 0; i < numPolygons; ++i)
589
 
        {
590
 
                _polygon* polygon = polygons[i];
591
 
                _polyDelete(polygon);
592
 
        }
593
 
        free(polygons);
594
 
        for (size_t i = 0; i < numInPoints; ++i)
595
 
        {
596
 
                _vertex v = vertices[i];
597
 
                free(v.edges);
598
 
        }
599
 
 
600
 
        free(vertices);
601
 
        
602
 
//      NSLog(@"number of generated polygons: %d", numPolygons);
603
 
 
604
 
        return var;
605
 
}
606
 
 
607
 
#define SQUISH_FORWARD_INNER            1
608
 
#define SQUISH_FORWARD_OUTER            2
609
 
#define SQUISH_BACKWARD_INNER           4
610
 
#define SQUISH_BACKWARD_OUTER           8
611
 
#define SQUISH_IGNORE_POINT_INNER       16
612
 
#define SQUISH_IGNORE_POINT_OUTER       32
613
 
 
614
 
void unsquishyOutline(CGPoint* points, CGPoint* innerPoints, CGPoint* outerPoints, size_t numPoints, float thickness)
615
 
{
616
 
        CGPoint* squishedInnerPoints = calloc(sizeof(*squishedInnerPoints), 2*numPoints);
617
 
        CGPoint* squishedOuterPoints = squishedInnerPoints + numPoints;
618
 
        uint8_t* squishedCorners = calloc(sizeof(*squishedCorners), numPoints);
619
 
 
620
 
        
621
 
        for (size_t i = 0; i < numPoints; ++i)
622
 
        {
623
 
                size_t i0 = (i) % numPoints;
624
 
                size_t i1 = (i+1) % numPoints;
625
 
                size_t i2 = (i+2) % numPoints;
626
 
                
627
 
                CGPoint p0 = points[i0];
628
 
                CGPoint p1 = points[i1];
629
 
                CGPoint p2 = points[i2];
630
 
 
631
 
                CGPoint pi0 = innerPoints[i0];
632
 
                CGPoint pi1 = innerPoints[i1];
633
 
                CGPoint pi2 = innerPoints[i2];
634
 
 
635
 
                CGPoint po0 = outerPoints[i0];
636
 
                CGPoint po1 = outerPoints[i1];
637
 
                CGPoint po2 = outerPoints[i2];
638
 
 
639
 
                squishedInnerPoints[i1] = p1;
640
 
                squishedOuterPoints[i1] = p1;
641
 
                
642
 
                squishedCorners[i1] = squishedCorners[i1]
643
 
                        | SQUISH_BACKWARD_OUTER*CGLineSegmentsIntersect(p0, po0, p1, po1)
644
 
                        | SQUISH_BACKWARD_INNER*CGLineSegmentsIntersect(p0, pi0, p1, pi1)
645
 
                        | SQUISH_FORWARD_OUTER*CGLineSegmentsIntersect(p2, po2, p1, po1)
646
 
                        | SQUISH_FORWARD_INNER*CGLineSegmentsIntersect(p2, pi2, p1, pi1);
647
 
        }
648
 
 
649
 
        size_t sbegin = 0;
650
 
        for (sbegin = 0; sbegin < numPoints; ++sbegin)
651
 
        {
652
 
 
653
 
                if (!(squishedCorners[sbegin] & (SQUISH_FORWARD_OUTER | SQUISH_FORWARD_INNER)))
654
 
                        break;
655
 
        }
656
 
        
657
 
        long didChange = 1;
658
 
        //while(didChange)
659
 
        {
660
 
                didChange = 0;
661
 
                // now that corners have been marked, walk em
662
 
                for (size_t ii = 0; ii < numPoints; ++ii)
663
 
                {
664
 
                        size_t i = (sbegin + ii) % numPoints;
665
 
                        if (!(squishedCorners[i] & (SQUISH_FORWARD_OUTER | SQUISH_FORWARD_INNER)))
666
 
                                continue;
667
 
                        
668
 
                        if ((squishedCorners[i] & SQUISH_FORWARD_INNER) && !(squishedCorners[i] & SQUISH_BACKWARD_INNER) && !(squishedCorners[i] & SQUISH_IGNORE_POINT_INNER))
669
 
                        {
670
 
                                size_t innerEnd = (i+1) % numPoints;
671
 
                                while ((innerEnd != i) && ((squishedCorners[innerEnd] & SQUISH_FORWARD_INNER) || (squishedCorners[innerEnd] & SQUISH_IGNORE_POINT_INNER)))
672
 
                                        innerEnd = (innerEnd+1) % numPoints;
673
 
                                        
674
 
                                if (innerEnd != i) // that'd mean we went all the way around
675
 
                                {
676
 
                                        size_t i0 = (i-1) % numPoints;
677
 
                                        size_t i1 = i;
678
 
                                        size_t i2 = innerEnd;
679
 
                                        size_t i3 = (innerEnd+1) % numPoints;
680
 
                                        CGPoint pp0 = squishedInnerPoints[i0];
681
 
                                        CGPoint pp1 = squishedInnerPoints[i1];
682
 
                                        CGPoint pp2 = squishedInnerPoints[i2];
683
 
                                        CGPoint pp3 = squishedInnerPoints[i3];
684
 
                                        
685
 
                                        CGPoint pp12 = CGLineIntersectionPoint(pp0, pp1, pp2, pp3);
686
 
                                        
687
 
                                        CGPoint e01 = CGPointSub(pp12, pp0);
688
 
                                        CGPoint e12 = CGPointSub(pp3, pp12);
689
 
 
690
 
                                        CGPoint n01 = CGPointScale(CGPointNormalize(CGPointMake(-e01.y, e01.x)), thickness*0.5f);
691
 
                                        CGPoint n12 = CGPointScale(CGPointNormalize(CGPointMake(-e12.y, e12.x)), thickness*0.5f);
692
 
                                        
693
 
                                        assert(!isnan(n01.x) && !isnan(n01.y));
694
 
                                        assert(!isnan(n12.x) && !isnan(n12.y));
695
 
                                        
696
 
                                        CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
697
 
                                        
698
 
                                        CGPoint ip = CGPointAdd(pp12, hn);
699
 
 
700
 
                                        for (size_t k = i; k != (innerEnd+1) % numPoints; k = (k+1) % numPoints)
701
 
                                        {
702
 
                                                squishedInnerPoints[k] = pp12;
703
 
                                                innerPoints[k] = ip;
704
 
                                                //squishedCorners[k] &= ~SQUISH_FORWARD_INNER;
705
 
                                                if ((k != i) && (k != innerEnd))
706
 
                                                        squishedCorners[k] |= SQUISH_IGNORE_POINT_INNER;
707
 
                                        }
708
 
                                        didChange = 1;
709
 
                                }
710
 
                        }
711
 
                        if ((squishedCorners[i] & SQUISH_FORWARD_OUTER) && !(squishedCorners[i] & SQUISH_BACKWARD_OUTER) && !(squishedCorners[i] & SQUISH_IGNORE_POINT_OUTER))
712
 
                        {
713
 
                                size_t outerEnd = (i+1) % numPoints;
714
 
                                while ((outerEnd != i) && ((squishedCorners[outerEnd] & SQUISH_FORWARD_OUTER) || (squishedCorners[outerEnd] & SQUISH_IGNORE_POINT_OUTER)))
715
 
                                        outerEnd = (outerEnd+1) % numPoints;
716
 
                                        
717
 
                                if (outerEnd != i) // that'd mean we went all the way around
718
 
                                {
719
 
                                        size_t i0 = (i-1) % numPoints;
720
 
                                        size_t i1 = i;
721
 
                                        size_t i2 = outerEnd;
722
 
                                        size_t i3 = (outerEnd+1) % numPoints;
723
 
                                        CGPoint pp0 = squishedOuterPoints[i0];
724
 
                                        CGPoint pp1 = squishedOuterPoints[i1];
725
 
                                        CGPoint pp2 = squishedOuterPoints[i2];
726
 
                                        CGPoint pp3 = squishedOuterPoints[i3];
727
 
                                        
728
 
                                        CGPoint pp12 = CGLineIntersectionPoint(pp0, pp1, pp2, pp3);
729
 
                                        
730
 
                                        CGPoint e01 = CGPointSub(pp12, pp0);
731
 
                                        CGPoint e12 = CGPointSub(pp3, pp12);
732
 
 
733
 
                                        CGPoint n01 = CGPointScale(CGPointNormalize(CGPointMake(-e01.y, e01.x)), thickness*0.5f);
734
 
                                        CGPoint n12 = CGPointScale(CGPointNormalize(CGPointMake(-e12.y, e12.x)), thickness*0.5f);
735
 
                                        
736
 
                                        assert(!isnan(n01.x) && !isnan(n01.y));
737
 
                                        assert(!isnan(n12.x) && !isnan(n12.y));
738
 
                                        
739
 
                                        CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
740
 
                                        
741
 
                                        CGPoint ip = CGPointSub(pp12, hn);
742
 
 
743
 
                                        for (size_t k = i; k != (outerEnd+1) % numPoints; k = (k+1) % numPoints)
744
 
                                        {
745
 
                                                squishedOuterPoints[k] = pp12;
746
 
                                                outerPoints[k] = ip;
747
 
                                                //squishedCorners[k] &= ~SQUISH_FORWARD_OUTER;
748
 
                                                if ((k != i) && (k != outerEnd))
749
 
                                                        squishedCorners[k] |= SQUISH_IGNORE_POINT_OUTER;
750
 
                                        }
751
 
                                        didChange = 1;
752
 
                                }
753
 
                        }
754
 
 
755
 
                }
756
 
 
757
 
                for (size_t i = 0; i < numPoints; ++i)
758
 
                {
759
 
                        squishedCorners[i] &= ~(SQUISH_FORWARD_INNER|SQUISH_BACKWARD_INNER|SQUISH_FORWARD_OUTER|SQUISH_BACKWARD_OUTER);
760
 
                }
761
 
                
762
 
                for (size_t i = 0; i < numPoints; ++i)
763
 
                {
764
 
                        size_t i0 = (i) % numPoints;
765
 
                        size_t i1 = (i+1) % numPoints;
766
 
                        size_t i2 = (i+2) % numPoints;
767
 
                        
768
 
                        while (squishedCorners[i0] & SQUISH_IGNORE_POINT_INNER)
769
 
                                i0 = (i0-1) % numPoints;
770
 
                        while (squishedCorners[i2] & SQUISH_IGNORE_POINT_INNER)
771
 
                                i2 = (i2+1) % numPoints;
772
 
 
773
 
                        CGPoint pii0 = squishedInnerPoints[i0];
774
 
                        CGPoint pii1 = squishedInnerPoints[i1];
775
 
                        CGPoint pii2 = squishedInnerPoints[i2];
776
 
 
777
 
 
778
 
                        CGPoint pi0 = innerPoints[i0];
779
 
                        CGPoint pi1 = innerPoints[i1];
780
 
                        CGPoint pi2 = innerPoints[i2];
781
 
 
782
 
                        
783
 
                        if (!(squishedCorners[i1] & SQUISH_IGNORE_POINT_INNER))
784
 
                        {
785
 
                                squishedCorners[i1] &= ~(SQUISH_FORWARD_INNER|SQUISH_BACKWARD_INNER);
786
 
                                squishedCorners[i1] |=
787
 
                                        SQUISH_BACKWARD_INNER*CGLineSegmentsIntersect(pii0, pi0, pii1, pi1)
788
 
                                        | SQUISH_FORWARD_INNER*CGLineSegmentsIntersect(pii2, pi2, pii1, pi1);
789
 
                        }                       
790
 
                }
791
 
 
792
 
                for (size_t i = 0; i < numPoints; ++i)
793
 
                {
794
 
                        size_t i0 = (i) % numPoints;
795
 
                        size_t i1 = (i+1) % numPoints;
796
 
                        size_t i2 = (i+2) % numPoints;
797
 
                        
798
 
                        while (squishedCorners[i0] & SQUISH_IGNORE_POINT_OUTER)
799
 
                                i0 = (i0-1) % numPoints;
800
 
                        while (squishedCorners[i2] & SQUISH_IGNORE_POINT_OUTER)
801
 
                                i2 = (i2+1) % numPoints;
802
 
 
803
 
                        CGPoint pii0 = squishedOuterPoints[i0];
804
 
                        CGPoint pii1 = squishedOuterPoints[i1];
805
 
                        CGPoint pii2 = squishedOuterPoints[i2];
806
 
 
807
 
 
808
 
                        CGPoint pi0 = outerPoints[i0];
809
 
                        CGPoint pi1 = outerPoints[i1];
810
 
                        CGPoint pi2 = outerPoints[i2];
811
 
 
812
 
                        
813
 
                        if (!(squishedCorners[i1] & SQUISH_IGNORE_POINT_OUTER))
814
 
                        {
815
 
                                squishedCorners[i1] &= ~(SQUISH_FORWARD_OUTER|SQUISH_BACKWARD_OUTER);
816
 
                                squishedCorners[i1] |=
817
 
                                        SQUISH_BACKWARD_OUTER*CGLineSegmentsIntersect(pii0, pi0, pii1, pi1)
818
 
                                        | SQUISH_FORWARD_OUTER*CGLineSegmentsIntersect(pii2, pi2, pii1, pi1);
819
 
                        }                       
820
 
                }
821
 
 
822
 
        }
823
 
        free(squishedInnerPoints);
824
 
        
825
 
        free(squishedCorners);
826
 
 
827
 
}
828
 
 
829
 
CGPoint* createOutline(CGPoint* points, size_t numPoints, float thickness)
830
 
{
831
 
        CGPoint* innerPoints = calloc(sizeof(*innerPoints), 2*numPoints);
832
 
        CGPoint* outerPoints = innerPoints + numPoints;
833
 
        
834
 
        for (size_t i = 0; i < numPoints; ++i)
835
 
        {
836
 
                size_t i0 = (i) % numPoints;
837
 
                size_t i1 = (i+1) % numPoints;
838
 
                size_t i2 = (i+2) % numPoints;
839
 
                
840
 
                CGPoint p0 = points[i0];
841
 
                CGPoint p1 = points[i1];
842
 
                CGPoint p2 = points[i2];
843
 
                
844
 
                CGPoint e01 = CGPointSub(p1,p0);
845
 
                CGPoint e12 = CGPointSub(p2,p1);
846
 
                
847
 
                CGPoint n01 = CGPointScale(CGPointNormalize(CGPointMake(-e01.y, e01.x)), thickness*0.5f);
848
 
                CGPoint n12 = CGPointScale(CGPointNormalize(CGPointMake(-e12.y, e12.x)), thickness*0.5f);
849
 
                
850
 
                assert(!isnan(n01.x) && !isnan(n01.y));
851
 
                assert(!isnan(n12.x) && !isnan(n12.y));
852
 
                
853
 
                CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
854
 
                
855
 
                //innerNormals[i1] = hn;
856
 
                //outerNormals[i1] = CGPointScale(hn, -1.0);
857
 
                
858
 
                innerPoints[i1] = CGPointAdd(p1, hn);
859
 
                outerPoints[i1] = CGPointSub(p1, hn);
860
 
        }
861
 
 
862
 
//      unsquishyOutline(points, innerPoints, outerPoints, numPoints, thickness);
863
 
        
864
 
        return innerPoints;
865
 
}
866
 
 
867
 
 
868
 
void _bezierPathDataExtractor(void *info, const CGPathElement *element)
869
 
{
870
 
        NSMutableData* data = info;
871
 
        [data appendBytes: &element->type length: sizeof(element->type)];
872
 
        switch(element->type)
873
 
        {
874
 
                case kCGPathElementMoveToPoint:
875
 
                        [data appendBytes: element->points length: sizeof(*element->points)];
876
 
                        break;
877
 
                case kCGPathElementAddLineToPoint:
878
 
                {
879
 
                        [data appendBytes: element->points length: sizeof(*element->points)];
880
 
                        break;
881
 
                }
882
 
                case kCGPathElementAddQuadCurveToPoint:
883
 
                {
884
 
                        [data appendBytes: element->points length: sizeof(*element->points)*2];
885
 
                        
886
 
                        break;
887
 
                }
888
 
                case kCGPathElementAddCurveToPoint:
889
 
                {
890
 
                        [data appendBytes: element->points length: sizeof(*element->points)*3];
891
 
                        
892
 
                        break;
893
 
                }
894
 
                case kCGPathElementCloseSubpath:
895
 
                {
896
 
                        break;
897
 
                }
898
 
        };
899
 
}
900
 
 
901
 
NSData* BezierPathToData(CGPathRef cpath)
902
 
{
903
 
        NSMutableData* data = [NSMutableData data];
904
 
        CGPathApply(cpath, data, _bezierPathDataExtractor);
905
 
 
906
 
        return data;
907
 
}
908
 
 
909
 
CGPathRef CreateBezierPathFromData(NSData* data)
910
 
{
911
 
        CGMutablePathRef path = CGPathCreateMutable();
912
 
        const void* bytes = [data bytes];
913
 
        size_t nbytes = [data length];
914
 
        size_t i = 0;
915
 
        while (i < nbytes)
916
 
        {
917
 
                CGPathElementType type = *((CGPathElementType*)(bytes+i));
918
 
                i += sizeof(type);
919
 
                switch(type)
920
 
                {
921
 
                        case kCGPathElementMoveToPoint:
922
 
                        {
923
 
                                CGPoint p;
924
 
                                memcpy(&p, bytes+i, sizeof(CGPoint));
925
 
                                i += sizeof(CGPoint);
926
 
                                CGPathMoveToPoint(path, nil, p.x, p.y);
927
 
                                break;
928
 
                        }
929
 
                        case kCGPathElementAddLineToPoint:
930
 
                        {
931
 
                                CGPoint p;
932
 
                                memcpy(&p, bytes+i, sizeof(CGPoint));
933
 
                                i += sizeof(CGPoint);
934
 
                                CGPathAddLineToPoint(path, nil, p.x, p.y);
935
 
                                break;
936
 
                        }
937
 
                        case kCGPathElementAddQuadCurveToPoint:
938
 
                        {
939
 
                                CGPoint p[2];
940
 
                                memcpy(p, bytes+i, sizeof(CGPoint)*2);
941
 
                                i += sizeof(CGPoint)*2;
942
 
                                CGPathAddQuadCurveToPoint(path, nil, p[0].x, p[0].y, p[1].x, p[1].y);                           
943
 
                                break;
944
 
                        }
945
 
                        case kCGPathElementAddCurveToPoint:
946
 
                        {
947
 
                                CGPoint p[3];
948
 
                                memcpy(p, bytes+i, sizeof(CGPoint)*3);
949
 
                                i += sizeof(CGPoint)*3;
950
 
                                CGPathAddCurveToPoint(path, nil, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y);                               
951
 
                                
952
 
                                break;
953
 
                        }
954
 
                        case kCGPathElementCloseSubpath:
955
 
                        {
956
 
                                CGPathCloseSubpath(path);                               
957
 
                                break;
958
 
                        }
959
 
                }
960
 
        }
961
 
 
962
 
        return (CGPathRef)path;
963
 
}
964
 
 
965
 
 
966
 
 
967
 
struct Spoke;
968
 
typedef struct Spoke Spoke;
969
 
 
970
 
struct Front;
971
 
typedef struct Front Front;
972
 
 
973
 
struct CollisionEstimate;
974
 
typedef struct CollisionEstimate CollisionEstimate;
975
 
 
976
 
typedef struct PolygonInsetRecord
977
 
{
978
 
        CGPoint*        vertices;
979
 
        float*          times;
980
 
        size_t          numVertices;
981
 
        uint16_t*       triangleIndices;
982
 
        size_t          numIndices;
983
 
} PolygonInsetRecord;
984
 
 
985
 
 
986
 
struct Spoke
987
 
{
988
 
        uint32_t        sourceVertexIndex, finalVertexIndex;
989
 
        CGPoint         velocity;
990
 
        float           start;
991
 
 
992
 
        Front*          leftFront;
993
 
        Front*          rightFront;
994
 
 
995
 
        size_t                          numEstimates;
996
 
        CollisionEstimate*      estimates;
997
 
};
998
 
 
999
 
struct Front
1000
 
{
1001
 
        Spoke*  leftSpoke;
1002
 
        Spoke*  rightSpoke;
1003
 
 
1004
 
        CGPoint velocity;
1005
 
        float   willCollapse;
1006
 
        
1007
 
};
1008
 
 
1009
 
typedef struct FrontsAndSpokesRec
1010
 
{
1011
 
        Front** fronts;
1012
 
        size_t  numFronts;
1013
 
        Spoke** spokes;
1014
 
        size_t  numSpokes;
1015
 
 
1016
 
} FrontsAndSpokesRec;
1017
 
 
1018
 
enum
1019
 
{
1020
 
        kHitSource,
1021
 
        kHitLeftRay,
1022
 
        kHitRightRay,
1023
 
        kHitFront,
1024
 
        kHitUnknown,
1025
 
        kHitLast
1026
 
};
1027
 
 
1028
 
 
1029
 
typedef struct r2
1030
 
{
1031
 
        float min, max;
1032
 
} r2;
1033
 
 
1034
 
struct CollisionEstimate
1035
 
{
1036
 
        Front*          front;
1037
 
//      Spoke*          spoke;
1038
 
//      int                     face;
1039
 
        r2                      range;
1040
 
};
1041
 
 
1042
 
struct _small_pool_block
1043
 
{
1044
 
        size_t available, used;
1045
 
        struct _small_pool_block* next;
1046
 
        void* bytes;
1047
 
};
1048
 
 
1049
 
static struct _small_pool_block*        _smallStackPoolHead = NULL;
1050
 
static struct _small_pool_block*        _smallStackPoolFirstFree = NULL;
1051
 
static size_t   _smallStackBaseBlockSize = 4096;
1052
 
 
1053
 
static void small_pool_init(void)
1054
 
{
1055
 
        while (_smallStackPoolHead)
1056
 
        {
1057
 
                struct _small_pool_block* next = _smallStackPoolHead->next;
1058
 
                free(_smallStackPoolHead);
1059
 
                _smallStackPoolHead = next;
1060
 
        }
1061
 
        _smallStackPoolHead = calloc(1,_smallStackBaseBlockSize);
1062
 
        _smallStackPoolHead->bytes = _smallStackPoolHead+1;
1063
 
        _smallStackPoolHead->available = _smallStackBaseBlockSize - sizeof(struct _small_pool_block);
1064
 
        _smallStackPoolFirstFree = _smallStackPoolHead;
1065
 
}
1066
 
 
1067
 
static void small_pool_destroy(void)
1068
 
{
1069
 
        while (_smallStackPoolHead)
1070
 
        {
1071
 
                struct _small_pool_block* next = _smallStackPoolHead->next;
1072
 
                free(_smallStackPoolHead);
1073
 
                _smallStackPoolHead = next;
1074
 
        }
1075
 
        _smallStackBaseBlockSize = 4096;
1076
 
        _smallStackPoolFirstFree = NULL;
1077
 
}
1078
 
 
1079
 
static void* small_malloc(size_t s)
1080
 
{
1081
 
        struct _small_pool_block* freeBlock = _smallStackPoolFirstFree;
1082
 
        while (s > freeBlock->available)
1083
 
        {
1084
 
                if (freeBlock->next)
1085
 
                        freeBlock = freeBlock->next;
1086
 
                else
1087
 
                {
1088
 
                        size_t size = MAX(_smallStackBaseBlockSize, s + sizeof(struct _small_pool_block));
1089
 
                        freeBlock->next = calloc(1, size);
1090
 
                        _smallStackBaseBlockSize *= 2;
1091
 
                        freeBlock = freeBlock->next;
1092
 
                        freeBlock->bytes = (void*)freeBlock + sizeof(struct _small_pool_block);
1093
 
                        freeBlock->available = size - sizeof(struct _small_pool_block);
1094
 
                        break;
1095
 
                }
1096
 
        }
1097
 
        
1098
 
        
1099
 
        void* result = freeBlock->bytes + freeBlock->used;
1100
 
        
1101
 
        freeBlock->used += s;
1102
 
        freeBlock->available -= s;
1103
 
        
1104
 
        assert(result);
1105
 
        return result;
1106
 
}
1107
 
 
1108
 
static r2 _rayInPlane(CGPoint pr0, CGPoint v, CGPoint pp0, CGPoint pn)
1109
 
{
1110
 
        r2 range = {INFINITY, -INFINITY};
1111
 
 
1112
 
        CGPoint d = CGPointSub(pp0, pr0);
1113
 
        CGPoint n = CGPointNormalize(pn);
1114
 
        int rayTowardsPlaneNormal = CGPointDot(n, v) > 0.0f;
1115
 
        
1116
 
        float td = CGPointDot(d, n);
1117
 
        float tr = CGPointDot(v, n);
1118
 
        
1119
 
        if (fabsf(tr) < FLT_EPSILON)
1120
 
                return range;
1121
 
        
1122
 
        assert(!isnan(tr) && !isnan(td));
1123
 
        
1124
 
        float t = td/tr;
1125
 
        if (rayTowardsPlaneNormal)
1126
 
        {
1127
 
                range.min = t;
1128
 
                range.max = INFINITY;
1129
 
        }
1130
 
        else
1131
 
        {
1132
 
                range.max = t;
1133
 
                range.min = -INFINITY;
1134
 
        }
1135
 
        
1136
 
        return range;
1137
 
        
1138
 
}
1139
 
 
1140
 
static int _r2containsValue(r2 range, float x)
1141
 
{
1142
 
        return (range.min <= x) && (range.max >= x);
1143
 
}
1144
 
 
1145
 
static r2 _r2intersect(r2 ra, r2 rb)
1146
 
{
1147
 
        return (r2){MAX(ra.min, rb.min), MIN(ra.max, rb.max)};
1148
 
}
1149
 
 
1150
 
static int _r2isEmpty(r2 r)
1151
 
{
1152
 
        return r.min >= r.max;
1153
 
}
1154
 
 
1155
 
static int _frontLoopsBelow(Front* front, int num)
1156
 
{
1157
 
        Front* f2 = front;
1158
 
        for (int i = 0; i < num; ++i)
1159
 
        {
1160
 
                f2 = f2->leftSpoke->leftFront;
1161
 
                if (f2 == front)
1162
 
                        return 1;
1163
 
        }
1164
 
        return 0;
1165
 
}
1166
 
 
1167
 
 
1168
 
static r2 _estimateSpokeHittingFront(Spoke* spoke, Front* front, CGPoint* vertices)
1169
 
{
1170
 
        // front plane wrong???
1171
 
        
1172
 
        
1173
 
 
1174
 
        CGPoint r0 = CGPointAdd(vertices[spoke->sourceVertexIndex], CGPointScale(spoke->velocity, -spoke->start));
1175
 
 
1176
 
 
1177
 
        Spoke* lspoke = front->leftSpoke;
1178
 
        Spoke* rspoke = front->rightSpoke;
1179
 
        CGPoint pl0 = CGPointAdd(vertices[lspoke->sourceVertexIndex], CGPointScale(lspoke->velocity, -lspoke->start));
1180
 
        CGPoint pr0 = CGPointAdd(vertices[rspoke->sourceVertexIndex], CGPointScale(rspoke->velocity, -rspoke->start));
1181
 
 
1182
 
        CGPoint rays[4] = {spoke->velocity, spoke->velocity, spoke->velocity, CGPointSub(spoke->velocity, front->velocity)};
1183
 
 
1184
 
        CGPoint ppoints[4] = {  pl0,
1185
 
                                                        pl0,
1186
 
                                                        pr0,
1187
 
                                                        pr0 // a point at t=0
1188
 
                                                };
1189
 
        CGPoint pnorms[4] = {   CGPointNormalize(front->velocity),
1190
 
                                                        CGPointNormalize(CGPointNegate(CGPointNormal(lspoke->velocity))),
1191
 
                                                        CGPointNormalize(CGPointNormal(rspoke->velocity)),
1192
 
                                                        CGPointNormalize(CGPointNegate(front->velocity))
1193
 
                                                };
1194
 
                                                
1195
 
        r2      ranges[4] = {{INFINITY,-INFINITY}, {INFINITY,-INFINITY}, {INFINITY,-INFINITY}, {INFINITY,-INFINITY}};
1196
 
        
1197
 
        
1198
 
        for (size_t i = 0; i < 4; ++i)
1199
 
        {
1200
 
                ranges[i] = _rayInPlane(r0, rays[i], ppoints[i], pnorms[i]);
1201
 
        }
1202
 
        
1203
 
        r2 minorr = _r2intersect(_r2intersect(ranges[0], ranges[1]), ranges[2]);
1204
 
        r2 finalr = _r2intersect(minorr, ranges[3]);
1205
 
 
1206
 
        if ((finalr.min != ranges[3].min) || (CGPointDot(spoke->velocity, front->velocity) > 0.0f))     // if the spoke doesn't enter through the front, it doesn't count
1207
 
                return (r2){INFINITY,-INFINITY};
1208
 
 
1209
 
        return finalr;
1210
 
}
1211
 
 
1212
 
static int _sortCompareEstimates(const void* _a, const void* _b)
1213
 
{
1214
 
        const CollisionEstimate* a = *((const CollisionEstimate**)_a);
1215
 
        const CollisionEstimate* b = *((const CollisionEstimate**)_b);
1216
 
        
1217
 
        if (a->range.min < b->range.min)
1218
 
                return -1;
1219
 
        else if (a->range.min > b->range.min)
1220
 
                return 1;
1221
 
        else
1222
 
                return 0;
1223
 
}
1224
 
 
1225
 
static int _sortCompareFronts(const void* _a, const void* _b)
1226
 
{
1227
 
        const Front* a = *((const Front**)_a);
1228
 
        const Front* b = *((const Front**)_b);
1229
 
        float timea = a->willCollapse;
1230
 
        float timeb = b->willCollapse;
1231
 
 
1232
 
/*
1233
 
        if (a->numEstimates)
1234
 
                timea = MIN(timea, a->estimates[0].range.min);
1235
 
        if (b->numEstimates)
1236
 
                timeb = MIN(timeb, b->estimates[0].range.min);
1237
 
*/
1238
 
        if (timea < timeb)
1239
 
                return -1;
1240
 
        else if (timea > timeb)
1241
 
                return 1;
1242
 
        else
1243
 
                return 0;
1244
 
}
1245
 
static int _sortCompareSpokes(const void* _a, const void* _b)
1246
 
{
1247
 
        const Spoke* a = *((const Spoke**)_a);
1248
 
        const Spoke* b = *((const Spoke**)_b);
1249
 
        float timea = INFINITY;
1250
 
        float timeb = INFINITY;
1251
 
 
1252
 
 
1253
 
        if (a->numEstimates)
1254
 
                timea = a->estimates[0].range.min;
1255
 
        if (b->numEstimates)
1256
 
                timeb = b->estimates[0].range.min;
1257
 
 
1258
 
        if (timea < timeb)
1259
 
                return -1;
1260
 
        else if (timea > timeb)
1261
 
                return 1;
1262
 
        else
1263
 
                return 0;
1264
 
}
1265
 
 
1266
 
 
1267
 
static void _sortFronts(Front** fronts, size_t numFronts)
1268
 
{       
1269
 
        mergesort(fronts, numFronts, sizeof(*fronts), _sortCompareFronts);      
1270
 
}
1271
 
 
1272
 
static void _sortSpokes(Spoke** spokes, size_t numSpokes)
1273
 
{
1274
 
        for (size_t i = 0; i < numSpokes; ++i)
1275
 
                mergesort(spokes[i]->estimates, spokes[i]->numEstimates, sizeof(*spokes[i]->estimates), _sortCompareEstimates);
1276
 
        
1277
 
        mergesort(spokes, numSpokes, sizeof(*spokes), _sortCompareSpokes);
1278
 
        
1279
 
}
1280
 
 
1281
 
/*
1282
 
static void _removeEstimateFromFront(Front* front, size_t ie)
1283
 
{
1284
 
        if (ie+1 != front->numEstimates)
1285
 
                front->estimates[ie] = front->estimates[front->numEstimates-1];
1286
 
        front->numEstimates--;
1287
 
}
1288
 
 
1289
 
static void _redactEstimateForSpokeToFronts(Spoke* spoke, Front** fronts, size_t numFronts)
1290
 
{
1291
 
        for (size_t i = 0; i < numFronts; ++i)
1292
 
        {
1293
 
                Front* front = fronts[i];
1294
 
                
1295
 
                if (!front->estimates)
1296
 
                        continue;
1297
 
 
1298
 
                for (size_t i = 0; i < front->numEstimates; ++i)
1299
 
                        if (front->estimates[i].spoke == spoke)
1300
 
                        {
1301
 
                                _removeEstimateFromFront(front, i);
1302
 
                                break;
1303
 
                        }
1304
 
        }
1305
 
}
1306
 
*/
1307
 
static CollisionEstimate _estimateForSpokeToFront(Spoke* spoke, Front* front, CGPoint* vertices, float time, float maxTime)
1308
 
{
1309
 
        CollisionEstimate estimate = {front, {INFINITY,-INFINITY}};
1310
 
 
1311
 
        r2 r = _estimateSpokeHittingFront(spoke, front, vertices);
1312
 
        
1313
 
//      if (face == 0)
1314
 
//              r.min = INFINITY;
1315
 
        if (r.min > r.max)
1316
 
                return estimate;
1317
 
//      if ((r.max <= time) || (r.min > maxTime))
1318
 
//              return estimate;
1319
 
 
1320
 
 
1321
 
//      estimate.face = face;
1322
 
        
1323
 
        assert(r.min > -INFINITY);
1324
 
 
1325
 
        estimate.range = r;
1326
 
        
1327
 
        return estimate;
1328
 
}
1329
 
 
1330
 
static float _frontStart(Front* front)
1331
 
{
1332
 
        return MAX(front->leftSpoke->start, front->rightSpoke->start);
1333
 
}
1334
 
 
1335
 
static void _recomputeEstimatesForSpoke(Spoke* spoke, Front** fronts, size_t numFronts, CGPoint* vertices, size_t maxEstimates, float time, float maxTime)
1336
 
{
1337
 
        spoke->numEstimates = 0;
1338
 
        for (size_t i = 0; i < numFronts; ++i)
1339
 
        {
1340
 
                Front* front = fronts[i];
1341
 
                
1342
 
                if ((spoke == front->leftSpoke) || (spoke == front->rightSpoke) || (front->leftSpoke->leftFront->leftSpoke == spoke) || (front->rightSpoke->rightFront->rightSpoke == spoke))
1343
 
                {
1344
 
                        continue;
1345
 
                }
1346
 
                if (_frontLoopsBelow(front, 4))
1347
 
                        continue;
1348
 
 
1349
 
                
1350
 
 
1351
 
                CollisionEstimate estimate = _estimateForSpokeToFront(spoke, front, vertices, time, maxTime);
1352
 
                                
1353
 
                if (estimate.range.min < MAX(spoke->start, _frontStart(front)))
1354
 
                        estimate.range.min = INFINITY;
1355
 
                        
1356
 
                if (_r2isEmpty(estimate.range))
1357
 
                        continue;
1358
 
 
1359
 
                if (!spoke->estimates)
1360
 
                        spoke->estimates = small_malloc(sizeof(*spoke->estimates)*maxEstimates);
1361
 
                assert(spoke->numEstimates < maxEstimates);
1362
 
                spoke->estimates[spoke->numEstimates++] = estimate;
1363
 
 
1364
 
        }
1365
 
}
1366
 
 
1367
 
static uint16_t _addVertex(PolygonInsetRecord* rec, CGPoint p, float t)
1368
 
{
1369
 
        assert(rec->numVertices < USHRT_MAX);
1370
 
        uint16_t i = rec->numVertices++;
1371
 
        rec->vertices = realloc(rec->vertices, sizeof(*rec->vertices)*(rec->numVertices));
1372
 
        rec->times = realloc(rec->times, sizeof(*rec->times)*(rec->numVertices));
1373
 
        rec->vertices[i] = p;
1374
 
        rec->times[i] = t;
1375
 
        return i;
1376
 
}
1377
 
 
1378
 
static void _addTriangle(PolygonInsetRecord* rec, uint16_t a, uint16_t b, uint16_t c)
1379
 
{
1380
 
        rec->triangleIndices = realloc(rec->triangleIndices, sizeof(*rec->triangleIndices)*(rec->numIndices+3));
1381
 
        rec->triangleIndices[rec->numIndices++] = a;
1382
 
        rec->triangleIndices[rec->numIndices++] = b;
1383
 
        rec->triangleIndices[rec->numIndices++] = c;
1384
 
}
1385
 
 
1386
 
 
1387
 
static Spoke* _allocSpoke(FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1388
 
{
1389
 
        Spoke* spoke = NULL;
1390
 
        if (!inactiveWalls->numSpokes)
1391
 
                spoke = small_malloc(sizeof(Spoke));
1392
 
        else
1393
 
        {
1394
 
                spoke = inactiveWalls->spokes[--inactiveWalls->numSpokes];
1395
 
        }
1396
 
        activeWalls->spokes[activeWalls->numSpokes++] = spoke;
1397
 
        //memset(spoke, 0x00, sizeof(*spoke));
1398
 
        return spoke;
1399
 
}
1400
 
 
1401
 
static Front* _allocFront(FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1402
 
{
1403
 
        Front* front = NULL;
1404
 
        if (!inactiveWalls->numFronts)
1405
 
                front = small_malloc(sizeof(Front));
1406
 
        else
1407
 
        {
1408
 
                front = inactiveWalls->fronts[--inactiveWalls->numFronts];
1409
 
        }
1410
 
        activeWalls->fronts[activeWalls->numFronts++] = front;
1411
 
        //memset(front, 0x00, sizeof(*front));
1412
 
        return front;
1413
 
}
1414
 
 
1415
 
static void _deactivateFront(Front* front, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1416
 
{
1417
 
        //memset(front, 0xFF, sizeof(*front));
1418
 
        inactiveWalls->fronts[inactiveWalls->numFronts++] = front;
1419
 
        
1420
 
        for (size_t i = 0; i < activeWalls->numFronts; ++i)
1421
 
        {
1422
 
                if (activeWalls->fronts[i] == front)
1423
 
                {
1424
 
                        if (i+1 < activeWalls->numFronts)
1425
 
                                activeWalls->fronts[i] = activeWalls->fronts[activeWalls->numFronts-1];
1426
 
                        
1427
 
                        activeWalls->numFronts--;
1428
 
                        break;
1429
 
                }
1430
 
        }
1431
 
}
1432
 
 
1433
 
static void _deactivateSpoke(Spoke* spoke, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1434
 
{
1435
 
        //memset(spoke, 0xFF, sizeof(*spoke));
1436
 
        inactiveWalls->spokes[inactiveWalls->numSpokes++] = spoke;
1437
 
        
1438
 
        for (size_t i = 0; i < activeWalls->numSpokes; ++i)
1439
 
        {
1440
 
                if (activeWalls->spokes[i] == spoke)
1441
 
                {
1442
 
                        if (i < activeWalls->numSpokes-1)
1443
 
                                activeWalls->spokes[i] = activeWalls->spokes[activeWalls->numSpokes-1];
1444
 
                        
1445
 
                        activeWalls->numSpokes--;
1446
 
                        break;
1447
 
                }
1448
 
        }
1449
 
}
1450
 
 
1451
 
static void _updateCollapseTime(Front* front, CGPoint* vertices, float now)
1452
 
{
1453
 
        
1454
 
        Spoke* spoke0 = front->leftSpoke;
1455
 
        Spoke* spoke1 = front->rightSpoke;
1456
 
        CGPoint a = vertices[spoke0->sourceVertexIndex], b = vertices[spoke1->sourceVertexIndex];
1457
 
        
1458
 
        CGPoint va = spoke0->velocity;
1459
 
        CGPoint vb = spoke1->velocity;
1460
 
        CGPoint vab = CGPointSub(vb,va);
1461
 
        a = CGPointAdd(a, CGPointScale(va, -spoke0->start));
1462
 
        b = CGPointAdd(b, CGPointScale(vb, -spoke1->start));
1463
 
 
1464
 
        CGPoint ab = CGPointSub(b,a);
1465
 
        float se  = CGPointDot(vab, ab);
1466
 
        
1467
 
        float t = - CGPointDot(ab,ab)/se;
1468
 
 
1469
 
        if (t > now)
1470
 
                front->willCollapse = t;
1471
 
        else
1472
 
                front->willCollapse = INFINITY;
1473
 
 
1474
 
}
1475
 
 
1476
 
static void _assertFrontIntegrity(Front* front)
1477
 
{
1478
 
        assert(front->leftSpoke != front->rightSpoke);
1479
 
        assert(front->leftSpoke->rightFront == front);
1480
 
        assert(front->rightSpoke->leftFront == front);
1481
 
 
1482
 
        assert(!CGPointEqualToPoint(CGPointZero, front->velocity));
1483
 
}
1484
 
 
1485
 
static void _assertSpokeIntegrity(Spoke* spoke)
1486
 
{
1487
 
        assert(spoke->leftFront != spoke->rightFront);
1488
 
        assert(spoke->rightFront->leftSpoke == spoke);
1489
 
        assert(spoke->leftFront->rightSpoke == spoke);
1490
 
 
1491
 
        assert(!CGPointEqualToPoint(CGPointZero, spoke->velocity));
1492
 
}
1493
 
 
1494
 
static void _collapseEndFront(Front* front0, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1495
 
{
1496
 
        NSLog(@"collapsing endcap... %f (%p)", time, front0);
1497
 
        Front* front1 = front0->rightSpoke->rightFront;
1498
 
        Front* front2 = front1->rightSpoke->rightFront;
1499
 
        
1500
 
        Spoke* spoke = front0->leftSpoke;
1501
 
        CGPoint c = CGPointAdd(rec->vertices[spoke->sourceVertexIndex], CGPointScale(spoke->velocity, time - spoke->start));
1502
 
        uint16_t mvi = _addVertex(rec, c, time);
1503
 
 
1504
 
        _addTriangle(rec, front0->leftSpoke->sourceVertexIndex, front0->rightSpoke->sourceVertexIndex, mvi);
1505
 
        _addTriangle(rec, front1->leftSpoke->sourceVertexIndex, front1->rightSpoke->sourceVertexIndex, mvi);
1506
 
        _addTriangle(rec, front2->leftSpoke->sourceVertexIndex, front2->rightSpoke->sourceVertexIndex, mvi);
1507
 
 
1508
 
        _deactivateSpoke(front0->rightSpoke, activeWalls, inactiveWalls);
1509
 
        _deactivateSpoke(front1->rightSpoke, activeWalls, inactiveWalls);
1510
 
        _deactivateSpoke(front2->rightSpoke, activeWalls, inactiveWalls);
1511
 
        _deactivateFront(front0, activeWalls, inactiveWalls);
1512
 
        _deactivateFront(front1, activeWalls, inactiveWalls);
1513
 
        _deactivateFront(front2, activeWalls, inactiveWalls);
1514
 
 
1515
 
}
1516
 
 
1517
 
static void _collapseFront(Front* front, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls, size_t maxEstimates, float maxTime)
1518
 
{
1519
 
//      NSLog(@"collapsing front... %f (%p,%f)", time, front, front->willCollapse);
1520
 
 
1521
 
        Spoke* leftSpoke = front->leftSpoke;
1522
 
        Spoke* rightSpoke = front->rightSpoke;
1523
 
        Front* leftFront = leftSpoke->leftFront;
1524
 
        Front* rightFront = rightSpoke->rightFront;
1525
 
 
1526
 
        if (front->leftSpoke->leftFront->leftSpoke->leftFront->leftSpoke->leftFront == front)
1527
 
        {
1528
 
                _collapseEndFront(front, time, rec, activeWalls, inactiveWalls);
1529
 
                return;
1530
 
        }
1531
 
 
1532
 
 
1533
 
//      if ((leftSpoke->start != 0.0) || (rightSpoke->start != 0.0))
1534
 
//              printf("collapsing non-starting front\n");
1535
 
 
1536
 
        _assertFrontIntegrity(front);
1537
 
        _assertFrontIntegrity(leftFront);
1538
 
        _assertFrontIntegrity(rightFront);
1539
 
        _assertSpokeIntegrity(leftSpoke);
1540
 
        _assertSpokeIntegrity(rightSpoke);
1541
 
 
1542
 
        CGPoint s = rec->vertices[leftSpoke->sourceVertexIndex];
1543
 
        
1544
 
        CGPoint c = CGPointAdd(s, CGPointScale(leftSpoke->velocity, time - leftSpoke->start));
1545
 
        
1546
 
        uint16_t mvi = _addVertex(rec, c, time);
1547
 
        
1548
 
        Spoke* newSpoke = _allocSpoke(activeWalls, inactiveWalls);
1549
 
        
1550
 
        CGPoint newRay = CGPointReverseProject(rightFront->velocity, CGPointAdd(rightFront->velocity, leftFront->velocity));
1551
 
//      CGPoint newRay = CGPointReverseProject(leftSpoke->velocity, CGPointAdd(rightSpoke->velocity, leftSpoke->velocity));
1552
 
        newSpoke->velocity = newRay;
1553
 
        newSpoke->sourceVertexIndex = mvi;
1554
 
        newSpoke->finalVertexIndex = -1;
1555
 
        newSpoke->start = time;
1556
 
 
1557
 
        assert(!isnan(newSpoke->velocity.x) && !isnan(newSpoke->velocity.y));
1558
 
 
1559
 
        newSpoke->leftFront = leftFront;
1560
 
        newSpoke->rightFront = rightFront;
1561
 
        
1562
 
        
1563
 
        leftFront->rightSpoke = newSpoke;
1564
 
        rightFront->leftSpoke = newSpoke;
1565
 
 
1566
 
        _addTriangle(rec, leftSpoke->sourceVertexIndex, rightSpoke->sourceVertexIndex, newSpoke->sourceVertexIndex);
1567
 
        _addTriangle(rec, leftFront->leftSpoke->sourceVertexIndex, leftSpoke->sourceVertexIndex, newSpoke->sourceVertexIndex);
1568
 
        _addTriangle(rec, rightSpoke->sourceVertexIndex, rightFront->rightSpoke->sourceVertexIndex, newSpoke->sourceVertexIndex);
1569
 
 
1570
 
        _deactivateFront(front, activeWalls, inactiveWalls);
1571
 
        _deactivateSpoke(leftSpoke, activeWalls, inactiveWalls);
1572
 
        _deactivateSpoke(rightSpoke, activeWalls, inactiveWalls);
1573
 
        
1574
 
        _assertFrontIntegrity(leftFront);
1575
 
        _assertFrontIntegrity(rightFront);
1576
 
        _assertSpokeIntegrity(newSpoke);
1577
 
        _assertSpokeIntegrity(leftFront->rightSpoke);
1578
 
        _assertSpokeIntegrity(rightFront->leftSpoke);
1579
 
 
1580
 
 
1581
 
/*
1582
 
        _updateCollapseTime(leftFront, rec->vertices, time);
1583
 
        _updateCollapseTime(rightFront, rec->vertices, time);
1584
 
        
1585
 
        printf("update l will collapse: %f (%p)\n", leftFront->willCollapse, leftFront);
1586
 
        printf("update r will collapse: %f (%p)\n", rightFront->willCollapse, rightFront);
1587
 
*/
1588
 
/*
1589
 
        _redactEstimateForSpokeToFronts(leftSpoke, activeWalls->fronts, activeWalls->numFronts);
1590
 
        _redactEstimateForSpokeToFronts(rightSpoke, activeWalls->fronts, activeWalls->numFronts);
1591
 
        _recomputeEstimateForSpokeToFronts(newSpoke, activeWalls->fronts, activeWalls->numFronts, rec->vertices, maxEstimates, time, maxTime);
1592
 
        
1593
 
        _recomputeEstimatesForFront(leftFront, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1594
 
        _recomputeEstimatesForFront(rightFront, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1595
 
*/
1596
 
 
1597
 
//      return MIN(leftFront->willCollapse, rightFront->willCollapse);
1598
 
}
1599
 
 
1600
 
static void _attachSpokeLeft(Front* front, Spoke* spoke)
1601
 
{
1602
 
        front->leftSpoke = spoke;
1603
 
        spoke->rightFront = front;
1604
 
}
1605
 
 
1606
 
static void _attachSpokeRight(Front* front, Spoke* spoke)
1607
 
{
1608
 
        front->rightSpoke = spoke;
1609
 
        spoke->leftFront = front;
1610
 
}
1611
 
 
1612
 
 
1613
 
static void _splitFront(Front* hitFront, Spoke* hittingSpoke, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls, size_t maxEstimates, float maxTime)
1614
 
{
1615
 
        // the hit front is split into two new fronts, and one final triangle, the hitFront is recycled.
1616
 
        // the two hitting fronts generate another three triangles, the hittingSpoke is recycled.
1617
 
        //
1618
 
        /*
1619
 
                |         |
1620
 
                -----------
1621
 
                    /|\
1622
 
                   / | \
1623
 
                  /  |  \
1624
 
                 /  / \  \
1625
 
 
1626
 
                |  \   /  |
1627
 
                |   \ /   |
1628
 
                |   /|\   |
1629
 
                ---/ | \---
1630
 
                  /  |  \
1631
 
                 /  / \  \
1632
 
                 
1633
 
                 
1634
 
        */
1635
 
        
1636
 
        NSLog(@"splitting front... %f (%p)", time, hitFront);
1637
 
        
1638
 
        assert(!_frontLoopsBelow(hitFront, 4));
1639
 
        
1640
 
        if (hitFront->leftSpoke->leftFront->leftSpoke->leftFront->leftSpoke->leftFront == hitFront)
1641
 
        {
1642
 
                _collapseEndFront(hitFront, time, rec, activeWalls, inactiveWalls);
1643
 
                return;
1644
 
        }
1645
 
        _assertFrontIntegrity(hitFront);
1646
 
        _assertSpokeIntegrity(hittingSpoke);
1647
 
        
1648
 
        CGPoint s = rec->vertices[hittingSpoke->sourceVertexIndex];
1649
 
        CGPoint c = CGPointAdd(s, CGPointScale(hittingSpoke->velocity, time - hittingSpoke->start));
1650
 
        uint32_t mvi = _addVertex(rec, c, time);
1651
 
 
1652
 
 
1653
 
        _addTriangle(rec, hitFront->leftSpoke->sourceVertexIndex, hitFront->rightSpoke->sourceVertexIndex, mvi);
1654
 
 
1655
 
        _addTriangle(rec,
1656
 
                                hittingSpoke->sourceVertexIndex,
1657
 
                                hittingSpoke->rightFront->rightSpoke->sourceVertexIndex,
1658
 
                                mvi);
1659
 
        _addTriangle(rec,
1660
 
                                hittingSpoke->leftFront->leftSpoke->sourceVertexIndex,
1661
 
                                hittingSpoke->sourceVertexIndex,
1662
 
                                mvi);
1663
 
 
1664
 
        Spoke* newSpokeLeft = _allocSpoke(activeWalls, inactiveWalls);
1665
 
        Spoke* newSpokeRight = _allocSpoke(activeWalls, inactiveWalls);
1666
 
 
1667
 
        Front* splitFrontLeft = _allocFront(activeWalls, inactiveWalls);
1668
 
        Front* splitFrontRight = _allocFront(activeWalls, inactiveWalls);
1669
 
        
1670
 
        Front* hittingFrontLeft = hittingSpoke->leftFront;
1671
 
        Front* hittingFrontRight = hittingSpoke->rightFront;
1672
 
 
1673
 
 
1674
 
        _attachSpokeLeft(splitFrontLeft, hitFront->leftSpoke);
1675
 
        _attachSpokeRight(splitFrontRight, hitFront->rightSpoke);
1676
 
 
1677
 
        _attachSpokeRight(splitFrontLeft, newSpokeRight);
1678
 
        _attachSpokeLeft(splitFrontRight, newSpokeLeft);
1679
 
 
1680
 
        _attachSpokeRight(hittingFrontLeft, newSpokeLeft);
1681
 
        _attachSpokeLeft(hittingFrontRight, newSpokeRight);
1682
 
 
1683
 
 
1684
 
        newSpokeLeft->sourceVertexIndex = mvi;
1685
 
        newSpokeRight->sourceVertexIndex = mvi;
1686
 
        newSpokeLeft->finalVertexIndex = -1;
1687
 
        newSpokeRight->finalVertexIndex = -1;
1688
 
        
1689
 
 
1690
 
        CGPoint newRayLeft = CGPointReverseProject(hittingFrontLeft->velocity, CGPointAdd(hittingFrontLeft->velocity, hitFront->velocity));
1691
 
        CGPoint newRayRight = CGPointReverseProject(hittingFrontRight->velocity, CGPointAdd(hittingFrontRight->velocity, hitFront->velocity));
1692
 
 
1693
 
        newSpokeLeft->velocity = newRayLeft;
1694
 
        newSpokeRight->velocity = newRayRight;
1695
 
        newSpokeLeft->start = time;
1696
 
        newSpokeRight->start = time;
1697
 
        
1698
 
        assert(!isnan(newSpokeLeft->velocity.x) && !isnan(newSpokeLeft->velocity.y));
1699
 
        assert(!isnan(newSpokeRight->velocity.x) && !isnan(newSpokeRight->velocity.y));
1700
 
 
1701
 
        splitFrontLeft->velocity = hitFront->velocity;
1702
 
        splitFrontRight->velocity = hitFront->velocity;
1703
 
                        
1704
 
        _assertFrontIntegrity(splitFrontLeft);
1705
 
        _assertFrontIntegrity(splitFrontRight);
1706
 
        _assertFrontIntegrity(hittingFrontLeft);
1707
 
        _assertFrontIntegrity(hittingFrontRight);
1708
 
 
1709
 
        _assertSpokeIntegrity(newSpokeLeft);
1710
 
        _assertSpokeIntegrity(newSpokeRight);
1711
 
 
1712
 
        _assertSpokeIntegrity(splitFrontLeft->leftSpoke);
1713
 
        _assertSpokeIntegrity(splitFrontRight->rightSpoke);
1714
 
        _assertSpokeIntegrity(hittingFrontLeft->leftSpoke);
1715
 
        _assertSpokeIntegrity(hittingFrontRight->rightSpoke);
1716
 
 
1717
 
 
1718
 
        _deactivateFront(hitFront, activeWalls, inactiveWalls);
1719
 
        _deactivateSpoke(hittingSpoke, activeWalls, inactiveWalls);
1720
 
/*
1721
 
        _updateCollapseTime(splitFrontLeft, rec->vertices);
1722
 
        _updateCollapseTime(splitFrontRight, rec->vertices);
1723
 
 
1724
 
        _updateCollapseTime(hittingFrontLeft, rec->vertices);
1725
 
        _updateCollapseTime(hittingFrontRight, rec->vertices);
1726
 
 
1727
 
//      _redactEstimateForSpokeToFronts(hittingSpoke, fronts, *numFrontsPtr);
1728
 
        _recomputeEstimateForSpokeToFronts(newSpokeLeft, activeWalls->fronts, activeWalls->numFronts, rec->vertices, maxEstimates, time, maxTime);
1729
 
        _recomputeEstimateForSpokeToFronts(newSpokeRight, activeWalls->fronts, activeWalls->numFronts, rec->vertices, maxEstimates, time, maxTime);
1730
 
        
1731
 
        _recomputeEstimatesForFront(splitFrontLeft, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1732
 
        _recomputeEstimatesForFront(splitFrontRight, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1733
 
        _recomputeEstimatesForFront(hittingFrontLeft, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1734
 
        _recomputeEstimatesForFront(hittingFrontRight, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1735
 
*/      
1736
 
}
1737
 
 
1738
 
PolygonInsetRecord InsetPolygon(CGPoint* sourceVertices, size_t numSourceVertices, float insetTime, int flags)
1739
 
{
1740
 
        small_pool_init();
1741
 
        
1742
 
        PolygonInsetRecord rec;
1743
 
 
1744
 
        rec.numIndices = 0;
1745
 
        rec.triangleIndices = NULL;
1746
 
        rec.numVertices = numSourceVertices;
1747
 
        rec.vertices = calloc(sizeof(*rec.vertices), rec.numVertices);
1748
 
        rec.times = calloc(sizeof(*rec.times), rec.numVertices);
1749
 
        memcpy(rec.vertices, sourceVertices, sizeof(CGPoint)*rec.numVertices);
1750
 
        size_t maxEstimates = numSourceVertices*10;
1751
 
        
1752
 
        FrontsAndSpokesRec activeWalls = {NULL, 0, NULL, 0};
1753
 
        FrontsAndSpokesRec inactiveWalls = {NULL, 0, NULL, 0};
1754
 
 
1755
 
        activeWalls.numFronts = numSourceVertices;
1756
 
        activeWalls.numSpokes = numSourceVertices;
1757
 
        size_t maxFronts = numSourceVertices*10;
1758
 
        size_t maxSpokes = numSourceVertices*10;
1759
 
        activeWalls.spokes = calloc(sizeof(*activeWalls.spokes), maxSpokes);
1760
 
        activeWalls.fronts = calloc(sizeof(*activeWalls.fronts), maxFronts);
1761
 
        inactiveWalls.spokes = calloc(sizeof(*activeWalls.spokes), maxSpokes);
1762
 
        inactiveWalls.fronts = calloc(sizeof(*activeWalls.fronts), maxFronts);
1763
 
 
1764
 
        activeWalls.spokes[0] = small_malloc(sizeof(Spoke)*numSourceVertices);
1765
 
        activeWalls.fronts[0] = small_malloc(sizeof(Front)*numSourceVertices);
1766
 
        
1767
 
        assert(activeWalls.spokes[0]);
1768
 
        assert(activeWalls.fronts[0]);
1769
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1770
 
        {
1771
 
                activeWalls.spokes[i] = activeWalls.spokes[0]+i;
1772
 
                activeWalls.fronts[i] = activeWalls.fronts[0]+i;
1773
 
        }
1774
 
 
1775
 
        // initialize spokes and fronts
1776
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1777
 
        {
1778
 
                size_t i1i = (i == 0 ? numSourceVertices-1 : i-1);
1779
 
                assert(i1i != numSourceVertices);
1780
 
                activeWalls.spokes[i]->leftFront = activeWalls.fronts [i1i];
1781
 
                activeWalls.spokes[i]->rightFront = activeWalls.fronts[i];
1782
 
 
1783
 
                activeWalls.fronts[i]->leftSpoke = activeWalls.spokes [i];
1784
 
                size_t ii = (i+1) % numSourceVertices;
1785
 
                assert(ii != numSourceVertices);
1786
 
                activeWalls.fronts[i]->rightSpoke = activeWalls.spokes[ii];
1787
 
        }
1788
 
 
1789
 
 
1790
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1791
 
        {
1792
 
                Spoke* spoke = activeWalls.spokes[i];
1793
 
                spoke->sourceVertexIndex = i;
1794
 
                spoke->finalVertexIndex = -1;
1795
 
                spoke->start = 0.0f;
1796
 
                
1797
 
        }
1798
 
        
1799
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1800
 
        {
1801
 
                Front* front = activeWalls.fronts[i];
1802
 
                CGPoint a = sourceVertices[front->leftSpoke->sourceVertexIndex];
1803
 
                CGPoint b = sourceVertices[front->rightSpoke->sourceVertexIndex];
1804
 
                front->velocity = CGPointNormalize(CGPointNormal(CGPointSub(b,a)));
1805
 
        }
1806
 
 
1807
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1808
 
        {
1809
 
                Spoke* spoke = activeWalls.spokes[i];
1810
 
                CGPoint nl = CGPointNormalize(spoke->leftFront->velocity),
1811
 
                                nr = CGPointNormalize(spoke->rightFront->velocity);
1812
 
 
1813
 
                CGPoint nh = CGPointNormalize(CGPointAdd(nl, nr));
1814
 
                float cosa = CGPointDot(nh,nl);
1815
 
                float speed = 1.0f/cosa;
1816
 
                spoke->velocity = CGPointScale(nh, speed);
1817
 
                spoke->start = 0.0f;
1818
 
                
1819
 
        }
1820
 
 
1821
 
        for (size_t i = 0; i < numSourceVertices; ++i)
1822
 
        {
1823
 
                _assertFrontIntegrity(activeWalls.fronts[i]);
1824
 
                _assertSpokeIntegrity(activeWalls.spokes[i]);
1825
 
        }
1826
 
        
1827
 
 
1828
 
        // enter the main loop, where we go through the priority queue, one by one, until we've reached the desired thickness or ran out of propagating edges
1829
 
        float currentTime = 0.0f;
1830
 
        while (currentTime < insetTime)
1831
 
        {
1832
 
                for (size_t i = 0; i < activeWalls.numFronts; ++i)
1833
 
                {
1834
 
                        Front* front = activeWalls.fronts[i];
1835
 
                        _updateCollapseTime(front, rec.vertices, currentTime);
1836
 
                        
1837
 
                        _assertFrontIntegrity(front);
1838
 
 
1839
 
                }
1840
 
                _sortFronts(activeWalls.fronts, activeWalls.numFronts);
1841
 
 
1842
 
                if (!(flags & kThickenNoSplitting))
1843
 
                {
1844
 
                        for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1845
 
                        {
1846
 
                                Spoke* spoke = activeWalls.spokes[i];
1847
 
                                _recomputeEstimatesForSpoke(spoke, activeWalls.fronts, activeWalls.numFronts, rec.vertices, maxEstimates, currentTime, insetTime);
1848
 
                                
1849
 
                                _assertSpokeIntegrity(spoke);
1850
 
 
1851
 
                        }
1852
 
 
1853
 
                        _sortSpokes(activeWalls.spokes, activeWalls.numSpokes);
1854
 
                }
1855
 
                
1856
 
                
1857
 
                Front* nextFront = activeWalls.fronts[0];
1858
 
                Spoke* nextSpoke = activeWalls.spokes[0];
1859
 
 
1860
 
 
1861
 
                float eTime = INFINITY;
1862
 
                if (nextSpoke->numEstimates && (nextSpoke->estimates->range.max > currentTime))
1863
 
                        eTime = nextSpoke->estimates->range.min;
1864
 
                
1865
 
                float cTime = nextFront->willCollapse;
1866
 
 
1867
 
 
1868
 
                assert(maxSpokes > activeWalls.numSpokes+1);
1869
 
                assert(maxFronts > activeWalls.numFronts+1);
1870
 
                
1871
 
//              printf("e %f c %f\n", eTime, cTime);
1872
 
 
1873
 
                if (!(flags & kThickenNoSplitting) && (eTime + FLT_EPSILON < cTime))
1874
 
                {
1875
 
                        if (eTime > insetTime)
1876
 
                                break;
1877
 
                        
1878
 
                        // so we have a legitimate hit
1879
 
                        // 1. find out if it's a spoke-spoke, or a spoke-front collision, other collisions are invalid
1880
 
                        // spoke/spoke means a left spoke must hit a right spoke, and the front in-between disappears
1881
 
                        // spoke/front means the front is split
1882
 
                        
1883
 
//                      assert(eTime + FLT_EPSILON >= currentTime);
1884
 
//                      assert(nextSpoke->estimates->face == kHitFront);
1885
 
 
1886
 
                        if (flags & kThickenStopOnFirstSplit)
1887
 
                        {
1888
 
                                currentTime = eTime;
1889
 
                                insetTime = currentTime;
1890
 
                                break;
1891
 
                        }
1892
 
                
1893
 
                        currentTime = eTime;
1894
 
                        _splitFront(nextSpoke->estimates->front, nextSpoke, currentTime, &rec, &activeWalls, &inactiveWalls, maxEstimates, insetTime);
1895
 
 
1896
 
                }
1897
 
                else
1898
 
                {
1899
 
                        if (cTime > insetTime)
1900
 
                                break;
1901
 
 
1902
 
                        currentTime = cTime;
1903
 
                        _collapseFront(nextFront, currentTime, &rec, &activeWalls, &inactiveWalls, maxEstimates, insetTime);
1904
 
                        
1905
 
 
1906
 
                }
1907
 
        }
1908
 
        
1909
 
        
1910
 
        // finalize the spokes, eg, add "final" vertices
1911
 
        size_t numFinalVertices = 0;
1912
 
        for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1913
 
        {
1914
 
                Spoke* spoke = activeWalls.spokes[i];
1915
 
                if (spoke->finalVertexIndex != -1)
1916
 
                        continue;
1917
 
                numFinalVertices++;
1918
 
                
1919
 
        }
1920
 
        
1921
 
        rec.vertices = realloc(rec.vertices, (rec.numVertices+numFinalVertices)*sizeof(*(rec.vertices)));
1922
 
        rec.times = realloc(rec.times, (rec.numVertices+numFinalVertices)*sizeof(*(rec.times)));
1923
 
 
1924
 
        for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1925
 
        {
1926
 
                Spoke* spoke = activeWalls.spokes[i];
1927
 
                if (spoke->finalVertexIndex != -1)
1928
 
                        continue;
1929
 
                
1930
 
                CGPoint src = rec.vertices[spoke->sourceVertexIndex];
1931
 
                CGPoint dst = CGPointAdd(src, CGPointScale(spoke->velocity, insetTime - spoke->start));
1932
 
                size_t fi = rec.numVertices++;
1933
 
                rec.vertices[fi] = dst;
1934
 
                rec.times[fi] = insetTime;
1935
 
                spoke->finalVertexIndex = fi;
1936
 
                
1937
 
        }
1938
 
        
1939
 
        // create triangles
1940
 
        assert(rec.numVertices < USHRT_MAX);
1941
 
 
1942
 
        rec.triangleIndices = realloc(rec.triangleIndices, sizeof(uint16_t)*(rec.numIndices+6*activeWalls.numFronts));
1943
 
        
1944
 
        
1945
 
        for (size_t i = 0; i < activeWalls.numFronts; ++i)
1946
 
        {
1947
 
                Front* front = activeWalls.fronts[i];
1948
 
                uint32_t i0 = front->leftSpoke->sourceVertexIndex;
1949
 
                uint32_t i1 = front->rightSpoke->sourceVertexIndex;
1950
 
                uint32_t i2 = front->leftSpoke->finalVertexIndex;
1951
 
                uint32_t i3 = front->rightSpoke->finalVertexIndex;
1952
 
                
1953
 
                if ((i0 != i1) && (i1 != i2) && (i2 != i0))
1954
 
                {
1955
 
                        rec.triangleIndices[rec.numIndices++] = i0;
1956
 
                        rec.triangleIndices[rec.numIndices++] = i1;
1957
 
                        rec.triangleIndices[rec.numIndices++] = i2;
1958
 
                }
1959
 
                if ((i1 != i2) && (i2 != i3) && (i3 != i1))
1960
 
                {
1961
 
                        rec.triangleIndices[rec.numIndices++] = i3;
1962
 
                        rec.triangleIndices[rec.numIndices++] = i2;
1963
 
                        rec.triangleIndices[rec.numIndices++] = i1;
1964
 
                }
1965
 
        }
1966
 
 
1967
 
        
1968
 
        free(activeWalls.spokes);
1969
 
        free(activeWalls.fronts);
1970
 
        free(inactiveWalls.spokes);
1971
 
        free(inactiveWalls.fronts);
1972
 
                        
1973
 
        small_pool_destroy();
1974
 
        
1975
 
        return rec;
1976
 
}
1977
 
 
1978
 
static void _addPirToVar(VertexArray* var, PolygonInsetRecord* rec, float thickness)
1979
 
{
1980
 
        size_t vo = var->numVertices;
1981
 
        var->numVertices += rec->numVertices;
1982
 
        var->vertices = realloc(var->vertices, sizeof(*var->vertices)*var->numVertices);
1983
 
        memset(var->vertices + vo, 0x00, sizeof(*var->vertices)*rec->numVertices);
1984
 
 
1985
 
        for (size_t i = 0; i < rec->numVertices; ++i)
1986
 
        {
1987
 
                PositionNormalTex3f3f2f* v = var->vertices + vo + i;
1988
 
                v->pos[0] = rec->vertices[i].x;
1989
 
                v->pos[1] = rec->vertices[i].y;
1990
 
                v->normal[2] = 1.0f;
1991
 
                float u = rec->times[i]/thickness;
1992
 
                v->texcoord[0] = 0.5f + 0.5f*u;
1993
 
        //      v->texcoord[0] = 0.0;
1994
 
        }
1995
 
        
1996
 
        size_t io = var->numIndices;
1997
 
        var->numIndices += rec->numIndices;
1998
 
        var->indices = realloc(var->indices, sizeof(*var->indices)*var->numIndices);
1999
 
        
2000
 
        for (size_t i = 0; i < rec->numIndices; ++i)
2001
 
                var->indices[io+i] = (vo + rec->triangleIndices[i]);
2002
 
        
2003
 
}
2004
 
 
2005
 
VertexArray* ThickenOutline(CGPoint* inPoints, size_t numInPoints, float thickness, int flags)
2006
 
{
2007
 
        VertexArray* var = [[VertexArray alloc] init];
2008
 
 
2009
 
        if (flags & kThickenInside)
2010
 
        {
2011
 
                PolygonInsetRecord rec = InsetPolygon(inPoints, numInPoints, thickness, flags);
2012
 
 
2013
 
                _addPirToVar(var, &rec, thickness);
2014
 
                free(rec.vertices);
2015
 
                free(rec.times);
2016
 
                free(rec.triangleIndices);
2017
 
        }
2018
 
        if (flags & kThickenOutside)
2019
 
        {
2020
 
                CGPoint* points = calloc(sizeof(CGPoint), numInPoints);
2021
 
                for (size_t i = 0; i < numInPoints; ++i)
2022
 
                        points[numInPoints - i - 1] = inPoints[i];
2023
 
                PolygonInsetRecord rec = InsetPolygon(points, numInPoints, thickness, flags);
2024
 
 
2025
 
                _addPirToVar(var, &rec, thickness);
2026
 
                free(rec.vertices);
2027
 
                free(rec.times);
2028
 
                free(rec.triangleIndices);
2029
 
                free(points);
2030
 
        }
2031
 
        
2032
 
        var->mode = GL_TRIANGLES;
2033
 
#ifdef SHOW_LINES
2034
 
        [var convertTriangleIndicesToLines];
2035
 
#endif
2036
 
        
2037
 
        return [var autorelease];
2038
 
}
2039
 
 
2040
 
 

Loggerhead 1.17 is a web-based interface for Bazaar branches