贝赛尔曲线点检测

      最近完整一个图像处理工具的第二期,其中将原来的模块的连接直线,升级为贝赛尔曲线(关键是看起来比较上档次)。随之问题就来了,如果检测鼠标在点击时,是否选中它了呢。直线好算,利用中学知识就行,那贝赛尔曲线呢?

如下图,是采用三阶贝赛尔曲线,利用GDI+直接画的:

  


什么是贝赛尔曲线,我就不解释了,关于它资料很多

这是三阶贝赛尔方程式:

inline double BezierFormula(int p0, int p1, int p2, int p3, double t){
    double r = 1.0 - t;
    return p0*r*r*r + 3*p1*t*r*r + 3*p2*t*t*r + p3*t*t*t;
}


检测算法如下:

//
// check point is where on specified bezier curve. half-find
// @param p0 start poing
// @param p1 contrl point
// @param p2 contrl point
// @param p3 end point
// @NOTE:
// p0(1-t)³+3p1t(1-t)²+3p2t²(1-t)+p3t³ = p
// where t in range of [0.0, 1.0]
// reference below:
// http://baike.baidu.com/link?url=n7iJBnCBzhkLtffffPQO1Vsx0JFuKN3qRWi4WDXpSR4VJ_y1XN4F6G0xjcpOUF_X
//
// @return
bool IsPointOnBezier(const Point& p, const Point& p0, const Point& p1, 
                     const Point& p2, const Point& p3){
    double left               = 0.0;
    double right              = 1.0;
    const int kTorlance       = 3;
    const double kGranularity = 0.000001;
    int y                     = INT_MAX;

    Rect bounds(MakeRect(p0, p3));
    bounds.Inflate(kTorlance, kTorlance);
    if(!bounds.Contains(p)){
        return false;
    }    

    while(abs(left - right) > kGranularity){
        double middle = (left + right) * 0.5;
        double x = BezierFormula(p0.X, p1.X, p2.X, p3.X, middle);
        if(abs(x - p.X) < 0.5){
            y = static_cast<int>(BezierFormula(p0.Y, p1.Y, p2.Y, p3.Y, middle) + 0.5f);
            break;
        }

        double  lr = BezierFormula(p0.X, p1.X, p2.X, p3.X, left) - p.X;
        double  mr = BezierFormula(p0.X, p1.X, p2.X, p3.X, middle) - p.X;

        if(lr * mr < 0)
            right = middle;
        else
            left = middle;        
    }
    
    return abs(y - p.Y) <= kTorlance;
}


算法核心是利用折半查找算法,计算查找点X对应的Y值,并看这个Y值是否在一定的容错范围内接受。

在找查区间的选择上,要通过符号来判断,不然无处理结束点在起如点左边的情形。
算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值