码迷,mamicode.com
首页 > 其他好文 > 详细

uva 12296(切割凸多边形)

时间:2015-07-31 10:43:46      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:

题意:有一个长l宽w的矩形,左下角坐标是(0,0),现在有n条线段把这个矩形切割,保证每条线段的两个端点落在矩形不同的边上,把矩形分成了若干区域,现在有m个圆画进矩形,问圆覆盖了哪些区域,并把这些区域的面积排序输出。
题解:先要切割矩形,方法是每读入一条线段都拿去处理切割出的新的区域把原先的区域替换,最后可以得到一个区域的vector,然后判断圆和区域的情况:
1.如果圆没有公共点,可以是圆在某个区域内,或某些区域在圆内。这时需要判断多边形是否有顶点在圆内,或圆心是否在那个多边形内。
2.判断圆和每个区域的交点,如果是线段两个端点在圆上,就用线段中点判断是否在圆内。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const double PI = acos(-1);
const double eps = 1e-9;
struct Point {
    double x, y;
    Point(double x = 0, double y = 0): x(x), y(y) {}
};
typedef Point Vector;
typedef vector<Point> Polygon;
struct Circle {
    Point c;
    double r;
    Circle() {}
    Circle(Point c, double r = 0): c(c), r(r) {}
    Point point(double a) {
        return Point(c.x + cos(a) * r, c.y + sin(a) * c.y);
    }
};
double Sqr(double x) {
    return x * x;
}
double dcmp(double x) {
    if (fabs(x) < eps)
        return 0;
    return x < 0 ? -1 : 1;
}
Vector operator + (const Point& A, const Point& B) {
    return Vector(A.x + B.x, A.y + B.y);
}
Vector operator - (const Point& A, const Point& B) {
    return Vector(A.x - B.x, A.y - B.y);
}
Vector operator * (const Point& A, double a) {
    return Vector(A.x * a, A.y * a);
}
Vector operator / (const Point& A, double a) {
    return Vector(A.x / a, A.y / a);
}
double Cross(const Vector& A, const Vector& B) {
    return A.x * B.y - A.y * B.x;
}
double Dot(const Vector& A, const Vector& B) {
    return A.x * B.x + A.y * B.y;
}
double Length(const Vector& A) {
    return sqrt(Dot(A, A));
}
bool operator < (const Point& A, const Point& B) {
    return A.x < B.x || (A.x == B.x && A.y < B.y);
}
bool operator == (const Point& A, const Point& B) {
    return A.x == B.x && A.y == B.y;
}

//向量A旋转rad弧度,rad负值为顺时针旋转
Point Rotate(Point A, double rad) {
    return Point(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}
//角度转化弧度
double torad(double deg) {
    return deg / 180.0 * PI;
}
//得到两直线交点 
Point GetLineIntersection(Point P, Point v, Point Q, Point w) {
    Point u = P - Q;
    double t = Cross(w, u) / Cross(v, w);
    return P + v * t;
}
//点p到线段AB的距离
double DistanceToSegment(Point p, Point A, Point B) {
    if (A == B)
        return Length(p - A);
    Point AB = B - A, AP = p - A, BP = p - B;
    if (dcmp(Dot(AB, AP)) < 0)
        return Length(AP);
    else if (dcmp(Dot(AB, BP)) > 0)
        return Length(BP);
    else
        return fabs(Cross(AB, AP)) / Length(AB);
}
//判断两个线段是否有交点(不包括端点)
bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
    double c1 = Cross(a2 - a1, b1 - a1);
    double c2 = Cross(a2 - a1, b2 - a1);
    double c3 = Cross(b2 - b1, a1 - b1);
    double c4 = Cross(b2 - b1, a2 - b1);
    return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}
//判断点p是否在线段a1--a2上(不包括端点)
bool OnSegment(const Point& p, const Point& a1, const Point& a2) {
    return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}
