您的位置:首页 > 其它

HDU 1154 (平面几何 点在多边形内)

2016-06-22 22:12 323 查看

题目链接:点击这里

题意:求一条直线在多边形内部的长度.

找到所有的交点, 去重以后是直线上的一系列的点. 然后相邻两个点构成的线段如果是多边形内部的或者多边形上的那就加上这个长度. 判断相邻点构成的线段是不是需要加上只需要判断中点在不在多边形内部(边界)就好了.

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

const double eps = 1e-8;
const double INF = 1e20;
const double pi = acos (-1.0);

int dcmp (double x) {
if (fabs (x) < eps) return 0;
return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}

//*************点
struct Point {
double x, y;
Point (double _x = 0, double _y = 0):x(_x), y(_y) {}
void input () {scanf ("%lf%lf", &x, &y);}
void output () {printf ("%.2f %.2f\n", x, y);}
bool operator == (const Point &b) const {
return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
}
bool operator < (const Point &b) const {
return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
}
Point operator + (const Point &b) const {
return Point (x+b.x, y+b.y);
}
Point operator - (const Point &b) const {
return Point (x-b.x, y-b.y);
}
Point operator * (double a) {
return Point (x*a, y*a);
}
Point operator / (double a) {
return Point (x/a, y/a);
}
double len2 () {//返回长度的平方
return sqr (x) + sqr (y);
}
double len () {//返回长度
return sqrt (len2 ());
}
};

double cross (Point a, Point b) {//叉积

return a.x*b.y-a.y*b.x;
}
double dot (Point a, Point b) {//点积

return a.x*b.x + a.y*b.y;
}
double dis (Point a, Point b) {//两个点的距离

Point p = b-a; return p.len ();
}
double rad_degree (double rad) {//弧度转化为角度

return rad/pi*180;
}
double rad (Point a, Point b) {//两个向量的夹角

return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) );
}
bool parallel (Point a, Point b) {//向量平行
double p = rad (a, b);
return dcmp (p) == 0 || dcmp (p-pi) == 0;
}

//************直线 线段
struct Line {
Point s, e;//直线的两个点
Line () {}
Line (Point _s, Point _e) : s(_s), e(_e) {}
//一个点和倾斜角确定直线
Line (Point p, double ang) {
s = p;
if (dcmp (ang-pi/2) == 0) {
e = s + Point (0, 1);
}
else
e = s + Point (1, tan (ang));
}
//ax+by+c=0确定直线
Line (double a, double b, double c) {
if (dcmp (a) == 0) {
s = Point (0, -c/b);
e = Point (1, -c/b);
}
else if (dcmp (b) == 0) {
s = Point (-c/a, 0);
e = Point (-c/a, 1);
}
else {
s = Point (0, -c/b);
e = Point (1, (-c-a)/b);
}
}
void input () {
s.input ();
e.input ();
}
};

int relation (Point p, Line l) {//点和直线的关系
//1:在左侧 2:在右侧 3:在直线上
int c = dcmp (cross (p-l.s, l.e-l.s));
if (c < 0) return 1;
else if (c > 0) return 2;
else return 3;
}

bool point_on_seg (Point p, Line l) {//判断点在线段上
return dcmp (cross (p-l.s, l.e-l.s)) == 0 &&
dcmp (dot (p-l.s, p-l.e) <= 0);
//如果忽略端点交点改成小于号就好了
}

bool parallel (Line a, Line b) {//直线平行
return parallel (a.e-a.s, b.e-b.s);
}

int seg_cross_seg (Line a, Line v) {//线段相交判断
//2:规范相交 1:不规范相交 0:不相交
int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
int d3 = dcmp (cross (v.e-v.s, a.s-v.s));
int d4 = dcmp (cross (v.e-v.s, a.e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1 == 0 && dcmp (dot (v.s-a.s, v.s-a.e)) <= 0) ||
(d2 == 0 && dcmp (dot (v.e-a.s, v.e-a.e)) <= 0) ||
(d3 == 0 && dcmp (dot (a.s-v.s, a.s-v.e)) <= 0) ||
(d4 == 0 && dcmp (dot (a.e-v.s, a.e-v.e)) <= 0);
}

int line_cross_seg (Line a, Line v) {//直线和线段相交判断 a直线v线段
//2:规范相交 1:非规范相交 0:不相交
int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
if ((d1^d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}

int line_cross_line (Line a, Line v) {//直线相交判断
//0:平行 1:重合 2:相交
if (parallel (a, v)) return relation (a.e, v) == 3;
return 2;
}

Point line_intersection (Line a, Line v) {//直线交点
//调用前确保有交点
double a1 = cross (v.e-v.s, a.s-v.s);
double a2 = cross (v.e-v.s, a.e-v.s);
return Point ((a.s.x*a2-a.e.x*a1)/(a2-a1), (a.s.y*a2-a.e.y*a1)/(a2-a1));
}

bool relation (Point q, Point *p, int n) {//点和多边形的关系(凸凹都可以)
//0:外部 1:内部 2:边上 3:顶点
for (int i = 0; i < n; i++) {
if (p[i] == q)
return 3;
}
for (int i = 0; i < n; i++) {
if (point_on_seg (q, Line (p[i], p[(i+1)%n])))
return 2;
}
int cnt = 0;
for (int i = 0; i < n; i++) {
int j = (i+1)%n;
int k = dcmp (cross (q-p[j], p[i]-p[j]));
int u = dcmp (p[i].y-q.y);
int v = dcmp (p[j].y-q.y);
if (k > 0 && u < 0 && v >= 0) cnt++;
if (k < 0 && v < 0 && u >= 0) cnt--;
}
return cnt != 0;
}

#define maxn 11111
int n, m;
Point p[maxn], q[maxn], ans[maxn];
Line l[maxn];
int cnt;

int main () {
while (scanf ("%d%d", &n, &m) == 2 && n+m) {
for (int i = 0; i < n; i++) {
p[i].input ();
}
while (m--) {
Line l; l.input ();
cnt = 0;
double res = 0;
for (int i = 0; i < n; i++) {
int j = (i+1)%n;
int cur = 0;
if (relation (p[i], l) == 3) ans[cnt++] = p[i], cur++;
if (relation (p[j], l) == 3) ans[cnt++] = p[j], cur++;
if (line_cross_seg (l, Line (p[j], p[i])) == 2) {
Point pp = line_intersection (l, Line (p[j], p[i]));
ans[cnt++] = pp;
}
}
sort (ans, ans+cnt);
int cur = 0;
for (int i = 0; i < cnt; i++) {
if (i && ans[i] == ans[i-1]) continue;
else ans[cur++] = ans[i];
} cnt = cur;
for (int i = 0; i < cnt-1; i++) {
int j = i+1;
if (relation ((ans[i]+ans[j])/2, p, n))
res += dis (ans[i], ans[j]);
}
printf ("%.3f\n", res);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: