计算几何一点点2

判断线段是否相交
跨立实验

前提:如果两线段相交,必定互相跨立。


也即是说:

1.P1 P2 在Q1Q2的两侧

2.Q1Q2 在P1P2的两侧

判断两点是否在一条直线的两侧就用到叉乘了。

(Q1P1 x Q1Q2) * (Q1Q2 x Q1P2)  <= 0 表示P1P2在Q1Q2的两侧

(P1Q2 x P1P2)  *  (P1P2 x P1Q2)  <= 0 表示Q1Q2在P1P2的两侧
poj  3304

就是给你一堆线段 问你是否存在这样一条直线 使得所有线段在直线上的投影均有公共部分 有输出Yes 没有输出No

解题方法 :
投影直线上有公共点的话就是说这条直线存在一个垂线经过所有线段 就是与所有线段均相交

只要枚举这些线段端点所确定的直线 是否存在一条与所有线段均相交即可

判断线段相交用的是叉乘 首先用两点p1,p2确定了一条直线 在用p1,p2分别与计算线段两个端点计算叉乘即可
叉乘之积>0就说明线段两端点在直线的同侧 也就是直线不经过此线段

注意 :
本题是double类型
判断是否有重点 重点定义为坐标非常接近的两点 <1e-8即可
判断叉乘之积时 只要<1e-8 即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
int m,n;
const  double eps = 1e-8;
const int maxn = 505;
int coun[maxn];
struct dia
{
    double x;
    double y;
} dian[maxn]; // 每个点的横纵坐标
struct lin
{
    dia a;//a  dixia
    dia b;
} line[maxn]; //上边  下边
double chaji(dia p0,dia p1,dia p2)//判断点在直线哪一侧,如果在左侧<0,如果在右侧,>0
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
//判段一条线段与其他线段相交
bool xiangjiao(dia a, dia b)
{
    if (fabs(a.x-b.x) < eps && fabs(a.y-b.y) < eps)//首先先判重  ,如果两点之间的距离小于1e-8,则认为是一个点,直接标记为错
        return false;
    for (int i = 0; i < n; i++)
        if (chaji(line[i].a, b, a) * chaji(line[i].b, b, a) > eps)//此处可以判断出这条直线是否经过其他线段
            return false;
    return true;
}
int main()
{
    int t, i, j;
    bool flag;
    scanf ("%d", &t);
    while (t--)
    {
        scanf ("%d", &n);
        for (i = 0; i < n; i++)
            scanf ("%lf%lf%lf%lf", &line[i].a.x, &line[i].a.y, &line[i].b.x, &line[i].b.y);
        flag = false;
        if (n < 3)
            flag = true;
            //枚举端点组合
        for (i = 0; i < n && !flag; i++)
        {
            if (xiangjiao(line[i].a, line[i].b))
                flag = true;
            for (j = i + 1; j < n && !flag; j++)
            {
                if (xiangjiao(line[i].a, line[j].a)||xiangjiao(line[i].a, line[j].b) ||xiangjiao(line[i].b, line[j].a) ||xiangjiao(line[i].b, line[j].b))
                    flag = true;
            }
        }
        if (flag)
            printf ("Yes!\n");
        else
            printf ("No!\n");
    }
    return 0;
}
判断两直线相交,平行 或重合。
POJ 1269 
题目给出两条线段的4个端点,判断相交,平行还是重合,如果相交,则输出交点横纵坐标。
需要注意: 1.先运用向量平行公式判断是否平行,再用叉积公式判断是否重合。
                  2.判断重合还是平时的等于零,都应该用<1e-8次方表示。
然后转载具体推导公式:
判断平行 ((p1.x-p2.x)*(p3.y-p4.y)-(p1.y-p2.y)*(p3.x-p4.x))==0说明向量平等。
判断重合:
double Line(dian p0,dian p1,dian p2)
{
    return (p1.x-p0.x)*(p2.y - p0.y)-(p2.x - p0.x)*(p1.y - p0.y);
}
fabs(Line(d1,d3,d4)*Line(d2,d3,d4))<eps
判断相交:
假设交点为p0(x0,y0)。则有:

(p1-p0)X(p2-p0)=0

(p3-p0)X(p2-p0)=0

展开后即是

(y1-y2)x0+(x2-x1)y0+x1y2-x2y1=0

(y3-y4)x0+(x4-x3)y0+x3y4-x4y3=0

x0,y0作为变量求解二元一次方程组。

假设有二元一次方程组

a1x+b1y+c1=0;

a2x+b2y+c2=0

那么

x=(c1*b2-c2*b1)/(a2*b1-a1*b2);

y=(a2*c1-a1*c2)/(a1*b2-a2*b1);

因为此处两直线不会平行,所以分母不会为0

就是一波推导,其实没啥好写的........

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
const int maxn = 1005;
const double eps = 1e-8;
using namespace std;
struct dian
{
    double x,y;
}d1,d2,d3,d4;
double Line(dian p0,dian p1,dian p2)
{
    return (p1.x-p0.x)*(p2.y - p0.y)-(p2.x - p0.x)*(p1.y - p0.y);
}
bool panduan()
{

    double a1,b1,c1,a2,b2,c2;
    double xx,yy;

    if(fabs((d1.y - d2.y)*(d3.x  - d4.x) - (d3.y - d4.y)*(d1.x - d2.x))<eps)
    {
        if(fabs(Line(d1,d3,d4)*Line(d2,d3,d4))<eps)
       {
           printf("LINE\n");
       }
       else
          printf("NONE\n");

    }
       else
       {
           a1 = d1.y - d2.y;
           b1 = d2.x - d1.x;
           c1 = d1.x*d2.y - d2.x*d1.y;
           a2 = d3.y - d4.y;
           b2 = d4.x - d3.x;
           c2 = d3.x*d4.y - d4.x*d3.y;

           xx = (c1*b2 - c2 *b1)/(a2*b1 - a1 * b2);
           yy = (a2*c1 - a1*c2)/(a1*b2 - a2 * b1);
           printf("POINT %.2f %.2f\n",xx,yy);

       }
}
int main()
{
  int n;
  cin>>n;
  printf("INTERSECTING LINES OUTPUT\n");
  for(int i = 0; i < n; i++)

  {
      scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&d1.x,&d1.y,&d2.x,&d2.y,&d3.x,&d3.y,&d4.x,&d4.y);
      panduan();
  }
  printf("END OF OUTPUT\n");

}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值