原题地址
某厂笔试原题,编程题第一题直接给我整傻了,分类讨论半天最终也没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");
}