ios - UIBezierPath - 起伏/嘈杂数据的平滑图表

标签 ios objective-c uibezierpath

我的目标是在我的用户在屏幕上滑动时实现类似 Adob​​e Illustrator 的线条。目前情况非常不稳定 - 这是当前情况的屏幕截图:

Noisy lines

我想我想要的很明显。我想让那些直线变得平滑。这叫抗锯齿吗?

- (void)touchesBegan: (CGPoint)point
{
    currentStroke = [[Stroke alloc] initWithStartPoint:point];
    [strokes addObject:currentStroke];
}

- (void)touchesMoved: (CGPoint)point
{
    if (!currentStroke) {
        [self touchesBegan:point];
    }
    [currentStroke.points addObject:[NSValue valueWithCGPoint:point]]
    pathTwo = [self createPath];
    [self scaleToFit];
    [self setNeedsDisplay];
}

- (UIBezierPath *)createPath {
    UIBezierPath * bezierPath = [UIBezierPath bezierPath];
    for (Stroke * stroke in strokes) {
        [bezierPath moveToPoint:stroke.startPoint];
        for (NSValue * value in stroke.points) {
            [bezierPath addLineToPoint:[value CGPointValue]];
        }
    }
    return bezierPath;
}

- (void)touchesEnded: (CGPoint)point
{
    [points removeAllObjects];
    [self setNeedsDisplay];
}

drawRect 里面有这个:

[[UIColor whiteColor] setStroke];
[pathTwo setLineWidth: _strokeWidth];
[pathTwo stroke];

编辑

我想我已经找到答案了... https://github.com/jnfisher/ios-curve-interpolation

鉴于我的 createPath 公式,我只是不知道如何使用它。

也许有人可以帮我插入阵列?

最佳答案

问题是您在手势中捕获的一系列点之间划出一条路径,而这些点并不都在同一条线上,因为它们包括用户手指在屏幕上拖动时发生的自然偏差.

这与“抗锯齿”完全无关,“抗锯齿”是一种使直线看起来更平滑的技术,不会在视觉上分散“锯齿”的注意力。但这里的问题不在于你试图改进单条直线的渲染,而是你一开始就没有画直线,而是画了一堆线段,这些线段不碰巧排队。

My goal is to achieve Adobe Illustrator like lines when my user swipes across the screen

在这种情况下,您不需要“抗锯齿”。您只需要一个 createPath

  • moveToPoint 到第一个点;和
  • addLineToPoint 到最后一个点。

只是不要担心中间的任何一点。这个简单的解决方案将产生一条直线,从您开始触摸的地方开始,一直延伸到触摸结束的地方,并且会一直这样做,直到您抬起手指。

我认为这将转化为:

- (UIBezierPath *)createPath {
    UIBezierPath * bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:stroke.startPoint];
    [bezierPath addLineToPoint:[[stroke.points lastObject] CGPointValue]];
    return bezierPath;
}

如果您不想要一条实际的线,而只是想平滑它,我建议 (a) 进行滚动平均以消除弹性数据点中的峰谷; (b) 使用 Hermite 或 Catmull-Rom 样条(如 https://spin.atomicobject.com/2014/05/28/ios-interpolating-points/ 中所述),因此生成的路径是平滑的而不是一系列线段。

因此

- (UIBezierPath * _Nullable)createActualPathFor:(Stroke *)stroke {
    if (stroke.points.count < 2) return nil;

    UIBezierPath * path = [UIBezierPath bezierPath];

    [path moveToPoint:[stroke.points.firstObject CGPointValue]];
    for (NSInteger i = 1; i < stroke.points.count; i++) {
        [path addLineToPoint:[stroke.points[i] CGPointValue]];
    }

    return path;
}

- (UIBezierPath * _Nullable)createSmoothedPathFor:(Stroke *)stroke interval:(NSInteger)interval {
    if (stroke.points.count < 2) return nil;

    NSMutableArray <NSValue *> *averagedPoints = [NSMutableArray arrayWithObject:stroke.points[0]];

    NSInteger current = 1;
    NSInteger count = 0;
    do {
        CGFloat sumX = 0;
        CGFloat sumY = 0;
        do {
            CGPoint point = [stroke.points[current] CGPointValue];
            sumX += point.x;
            sumY += point.y;
            current++;
            count++;
        } while (count < interval && current < stroke.points.count);

        if (count >= interval) {
            CGPoint average = CGPointMake(sumX / count, sumY / count);
            [averagedPoints addObject:[NSValue valueWithCGPoint:average]];
            count = 0;
        }
    } while (current < stroke.points.count);

    if (count != 0) {
        [averagedPoints addObject:stroke.points.lastObject];
    }

    return [UIBezierPath interpolateCGPointsWithHermite:averagedPoints closed:false];
}

将产生以下结果(其中实际数据点为蓝色,平滑再现为红色):

enter image description here

请注意,我假设您的 Strokepoints 数组包含起点,因此您可能需要相应地进行调整。

关于ios - UIBezierPath - 起伏/嘈杂数据的平滑图表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47498816/

相关文章:

ios - 为什么 subview Controller 会占据整个屏幕?

iphone - underPageBackgroundColor 被批准了吗?

ios - 使用比率使绘图适合 iPad 和 iPhone

ios - 使用 UIBezierPath 绘制极坐标函数

iphone - 弹出回 View Controller 时如何更改单元格的背景图像?

ios - 在 iOS 中存储自定义对象(未实现 NSCoding)的方法

iphone - 检查是否设置了 BOOL(不能用 ==nil 完成)

ios - 形状图层的动画路径

ios - AVCaptureDevice videoZoomFactor 始终超出范围

objective-c - openCV cvContourArea