5
// Created by döme on 05.08.2009.
6
// Copyright 2009 __MyCompanyName__. All rights reserved.
9
#import "Triangulation.h"
12
#import "VertexArray.h"
14
//#define SHOW_LINES 1
16
struct _bezierElementExtractorRec
20
float targetResolution;
23
void _bezierPathElementExtractor(void *info,
24
const CGPathElement *element)
26
struct _bezierElementExtractorRec* rec = info;
29
case kCGPathElementMoveToPoint:
30
if (rec->numPoints && CGPointEqualToPoint(element->points[0], rec->points[rec->numPoints-1]))
32
rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+1));
33
rec->points[rec->numPoints++] = element->points[0];
35
case kCGPathElementAddLineToPoint:
37
CGPoint c0 = element->points[0];
38
//CGPoint c1 = element->points[1];
40
//if (rec->numPoints && CGPointEqualToPoint(c1, lastPoint))
42
rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+1));
43
rec->points[rec->numPoints++] = c0;
46
case kCGPathElementAddQuadCurveToPoint:
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)));
53
int numSegments = 2 + (int)(approxLength/rec->targetResolution);
55
rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+numSegments));
57
for (int i = 0; i < numSegments; ++i)
59
float t = (i+1)/(float)numSegments;
60
rec->points[rec->numPoints+i] = quadraticPointAtT(c0, c1, c2, t);
63
rec->numPoints += numSegments;
67
case kCGPathElementAddCurveToPoint:
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)));
76
int numSegments = 3 + (int)(approxLength/rec->targetResolution);
78
rec->points = realloc(rec->points, sizeof(*rec->points)*(rec->numPoints+numSegments));
80
for (int i = 0; i < numSegments; ++i)
82
float t = (i+1)/(float)numSegments;
83
CGPoint p = cubicPointAtT(c0, c1, c2, c3, t);
84
rec->points[rec->numPoints+i] = p;
87
rec->numPoints += numSegments;
91
case kCGPathElementCloseSubpath:
98
void SimpleBezierPathToPolyline(CGPathRef cpath, CGPoint** outPoints, size_t* numOutPoints)
100
struct _bezierElementExtractorRec lineRec = {NULL, 0, 5.0f};
101
CGPathApply(cpath, &lineRec, _bezierPathElementExtractor);
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);
107
*outPoints = lineRec.points;
108
*numOutPoints = lineRec.numPoints;
112
typedef struct _vertex _vertex;
115
typedef struct _edge _edge;
117
typedef struct _polygon
139
void _vertexAddEdge(_vertex* self, _edge* edge)
141
self->edges = realloc(self->edges, sizeof(*self->edges)*(self->numEdges+1));
142
self->edges[self->numEdges++] = edge;
145
_edge* _edgeCreate(size_t v0, size_t v1, _edge* dual, _vertex* vertices)
147
_edge* self = calloc(1, sizeof(*self));
151
self->vertices[0] = v0;
152
self->vertices[1] = v1;
157
_vertexAddEdge(&vertices[v0], self);
158
_vertexAddEdge(&vertices[v1], self);
164
_polygon* _polyCreate(void)
166
_polygon* self = calloc(1, sizeof(*self));
171
void _polyRemoveEdge(_polygon* self, _edge* edge)
173
if (edge == self->firstEdge)
174
self->firstEdge = edge->nextEdge;
177
edge->prevEdge->nextEdge = edge->nextEdge;
179
edge->nextEdge->prevEdge = edge->prevEdge;
180
edge->prevEdge = NULL;
181
edge->nextEdge = NULL;
182
edge->polygon = NULL;
187
void _polyDelete(_polygon* self)
189
while (self->numEdges)
191
_edge* edge = self->firstEdge;
192
_polyRemoveEdge(self, edge);
200
void _polyReplaceEdgesWithEdge(_polygon* self, _edge* e0, _edge* e1, _edge* replacement)
202
if (e0->polygon == self)
204
if (e1->polygon == self)
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;
214
if ((self->firstEdge == e0) || (self->firstEdge == e1))
215
self->firstEdge = replacement;
217
replacement->polygon = self;
222
void _polyAddEdge(_polygon* self, _edge* edge)
224
edge->polygon = self;
228
edge->nextEdge = self->firstEdge;
229
edge->prevEdge = self->firstEdge->prevEdge;
231
edge->nextEdge->prevEdge = edge;
232
edge->prevEdge->nextEdge = edge;
236
self->firstEdge = edge;
237
edge->nextEdge = edge;
238
edge->prevEdge = edge;
244
void polygonRobustnessCheck(_polygon* polygon, _vertex* vertices)
246
_edge* edge0 = polygon->firstEdge;
247
for (size_t i = 0; i < polygon->numEdges; ++i, edge0 = edge0->nextEdge)
249
CGPoint a0 = vertices[edge0->vertices[0]].pos;
250
CGPoint a1 = vertices[edge0->vertices[1]].pos;
252
assert(!CGPointEqualToPoint(a0, a1));
254
_edge* edge1 = edge0->nextEdge->nextEdge;
255
for (size_t j = i+2; j < polygon->numEdges; ++j, edge1 = edge1->nextEdge)
257
CGPoint b0 = vertices[edge1->vertices[0]].pos;
258
CGPoint b1 = vertices[edge1->vertices[1]].pos;
260
if (CGLineSegmentsIntersect(a0,a1,b0,b1))
262
NSLog(@"oops, found a baddie");
269
_polygon* triangulatePolygon(_polygon* polygon, _vertex* vertices)
271
if (polygon->numEdges < 4)
275
//NSMutableArray* rejectionList = [NSMutableArray array];;
277
_edge* edge0 = polygon->firstEdge;
278
for (size_t i = 0; i < polygon->numEdges; ++i, edge0 = edge0->nextEdge)
280
_edge* edge1 = edge0->nextEdge;
282
assert(edge0->vertices[1] == edge1->vertices[0]);
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);
290
float ecross = CGPointCross(e01, e12);
294
//[rejectionList addObject: [NSString stringWithFormat: @"wrong winding %zu %zu, %f", i0,i1, ecross]];
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
303
size_t numNonEdges = polygon->numEdges - 3;
305
int intersectFound = 0;
307
_edge* nonEdge = edge1->nextEdge;
308
for (size_t j = 0; j < numNonEdges; ++j, nonEdge = nonEdge->nextEdge)
310
CGPoint x = vertices[nonEdge->vertices[1]].pos;
313
if (CGPointInTriangle(x, p0, p1, p2))
316
//[rejectionList addObject: [NSString stringWithFormat: @"vertex in triangle %zu %zu X %zu", i0,i1, nonEdge->vertices[0]]];
326
// the new edge doesn't intersect anything, so we can go on and create the new triangle
328
_edge* edge2 = _edgeCreate(edge1->vertices[1], edge0->vertices[0], NULL, vertices);
329
_edge* edgeRedux = _edgeCreate(edge0->vertices[0], edge1->vertices[1], edge2, vertices);
331
_polyReplaceEdgesWithEdge(polygon, edge0, edge1, edgeRedux); // important to replace first, due to edge prev/next pointers
333
_polygon* reducedPoly = _polyCreate();
334
_polyAddEdge(reducedPoly, edge0);
335
_polyAddEdge(reducedPoly, edge1);
336
_polyAddEdge(reducedPoly, edge2);
338
assert(edge0->vertices[1] == edge1->vertices[0]);
339
assert(edge1->vertices[1] == edge2->vertices[0]);
340
assert(edge2->vertices[1] == edge0->vertices[0]);
342
assert(edge0->vertices[0] == edgeRedux->vertices[0]);
343
assert(edgeRedux->vertices[1] == edge1->vertices[1]);
350
polygonRobustnessCheck(polygon, vertices);
352
//NSLog(@"%@", rejectionList);
357
long edgeCanBeFlipped(_edge* edge, _vertex* vertices)
361
if (edge->polygon->numEdges != 3)
363
if (edge->dual->polygon->numEdges != 3)
369
long edgeShouldBeFlipped(_edge* edge, _vertex* vertices)
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;
376
if (CGPointInCircumCircule(d0, a0, b0, c0))
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;
384
if (CGPointInCircumCircule(d1, a1, b1, c1))
390
void flipEdge(_edge* edge)
392
_polygon* p0 = edge->polygon;
393
_polygon* p1 = edge->dual->polygon;
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;
414
if (b0 == p0->firstEdge)
416
if (b1 == p1->firstEdge)
423
void flipEdgesNextToNewPolygon(_polygon* polygon, _vertex* vertices)
425
if (polygon->numEdges != 3)
428
_edge* edge = polygon->firstEdge;
429
for (size_t i = 0; i < 3; ++i, edge = edge->nextEdge)
431
if (edgeCanBeFlipped(edge, vertices) && edgeShouldBeFlipped(edge, vertices))
433
//NSLog(@"flipping edge");
439
_polygon** triangulatePolygons(_polygon** polygons, size_t* numPolygonsPtr, _vertex* vertices, size_t numVertices)
441
// starting at the last polygon on the list, we try to create a correctly winded triangle out of it
443
size_t numPolygons = *numPolygonsPtr;
445
for (size_t i = 0; i < numPolygons; ++i)
447
_polygon* reducedPoly = triangulatePolygon(polygons[i], vertices);
451
polygons = realloc(polygons, sizeof(*polygons)*(numPolygons+1));
452
polygons[numPolygons++] = reducedPoly;
455
//flipEdgesNextToNewPolygon(reducedPoly, vertices);
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]);
460
else if (polygons[i]->numEdges > 3)
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]);
470
*numPolygonsPtr = numPolygons;
474
VertexArray* TriangulateOutline(CGPoint* inPoints, size_t numInPoints)
476
_polygon* initialPoly = _polyCreate();
478
_vertex* vertices = calloc(numInPoints, sizeof(*vertices));
480
for (size_t i = 0; i < numInPoints; ++i)
482
vertices[i].pos = inPoints[i];
484
assert(!CGPointEqualToPoint(vertices[i-1].pos, vertices[i].pos));
487
if (CGPointEqualToPoint(vertices[numInPoints-1].pos, vertices[0].pos))
490
for (size_t i = 0; i+1 < numInPoints; ++i)
492
_polyAddEdge(initialPoly, _edgeCreate(i, i+1, NULL, vertices));
494
_polyAddEdge(initialPoly, _edgeCreate(numInPoints-1, 0, NULL, vertices));
496
polygonRobustnessCheck(initialPoly, vertices);
498
_polygon** polygons = calloc(1, sizeof(*polygons));
499
polygons[0] = initialPoly;
500
size_t numPolygons = 1;
502
polygons = triangulatePolygons(polygons, &numPolygons, vertices, numInPoints);
505
VertexArray* var = [[[VertexArray alloc] init] autorelease];
508
var->mode = GL_LINES;
510
var->mode = GL_TRIANGLES;
513
var->vertices = calloc(numInPoints, sizeof(*var->vertices));
514
var->numVertices = numInPoints;
516
for (size_t i = 0; i < numInPoints; ++i)
518
PositionNormalTex3f3f2f* vertex = var->vertices+i;
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;
531
size_t numIndices = 0;
533
for (size_t i = 0; i < numPolygons; ++i)
534
numIndices += 2*polygons[i]->numEdges;
535
uint16_t* indices = calloc(numIndices, sizeof(*indices));
538
uint16_t* indices = calloc(3*numPolygons, sizeof(*indices));
540
for (size_t i = 0; i < numPolygons; ++i)
542
_polygon* polygon = polygons[i];
543
if (polygon->numEdges != 3)
545
NSLog(@"whoops, polygon with %d sides instead of 3, skipping.", polygon->numEdges);
550
_edge* edge = polygon->firstEdge;
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);
563
//if (polygon->numEdges != 3)
564
for (size_t j = 0; j < polygon->numEdges; ++j, edge = edge->nextEdge)
566
indices[numIndices++] = edge->vertices[0];
567
indices[numIndices++] = edge->vertices[1];
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];
584
var->numIndices = numIndices;
585
var->indices = indices;
588
for (size_t i = 0; i < numPolygons; ++i)
590
_polygon* polygon = polygons[i];
591
_polyDelete(polygon);
594
for (size_t i = 0; i < numInPoints; ++i)
596
_vertex v = vertices[i];
602
// NSLog(@"number of generated polygons: %d", numPolygons);
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
614
void unsquishyOutline(CGPoint* points, CGPoint* innerPoints, CGPoint* outerPoints, size_t numPoints, float thickness)
616
CGPoint* squishedInnerPoints = calloc(sizeof(*squishedInnerPoints), 2*numPoints);
617
CGPoint* squishedOuterPoints = squishedInnerPoints + numPoints;
618
uint8_t* squishedCorners = calloc(sizeof(*squishedCorners), numPoints);
621
for (size_t i = 0; i < numPoints; ++i)
623
size_t i0 = (i) % numPoints;
624
size_t i1 = (i+1) % numPoints;
625
size_t i2 = (i+2) % numPoints;
627
CGPoint p0 = points[i0];
628
CGPoint p1 = points[i1];
629
CGPoint p2 = points[i2];
631
CGPoint pi0 = innerPoints[i0];
632
CGPoint pi1 = innerPoints[i1];
633
CGPoint pi2 = innerPoints[i2];
635
CGPoint po0 = outerPoints[i0];
636
CGPoint po1 = outerPoints[i1];
637
CGPoint po2 = outerPoints[i2];
639
squishedInnerPoints[i1] = p1;
640
squishedOuterPoints[i1] = p1;
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);
650
for (sbegin = 0; sbegin < numPoints; ++sbegin)
653
if (!(squishedCorners[sbegin] & (SQUISH_FORWARD_OUTER | SQUISH_FORWARD_INNER)))
661
// now that corners have been marked, walk em
662
for (size_t ii = 0; ii < numPoints; ++ii)
664
size_t i = (sbegin + ii) % numPoints;
665
if (!(squishedCorners[i] & (SQUISH_FORWARD_OUTER | SQUISH_FORWARD_INNER)))
668
if ((squishedCorners[i] & SQUISH_FORWARD_INNER) && !(squishedCorners[i] & SQUISH_BACKWARD_INNER) && !(squishedCorners[i] & SQUISH_IGNORE_POINT_INNER))
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;
674
if (innerEnd != i) // that'd mean we went all the way around
676
size_t i0 = (i-1) % numPoints;
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];
685
CGPoint pp12 = CGLineIntersectionPoint(pp0, pp1, pp2, pp3);
687
CGPoint e01 = CGPointSub(pp12, pp0);
688
CGPoint e12 = CGPointSub(pp3, pp12);
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);
693
assert(!isnan(n01.x) && !isnan(n01.y));
694
assert(!isnan(n12.x) && !isnan(n12.y));
696
CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
698
CGPoint ip = CGPointAdd(pp12, hn);
700
for (size_t k = i; k != (innerEnd+1) % numPoints; k = (k+1) % numPoints)
702
squishedInnerPoints[k] = pp12;
704
//squishedCorners[k] &= ~SQUISH_FORWARD_INNER;
705
if ((k != i) && (k != innerEnd))
706
squishedCorners[k] |= SQUISH_IGNORE_POINT_INNER;
711
if ((squishedCorners[i] & SQUISH_FORWARD_OUTER) && !(squishedCorners[i] & SQUISH_BACKWARD_OUTER) && !(squishedCorners[i] & SQUISH_IGNORE_POINT_OUTER))
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;
717
if (outerEnd != i) // that'd mean we went all the way around
719
size_t i0 = (i-1) % numPoints;
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];
728
CGPoint pp12 = CGLineIntersectionPoint(pp0, pp1, pp2, pp3);
730
CGPoint e01 = CGPointSub(pp12, pp0);
731
CGPoint e12 = CGPointSub(pp3, pp12);
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);
736
assert(!isnan(n01.x) && !isnan(n01.y));
737
assert(!isnan(n12.x) && !isnan(n12.y));
739
CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
741
CGPoint ip = CGPointSub(pp12, hn);
743
for (size_t k = i; k != (outerEnd+1) % numPoints; k = (k+1) % numPoints)
745
squishedOuterPoints[k] = pp12;
747
//squishedCorners[k] &= ~SQUISH_FORWARD_OUTER;
748
if ((k != i) && (k != outerEnd))
749
squishedCorners[k] |= SQUISH_IGNORE_POINT_OUTER;
757
for (size_t i = 0; i < numPoints; ++i)
759
squishedCorners[i] &= ~(SQUISH_FORWARD_INNER|SQUISH_BACKWARD_INNER|SQUISH_FORWARD_OUTER|SQUISH_BACKWARD_OUTER);
762
for (size_t i = 0; i < numPoints; ++i)
764
size_t i0 = (i) % numPoints;
765
size_t i1 = (i+1) % numPoints;
766
size_t i2 = (i+2) % numPoints;
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;
773
CGPoint pii0 = squishedInnerPoints[i0];
774
CGPoint pii1 = squishedInnerPoints[i1];
775
CGPoint pii2 = squishedInnerPoints[i2];
778
CGPoint pi0 = innerPoints[i0];
779
CGPoint pi1 = innerPoints[i1];
780
CGPoint pi2 = innerPoints[i2];
783
if (!(squishedCorners[i1] & SQUISH_IGNORE_POINT_INNER))
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);
792
for (size_t i = 0; i < numPoints; ++i)
794
size_t i0 = (i) % numPoints;
795
size_t i1 = (i+1) % numPoints;
796
size_t i2 = (i+2) % numPoints;
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;
803
CGPoint pii0 = squishedOuterPoints[i0];
804
CGPoint pii1 = squishedOuterPoints[i1];
805
CGPoint pii2 = squishedOuterPoints[i2];
808
CGPoint pi0 = outerPoints[i0];
809
CGPoint pi1 = outerPoints[i1];
810
CGPoint pi2 = outerPoints[i2];
813
if (!(squishedCorners[i1] & SQUISH_IGNORE_POINT_OUTER))
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);
823
free(squishedInnerPoints);
825
free(squishedCorners);
829
CGPoint* createOutline(CGPoint* points, size_t numPoints, float thickness)
831
CGPoint* innerPoints = calloc(sizeof(*innerPoints), 2*numPoints);
832
CGPoint* outerPoints = innerPoints + numPoints;
834
for (size_t i = 0; i < numPoints; ++i)
836
size_t i0 = (i) % numPoints;
837
size_t i1 = (i+1) % numPoints;
838
size_t i2 = (i+2) % numPoints;
840
CGPoint p0 = points[i0];
841
CGPoint p1 = points[i1];
842
CGPoint p2 = points[i2];
844
CGPoint e01 = CGPointSub(p1,p0);
845
CGPoint e12 = CGPointSub(p2,p1);
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);
850
assert(!isnan(n01.x) && !isnan(n01.y));
851
assert(!isnan(n12.x) && !isnan(n12.y));
853
CGPoint hn = CGPointReverseProject(n01, CGPointAdd(n01,n12));
855
//innerNormals[i1] = hn;
856
//outerNormals[i1] = CGPointScale(hn, -1.0);
858
innerPoints[i1] = CGPointAdd(p1, hn);
859
outerPoints[i1] = CGPointSub(p1, hn);
862
// unsquishyOutline(points, innerPoints, outerPoints, numPoints, thickness);
868
void _bezierPathDataExtractor(void *info, const CGPathElement *element)
870
NSMutableData* data = info;
871
[data appendBytes: &element->type length: sizeof(element->type)];
872
switch(element->type)
874
case kCGPathElementMoveToPoint:
875
[data appendBytes: element->points length: sizeof(*element->points)];
877
case kCGPathElementAddLineToPoint:
879
[data appendBytes: element->points length: sizeof(*element->points)];
882
case kCGPathElementAddQuadCurveToPoint:
884
[data appendBytes: element->points length: sizeof(*element->points)*2];
888
case kCGPathElementAddCurveToPoint:
890
[data appendBytes: element->points length: sizeof(*element->points)*3];
894
case kCGPathElementCloseSubpath:
901
NSData* BezierPathToData(CGPathRef cpath)
903
NSMutableData* data = [NSMutableData data];
904
CGPathApply(cpath, data, _bezierPathDataExtractor);
909
CGPathRef CreateBezierPathFromData(NSData* data)
911
CGMutablePathRef path = CGPathCreateMutable();
912
const void* bytes = [data bytes];
913
size_t nbytes = [data length];
917
CGPathElementType type = *((CGPathElementType*)(bytes+i));
921
case kCGPathElementMoveToPoint:
924
memcpy(&p, bytes+i, sizeof(CGPoint));
925
i += sizeof(CGPoint);
926
CGPathMoveToPoint(path, nil, p.x, p.y);
929
case kCGPathElementAddLineToPoint:
932
memcpy(&p, bytes+i, sizeof(CGPoint));
933
i += sizeof(CGPoint);
934
CGPathAddLineToPoint(path, nil, p.x, p.y);
937
case kCGPathElementAddQuadCurveToPoint:
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);
945
case kCGPathElementAddCurveToPoint:
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);
954
case kCGPathElementCloseSubpath:
956
CGPathCloseSubpath(path);
962
return (CGPathRef)path;
968
typedef struct Spoke Spoke;
971
typedef struct Front Front;
973
struct CollisionEstimate;
974
typedef struct CollisionEstimate CollisionEstimate;
976
typedef struct PolygonInsetRecord
981
uint16_t* triangleIndices;
983
} PolygonInsetRecord;
988
uint32_t sourceVertexIndex, finalVertexIndex;
996
CollisionEstimate* estimates;
1009
typedef struct FrontsAndSpokesRec
1016
} FrontsAndSpokesRec;
1034
struct CollisionEstimate
1042
struct _small_pool_block
1044
size_t available, used;
1045
struct _small_pool_block* next;
1049
static struct _small_pool_block* _smallStackPoolHead = NULL;
1050
static struct _small_pool_block* _smallStackPoolFirstFree = NULL;
1051
static size_t _smallStackBaseBlockSize = 4096;
1053
static void small_pool_init(void)
1055
while (_smallStackPoolHead)
1057
struct _small_pool_block* next = _smallStackPoolHead->next;
1058
free(_smallStackPoolHead);
1059
_smallStackPoolHead = next;
1061
_smallStackPoolHead = calloc(1,_smallStackBaseBlockSize);
1062
_smallStackPoolHead->bytes = _smallStackPoolHead+1;
1063
_smallStackPoolHead->available = _smallStackBaseBlockSize - sizeof(struct _small_pool_block);
1064
_smallStackPoolFirstFree = _smallStackPoolHead;
1067
static void small_pool_destroy(void)
1069
while (_smallStackPoolHead)
1071
struct _small_pool_block* next = _smallStackPoolHead->next;
1072
free(_smallStackPoolHead);
1073
_smallStackPoolHead = next;
1075
_smallStackBaseBlockSize = 4096;
1076
_smallStackPoolFirstFree = NULL;
1079
static void* small_malloc(size_t s)
1081
struct _small_pool_block* freeBlock = _smallStackPoolFirstFree;
1082
while (s > freeBlock->available)
1084
if (freeBlock->next)
1085
freeBlock = freeBlock->next;
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);
1099
void* result = freeBlock->bytes + freeBlock->used;
1101
freeBlock->used += s;
1102
freeBlock->available -= s;
1108
static r2 _rayInPlane(CGPoint pr0, CGPoint v, CGPoint pp0, CGPoint pn)
1110
r2 range = {INFINITY, -INFINITY};
1112
CGPoint d = CGPointSub(pp0, pr0);
1113
CGPoint n = CGPointNormalize(pn);
1114
int rayTowardsPlaneNormal = CGPointDot(n, v) > 0.0f;
1116
float td = CGPointDot(d, n);
1117
float tr = CGPointDot(v, n);
1119
if (fabsf(tr) < FLT_EPSILON)
1122
assert(!isnan(tr) && !isnan(td));
1125
if (rayTowardsPlaneNormal)
1128
range.max = INFINITY;
1133
range.min = -INFINITY;
1140
static int _r2containsValue(r2 range, float x)
1142
return (range.min <= x) && (range.max >= x);
1145
static r2 _r2intersect(r2 ra, r2 rb)
1147
return (r2){MAX(ra.min, rb.min), MIN(ra.max, rb.max)};
1150
static int _r2isEmpty(r2 r)
1152
return r.min >= r.max;
1155
static int _frontLoopsBelow(Front* front, int num)
1158
for (int i = 0; i < num; ++i)
1160
f2 = f2->leftSpoke->leftFront;
1168
static r2 _estimateSpokeHittingFront(Spoke* spoke, Front* front, CGPoint* vertices)
1170
// front plane wrong???
1174
CGPoint r0 = CGPointAdd(vertices[spoke->sourceVertexIndex], CGPointScale(spoke->velocity, -spoke->start));
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));
1182
CGPoint rays[4] = {spoke->velocity, spoke->velocity, spoke->velocity, CGPointSub(spoke->velocity, front->velocity)};
1184
CGPoint ppoints[4] = { pl0,
1187
pr0 // a point at t=0
1189
CGPoint pnorms[4] = { CGPointNormalize(front->velocity),
1190
CGPointNormalize(CGPointNegate(CGPointNormal(lspoke->velocity))),
1191
CGPointNormalize(CGPointNormal(rspoke->velocity)),
1192
CGPointNormalize(CGPointNegate(front->velocity))
1195
r2 ranges[4] = {{INFINITY,-INFINITY}, {INFINITY,-INFINITY}, {INFINITY,-INFINITY}, {INFINITY,-INFINITY}};
1198
for (size_t i = 0; i < 4; ++i)
1200
ranges[i] = _rayInPlane(r0, rays[i], ppoints[i], pnorms[i]);
1203
r2 minorr = _r2intersect(_r2intersect(ranges[0], ranges[1]), ranges[2]);
1204
r2 finalr = _r2intersect(minorr, ranges[3]);
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};
1212
static int _sortCompareEstimates(const void* _a, const void* _b)
1214
const CollisionEstimate* a = *((const CollisionEstimate**)_a);
1215
const CollisionEstimate* b = *((const CollisionEstimate**)_b);
1217
if (a->range.min < b->range.min)
1219
else if (a->range.min > b->range.min)
1225
static int _sortCompareFronts(const void* _a, const void* _b)
1227
const Front* a = *((const Front**)_a);
1228
const Front* b = *((const Front**)_b);
1229
float timea = a->willCollapse;
1230
float timeb = b->willCollapse;
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);
1240
else if (timea > timeb)
1245
static int _sortCompareSpokes(const void* _a, const void* _b)
1247
const Spoke* a = *((const Spoke**)_a);
1248
const Spoke* b = *((const Spoke**)_b);
1249
float timea = INFINITY;
1250
float timeb = INFINITY;
1253
if (a->numEstimates)
1254
timea = a->estimates[0].range.min;
1255
if (b->numEstimates)
1256
timeb = b->estimates[0].range.min;
1260
else if (timea > timeb)
1267
static void _sortFronts(Front** fronts, size_t numFronts)
1269
mergesort(fronts, numFronts, sizeof(*fronts), _sortCompareFronts);
1272
static void _sortSpokes(Spoke** spokes, size_t numSpokes)
1274
for (size_t i = 0; i < numSpokes; ++i)
1275
mergesort(spokes[i]->estimates, spokes[i]->numEstimates, sizeof(*spokes[i]->estimates), _sortCompareEstimates);
1277
mergesort(spokes, numSpokes, sizeof(*spokes), _sortCompareSpokes);
1282
static void _removeEstimateFromFront(Front* front, size_t ie)
1284
if (ie+1 != front->numEstimates)
1285
front->estimates[ie] = front->estimates[front->numEstimates-1];
1286
front->numEstimates--;
1289
static void _redactEstimateForSpokeToFronts(Spoke* spoke, Front** fronts, size_t numFronts)
1291
for (size_t i = 0; i < numFronts; ++i)
1293
Front* front = fronts[i];
1295
if (!front->estimates)
1298
for (size_t i = 0; i < front->numEstimates; ++i)
1299
if (front->estimates[i].spoke == spoke)
1301
_removeEstimateFromFront(front, i);
1307
static CollisionEstimate _estimateForSpokeToFront(Spoke* spoke, Front* front, CGPoint* vertices, float time, float maxTime)
1309
CollisionEstimate estimate = {front, {INFINITY,-INFINITY}};
1311
r2 r = _estimateSpokeHittingFront(spoke, front, vertices);
1314
// r.min = INFINITY;
1317
// if ((r.max <= time) || (r.min > maxTime))
1321
// estimate.face = face;
1323
assert(r.min > -INFINITY);
1330
static float _frontStart(Front* front)
1332
return MAX(front->leftSpoke->start, front->rightSpoke->start);
1335
static void _recomputeEstimatesForSpoke(Spoke* spoke, Front** fronts, size_t numFronts, CGPoint* vertices, size_t maxEstimates, float time, float maxTime)
1337
spoke->numEstimates = 0;
1338
for (size_t i = 0; i < numFronts; ++i)
1340
Front* front = fronts[i];
1342
if ((spoke == front->leftSpoke) || (spoke == front->rightSpoke) || (front->leftSpoke->leftFront->leftSpoke == spoke) || (front->rightSpoke->rightFront->rightSpoke == spoke))
1346
if (_frontLoopsBelow(front, 4))
1351
CollisionEstimate estimate = _estimateForSpokeToFront(spoke, front, vertices, time, maxTime);
1353
if (estimate.range.min < MAX(spoke->start, _frontStart(front)))
1354
estimate.range.min = INFINITY;
1356
if (_r2isEmpty(estimate.range))
1359
if (!spoke->estimates)
1360
spoke->estimates = small_malloc(sizeof(*spoke->estimates)*maxEstimates);
1361
assert(spoke->numEstimates < maxEstimates);
1362
spoke->estimates[spoke->numEstimates++] = estimate;
1367
static uint16_t _addVertex(PolygonInsetRecord* rec, CGPoint p, float t)
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;
1378
static void _addTriangle(PolygonInsetRecord* rec, uint16_t a, uint16_t b, uint16_t c)
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;
1387
static Spoke* _allocSpoke(FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1389
Spoke* spoke = NULL;
1390
if (!inactiveWalls->numSpokes)
1391
spoke = small_malloc(sizeof(Spoke));
1394
spoke = inactiveWalls->spokes[--inactiveWalls->numSpokes];
1396
activeWalls->spokes[activeWalls->numSpokes++] = spoke;
1397
//memset(spoke, 0x00, sizeof(*spoke));
1401
static Front* _allocFront(FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1403
Front* front = NULL;
1404
if (!inactiveWalls->numFronts)
1405
front = small_malloc(sizeof(Front));
1408
front = inactiveWalls->fronts[--inactiveWalls->numFronts];
1410
activeWalls->fronts[activeWalls->numFronts++] = front;
1411
//memset(front, 0x00, sizeof(*front));
1415
static void _deactivateFront(Front* front, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1417
//memset(front, 0xFF, sizeof(*front));
1418
inactiveWalls->fronts[inactiveWalls->numFronts++] = front;
1420
for (size_t i = 0; i < activeWalls->numFronts; ++i)
1422
if (activeWalls->fronts[i] == front)
1424
if (i+1 < activeWalls->numFronts)
1425
activeWalls->fronts[i] = activeWalls->fronts[activeWalls->numFronts-1];
1427
activeWalls->numFronts--;
1433
static void _deactivateSpoke(Spoke* spoke, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1435
//memset(spoke, 0xFF, sizeof(*spoke));
1436
inactiveWalls->spokes[inactiveWalls->numSpokes++] = spoke;
1438
for (size_t i = 0; i < activeWalls->numSpokes; ++i)
1440
if (activeWalls->spokes[i] == spoke)
1442
if (i < activeWalls->numSpokes-1)
1443
activeWalls->spokes[i] = activeWalls->spokes[activeWalls->numSpokes-1];
1445
activeWalls->numSpokes--;
1451
static void _updateCollapseTime(Front* front, CGPoint* vertices, float now)
1454
Spoke* spoke0 = front->leftSpoke;
1455
Spoke* spoke1 = front->rightSpoke;
1456
CGPoint a = vertices[spoke0->sourceVertexIndex], b = vertices[spoke1->sourceVertexIndex];
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));
1464
CGPoint ab = CGPointSub(b,a);
1465
float se = CGPointDot(vab, ab);
1467
float t = - CGPointDot(ab,ab)/se;
1470
front->willCollapse = t;
1472
front->willCollapse = INFINITY;
1476
static void _assertFrontIntegrity(Front* front)
1478
assert(front->leftSpoke != front->rightSpoke);
1479
assert(front->leftSpoke->rightFront == front);
1480
assert(front->rightSpoke->leftFront == front);
1482
assert(!CGPointEqualToPoint(CGPointZero, front->velocity));
1485
static void _assertSpokeIntegrity(Spoke* spoke)
1487
assert(spoke->leftFront != spoke->rightFront);
1488
assert(spoke->rightFront->leftSpoke == spoke);
1489
assert(spoke->leftFront->rightSpoke == spoke);
1491
assert(!CGPointEqualToPoint(CGPointZero, spoke->velocity));
1494
static void _collapseEndFront(Front* front0, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls)
1496
NSLog(@"collapsing endcap... %f (%p)", time, front0);
1497
Front* front1 = front0->rightSpoke->rightFront;
1498
Front* front2 = front1->rightSpoke->rightFront;
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);
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);
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);
1517
static void _collapseFront(Front* front, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls, size_t maxEstimates, float maxTime)
1519
// NSLog(@"collapsing front... %f (%p,%f)", time, front, front->willCollapse);
1521
Spoke* leftSpoke = front->leftSpoke;
1522
Spoke* rightSpoke = front->rightSpoke;
1523
Front* leftFront = leftSpoke->leftFront;
1524
Front* rightFront = rightSpoke->rightFront;
1526
if (front->leftSpoke->leftFront->leftSpoke->leftFront->leftSpoke->leftFront == front)
1528
_collapseEndFront(front, time, rec, activeWalls, inactiveWalls);
1533
// if ((leftSpoke->start != 0.0) || (rightSpoke->start != 0.0))
1534
// printf("collapsing non-starting front\n");
1536
_assertFrontIntegrity(front);
1537
_assertFrontIntegrity(leftFront);
1538
_assertFrontIntegrity(rightFront);
1539
_assertSpokeIntegrity(leftSpoke);
1540
_assertSpokeIntegrity(rightSpoke);
1542
CGPoint s = rec->vertices[leftSpoke->sourceVertexIndex];
1544
CGPoint c = CGPointAdd(s, CGPointScale(leftSpoke->velocity, time - leftSpoke->start));
1546
uint16_t mvi = _addVertex(rec, c, time);
1548
Spoke* newSpoke = _allocSpoke(activeWalls, inactiveWalls);
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;
1557
assert(!isnan(newSpoke->velocity.x) && !isnan(newSpoke->velocity.y));
1559
newSpoke->leftFront = leftFront;
1560
newSpoke->rightFront = rightFront;
1563
leftFront->rightSpoke = newSpoke;
1564
rightFront->leftSpoke = newSpoke;
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);
1570
_deactivateFront(front, activeWalls, inactiveWalls);
1571
_deactivateSpoke(leftSpoke, activeWalls, inactiveWalls);
1572
_deactivateSpoke(rightSpoke, activeWalls, inactiveWalls);
1574
_assertFrontIntegrity(leftFront);
1575
_assertFrontIntegrity(rightFront);
1576
_assertSpokeIntegrity(newSpoke);
1577
_assertSpokeIntegrity(leftFront->rightSpoke);
1578
_assertSpokeIntegrity(rightFront->leftSpoke);
1582
_updateCollapseTime(leftFront, rec->vertices, time);
1583
_updateCollapseTime(rightFront, rec->vertices, time);
1585
printf("update l will collapse: %f (%p)\n", leftFront->willCollapse, leftFront);
1586
printf("update r will collapse: %f (%p)\n", rightFront->willCollapse, rightFront);
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);
1593
_recomputeEstimatesForFront(leftFront, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1594
_recomputeEstimatesForFront(rightFront, activeWalls->spokes, activeWalls->numSpokes, rec->vertices, maxEstimates, time, maxTime);
1597
// return MIN(leftFront->willCollapse, rightFront->willCollapse);
1600
static void _attachSpokeLeft(Front* front, Spoke* spoke)
1602
front->leftSpoke = spoke;
1603
spoke->rightFront = front;
1606
static void _attachSpokeRight(Front* front, Spoke* spoke)
1608
front->rightSpoke = spoke;
1609
spoke->leftFront = front;
1613
static void _splitFront(Front* hitFront, Spoke* hittingSpoke, float time, PolygonInsetRecord* rec, FrontsAndSpokesRec* activeWalls, FrontsAndSpokesRec* inactiveWalls, size_t maxEstimates, float maxTime)
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.
1636
NSLog(@"splitting front... %f (%p)", time, hitFront);
1638
assert(!_frontLoopsBelow(hitFront, 4));
1640
if (hitFront->leftSpoke->leftFront->leftSpoke->leftFront->leftSpoke->leftFront == hitFront)
1642
_collapseEndFront(hitFront, time, rec, activeWalls, inactiveWalls);
1645
_assertFrontIntegrity(hitFront);
1646
_assertSpokeIntegrity(hittingSpoke);
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);
1653
_addTriangle(rec, hitFront->leftSpoke->sourceVertexIndex, hitFront->rightSpoke->sourceVertexIndex, mvi);
1656
hittingSpoke->sourceVertexIndex,
1657
hittingSpoke->rightFront->rightSpoke->sourceVertexIndex,
1660
hittingSpoke->leftFront->leftSpoke->sourceVertexIndex,
1661
hittingSpoke->sourceVertexIndex,
1664
Spoke* newSpokeLeft = _allocSpoke(activeWalls, inactiveWalls);
1665
Spoke* newSpokeRight = _allocSpoke(activeWalls, inactiveWalls);
1667
Front* splitFrontLeft = _allocFront(activeWalls, inactiveWalls);
1668
Front* splitFrontRight = _allocFront(activeWalls, inactiveWalls);
1670
Front* hittingFrontLeft = hittingSpoke->leftFront;
1671
Front* hittingFrontRight = hittingSpoke->rightFront;
1674
_attachSpokeLeft(splitFrontLeft, hitFront->leftSpoke);
1675
_attachSpokeRight(splitFrontRight, hitFront->rightSpoke);
1677
_attachSpokeRight(splitFrontLeft, newSpokeRight);
1678
_attachSpokeLeft(splitFrontRight, newSpokeLeft);
1680
_attachSpokeRight(hittingFrontLeft, newSpokeLeft);
1681
_attachSpokeLeft(hittingFrontRight, newSpokeRight);
1684
newSpokeLeft->sourceVertexIndex = mvi;
1685
newSpokeRight->sourceVertexIndex = mvi;
1686
newSpokeLeft->finalVertexIndex = -1;
1687
newSpokeRight->finalVertexIndex = -1;
1690
CGPoint newRayLeft = CGPointReverseProject(hittingFrontLeft->velocity, CGPointAdd(hittingFrontLeft->velocity, hitFront->velocity));
1691
CGPoint newRayRight = CGPointReverseProject(hittingFrontRight->velocity, CGPointAdd(hittingFrontRight->velocity, hitFront->velocity));
1693
newSpokeLeft->velocity = newRayLeft;
1694
newSpokeRight->velocity = newRayRight;
1695
newSpokeLeft->start = time;
1696
newSpokeRight->start = time;
1698
assert(!isnan(newSpokeLeft->velocity.x) && !isnan(newSpokeLeft->velocity.y));
1699
assert(!isnan(newSpokeRight->velocity.x) && !isnan(newSpokeRight->velocity.y));
1701
splitFrontLeft->velocity = hitFront->velocity;
1702
splitFrontRight->velocity = hitFront->velocity;
1704
_assertFrontIntegrity(splitFrontLeft);
1705
_assertFrontIntegrity(splitFrontRight);
1706
_assertFrontIntegrity(hittingFrontLeft);
1707
_assertFrontIntegrity(hittingFrontRight);
1709
_assertSpokeIntegrity(newSpokeLeft);
1710
_assertSpokeIntegrity(newSpokeRight);
1712
_assertSpokeIntegrity(splitFrontLeft->leftSpoke);
1713
_assertSpokeIntegrity(splitFrontRight->rightSpoke);
1714
_assertSpokeIntegrity(hittingFrontLeft->leftSpoke);
1715
_assertSpokeIntegrity(hittingFrontRight->rightSpoke);
1718
_deactivateFront(hitFront, activeWalls, inactiveWalls);
1719
_deactivateSpoke(hittingSpoke, activeWalls, inactiveWalls);
1721
_updateCollapseTime(splitFrontLeft, rec->vertices);
1722
_updateCollapseTime(splitFrontRight, rec->vertices);
1724
_updateCollapseTime(hittingFrontLeft, rec->vertices);
1725
_updateCollapseTime(hittingFrontRight, rec->vertices);
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);
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);
1738
PolygonInsetRecord InsetPolygon(CGPoint* sourceVertices, size_t numSourceVertices, float insetTime, int flags)
1742
PolygonInsetRecord rec;
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;
1752
FrontsAndSpokesRec activeWalls = {NULL, 0, NULL, 0};
1753
FrontsAndSpokesRec inactiveWalls = {NULL, 0, NULL, 0};
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);
1764
activeWalls.spokes[0] = small_malloc(sizeof(Spoke)*numSourceVertices);
1765
activeWalls.fronts[0] = small_malloc(sizeof(Front)*numSourceVertices);
1767
assert(activeWalls.spokes[0]);
1768
assert(activeWalls.fronts[0]);
1769
for (size_t i = 0; i < numSourceVertices; ++i)
1771
activeWalls.spokes[i] = activeWalls.spokes[0]+i;
1772
activeWalls.fronts[i] = activeWalls.fronts[0]+i;
1775
// initialize spokes and fronts
1776
for (size_t i = 0; i < numSourceVertices; ++i)
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];
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];
1790
for (size_t i = 0; i < numSourceVertices; ++i)
1792
Spoke* spoke = activeWalls.spokes[i];
1793
spoke->sourceVertexIndex = i;
1794
spoke->finalVertexIndex = -1;
1795
spoke->start = 0.0f;
1799
for (size_t i = 0; i < numSourceVertices; ++i)
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)));
1807
for (size_t i = 0; i < numSourceVertices; ++i)
1809
Spoke* spoke = activeWalls.spokes[i];
1810
CGPoint nl = CGPointNormalize(spoke->leftFront->velocity),
1811
nr = CGPointNormalize(spoke->rightFront->velocity);
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;
1821
for (size_t i = 0; i < numSourceVertices; ++i)
1823
_assertFrontIntegrity(activeWalls.fronts[i]);
1824
_assertSpokeIntegrity(activeWalls.spokes[i]);
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)
1832
for (size_t i = 0; i < activeWalls.numFronts; ++i)
1834
Front* front = activeWalls.fronts[i];
1835
_updateCollapseTime(front, rec.vertices, currentTime);
1837
_assertFrontIntegrity(front);
1840
_sortFronts(activeWalls.fronts, activeWalls.numFronts);
1842
if (!(flags & kThickenNoSplitting))
1844
for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1846
Spoke* spoke = activeWalls.spokes[i];
1847
_recomputeEstimatesForSpoke(spoke, activeWalls.fronts, activeWalls.numFronts, rec.vertices, maxEstimates, currentTime, insetTime);
1849
_assertSpokeIntegrity(spoke);
1853
_sortSpokes(activeWalls.spokes, activeWalls.numSpokes);
1857
Front* nextFront = activeWalls.fronts[0];
1858
Spoke* nextSpoke = activeWalls.spokes[0];
1861
float eTime = INFINITY;
1862
if (nextSpoke->numEstimates && (nextSpoke->estimates->range.max > currentTime))
1863
eTime = nextSpoke->estimates->range.min;
1865
float cTime = nextFront->willCollapse;
1868
assert(maxSpokes > activeWalls.numSpokes+1);
1869
assert(maxFronts > activeWalls.numFronts+1);
1871
// printf("e %f c %f\n", eTime, cTime);
1873
if (!(flags & kThickenNoSplitting) && (eTime + FLT_EPSILON < cTime))
1875
if (eTime > insetTime)
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
1883
// assert(eTime + FLT_EPSILON >= currentTime);
1884
// assert(nextSpoke->estimates->face == kHitFront);
1886
if (flags & kThickenStopOnFirstSplit)
1888
currentTime = eTime;
1889
insetTime = currentTime;
1893
currentTime = eTime;
1894
_splitFront(nextSpoke->estimates->front, nextSpoke, currentTime, &rec, &activeWalls, &inactiveWalls, maxEstimates, insetTime);
1899
if (cTime > insetTime)
1902
currentTime = cTime;
1903
_collapseFront(nextFront, currentTime, &rec, &activeWalls, &inactiveWalls, maxEstimates, insetTime);
1910
// finalize the spokes, eg, add "final" vertices
1911
size_t numFinalVertices = 0;
1912
for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1914
Spoke* spoke = activeWalls.spokes[i];
1915
if (spoke->finalVertexIndex != -1)
1921
rec.vertices = realloc(rec.vertices, (rec.numVertices+numFinalVertices)*sizeof(*(rec.vertices)));
1922
rec.times = realloc(rec.times, (rec.numVertices+numFinalVertices)*sizeof(*(rec.times)));
1924
for (size_t i = 0; i < activeWalls.numSpokes; ++i)
1926
Spoke* spoke = activeWalls.spokes[i];
1927
if (spoke->finalVertexIndex != -1)
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;
1940
assert(rec.numVertices < USHRT_MAX);
1942
rec.triangleIndices = realloc(rec.triangleIndices, sizeof(uint16_t)*(rec.numIndices+6*activeWalls.numFronts));
1945
for (size_t i = 0; i < activeWalls.numFronts; ++i)
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;
1953
if ((i0 != i1) && (i1 != i2) && (i2 != i0))
1955
rec.triangleIndices[rec.numIndices++] = i0;
1956
rec.triangleIndices[rec.numIndices++] = i1;
1957
rec.triangleIndices[rec.numIndices++] = i2;
1959
if ((i1 != i2) && (i2 != i3) && (i3 != i1))
1961
rec.triangleIndices[rec.numIndices++] = i3;
1962
rec.triangleIndices[rec.numIndices++] = i2;
1963
rec.triangleIndices[rec.numIndices++] = i1;
1968
free(activeWalls.spokes);
1969
free(activeWalls.fronts);
1970
free(inactiveWalls.spokes);
1971
free(inactiveWalls.fronts);
1973
small_pool_destroy();
1978
static void _addPirToVar(VertexArray* var, PolygonInsetRecord* rec, float thickness)
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);
1985
for (size_t i = 0; i < rec->numVertices; ++i)
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;
1996
size_t io = var->numIndices;
1997
var->numIndices += rec->numIndices;
1998
var->indices = realloc(var->indices, sizeof(*var->indices)*var->numIndices);
2000
for (size_t i = 0; i < rec->numIndices; ++i)
2001
var->indices[io+i] = (vo + rec->triangleIndices[i]);
2005
VertexArray* ThickenOutline(CGPoint* inPoints, size_t numInPoints, float thickness, int flags)
2007
VertexArray* var = [[VertexArray alloc] init];
2009
if (flags & kThickenInside)
2011
PolygonInsetRecord rec = InsetPolygon(inPoints, numInPoints, thickness, flags);
2013
_addPirToVar(var, &rec, thickness);
2016
free(rec.triangleIndices);
2018
if (flags & kThickenOutside)
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);
2025
_addPirToVar(var, &rec, thickness);
2028
free(rec.triangleIndices);
2032
var->mode = GL_TRIANGLES;
2034
[var convertTriangleIndicesToLines];
2037
return [var autorelease];