关闭

叉积、线段相交判断、凸包

6493人阅读 评论(0) 收藏 举报
分类:

一、叉积

叉积的计算是线段方法的核心。对于向来p1和p2,叉积是由点(0,0)、p1、p2和p1+p2构成的平行四边形的有向面积。另一种与之等价但更有效的的叉积定义方式是将其看做矩阵行列式:

p1×p2 = x1y2 - x2y1 = - p2×p1

若p1×p2为正,则相对于原点(0,0)来说,p1位于p2顺时针方向;若p1×p2为负,p1位于p2逆时针方向;若为0则方向相同,或相反。


若是相对于点p0(x0,y0)而非原点,则p0p1p0p2的叉积为(p1-p0)×(p2-p0) = (x1-x0)(y2-y0)-(x2-x0)(y1-y0)。


确定连续线段是向左转还是向右转

对于线段p0p1和p1p2,采用叉积可以避免计算角度,只需简单的计算一下p0p2是位于p0p1的顺时针还是逆时针方向。计算叉积

(p2-p0)×(p1-p0) = (x2-x0)(y1-y0) - (x1-x0)(y2-y0)

若结果为负,p0p2p0p1的逆时针方向,在p1处左转;结果为正则右转;为0表示三点共线。


判断两条线段是否相交

要判断两条线段是否相交,则需要检查每条线段是否跨越了另一条线段的直线。如果点p1位于某直线的一边,而点p2位于该直线的另一边,则称p1p2跨越了这条直线。两条线段相交,当且仅当下面两个条件至少成立一个:

  1. 每条线段都跨越了包含另一条线段的直线

  2. 一条线段的一个端点落在另一条线段上


二、确定任意一对线段是否相交

给定一个线段的集合,仅仅判断是否有两个线段相交,不必输出所有相交的线段对。此处我们假设,线段均不垂直。


我们使用“扫除”算法来解决这个问题。在扫除过程中,一条假想的扫除线穿过一个给定的几何物体集合,会与集合中的部分线段相交。下图中扫除线r与线段a、c相交,且与a的交点的y坐标值大于c的,则认为此处a>c。

在图(a)中,在r处,a>c;在t处,a还是>c,那么我们认为a和c没有相交。而在图(b)中,在v处,e>f,而在图w处,f>e,故e和f相交。


上图描述了一个算法,我们按照线段端点的x坐标,从小到达,进行“扫除”。当在一个线段的左端点扫除时,将所有相交的线段序列按序放入一个“完全前序关系T”中。当扫到线段的右端点时,从T中去除该线段。但是,如果位于在该线段上方的线段集合,与位于该线段下方的线段集合有交集,则表明有线段相交。


关键在于,如果存储T,如果求交集。可以用红黑树来存储T。


算法步骤

1. 初始化T为空集

2. 对线段的端点排序

3. 在端点p处,开始扫除,从最左边的处开始

    如果p是线段s的左端点

        Insert(T, s);

            如果有线段在扫除线处相交

                return true;

    如果p是线段的右端点

        如果above(T, s) 和 below(T, s)有交集,则

            return true;//即线段集中存在线段相交

        无交集则,Delete(T, s);

4. return false


三、寻找凸包

点集Q的凸包,是一个最小的凸多边形P,满足Q中的每个点都在P的边界上,或者在P的内部。


Graham扫描法: 复杂度O(nlogn)

  1. 选取y最小的点,多个y最小的话,选取其中x最小的点,作为p0

  2. 剩余的点,按照p0和pi的极角的逆时针排序,编号为p1,p2,...,pm

  3. 如果m小于2,表示点数小于3,形不成多边形

  4. 设定以空栈S,将p0、p1、p2压入栈中。

  5. for i=3 to m

    1. 得到栈顶的2个点pi-1和pi-2,如果t1t0t0pi转的时候,不是左转,就把顶点t0出栈;

    2. 如果出栈了t0,就继续a,直到栈的顶点不再出栈位置

    3. 将pi入栈

  6. return S

图中,从a到f是一步一步选择的过程。


Jarvis步进法:复杂度O(nh),h是凸包顶点数

