如何在移动时平滑 iOS 绘图应用程序中的一组点?我尝试过 UIBezierpaths,但当我只是将点 1,2,3,4 - 2,3,4,5 移动时,我得到的只是它们相交处的锯齿状末端。我听说过样条曲线和所有其他类型。我对 iPhone 编程很陌生,不明白如何在我的石英绘图应用程序中对其进行编程。一个可靠的例子将不胜感激,我花了几周的时间在圈子里跑来跑去,但我似乎永远找不到任何用于此任务的 iOS 代码。大多数帖子只是链接到 Java 模拟或维基百科上有关曲线拟合的页面,这对我没有任何帮助。我也不想切换到 openGL ES。我希望有人最终可以提供代码来回答这个流传的问题。
这是我的 UIBezierPath 代码,它在交叉点留下边缘///
更新为以下答案
#define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]
#define POINT(_INDEX_) [(NSValue *)[points objectAtIndex:_INDEX_] CGPointValue]
- (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity
{
NSMutableArray *points = [(NSMutableArray*)[self pointsOrdered] mutableCopy];
if (points.count < 4) return [self bezierPath];
// Add control points to make the math make sense
[points insertObject:[points objectAtIndex:0] atIndex:0];
[points addObject:[points lastObject]];
UIBezierPath *smoothedPath = [self bezierPath];
[smoothedPath removeAllPoints];
[smoothedPath moveToPoint:POINT(0)];
for (NSUInteger index = 1; index < points.count - 2; index++)
{
CGPoint p0 = POINT(index - 1);
CGPoint p1 = POINT(index);
CGPoint p2 = POINT(index + 1);
CGPoint p3 = POINT(index + 2);
// now add n points starting at p1 + dx/dy up until p2 using Catmull-Rom splines
for (int i = 1; i < granularity; i++)
{
float t = (float) i * (1.0f / (float) granularity);
float tt = t * t;
float ttt = tt * t;
CGPoint pi; // intermediate point
pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt);
pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt);
[smoothedPath addLineToPoint:pi];
}
// Now add p2
[smoothedPath addLineToPoint:p2];
}
// finish by adding the last point
[smoothedPath addLineToPoint:POINT(points.count - 1)];
return smoothedPath;
}
- (PVPoint *)pointAppendingCGPoint:(CGPoint)CGPoint
{
PVPoint *newPoint = [[PVPoint alloc] initInsertingIntoManagedObjectContext:[self managedObjectContext]];
[newPoint setCGPoint:CGPoint];
[newPoint setOrder:[NSNumber numberWithUnsignedInteger:[[self points] count]]];
[[self mutableSetValueForKey:@"points"] addObject:newPoint];
[(NSMutableArray *)[self pointsOrdered] addObject:newPoint];
[[self bezierPath] addLineToPoint:CGPoint];
return [newPoint autorelease];
if ([self bezierPath] && [pointsOrdered count] > 3)
{
PVPoint *control1 = [pointsOrdered objectAtIndex:[pointsOrdered count] - 2];
PVPoint *control2 = [pointsOrdered objectAtIndex:[pointsOrdered count] - 1];
[bezierPath moveToPoint:[[pointsOrdered objectAtIndex:[pointsOrdered count] - 3] CGPoint]];
[[self bezierPath] addCurveToPoint:CGPoint controlPoint1:[control1 CGPoint] controlPoint2:[control2 CGPoint]];
}
}
- (BOOL)isComplete { return [[self points] count] > 1; }
- (UIBezierPath *)bezierPath
{
if (!bezierPath)
{
bezierPath = [UIBezierPath bezierPath];
for (NSUInteger p = 0; p < [[self points] count]; p++)
{
if (!p) [bezierPath moveToPoint:[(PVPoint *)[[self pointsOrdered] objectAtIndex:p] CGPoint]];
else [bezierPath addLineToPoint:[(PVPoint *)[[self pointsOrdered] objectAtIndex:p] CGPoint]];
}
[bezierPath retain];
}
return bezierPath;
}
- (CGPathRef)CGPath
{
return [[self bezierPath] CGPath];
}
我刚刚在我正在从事的项目中实现了类似的东西。我的解决方案是使用 Catmull-Rom 样条线而不是贝塞尔样条线。它们通过一组点提供非常平滑的曲线,而不是“围绕”点的贝塞尔样条曲线。
// Based on code from Erica Sadun
#import "UIBezierPath+Smoothing.h"
void getPointsFromBezier(void *info, const CGPathElement *element);
NSArray *pointsFromBezierPath(UIBezierPath *bpath);
#define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]
#define POINT(_INDEX_) [(NSValue *)[points objectAtIndex:_INDEX_] CGPointValue]
@implementation UIBezierPath (Smoothing)
// Get points from Bezier Curve
void getPointsFromBezier(void *info, const CGPathElement *element)
{
NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;
// Retrieve the path element type and its points
CGPathElementType type = element->type;
CGPoint *points = element->points;
// Add the points if they're available (per type)
if (type != kCGPathElementCloseSubpath)
{
[bezierPoints addObject:VALUE(0)];
if ((type != kCGPathElementAddLineToPoint) &&
(type != kCGPathElementMoveToPoint))
[bezierPoints addObject:VALUE(1)];
}
if (type == kCGPathElementAddCurveToPoint)
[bezierPoints addObject:VALUE(2)];
}
NSArray *pointsFromBezierPath(UIBezierPath *bpath)
{
NSMutableArray *points = [NSMutableArray array];
CGPathApply(bpath.CGPath, (__bridge void *)points, getPointsFromBezier);
return points;
}
- (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity;
{
NSMutableArray *points = [pointsFromBezierPath(self) mutableCopy];
if (points.count < 4) return [self copy];
// Add control points to make the math make sense
[points insertObject:[points objectAtIndex:0] atIndex:0];
[points addObject:[points lastObject]];
UIBezierPath *smoothedPath = [self copy];
[smoothedPath removeAllPoints];
[smoothedPath moveToPoint:POINT(0)];
for (NSUInteger index = 1; index < points.count - 2; index++)
{
CGPoint p0 = POINT(index - 1);
CGPoint p1 = POINT(index);
CGPoint p2 = POINT(index + 1);
CGPoint p3 = POINT(index + 2);
// now add n points starting at p1 + dx/dy up until p2 using Catmull-Rom splines
for (int i = 1; i < granularity; i++)
{
float t = (float) i * (1.0f / (float) granularity);
float tt = t * t;
float ttt = tt * t;
CGPoint pi; // intermediate point
pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt);
pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt);
[smoothedPath addLineToPoint:pi];
}
// Now add p2
[smoothedPath addLineToPoint:p2];
}
// finish by adding the last point
[smoothedPath addLineToPoint:POINT(points.count - 1)];
return smoothedPath;
}
@end
最初的 Catmull-Rom 实现基于 Erica Sadun 在她的一本书中的一些代码,我对其进行了稍微修改以允许完全平滑的曲线。这是作为 UIBezierPath 上的一个类别实现的,对我来说效果很好。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)