框选线段 (计算几何)

原题地址
某厂笔试原题,编程题第一题直接给我整傻了,分类讨论半天最终也没ac,没练过计算几何的下场吧…
题意:给定一个矩阵的坐标和两个点的坐标,要求这两个点连起来的线段被这个矩阵所截断的线段端点坐标。
思路:利用向量解会非常方便,求出两点形成的向量,然后分别对横纵坐标求出偏移量,这样我们就可以很方便地得出线段两端点在任意延长线上的坐标。然后对两点分别进行讨论。比如,如果该点在矩阵右端点的右边,那么这个点射出去的线就有可能被矩阵右边线截取,所以可以根据偏移量求出这个点在线段延长线上,横坐标和矩阵右边线对齐的点。但是通过画图可以得知,有些情况不一样会被右边线截取,如果纵坐标大于矩阵上面,那么有可能被上边线截取, 那么如何得知是被哪个线截取了呢?很简单,刚才在讨论右边线上的点的时候,如果真的被右边线截取了,那么算出的点的纵坐标必然在上下两边线中间,所以如果在两边,就必然被上下两边线中的一个截取,这时再讨论这种情况即可。接下来考虑特殊情况:

  • 线段与矩阵没有交点
    这种情况再使用上述算法以后,两点坐标会变成同一个,可以自己画图试试。
  • 点在矩阵内部
    事先特判即可
#include<iostream>
#include<cstdio>
using namespace std;
struct Point
{
    double x,y;
};
struct Rect
{
    Point left,right;
    bool contain(Point p)
    {
        return (p.x>=left.x&&p.y>=left.y&&p.x<=right.x&&p.y<=right.y);
    }
    void cut(Point &p,Point dir)
    {
        if(contain(p)) return;
        Point k={1,dir.y/dir.x};//偏移量
        //cout<<111<<' '<<p.x<<' '<<right.x<<endl;
        if(p.x>right.x)
        {
            p={right.x,p.y+k.y*(right.x-p.x)};
         //   cout<<p.x<<' '<<p.y<<endl;
        }
        else if(p.x<left.x)
        {
            p={left.x,p.y+k.y*(left.x-p.x)};
        }
        k={dir.x/dir.y,1};//偏移量
        if(p.y>right.y)//这里的if和if else执行的条件是左右边线没有截取到
        {
            p={p.x+k.x*(right.y-p.y),right.y};
        }
        else if(p.y<left.y)
        {
            p={p.x+k.x*(left.y-p.y),left.y};
        }
    }
};
int main()
{
    Rect rect;
    Point p1,p2;
    cin>>rect.left.x>>rect.left.y>>rect.right.x>>rect.right.y>>p1.x>>p1.y>>p2.x>>p2.y;
    Point dir={p2.x-p1.x,p2.y-p1.y};
    rect.cut(p1,dir);
    rect.cut(p2,dir);
   // cout<<p1.x<<' '<<p1.y<<' '<<p2.x<<' '<<p2.y<<endl;
    if(p1.x==p2.x&&p1.y==p2.y) puts("-1");
    else printf("(%.2f,%.2f)\n(%.2f,%.2f)\n",p1.x,p1.y,p2.x,p2.y);
	//system("pause");
}
上一篇:MFC初探 —— 双击Picture Control具体位置放大图片


下一篇:Winform C#截屏实现