博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS 沿曲线线性渐变的贝塞尔曲线
阅读量:7076 次
发布时间:2019-06-28

本文共 3502 字,大约阅读时间需要 11 分钟。

大致思路是,先获取到贝塞尔曲线上所有的点,然后在计算每个点的t值,然后根据t值来计算每个点的颜色。这种方式会在顶点的位置计算会有一些问题,整体来说只是一种思路,具体效果有待考验。

1、获取贝塞尔曲线上所有的点

如何获取贝塞尔曲线上所有的点?这个其实是比较简单的,可以利用UIBezierPath画一条曲线,渲染到CAShapeLayer (fillColor:clearColor,strokeColor:redColor)上,然后遍历CAShapeLayer上的像素,只要像素的有色值那就是需要的点。同时由于这样渲染出的线条已经处理好了锯齿问题(即像素透明度), 所以为后面的处理省下了很多的事情。

2、计算每个点的 t 值

现在已经得到了需要的点,剩下的就是计算每个点的t值了。计算t值也就是一个解方程的过程,这里说的是二次贝塞尔曲线,涉及到的就是一元二次方程。但是在像素点的坐标值都是整数型的,不是所有的点都是在曲线上的,所以解出来的 t 值多少会有些误差,不过效果还是可以的,对整体的渐变影响不大。

// 根据 x 计算 t- (float)baseOnXWithPoint:(CGPoint)point {    float a = _startPoint.x - 2 * _controlPoint.x + _endPoint.x;    float b = 2 * _controlPoint.x - 2 * _startPoint.x;    float c = _startPoint.x - point.x;    float condition = pow(b, 2) - 4 * a * c;    if (a != 0 ) {        if (condition >= 0) {            NSArray *r = [self quadraticEquationWithA:a b:b c:c];            if (r && r.count > 0) {                float t = [self betterRWithRs:r targetPoint:point];                return t;            }        }    } else {        // 一元一次方程求解        float t = (-c)/b;        return t;    }    return -1;}// 根据 y 计算 t- (float)baseOnYWithPoint:(CGPoint)point {    float a = _startPoint.y - 2 * _controlPoint.y + _endPoint.y;    float b = 2 * _controlPoint.y - 2 * _startPoint.y;    float c = _startPoint.y - point.y;    float condition = pow(b, 2) - 4 * a * c;    if ( a != 0) {        if (condition >= 0) {            NSArray *r = [self quadraticEquationWithA:a b:b c:c];            if (r && r.count > 0) {                float t = [self betterRWithRs:r targetPoint:point];                return t;            }        }    } else {        // 一元一次方程求解        float t = (-c)/b;        return t;    }    return -1;}复制代码

这里会有两个方程,一个是以x为参数,一个以y为参数。这两个方程都会用到。为什么要用两个方程?因为有的点通过x或者y 并不能解得结果,比如说顶点附近的点,通过点做 x 轴的 垂线,可能与曲线并不会交点,也就意味着不会有解。所以如果以x为参数无解,那就再用y为参数的方程解一次,如果还没有解,那这个点就认为是不在线上的了。

在计算的过程中还有一个问题:如果以x 为参数计算,那么 X 方向上顶点附近的点(如果有顶点)计算出来的t值误差会比较大。所以在计算的时候做了一些判断,如果是顶点附近的点,以y为参数计算

- (float)quadraticEquationWithPoint:(CGPoint)point  {    float t = [self baseOnXWithPoint:point];    // 如果没有结果 即 t = -1,则依据Y从新计算    // 如果计算的结果为 X 方向上的顶点,由于顶点位置计算不准确,所以根据Y从新计算    if (t == -1 || fabs([self tForXAtVertexPoint] - t) < 0.1) {        float otherT = [self baseOnYWithPoint:point];        if (otherT == -1) {            return t;        }        t = otherT;    }    return t;}复制代码

对于一元二次方程,是会有两个根的情况的,所以对于解出来的结果需要进行比对,找到与目标点最接近的t值

// 筛选结果- (float)betterRWithRs:(NSArray *)rs targetPoint:(CGPoint)point{    CGFloat distance = NSNotFound;    NSInteger betterIndex = 0;    for (NSInteger i = 0; i < rs.count; i ++) {        float t = [[rs objectAtIndex:i] floatValue];        CGFloat x = [self xAtT:t];        CGFloat y = [self yAtT:t];        if (distance == NSNotFound) {            distance = [self distanceWithPoint:CGPointMake(x, y) point1:point];            betterIndex = i;        } else {            if (distance > [self distanceWithPoint:CGPointMake(x, y) point1:point]) {                distance = [self distanceWithPoint:CGPointMake(x, y) point1:point];                betterIndex = i;            }        }    }    float t = [rs[betterIndex] floatValue];    if (t >= 1) {        if ([self isNearbyTargetPoint:_endPoint x:point.x y:point.y]) {            return 1;        } else {            return -1;        }    }    if (t <= 0) {        if ([self isNearbyTargetPoint:_startPoint x:point.x y:point.y]) {            return 0;        } else {            return -1;        }    }    return [rs[betterIndex] floatValue];}复制代码

可以先看下效果。整体来说效果还是理想的,并且也支持了线宽的问题。


转载地址:http://vluml.baihongyu.com/

你可能感兴趣的文章
移动web开发中,好用的小方法
查看>>
Go 语言的垃圾回收演化历程:垃圾回收和运行时问题
查看>>
【Java资源免费分享,网盘自己拿】
查看>>
webpack配置(第四步:html篇(进阶篇))
查看>>
Spring Boot开启的2种方式
查看>>
阿里云服务提供商分享CDN访问异常该如何排查
查看>>
利用Sympy计算sin1°的最小多项式
查看>>
Vuejs响应式原理
查看>>
【Nebula系列】C++反射机制:可变参数模板实现C++反射
查看>>
mac 终端 常用命令
查看>>
2016年人工智能产业梳理:一朝引爆,稳步前进(下篇)
查看>>
django 1.8 官方文档翻译:5-1-2 表单API
查看>>
区块链将会怎样颠覆Google、Amazon、Facebook和Apple?
查看>>
VR直播很火,但能取代传统电视直播吗?
查看>>
[转]区块链代码快速学习实践
查看>>
QuickBI助你成为分析师——计算字段功能
查看>>
《王牌特工2》情景再现,Youbionic推出可穿戴式机械手
查看>>
雪城大学信息安全讲义 五、竞态条件
查看>>
干货分享:MySQL之化险为夷的【钻石】抢购风暴
查看>>
量子通信能否跨越“死亡之谷”?2017年市场化的量子通信产品可能产生
查看>>