先找到最下边结点里最左边的点p0,然后寻找使得p0p1极角最小的点,则p1也是凸包顶点;继续寻找使得p1p2极角最小的点,直到达到最高点pk,上图是p3,此时已经构造好了CH(Q)的右链。为了构造左链,寻找pk+1使得pkpk+1极角最小,但此时x轴啊原x轴的负方向。


除此之外,还有增量法、分治法、剪枝-搜索方法,其中剪枝-搜索方法复杂度为O(nlgh)。

4
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

判断两条线段是否相交(三种算法)

算法1:   [cpp] view plaincopy ///----------alg 1------------   struct Po...
  • yanjunmu
  • yanjunmu
  • 2015-07-02 17:49
  • 6679

判断两条线段是否相交 计算几何

对于线段A,B 线段A与直线B相交 ,线段B与直线A相交 ,那么就可以认为线段A 和线段B相交。 关键问题是:如何判断直线AB是否与线段CD相交呢? 设直线AB的方程为:f(x,y) = 0,直线方程...
  • exchan
  • exchan
  • 2016-12-08 21:31
  • 2053

计算几何基础——矢量和叉积 && 叉积、线段相交判断、凸包(转载)

转载自 http://www.cnblogs.com/bfshm/articles/3620500.html 矢量       如果一条线段的端点是有次序之分的话,那么这种线段就称为 有向线段,如...
  • itismelzp
  • itismelzp
  • 2015-10-27 17:11
  • 1316

POJ 3304 判断线段相交(叉积)

题目链接:http://poj.org/problem?id=3304 题解:同样是叉积的运用  #include #include #include #define N 11...
  • fjy4328286
  • fjy4328286
  • 2014-03-26 09:40
  • 401

POJ3304---Segments (基础计算几何:叉积判断线段相交)

【题目来源】:https://vjudge.net/problem/POJ-3304 【题意】 给出n条线段的起始点坐标,然后问,有没有这样一条直线:所有线段在该直线上的投影至少有一个共同点。 ...
  • duan_1998
  • duan_1998
  • 2017-07-18 11:24
  • 110

ccsu1359 木棒相交 (叉积线段判交,并查集判断是否属于同一个集合)

题意:判断n条木棒中木棒a是否与木棒b相交。其中木棒的相交具有传递性。    首先用一个判断线段是否相交的函数判断相交:    struct Point { double x; ...
  • LiWen_7
  • LiWen_7
  • 2012-03-07 20:33
  • 587

使用叉积判断两条线段是否相交

来自个人百度空间的文章---2012.2.19 一、基础知识       求两条线段是否相交首先要求两条线段通过快速排斥实验,即做出能包含两条线段的最小的矩形,既是以两条线段作为对角线...
  • pppaass
  • pppaass
  • 2015-07-06 15:20
  • 455

POJ3304_Segments_叉积::判断直线与线段是否相交

题意给出 n 个线段,问是否存在一条直线,当这 n 条线段投影在直线上时,至少有一个公共点。
  • yuege38
  • yuege38
  • 2017-07-19 17:24
  • 196

POJ1127_Jack Straws_叉积::判断两线段是否相交

题意给出 n 条线段端点的坐标,然后给出若干组询问。每组询问包含两个数字,输出这两个数字代表的线段是否联通。线段从 1 到 n 编号。通过联通的线段间接连在一起的线段,认为这两条线段也是联通的。思路判...
  • yuege38
  • yuege38
  • 2017-06-21 21:30
  • 180

hdu 1558 Segment set 并查集 叉积判断线段是否相交

hdu1558 题意:当输入P的时候,画一条线段,并且线段是有标号顺序的,如果两个线段相交即相当于联通了, 当输入Q的时候询问这个与这条线段联通的线段有几条(包括它本身) #include #i...
  • zhubing0331
  • zhubing0331
  • 2017-05-01 16:26
  • 131
    个人资料
    • 访问:592076次
    • 积分:7631
    • 等级:
    • 排名:第3263名
    • 原创:190篇
    • 转载:6篇
    • 译文:0篇
    • 评论:98条
    博客专栏
    文章分类
    最新评论