UVA_191_Intersection

来源:互联网 发布:高校综合数据分析平台 编辑:程序博客网 时间:2024/04/30 14:58
#include<iostream>#include<sstream>#include<string>#include<vector>#include<list>#include<set>#include<map>#include<stack>#include<queue>#include<algorithm>#include<numeric>#include<cmath>#pragma warning(disable:4996)using std::cin;using std::cout;using std::endl;using std::stringstream;using std::string;using std::vector;using std::list;using std::pair;using std::set;using std::multiset;using std::map;using std::multimap;using std::stack;using std::queue;using std::priority_queue;class Point{public:long double x, y;Point() {}Point(const long double &X, const long double &Y){x = X;y = Y;}};class Line{public:long double a, b, c;//ax+by=clong double x_min, x_max, y_min, y_max;//直线的值域Line() {}Line(const Point &first, const Point &second){x_min = std::min(first.x, second.x);x_max = std::max(first.x, second.x);y_min = std::min(first.y, second.y);y_max = std::max(first.y, second.y);if (first.x != second.x)//斜率式可行{b = 1;a = -(first.y - second.y) / (first.x - second.x);c = first.y + a*first.x;}else//k->无穷{b = 0;a = 1;c = first.x;}}bool lineIntersected(const Line &line)//直线相交的判定{auto D = a*line.b - line.a*b;if (D){return true;}return false;}bool lineParallel(const Line&line)//判断两直线是否平行{auto D = a*line.b - line.a*b;if (!D){return true;}return false;}bool lineOverlapped(const Line&line)//判断两直线是否重合(平行的特例){auto D = a*line.b - line.a*b;auto Dx = c*line.b - line.c*b;auto Dy = a*line.c - line.a*c;if (!D&&!Dx&&!Dy){return true;}return false;}long double fixed(long double value){value *= (long double)1000000000000.0;value += 0.5;value = floor(value);value /= (long double)1000000000000.0;return value;}Point getIntersection(const Line&line)//行列式求两直线交点,要修正误差{auto D = a*line.b - line.a*b;auto Dx = c*line.b - line.c*b;auto Dy = a*line.c - line.a*c;return{ fixed(Dx / D),fixed(Dy / D) };}bool segmentIntersected(const Line &line){if (lineIntersected(line)){auto point = getIntersection(line);if (point.x >= x_min&&point.x <= x_max&&point.y >= y_min&&point.y <= y_max&&point.x >= line.x_min&&point.x <= line.x_max&&point.y >= line.y_min&&point.y <= line.y_max)//交点在两线段的值域内{return true;}}return false;}bool segmentOverlapped(const Line &line){if (lineOverlapped(line)){if ((x_min <= line.x_max&&x_min >= line.x_min) || (x_max <= line.x_max&&x_max >= line.x_min)){return true;}}return false;}};class Rectangle{public:long double left, right, top, bottom;bool inRectangle(const Point &point){if (point.x >= left&&point.x <= right&&point.y >= bottom&&point.y <= top){return true;}return false;}};int main(){//freopen("input.txt", "r", stdin);//freopen("output.txt", "w", stdout);int n;while (cin >> n){for (int i = 0; i < n; i++){long double x1, y1, x2, y2;cin >> x1 >> y1 >> x2 >> y2;Rectangle rectangle;cin >> rectangle.left >> rectangle.top >> rectangle.right >> rectangle.bottom;if (rectangle.left > rectangle.right){std::swap(rectangle.left, rectangle.right);}if (rectangle.bottom > rectangle.top){std::swap(rectangle.bottom, rectangle.top);}if (rectangle.inRectangle({ x1,y1 }) || rectangle.inRectangle({ x2,y2 })){//只要一个端点在矩形内,就有交点  cout << 'T' << endl;}else{Line line({ x1,y1 }, { x2,y2 });vector<long double>segment(4);segment[0] = rectangle.top;segment[1] = rectangle.right;segment[2] = rectangle.bottom;segment[3] = rectangle.left;bool flag = false;for (int i = 0; i < 4; i++){Line another({ segment[i],segment[(i + 1) % 4] }, { segment[(i + 1) % 4],segment[(i + 2) % 4] });if (line.segmentIntersected(another)||line.lineOverlapped(another)){flag = true;break;}}if (flag){cout << 'T' << endl;}else{cout << 'F' << endl;}}}}return 0;}
<pre name="code" class="cpp">#include<iostream>  #include<sstream>  #include<string>  #include<vector>  #include<list>  #include<set>  #include<map>  #include<stack>  #include<queue>  #include<algorithm>  #include<numeric>  #include<cmath>  #pragma warning(disable:4996)  using std::cin;using std::cout;using std::endl;using std::stringstream;using std::string;using std::vector;using std::list;using std::pair;using std::set;using std::multiset;using std::map;using std::multimap;using std::stack;using std::queue;using std::priority_queue;using std::swap;using std::min;using std::max;class Point {public:double x,y; };const double eps = 1e-20;bool isEqual(const double &a,const double &b) {return (abs(a - b) < eps);}//判断两点是否相等bool operator==(const Point &p1, const Point &p2) {return (isEqual(p1.x, p2.x) && isEqual(p1.y, p2.y));}//比较两点坐标大小,先比较x坐标,若相同则比较y坐标bool operator>(const Point &p1, const Point &p2) {return (p1.x > p2.x || (isEqual(p1.x, p2.x) && p1.y > p2.y));}//计算两向量外积(叉乘)double operator^(const Point &p1, const Point &p2){return (p1.x * p2.y - p1.y * p2.x);}//判定两线段位置关系,并求出交点(如果存在)。返回值列举如下://[有重合] 完全重合(6),1个端点重合且共线(5),部分重合(4)//[无重合] 两端点相交(3),交于线上(2),正交(1),无交(0),参数错误(-1)int Intersection(Point p1, Point p2, Point p3, Point p4, Point &point) {//保证参数p1!=p2,p3!=p4if (p1 == p2 || p3 == p4){return -1; //返回-1代表至少有一条线段首尾重合,不能构成线段}//为方便运算,保证各线段的起点在前,终点在后。if (p1 > p2) {swap(p1, p2);}if (p3 > p4) {swap(p3, p4);}//判定两线段是否完全重合if (p1 == p3 && p2 == p4) {return 6;}//求出两线段构成的向量Point v1 = { p2.x - p1.x, p2.y - p1.y }, v2 = { p4.x - p3.x, p4.y - p3.y };//求两向量外积,平行时外积为0double Cross = v1 ^ v2;//如果起点重合if (p1 == p3) {point = p1;//起点重合且共线(平行)返回5;不平行则交于端点,返回3return (isEqual(Cross, 0) ? 5 : 3);}//如果终点重合if (p2 == p4){point = p2;//终点重合且共线(平行)返回5;不平行则交于端点,返回3return (isEqual(Cross, 0) ? 5 : 3);}//如果两线端首尾相连if (p1 == p4) {point = p1;return 3;}if (p2 == p3) {point = p2;return 3;}//经过以上判断,首尾点相重的情况都被排除了//将线段按起点坐标排序。若线段1的起点较大,则将两线段交换if (p1 > p3) {swap(p1, p3);swap(p2, p4);//更新原先计算的向量及其外积swap(v1, v2);Cross = v1 ^ v2;}//处理两线段平行的情况if (isEqual(Cross, 0)) {//做向量v1(p1, p2)和vs(p1,p3)的外积,判定是否共线Point vs = { p3.x - p1.x, p3.y - p1.y };//外积为0则两平行线段共线,下面判定是否有重合部分if (isEqual(v1 ^ vs, 0)) {//前一条线的终点大于后一条线的起点,则判定存在重合if (p2 > p3) {point = p3;return 4; //返回值4代表线段部分重合}}//若三点不共线,则这两条平行线段必不共线。 //不共线或共线但无重合的平行线均无交点return 0;} //以下为不平行的情况,先进行快速排斥试验  //x坐标已有序,可直接比较。y坐标要先求两线段的最大和最小值double ymax1 = p1.y, ymin1 = p2.y, ymax2 = p3.y, ymin2 = p4.y;if (ymax1 < ymin1) {swap(ymax1, ymin1);}if (ymax2 < ymin2) {swap(ymax2, ymin2);}//如果以两线段为对角线的矩形不相交,则无交点if (p1.x > p4.x || p2.x < p3.x || ymax1 < ymin2 || ymin1 > ymax2) {return 0;}//下面进行跨立试验Point vs1 = { p1.x - p3.x, p1.y - p3.y }, vs2 = { p2.x - p3.x, p2.y - p3.y };Point vt1 = { p3.x - p1.x, p3.y - p1.y }, vt2 = { p4.x - p1.x, p4.y - p1.y };double s1v2, s2v2, t1v1, t2v1;//根据外积结果判定否交于线上if (isEqual(s1v2 = vs1 ^ v2, 0) && p4 > p1 && p1 > p3) {point = p1;return 2;}if (isEqual(s2v2 = vs2 ^ v2, 0) && p4 > p2 && p2 > p3) {point = p2;return 2;}if (isEqual(t1v1 = vt1 ^ v1, 0) && p2 > p3 && p3 > p1) {point = p3;return 2;}if (isEqual(t2v1 = vt2 ^ v1, 0) && p2 > p4 && p4 > p1) {point = p4;return 2;} //未交于线上,则判定是否相交if (s1v2 * s2v2 > 0 || t1v1 * t2v1 > 0) {return 0;} //以下为相交的情况,算法详见文档  //计算二阶行列式的两个常数项double ConA = p1.x * v1.y - p1.y * v1.x;double ConB = p3.x * v2.y - p3.y * v2.x;//计算行列式D1和D2的值,除以系数行列式的值,得到交点坐标point.x = (ConB * v1.x - ConA * v2.x) / Cross;point.y = (ConB * v1.y - ConA * v2.y) / Cross;//正交返回1return 1;}bool in(const double &value,const double &lower_bound,const double&higher_bound){if (value-lower_bound>eps&&higher_bound-value>eps){return true;}return false;}//主函数int main() {//freopen("input.txt", "r", stdin);  //freopen("output.txt", "w", stdout); int n;while (cin >> n){while (n--){double x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;double left, top, right, bottom; cin >> left >> top >> right >> bottom;if (left > right) swap(left, right);if (bottom > top) swap(bottom, top);if ((in(x1,left,right)&&in(y1,bottom,top))||(in(y2,bottom,top) && in(x2, left, right))){cout << 'T' << endl;continue;}else{vector<double>rectangle;rectangle.push_back(left);rectangle.push_back(top);rectangle.push_back(right);rectangle.push_back(bottom);bool flag = false;for (int i = 0; i < 4; i++){Point point;int type = Intersection({ x1,y1 }, { x2,y2 }, { rectangle[i % 4],rectangle[(i + 1) % 4] }, { rectangle[(i + 1) % 4] ,rectangle[(i + 2) % 4] }, point);if (type>0){cout << 'T' << endl;flag = true;break;}}if (!flag){cout << 'F' << endl;}}}}return 0;}




0 0
原创粉丝点击