forked from shaojiankui/JKCategories
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jakey
committed
Aug 24, 2015
1 parent
75e13e5
commit 93f5767
Showing
5 changed files
with
181 additions
and
2 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
Categories/UIKit/UIBezierPath/UIBezierPath+LxThroughPointsBezier.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// | ||
// UIBezierPath+LxThroughPointsBezier.h | ||
// LxThroughPointsBezierDemo | ||
// | ||
// A funny iOS library. Draw a smooth bezier through several points you designated. The curve‘s bend level is adjustable. | ||
|
||
//https://github.com/DeveloperLx/LxThroughPointsBezier | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
@interface UIBezierPath (LxThroughPointsBezier) | ||
|
||
/** | ||
* The curve‘s bend level. The good value is about 0.6 ~ 0.8. The default and recommended value is 0.7. | ||
*/ | ||
@property (nonatomic) CGFloat contractionFactor; | ||
|
||
/** | ||
* You must wrap CGPoint struct to NSValue object. | ||
* | ||
* @param pointArray Points you want to through. You must give at least 1 point for drawing curve. | ||
*/ | ||
- (void)addBezierThroughPoints:(NSArray *)pointArray; | ||
|
||
@end |
148 changes: 148 additions & 0 deletions
148
Categories/UIKit/UIBezierPath/UIBezierPath+LxThroughPointsBezier.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
|
||
// | ||
// UIBezierPath+LxThroughPointsBezier.m | ||
// LxThroughPointsBezierDemo | ||
// | ||
|
||
#import "UIBezierPath+LxThroughPointsBezier.h" | ||
#import <objc/runtime.h> | ||
|
||
@implementation UIBezierPath (LxThroughPointsBezier) | ||
|
||
- (void)setContractionFactor:(CGFloat)contractionFactor | ||
{ | ||
objc_setAssociatedObject(self, @selector(contractionFactor), @(contractionFactor), OBJC_ASSOCIATION_RETAIN_NONATOMIC); | ||
} | ||
|
||
- (CGFloat)contractionFactor | ||
{ | ||
id contractionFactorAssociatedObject = objc_getAssociatedObject(self, @selector(contractionFactor)); | ||
if (contractionFactorAssociatedObject == nil) { | ||
return 0.7; | ||
} | ||
return [contractionFactorAssociatedObject floatValue]; | ||
} | ||
|
||
- (void)addBezierThroughPoints:(NSArray *)pointArray | ||
{ | ||
NSAssert(pointArray.count > 0, @"You must give at least 1 point for drawing the curve."); | ||
|
||
if (pointArray.count < 3) { | ||
switch (pointArray.count) { | ||
case 1: | ||
{ | ||
NSValue * point0Value = pointArray[0]; | ||
CGPoint point0 = [point0Value CGPointValue]; | ||
[self addLineToPoint:point0]; | ||
} | ||
break; | ||
case 2: | ||
{ | ||
NSValue * point0Value = pointArray[0]; | ||
CGPoint point0 = [point0Value CGPointValue]; | ||
NSValue * point1Value = pointArray[1]; | ||
CGPoint point1 = [point1Value CGPointValue]; | ||
[self addQuadCurveToPoint:point1 controlPoint:ControlPointForTheBezierCanThrough3Point(self.currentPoint, point0, point1)]; | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
CGPoint previousPoint = CGPointZero; | ||
|
||
CGPoint previousCenterPoint = CGPointZero; | ||
CGPoint centerPoint = CGPointZero; | ||
CGFloat centerPointDistance = 0; | ||
|
||
CGFloat obliqueAngle = 0; | ||
|
||
CGPoint previousControlPoint1 = CGPointZero; | ||
CGPoint previousControlPoint2 = CGPointZero; | ||
CGPoint controlPoint1 = CGPointZero; | ||
|
||
previousPoint = self.currentPoint; | ||
|
||
for (int i = 0; i < pointArray.count; i++) { | ||
|
||
NSValue * pointIValue = pointArray[i]; | ||
CGPoint pointI = [pointIValue CGPointValue]; | ||
|
||
if (i > 0) { | ||
|
||
previousCenterPoint = CenterPointOf(self.currentPoint, previousPoint); | ||
centerPoint = CenterPointOf(previousPoint, pointI); | ||
|
||
centerPointDistance = DistanceBetweenPoint(previousCenterPoint, centerPoint); | ||
|
||
obliqueAngle = ObliqueAngleOfStraightThrough(centerPoint, previousCenterPoint); | ||
|
||
previousControlPoint2 = CGPointMake(previousPoint.x - 0.5 * self.contractionFactor * centerPointDistance * cos(obliqueAngle), previousPoint.y - 0.5 * self.contractionFactor * centerPointDistance * sin(obliqueAngle)); | ||
controlPoint1 = CGPointMake(previousPoint.x + 0.5 * self.contractionFactor * centerPointDistance * cos(obliqueAngle), previousPoint.y + 0.5 * self.contractionFactor * centerPointDistance * sin(obliqueAngle)); | ||
} | ||
|
||
if (i == 1) { | ||
|
||
[self addQuadCurveToPoint:previousPoint controlPoint:previousControlPoint2]; | ||
} | ||
else if (i > 1 && i < pointArray.count - 1) { | ||
|
||
[self addCurveToPoint:previousPoint controlPoint1:previousControlPoint1 controlPoint2:previousControlPoint2]; | ||
} | ||
else if (i == pointArray.count - 1) { | ||
|
||
[self addCurveToPoint:previousPoint controlPoint1:previousControlPoint1 controlPoint2:previousControlPoint2]; | ||
[self addQuadCurveToPoint:pointI controlPoint:controlPoint1]; | ||
} | ||
else { | ||
|
||
} | ||
|
||
previousControlPoint1 = controlPoint1; | ||
previousPoint = pointI; | ||
} | ||
} | ||
|
||
CGFloat ObliqueAngleOfStraightThrough(CGPoint point1, CGPoint point2) // [-π/2, 3π/2) | ||
{ | ||
CGFloat obliqueRatio = 0; | ||
CGFloat obliqueAngle = 0; | ||
|
||
if (point1.x > point2.x) { | ||
|
||
obliqueRatio = (point2.y - point1.y) / (point2.x - point1.x); | ||
obliqueAngle = atan(obliqueRatio); | ||
} | ||
else if (point1.x < point2.x) { | ||
|
||
obliqueRatio = (point2.y - point1.y) / (point2.x - point1.x); | ||
obliqueAngle = M_PI + atan(obliqueRatio); | ||
} | ||
else if (point2.y - point1.y >= 0) { | ||
|
||
obliqueAngle = M_PI/2; | ||
} | ||
else { | ||
obliqueAngle = -M_PI/2; | ||
} | ||
|
||
return obliqueAngle; | ||
} | ||
|
||
CGPoint ControlPointForTheBezierCanThrough3Point(CGPoint point1, CGPoint point2, CGPoint point3) | ||
{ | ||
return CGPointMake(2 * point2.x - (point1.x + point3.x) / 2, 2 * point2.y - (point1.y + point3.y) / 2); | ||
} | ||
|
||
CGFloat DistanceBetweenPoint(CGPoint point1, CGPoint point2) | ||
{ | ||
return sqrt((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y)); | ||
} | ||
|
||
CGPoint CenterPointOf(CGPoint point1, CGPoint point2) | ||
{ | ||
return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2); | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters