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);
607
829
CGPoint* createOutline(CGPoint* points, size_t numPoints, float thickness)
609
831
CGPoint* innerPoints = calloc(sizeof(*innerPoints), 2*numPoints);
610
832
CGPoint* outerPoints = innerPoints + numPoints;
611
// uint8_t* squishedEdges = calloc(sizeof(*squishedEdges), numPoints);
613
834
for (size_t i = 0; i < numPoints; ++i)
615
836
size_t i0 = (i) % numPoints;