写了三天的半平面交总觉得自己姿势有问题。。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define eps 1e-8
using namespace std;
struct Point {
double x, y;
Point(double _x = 0. , double _y = 0. ) : x(_x), y(_y) {};
}Ext[65];
struct Vector {
Point s, e;
double k, d; // 极角 截距
}V[65];
int tot = 0;
inline int dcmp(double x) { if (x < -eps) return -1; return x > eps; }
inline double Cross(double x1, double y1, double x2, double y2)
{
return x1 * y2 - x2 * y1;
}
inline double Cross(Point O, Point A, Point B)
{ // 向量 OA 与 OB 的叉积
return (A.x - O.x) * (B.y - O.y) - (B.x - O.x) * (A.y - O.y);
}
inline void SetLine(double x1, double y1, double x2, double y2, Vector &v)
{ // 向量左边为有效平面
v.s = Point(x1, y1); v.e = Point(x2, y2);
v.k = atan2(y2 - y1, x2 - x1);
if (dcmp(x1 - x2)) v.d = Cross(x1, y1, x2, y2) / fabs(x1 - x2);
else v.d = Cross(x1, y1, x2, y2) / fabs(y1 - y2);
}
inline Point Revolve(double cosA, double sinA, Point A, Point B)
{ // 将向量 AB 逆时针旋转角度A
Point B_;
B_.x = (B.x - A.x) * cosA - (B.y - A.y) * sinA + A.x;
B_.y = (B.x - A.x) * sinA + (B.y - A.y) * cosA + A.y;
return B_;
}
inline bool VecCmp(const Vector &a,const Vector &b)
{
if (dcmp(a.k - b.k)) return a.k < b.k;
return a.d < b.d;
}
inline bool Parallel(Vector a, Vector b)
{ // 向量平行
double u = Cross(a.s.x - a.e.x, a.s.y - a.e.y, b.s.x - b.e.x, b.s.y - b.e.y);
return !dcmp(u);
}
Point CrossPoint(Vector a, Vector b)
{ // 向量求交点
Point res;
double u = Cross(a.s, a.e, b.s), v = Cross(a.e, a.s, b.e);
res.x = (b.s.x * v + b.e.x * u) / (u + v);
res.y = (b.s.y * v + b.e.y * u) / (u + v);
return res;
}
inline bool EqualPoint(Point &a, Point &b)
{
return !dcmp(a.x - b.x) && !dcmp(a.y - b.y);
}
Vector deq[65];
void HalfPanelCross(Vector *v, int &N, Point *p, int &M)
{
sort(v, v + N, VecCmp); int tn = 1; M = 0;
for (int i = 1; i < N; ++ i) {
if (dcmp(v[i].k - v[i - 1].k)) v[tn ++] = v[i];
}
N = tn; if (N < 3) return;
deq[0] = v[0]; deq[1] = v[1];
int head = 0, tail = 1;
for (int i = 2; i < N; ++ i) {
if (Parallel(deq[tail], deq[tail - 1]) || Parallel(deq[head], deq[head + 1])) return;
while ( head < tail && dcmp( Cross(v[i].s, v[i].e, CrossPoint(deq[tail], deq[tail - 1])) ) < 0 ) -- tail;
while ( head < tail && dcmp( Cross(v[i].s, v[i].e, CrossPoint(deq[head], deq[head + 1])) ) < 0 ) ++ head;
deq[++ tail] = v[i];
}
while ( head < tail && dcmp( Cross(deq[head].s, deq[head].e, CrossPoint(deq[tail], deq[tail - 1])) ) < 0 ) -- tail;
while ( head < tail && dcmp( Cross(deq[tail].s, deq[tail].e, CrossPoint(deq[head], deq[head + 1])) ) < 0 ) ++ head;
if (tail < head + 1) return;
for (int i = head; i < tail; ++ i) {
p[M ++] = CrossPoint(deq[i], deq[i + 1]);
}
p[M ++] = CrossPoint(deq[tail], deq[head]);
M = (int)(unique(p, p + M, EqualPoint) - p);
}
double PolygonArea(Point *p, int M)
{
double S = p[0].y * (p[M - 1].x - p[1].x);
for (int i = 1; i < M; ++ i) {
S += p[i].y * (p[i - 1].x - p[(i + 1) % M].x);
}
return fabs(S * 0.5);
}
int main()
{
SetLine(0. , 0. , 10. , 0. , V[tot ++]);
SetLine(0. , 10. , 0. , 0. , V[tot ++]);
SetLine(10. , 10. , 0. , 10. , V[tot ++]);
SetLine(10. , 0. , 10. , 10. , V[tot ++]);
Point Last = Point(0. , 0.), Next, Mid, Temp;
string s; int CntLine = 0;
ios :: sync_with_stdio(false); bool flag = 0;
while (cin >> Next.x >> Next.y >> s) {
if (s == "Same" || flag) { flag = 1; printf("0.00\n"); continue; }
Mid = Point((Last.x + Next.x) * 0.5, (Last.y + Next.y) * 0.5);
if (s == "Colder") Temp = Revolve(0. , 1. , Mid, Next);
else if (s == "Hotter")Temp = Revolve(0. , -1. , Mid, Next);
SetLine(Mid.x, Mid.y, Temp.x, Temp.y, V[tot ++]);
HalfPanelCross(V, tot, Ext, CntLine);
if (CntLine < 3) { flag = 1; printf("0.00\n"); }
else printf("%.2f\n", PolygonArea(Ext, CntLine));
Last = Next;
}
return 0;
}