Skip to content

Commit

Permalink
Merge pull request jnfisher#5 from letatas/fix#3
Browse files Browse the repository at this point in the history
Using epsilon to prevent numerical imprecision due to floating point comparison to zero.
  • Loading branch information
jnfisher committed May 8, 2015
2 parents e3d1c0a + fa39ab5 commit 7eeda39
Showing 1 changed file with 18 additions and 16 deletions.
34 changes: 18 additions & 16 deletions Curve Interpolation/UIBezierPath+Interpolation.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,36 @@
#import "UIBezierPath+Interpolation.h"
#import "CGPointExtension.h"

#define kEPSILON 1.0e-5

@implementation UIBezierPath (Interpolation)

+(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha {
if ([pointsAsNSValues count] < 4)
return nil;

int endIndex = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-2);
NSInteger endIndex = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-2);
NSAssert(alpha >= 0.0 && alpha <= 1.0, @"alpha value is between 0.0 and 1.0, inclusive");

UIBezierPath *path = [UIBezierPath bezierPath];
int startIndex = (closed ? 0 : 1);
for (int ii=startIndex; ii < endIndex; ++ii) {
NSInteger startIndex = (closed ? 0 : 1);
for (NSInteger ii=startIndex; ii < endIndex; ++ii) {
CGPoint p0, p1, p2, p3;
int nextii = (ii+1)%[pointsAsNSValues count];
int nextnextii = (nextii+1)%[pointsAsNSValues count];
int previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1);
NSInteger nextii = (ii+1)%[pointsAsNSValues count];
NSInteger nextnextii = (nextii+1)%[pointsAsNSValues count];
NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1);

[pointsAsNSValues[ii] getValue:&p1];
[pointsAsNSValues[previi] getValue:&p0];
[pointsAsNSValues[nextii] getValue:&p2];
[pointsAsNSValues[nextnextii] getValue:&p3];

float d1 = ccpLength(ccpSub(p1, p0));
float d2 = ccpLength(ccpSub(p2, p1));
float d3 = ccpLength(ccpSub(p3, p2));
CGFloat d1 = ccpLength(ccpSub(p1, p0));
CGFloat d2 = ccpLength(ccpSub(p2, p1));
CGFloat d3 = ccpLength(ccpSub(p3, p2));

CGPoint b1, b2;
if (d1 == 0) {
if (fabs(d1) < kEPSILON) {
b1 = p1;
}
else {
Expand All @@ -46,7 +48,7 @@ +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues c
b1 = ccpMult(b1, 1.0 / (3*powf(d1, alpha)*(powf(d1, alpha)+powf(d2, alpha))));
}

if (d3 == 0) {
if (fabs(d3) < kEPSILON) {
b2 = p2;
}
else {
Expand All @@ -72,25 +74,25 @@ +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues clos
if ([pointsAsNSValues count] < 2)
return nil;

int nCurves = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-1);
NSInteger nCurves = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-1);

UIBezierPath *path = [UIBezierPath bezierPath];
for (int ii=0; ii < nCurves; ++ii) {
for (NSInteger ii=0; ii < nCurves; ++ii) {
NSValue *value = pointsAsNSValues[ii];

CGPoint curPt, prevPt, nextPt, endPt;
[value getValue:&curPt];
if (ii==0)
[path moveToPoint:curPt];

int nextii = (ii+1)%[pointsAsNSValues count];
int previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1);
NSInteger nextii = (ii+1)%[pointsAsNSValues count];
NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1);

[pointsAsNSValues[previi] getValue:&prevPt];
[pointsAsNSValues[nextii] getValue:&nextPt];
endPt = nextPt;

float mx, my;
CGFloat mx, my;
if (closed || ii > 0) {
mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5;
my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5;
Expand Down

0 comments on commit 7eeda39

Please sign in to comment.