绘制平滑曲线 - 所需方法

2023-12-24

如何在移动时平滑 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(使用前将#替换为@)

绘制平滑曲线 - 所需方法 的相关文章

  • 如何使用逗号和行分隔符对字符串进行标记

    我正在 Swift 中制作一个简单的 String Tokenizer 就像在 Java 中一样 但这对我来说确实不起作用 我的数据源中每行的末尾用 分隔 数据用逗号分隔 例如 字符串 1 字符串 2 字符串 3 字符串 1 字符串 2 字
  • 与 parse-server 和 auth0 的自定义身份验证集成

    我想将 auth0 com 与开源解析服务器结合使用 我当前的方法是通过 iOS 的 Lock 库使用标准登录从 auth0 获取令牌 使用该令牌 我想在解析服务器上调用自定义身份验证方法 该方法检查令牌是否有效 如果有效则将登录用户 我的
  • iOS 上关键 ClientState 警告的默认访问速度缓慢

    在测试我的 iOS 应用程序时 我收到 对关键 ClientState 的默认访问速度慢 耗时 0 034635 秒 容差为 0 020000 警告 它似乎是间歇性发生的 我试图环顾四周看看它是关于什么的 但我并不完全确定 任何帮助表示赞赏
  • 从设备获取联系人列表时出现问题

    这段代码有什么问题 NSMutableArray contactArray NSMutableArray alloc init ABAddressBookRef addressBook ABAddressBookCreate CFArray
  • 调用当前的 Modal ViewController 两次?

    我遇到了 UIViewController presentModalViewController 被调用两次的问题 我有一个模态视图 我试图调出另一个模态视图 但第二次没有任何反应 我怀疑它被隐藏了 还有其他人这样做过吗 您不能在同一个父控
  • UIAlertView 每次调用都会弹出三次,而不是一次

    我在程序的两个不同部分中从 NSAlert 中得到了奇怪的行为 行为是 出现警报 然后自发地消失 警报重新出现 然后一直保留 直到用户解除 即正常行为 警报再次出现 此行为仅在第一次调用显示警报的方法时发生 第一次之后 它的行为就正常了 以
  • 自定义 UINavigationController UINavigationBar

    基本上我想要一个定制UINavigationBar 我不希望它是 半透明 或任何东西 就像图片应用程序一样 我基本上想完全删除它 但我仍然希望能够在按下导航控制器时添加后退按钮等 并且我想要视图 例如 UITableViewControll
  • iOS - 在相机上放置自定义叠加层(垂直对齐)。顶部黑条的大小

    我正在寻找以下问题的编程解决方案 我想在相机 iOS 上绘制自定义叠加层 我希望它位于相机输出视图的垂直中央 我已经完成了相对于屏幕而不是相机图片居中绘制自定义视图 为此 我需要获得顶部黑条的大小 我怎么才能得到它 顶部和底部栏的大小不相等
  • iOS 7 NS 单线程安全合并冲突

    重新排序两行后 在单线程应用程序上保存简单的数据时遇到问题 我已经成功地简化了编码以重现错误 并且希望其他人尝试这一点时得到第二个意见 这是一次健全性检查 因为我怀疑 iOS 7 引入的核心数据问题 而这在 iOS 6 中工作正常 首先 启
  • 广告标识符和标识符ForVendor返回“00000000-0000-0000-0000-000000000000”

    我已经实现了这个方法来获得advertisingIdentifier and identifierForVendor NSString advertisingIdentifier if NSClassFromString ASIdentif
  • UIScrollView 与 UITabBarController 切断

    我有一个 UIScrollView 我将其放置在视图中 界面生成器文档 xib m h 但是 UIScrollView 的下半部分被剪切 并且由于我有一个 UITabBarController 而没有显示其下半部分 我在 appdelega
  • 使用标识符启动 iPhone 应用程序

    我正在尝试在我的应用程序中启动应用程序 例如 如果我按下 testApp1 中的按钮 它应该打开 testApp2 有没有办法用应用程序标识符来做到这一点 我听说过一种名为的未记录方法launchApplicationWithIdentif
  • 增加 iPhone 的推送通知徽章

    是否可以在收到通知时增加徽章值 或者我应该将计数作为有效负载发送吗 如果我每次都将徽章值发送为 1 那么如果应用程序未打开 我如何增加应用程序图标中的徽章值 我已经使用了这段代码 但不起作用 void application UIAppli
  • 使用ios sdk在youtube上上传视频的方法[重复]

    这个问题在这里已经有答案了 可能的重复 如何从 iOS 应用程序中将视频上传到 YouTube https stackoverflow com questions 3528568 how do i upload a video to you
  • Swift - 保存在 TableView 中选择的复选标记

    我对 Swift 相当陌生 并且在 TableView 多重选择方面遇到问题 我有多个选择 可以用复选标记进行检查 类似于待办事项列表 当我检查项目时 我希望能够返回 ListView 并保存我的选择 我假设将其保持在已保存状态的代码将位于
  • 如何检测 UITableView 中某个单元格的双击?

    如何检测某个单元格上的双击UITableView i e 如果用户进行了一次触摸 我想执行一个操作 如果用户进行了两次触摸 我想执行另一个操作 我还需要知道进行触摸的索引路径 我怎样才能实现这个目标 Thanks 如果您不想创建子类UITa
  • Objective-C 点表示法与类方法?

    请注意 我特别指的是点表示法与类方法一起使用 而不是与实例方法一起使用 出于好奇 我想看看如果我尝试在类方法中使用 Objective C 点表示法语法会发生什么 我的实验如下 import
  • iOS 搜索栏不显示结果

    更新 这实际上有效 我的自定义单元格的样式尚未出现 因此单元格看起来是空白的 那我怎样才能得到searchResultsTableView使用我的自定义单元格 我在表格视图中实现了搜索栏 当我调试时搜索 过滤所有工作 但是当我在搜索栏中输入
  • 刷新单元格的 UITableView 队列

    我想知道如果调用 UITableView reloadData 时 UITableView 队列被刷新 是否有人可以回复我 我正在尝试这样做 但这对我没有帮助 有什么建议吗 如果你查看 UITableView 的头文件 你可以看到有一个名为
  • iOS 中是否需要 Google App Indexing SDK 才能使用 Google DeepLinking?

    我想用谷歌应用程序索引与我的网页和 iOS 应用程序 我支持通用链接 or 深层链接用谷歌术语 与苹果Search并相应地设置我的网页 From 谷歌文档 https developers google com app indexing i

随机推荐

  • 如何在 Windows 窗体 PictureBox 中选择区域?

    我想通过允许用户选择来获取 PictureBox 中图片的一部分 矩形区域 类似于在 Photoshop 中使用选择工具完成的操作 我怎样才能做到这一点 您必须根据单击和拖动的位置绘制矩形或线条 你的起点是鼠标 x y 然后你会从鼠标释放
  • 如何使用 Twitter 搜索 API 获取推文的位置

    The statuses user timelineTwitter API 的一部分将地理位置数据作为 地点 与每条推文一起返回 另一方面 搜索 API 不会返回此位置数据 据我所知 有没有办法通过搜索 API 获取位置数据 有一个geo每
  • 使用 Python 实例化 TensorFlow 模型时出现 google.protobuf.text_format.ParseError

    我使用的是 Ubuntu 16 04 我有 Python 2 7 12 Python 3 5 2 tensorflow 1 2 0 rc1 protobuf 3 3 0 我想关注这个tutorial https gist github co
  • 如何从现有的“步骤列表”定义匹配的轴槽口

    我需要一种方法来对齐两个单独轴上的刻度线 同时能够控制 步长 值 刻度线之间的值 其中两个轴都从标记 0 开始并以不同的最大值结束 为什么会出现这个问题 Flot JS 图表包有一个对齐刻度线的选项 但是当我这样做时 我无法控制步长值 然而
  • 当我抛出异常时,内存会被释放吗?

    我正在与一些同事争论当你在动态分配的类中抛出异常时会发生什么 我知道malloc被调用 然后是类的构造函数 构造函数永远不会返回 那么会发生什么malloc 考虑以下示例 class B public B cout lt lt B B lt
  • 在 Woocommerce 中更改删除购物车项目 url

    我的简单问题是如何使这段代码正常工作 esc url WC gt cart gt get cart url gt get remove url cart item key 以上我已经尝试过 当前代码如下 esc url woocommerc
  • Android studio - 无法从文件 app.iml 加载设置,文件不存在?

    我在直接使用 Android studio 从在线 git 存储库导入项目时遇到了这个问题 结果发现 idea module xml 引用中的 iml 文件没有生成 转到项目根目录 删除整个存储库中的所有 iml 文件 确保 android
  • 使用标题区域中特定字段的变量计算平均值

    我有一个变量 用于存储特定字段的计算平均值 有没有办法在中使用这个变量Title乐队 当我尝试这样做时 我只是得到null in the Title但正确的值在栏页脚 我看到的唯一另一种可能性是 在 Java 中预先计算它并将其作为参数传递
  • 基本互斥锁和原子整数哪个更有效?

    对于像计数器这样简单的东西 如果多个线程会增加数量 我读到互斥锁会降低效率 因为线程必须等待 所以 对我来说 原子计数器是最有效的 但我读到在内部它基本上是一个锁 所以我想我很困惑为什么其中一个比另一个更有效 原子操作利用处理器支持 比较和
  • 数组值可以通过变量变量访问吗?

    我有一个只能通过变量正确访问的数组 如下所示 foo bar pie fixed name variable foo bar echo fixed name variable 这在理论上是回响的pie 但它只是不返回任何东西 所以我需要知道
  • tortoisehg gui 相当于执行“hg push -r”的操作是什么

    我没有看到完成此任务的选项 我只想推送与我的默认分支相关的变更集 而不是我拥有的任何其他本地分支 我想我可以通过使用存储库资源管理器来做到这一点 如下所示 在存储库地址下方的工具栏上 第一个组合框允许我选择一个分支 我将其设置为默认值 然而
  • ListView 中的复选框

    我希望填充一个列表视图 其中包含复选框作为 Android 应用程序中的列表项 我已经实现了一个列表视图 但是如果我选中列表中的任何一个复选框 它会检查列表视图中的其他一些列表 提前致谢 对于自定义布局
  • 根据 C# 中的条件从 JSON 中删除元素

    我有一个 JSON 字符串 我希望能够在 C 中修改它 我希望能够根据其中一个子值是某个值时删除一组数据 采取以下 responseHeader status 0 QTime 0 params explainOther fl score i
  • Ubuntu 16.04 正式支持 SCHED_DEADLINE 吗?

    目前我运行的是 Ubuntu 16 04 Linux 内核版本为 4 16 我编写了一个虚拟程序 将其调度程序更改为 SCHED DEADLINE 但是当我尝试编译它时 它找不到 SCHED DEADLINE 所需的结构和宏的定义 大部分代
  • Java 抽象类:为派生类返回“this”指针

    我正在尝试使用辅助方法编写一些自定义异常来设置变量 如下所示 public class KeyException extends RuntimeException protected String Id protected KeyExcep
  • 将 security=none 应用于上下文根和静态资源:spring security 版本 3.1

    我的应用程序编译为 ROOT war 这基本上意味着我没有除 之外的上下文根 有些页面需要保护 然而有些 URL 不需要它 例如我的http localhost 8080 com http localhost 8080 给出该应用程序的主页
  • 使用 php 处理 Jquery Ajax 表单提交

    最近 我在尝试使用 Jquery 和 Ajax 提交表单时一直在与它们作斗争 我有一个非常简单的表单 其中包含用户名字段和密码字段以及提交按钮 该表单应该做的是 一旦提交表单 信息将通过 Ajax 发送到 php 文件 然后该文件将所述表单
  • 停止更新*无效反应输入

    我正在寻找停止的方法update Input使我的 Shiny 应用程序中的无功值无效的函数 我希望更新函数仅更改可视 UI 组件 而不更改底层反应值 这是一个代表 library shiny ui lt fluidPage sliderI
  • 如何在 Midnight Commander 中过滤目录

    也许是一个愚蠢的问题 但如何在 Midnight Commander 中过滤目录 例如 我有一个包含很多目录的文件夹 其命名如下 holidays 2016 birthdays 2016 holidays 2015 我怎样才能过滤像 201
  • 绘制平滑曲线 - 所需方法

    如何在移动时平滑 iOS 绘图应用程序中的一组点 我尝试过 UIBezierpaths 但当我只是将点 1 2 3 4 2 3 4 5 移动时 我得到的只是它们相交处的锯齿状末端 我听说过样条曲线和所有其他类型 我对 iPhone 编程很陌