判断触摸点在一条直线上(Swift 方法)

31 篇文章 5 订阅

最近在做扫地机项目,其中有个虚拟墙的功能,我们需要绘制并移动虚拟墙,这牵涉到一个知识点:判断我们的手指触摸点在虚拟墙(直线)上,研究了很久,找到一个方法,记录下来,以备后续之用:

 /* 判断触摸点在虚拟墙(直线)上*/
    func pointIsinLine(point:CGPoint,startpoint p0:CGPoint,endpoint p1:CGPoint) -> Bool {
        //设置一个点到线段的允许的最大值
        let maxAllowOffsetLength:Float = 10
        //通过直线方程的两点式计算出一般式的ABC参数
        let A = p1.y - p0.y
        let B = p0.x - p1.x
        let C = p1.x * p0.y - p0.x * p1.y
        
        //带入点到直
        let sqrt:Float = sqrtf(powf(Float(A), 2) + powf(Float(B),2))
        
        var dis:Float = fabsf( Float(A * point.x + B * point.y + C) / sqrt )
        //果该距离大于允许值说明则不在线段上
        if dis > maxAllowOffsetLength || dis.isNaN {
            return false
        }else {
            //否则我们要进一步判断,投影点是否在线段上,根据公式求出投影点的X坐标jiaoX
            let D = (A * point.y - B * point.x)
            let jiaoX = -(A * C + B * D) / (pow(B, 2) + pow(A, 2))
            let t = (jiaoX - p0.x) / (p1.x - p0.x)
            if t > 1 || t.isNaN {
                //最小距离为到p1点的距离
                dis = Float(LengthOfTwoPoint(point1: p1, point2: point))
            }else if (t < 0){
                //最小距离为到p2点的距离
                dis = Float(LengthOfTwoPoint(point1: p0, point2: point))
            }
            //再次判断真正的最小距离是否小于允许值,小于则该点在直线上,反之则不在
            if (dis <= maxAllowOffsetLength) {
                Log("在此直线上")
                return true
            }else{
                return false
            }
        }
    }
    
    /* 这里是求两点距离公式 */
    func LengthOfTwoPoint( point1:CGPoint, point2:CGPoint) -> CGFloat{
        return sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
    }

OC代码:

- (BOOL)Judgepoint:(CGPoint)point isInLineByTwoPoint:(CGPoint)p0 p1:(CGPoint)p1{
    //先设置一个所允许的最大值,点到线段的最短距离小于该值说明点在线段上
    CGFloat maxAllowOffsetLength = 15;
    //通过直线方程的两点式计算出一般式的ABC参数,具体可以自己拿起笔换算一下,很容易
    CGFloat A = p1.y - p0.y;
    CGFloat B = p0.x - p1.x;
    CGFloat C = p1.x * p0.y - p0.x * p1.y;
    //带入点到直线的距离公式求出点到直线的距离dis
    CGFloat dis = fabs((A * point.x + B * point.y + C) / sqrt(pow(A, 2) + pow(B, 2)));
    //如果该距离大于允许值说明则不在线段上
    if (dis > maxAllowOffsetLength || isnan(dis)) {
        return NO;
    }else{
    //否则我们要进一步判断,投影点是否在线段上,根据公式求出投影点的X坐标jiaoX
        CGFloat D = (A * point.y - B * point.x);
        CGFloat jiaoX = -(A * C + B *D) / (pow(B, 2) + pow(A, 2));
        //判断jiaoX是否在线段上,t如果在0~1之间说明在线段上,大于1则说明不在线段且靠近端点p1,小于0则不在线段上且靠近端点p0,这里用了插值的思想
        CGFloat t = (jiaoX - p0.x) / (p1.x - p0.x);
        if (t > 1  || isnan(t)) {
        //最小距离为到p1点的距离
            dis = LengthOfTwoPoint(p1, point);
        }else if (t < 0){
        //最小距离为到p2点的距离
            dis = LengthOfTwoPoint(p0, point);
        }
        //再次判断真正的最小距离是否小于允许值,小于则该点在直线上,反之则不在
        if (dis <= maxAllowOffsetLength) {
            return YES;
        }else{
            return NO;
        }
    }
}

//这里是求两点距离公式
static inline CGFloat LengthOfTwoPoint(CGPoint point1, CGPoint point2){
    return sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值