//求多边形面积
double PolygonArea(Polygon res) {
    double area = 0;
    int m = res.size();
    for (int i = 1; i < m - 1; i++)
        area += Cross(res[i] - res[0], res[i + 1] - res[0]);
    return area / 2;
}
bool isPointInPolygon(Point p, Polygon res) {
    int wn = 0, cnt = res.size();
    for (int i = 0; i < cnt; i++) {
        if (res[i] == p || res[(i + 1) % cnt] == p || OnSegment(p, res[i], res[(i + 1) % cnt]))
            return 1;//边界上
        int k = dcmp(Cross(res[(i + 1) % cnt] - res[i], p - res[i]));
        int d1 = dcmp(res[i].y - p.y);
        int d2 = dcmp(res[(i + 1) % cnt].y - p.y);
        if (k > 0 && d1 <= 0 && d2 > 0)
            wn++;
        if (k < 0 && d2 <= 0 && d1 > 0)
            wn--;
    }
    if (wn)
        return 1;//内部
    return 0;//外部
}
bool isPointInCircle(Point p, Point center, double r) {
    return dcmp(Length(p - center) - r) < 0;
}
//圆和直线的交点
int GetLineCircleIntersection(Point A, Point B, Point C, double r, double& t1, double& t2) {
    // A --> B 直线  C圆心 r半径
    // {x = x0 + cos(a) * t      y = y0 + sin(a) * t}
    // (A.x + (B.x - A.x)t - C.x)^2 + (A.y + (B.y - A.y)t - C.y)^2 = r * r
    // a * a + c * c --> A     2 * a * b + 2 * c * d --> B   b * b + d * d - r * r --> C
    double a = B.x - A.x;
    double b = A.x - C.x;
    double c = B.y - A.y;
    double d = A.y - C.y;
    double e = a * a + c * c;
    double f = 2 * (a * b + c * d);
    double g = b * b + d * d - r * r;
    double delta = f * f - 4 * e * g;
    if (dcmp(delta) < 0)
        return 0;
    if (dcmp(delta) == 0) {
        t1 = t2 = -f / (2 * e);
        return 1;
    }
    t1 = (-f - sqrt(delta)) / (2 * e);
    t2 = (-f + sqrt(delta)) / (2 * e);
    return 2;
}

bool CircleIntersectionSegment(Point A, Point B, Point C, double r) {
    double t1, t2;//参数
    int cnt = GetLineCircleIntersection(A, B, C, r, t1, t2);
    if (cnt <= 1)
        return false;
    if (dcmp(t1) > 0 && dcmp(t1 - 1) < 0)
        return true;
    if (dcmp(t2) > 0 && dcmp(t2 - 1) < 0)
        return true;
    return false;
}
//切割多边形,返回有向直线A->B左边的多边形
Polygon CutPolygon(Polygon poly, Point A, Point B) {
    Polygon newpoly;
    int n = poly.size();
    for (int i = 0; i < n; i++) {
        Point C = poly[i];
        Point D = poly[(i + 1) % n];
        if (dcmp(Cross(B - A, C - A)) >= 0)
            newpoly.push_back(C);
        if (dcmp(Cross(B - A, C - D)) != 0) {
            Point ip = GetLineIntersection(A, B - A, C, D - C);
            if (OnSegment(ip, C, D))
                newpoly.push_back(ip);
        }
    }
    return newpoly;
}

vector<Polygon> pieces;
int n, m, l, w;

bool DiscIntersectPolygon(Polygon poly, Point p, double r) {
    if (isPointInPolygon(p, poly)) //判断是否圆心在多边形内
        return true;
    if (isPointInCircle(poly[0], p, r)) //判断整个多边形是否在圆内
        return true;
    int cnt = poly.size();
    for (int i = 0; i < cnt; i++) {
        if (CircleIntersectionSegment(poly[i], poly[(i + 1) % cnt], p, r)) //判断线段是否和圆有交点
            return true;
        if (isPointInCircle((poly[i] + poly[(i + 1) % cnt]) * 0.5, p, r)) //判断线段中点是否在圆内
            return true;
    }
    return false;
}

int main() {
    while (scanf("%d%d%d%d", &n, &m, &l, &w) == 4 && n + m + l + w) {
        pieces.clear();
        Polygon ploy;
        ploy.push_back(Point(0, 0));
        ploy.push_back(Point(l, 0));
        ploy.push_back(Point(l, w));
        ploy.push_back(Point(0, w));
        pieces.push_back(ploy);
        double x1, x2, y1, y2;
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            vector<Polygon> temp;
            for (int j = 0; j < pieces.size(); j++) {
                Polygon poly1 = CutPolygon(pieces[j], Point(x1, y1), Point(x2, y2)); //一条线分两个方向划分不同块
                Polygon poly2 = CutPolygon(pieces[j], Point(x2, y2), Point(x1, y1));    
                if (poly1.size() >= 3)
                    temp.push_back(poly1);
                if (poly2.size() >= 3)
                    temp.push_back(poly2);  
            }
            pieces = temp;
        }
        double x, y, r;
        for (int i = 0; i < m; i++) {
            scanf("%lf%lf%lf", &x, &y, &r);
            vector<double> res;
            for (int j = 0; j < pieces.size(); j++)
                if (DiscIntersectPolygon(pieces[j], Point(x, y), r))
                    res.push_back(fabs(PolygonArea(pieces[j])));
            int temp = res.size();
            printf("%d", temp);
            sort(res.begin(), res.end());
            for (int j = 0; j < temp; j++)
                printf(" %.2lf", res[j]);
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

uva 12296(切割凸多边形)

标签:

原文地址:http://blog.csdn.net/hyczms/article/details/47165057

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!