利用矢量计算快速判定一点在直线的哪一侧

很实用的一片判断点与直线关系的文章,转自:http://www.cnblogs.com/vilyLei/articles/1567852.html


这个例子是用来说明矢量运算可以快速判定一点在直线的哪一侧。



如上图所示,直线是从pA到pB的直线AB。下面的工作是构建一个方法,来判断某点在这条直线AB的左下侧还是右上侧。
如上图所示,pC点就在直线AB的右上侧,而pD点就在直线AB的左下侧。

这里要用矢量运算来解决这个问题,所以需要用到2D空间的矢量类,这个类:Vector_2D.as在此处http://www.cnblogs.com/vilyLei/articles/1567703.html可以找见。
下面用的Vector_2D类都指的是这个矢量类,每个Vector_2D类实例的方法都是这个类中已有的方法。

注:这里的矢量指的是数学或物理上的矢量,不是cs4中的Vector,它也叫向量。当然有很多东西可以在逻辑上表示为矢量,例如rgb颜色。

首先定义四个矢量对象来记录四个位置(pA,pB,pC,pD四个点)

  //定义四个点矢量来记录四个点的相应位置
  private var _a_V:Vector_2D = new Vector_2D(196,123);
  private var _b_V:Vector_2D = new Vector_2D(370,230);
  private var _c_V:Vector_2D = new Vector_2D(422,112);
  private var _d_V:Vector_2D = new Vector_2D(159,296);


接着定义点pA到点pC的矢量,如上图pA到pC的箭头所示:
  private var _ac_V:Vector_2D = null;
定义点pB到点pC的矢量,如上图pB到pC的箭头所示:
  private var _bc_V:Vector_2D = null;

定义点pA到点pD的矢量,如上图pA到pD的箭头所示:
  private var _ad_V:Vector_2D = null;
定义点pB到点pD的矢量,如上图pB到pD的箭头所示:
  private var _bd_V:Vector_2D = null;

接下来计算出_ab_V, _bc_V, _bd_V这三个矢量:
   //_c_V减去_a_V 就可以计算出点pA到点pC的矢量
   _ac_V = _c_V.minusNew(_a_V);
   //_c_V减去_b_V 就可以计算出点pB到点pC的矢量
   _bc_V = _c_V.minusNew(_b_V);
   //_d_V减去_a_V 就可以计算出点pA到点pD的矢量
   _ad_V = _d_V.minusNew(_a_V);
   //_d_V减去_b_V 就可以计算出点pB到点pD的矢量
   _bd_V = _d_V.minusNew(_b_V);

现在来做一个测试,需要用到矢量叉乘,即Vector_2D类的cross(...)方法。
这里简要介绍一下叉乘。对于2D矢量的叉乘最后得到的一定是一个数字,它可能大于零,可能等于零,也可能小于零
如果两个矢量的方向夹角是180度/0度的时候,它们的叉乘值一定是等于零(当然在计算机中可能是 0.0001),对应的数学公式为A x B = |A|*|B|*sin(angle)
一定要记住叉乘不遵循交换律。

例如矢量A×矢量B=矢量C
设想矢量A沿小于180度的角度转向矢量B
将右手的四指指向矢量A的方向,右手的四指弯曲代表上述旋转方向,则伸直的拇指指向它们的叉乘得到的矢量C

如上图所示,利用Vector_2D类,可以计算出_ac_V 与_bc_V 的叉乘结果
 var crossNum:Number = _ac_V.cross(_bc_V);
得到的 crossNum是小于零的。

同理_ad_V 与_bd_V 的叉乘结果是:
 crossNum = _ad_V.cross(_bd_V);
crossNum大于零。

继续推测,得到一个方法:
 对于任意一个点P,建立矢量tP_V来记录这个点的坐标,算出 点pA到点P的矢量tA_V 和 点pB到点P的矢量tB_V,再计算出这两个矢量的叉乘
 crossNum = tA_V.cross(tB_V);(不能写成 tB_V.cross(tA_V) )
 if(crossNum < 0){
  //说明P点在直线AB的右上侧
 }else{
  //说明P点在直线AB的左下侧
 }

演示代码如下:

package
{
    /**//**
      * Copyright (C) 2009-2010 Vily
     *
     * @class name(类名):    TestLineSideMain
     *
     * @author(创建人): Vily
     *
     * @version(版本): v1.1
     *
     * @create date(创建日期): 2009-9-16
     *
     * @purpose(对此类实现的功能的描述):TestLineSideMain文档类
     *
     * @public properties(公开的属性): None. Static constants only.
     * @public methods(公开的方法):
     *             TestLineSideMain( ) - Constructor. 
     *
     */
    import flash.display.Sprite;
    import org.vily.primitives.Vector_2D;    
    public class TestLineSideMain extends Sprite{
        
        //定义四个点矢量来记录四个点的相应位置
        private var _a_V:Vector_2D = new Vector_2D(196,123);
        private var _b_V:Vector_2D = new Vector_2D(370,273);
        private var _c_V:Vector_2D = new Vector_2D(422,112);
        private var _d_V:Vector_2D = new Vector_2D(159,296);
        //是个测试用的矢量
        private var _ac_V:Vector_2D = null;
        private var _bc_V:Vector_2D = null;
        private var _ad_V:Vector_2D = null;
        private var _bd_V:Vector_2D = null;
        public function TestLineSideMain(){
            init();
        }
        /**//**
         *    系统程序初始化入口
         */
        private function init():void{
            trace("init");
            initObj();            
        }
        /**//**
         *    初始化非显示对象
         */
        private function initObj():void{
            
            //_c_V减去_a_V
            _ac_V = _c_V.minusNew(_a_V);
            //_c_V减去_b_V
            _bc_V = _c_V.minusNew(_b_V);
            //_d_V减去_a_V
            _ad_V = _d_V.minusNew(_a_V);
            //_d_V减去_b_V
            _bd_V = _d_V.minusNew(_b_V);
            
            var crossNum:Number = _ac_V.cross(_bc_V);//crossNum小于零
            crossNum = _ad_V.cross(_bd_V);//crossNum大于零
            
            //判定任意点tP_V在直线的左下侧还是右上侧
            var tP_V:Vector_2D = new Vector_2D(Math.random()*400,Math.random()*400);
            var tA_V:Vector_2D = tP_V.minusNew(_a_V);
            var tB_V:Vector_2D = tP_V.minusNew(_b_V);
            crossNum = tA_V.cross(tB_V);
            
            if(crossNum < 0){
                trace("在右上侧");
            }else{
                trace("在左下侧");
            }
        }        
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用矢量方法判断直线的哪侧可以通过计算直线向量的投影来实现。具体步骤如下: 1. 计算直线的法向量,可以通过直线的两个坐标计算得到。 2. 将的坐标与直线上任意一点的坐标作差,得到一个向量。 3. 计算向量直线向量上的投影,投影的长度即为直线的距离。 4. 判断直线的哪一侧,可以通过将的坐标代入直线方程,判断直线上方还是下方。 下面是一个示例代码,假设直线的两个分别为 (x1, y1) 和 (x2, y2),的坐标为 (x, y): ```python def point_to_line_distance_by_vector(x1, y1, x2, y2, x, y): # 计算直线的法向量 dx = x2 - x1 dy = y2 - y1 normal_vector = [-dy, dx] # 将的坐标与直线上任意一点的坐标作差,得到一个向量 point_vector = [x - x1, y - y1] # 计算向量直线向量上的投影,投影的长度即为直线的距离 distance = abs(np.dot(point_vector, normal_vector)) / math.sqrt(np.dot(normal_vector, normal_vector)) # 判断直线的哪一侧 if y > (y2 - y1) / (x2 - x1) * (x - x1) + y1: return distance, "上方" else: return distance, "下方" ``` 调用方式为: ```python distance, position = point_to_line_distance_by_vector(0, 0, 1, 1, 2, 0) print("直线的距离为:", distance) print("直线的", position) ``` 其中,(0, 0) 和 (1, 1) 分别为直线上的两个,(2, 0) 为的坐标。输出结果为: ``` 直线的距离为: 0.7071067811865475 直线的下方 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值