在一个简单多边形内有一个灯泡,问灯泡能够照到的面积。我是看了封尘记忆的blog的,大概理解了。
主要看这个图,然后和代码结合起来看。。多边形是ABCDE,因为EA边跨过了x轴负半轴,所以多添加一个在负半轴上的点M。扫描线扫过去阴影部分面积答案加起来就好了。
扫描线有一条入点和一个出点,point里面有重载小于号,是保证入点的极角小于出点的极角。seg重载小于号,新插入的线段必须得跟已经插入的线段,按照到原点的距离排序。然后就是用multiset。。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
using namespace std;
#define LL long long
#define eps 1e-8
#define inf 0x3f3f3f3f
#define Pi acos( -1.0 )
#define pb push_back
#define mnx 60100
#define mxn 200
int dcmp( double x ){
if( fabs( x ) < eps ) return 0;
return x < 0 ? -1 : 1;
}
struct point{
double x, y, ang;
point( double x = 0, double y = 0 ) : x(x), y(y) {
ang = atan2( y, 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 * ( const double &k ) const{
return point( x * k, y * k );
}
point operator / ( const double &k ) const{
return point( x / k, y / k );
}
bool operator < ( const point &b ) const{
return ang > b.ang;
}
bool operator == ( const point &b ) const{
return dcmp( x - b.x ) == 0 && dcmp( y - b.y ) == 0;
}
double len(){
return sqrt( x * x + y * y );
}
};
typedef point Vector;
double dot( Vector a, Vector b ){
return a.x * b.x + a.y * b.y;
}
double cross( Vector a, Vector b ){
return a.x * b.y - a.y * b.x;
}
point get_intersection( point au, point av, point bu, point bv ){
Vector u = au - bu, aV = av - au, bV = bv - bu;
double t = cross( bV, u ) / cross( aV, bV );
return au + aV * t;
}
const point o = point( 0, 0 );
point base;
struct Seg{
point u, v;
int id, in;
double ang;
Seg(){}
Seg( point u, point v, int in, int id, double ang ) : u(u), v(v), in(in), id(id), ang(ang) {}
bool operator < ( const Seg &b ) const {
if( u == b.u ){
return cross( v - u, b.v - u ) < 0;
}
point aa = get_intersection( u, v, o, base );
point bb = get_intersection( b.u, b.v, o, base );
return aa.len() < bb.len();
}
}L[mnx<<1];
bool cmp( const Seg &a, const Seg &b ){
return a.ang < b.ang || ( a.ang == b.ang && a.in > b.in );
}
int n, all;
point p[mnx];
void add( point a, point b, int kk ){
if( a < b ) swap( a, b );
L[all++] = Seg( a, b, 1, kk, a.ang );
L[all++] = Seg( b, a, 0, kk, b.ang );
}
double cal( const Seg &seg, double pre, double now ){
point aa = get_intersection( seg.u, seg.v, o, point( cos(pre), sin(pre) ) );
point bb = get_intersection( seg.u, seg.v, o, point( cos(now), sin(now) ) );
return fabs( 0.5 * cross( aa, bb ) );
}
multiset<Seg> S;
multiset<Seg>::iterator itArr[mnx<<1];
void solve(){
S.clear();
double ans = 0, pre = -Pi;
for( int i = 0; i < all; ++i ){
double nowAng = L[i].ang;
base = L[i].u;
if( L[i].in ){
if( !S.empty() )
ans += cal( *S.begin(), pre, nowAng );
itArr[L[i].id] = S.insert( L[i] );
}
else{
ans += cal( *S.begin(), pre, nowAng );
S.erase( itArr[L[i].id] );
}
pre = nowAng;
}
printf( "%.10lf\n", ans );
}
int main(){
//freopen( "out.txt", "w", stdout );
point c;
while( scanf( "%lf%lf", &c.x, &c.y ) != EOF ){
scanf( "%d", &n );
for( int i = 0; i < n; ++i ){
scanf( "%lf%lf", &p[i].x, &p[i].y );
p[i] = p[i] - c, p[i].ang = atan2( p[i].y, p[i].x );
}
p[n] = p[0];
all = 0;
for( int i = 0, k = 0; i < n; ++i ){
double d = fabs( p[i+1].ang - p[i].ang );
if( d < Pi )
add( p[i], p[i+1], k++ );
else{
point tmp = get_intersection( p[i], p[i+1], o, point( -1.0, 0 ) );
tmp.ang = Pi * dcmp( p[i].ang );
add( p[i], tmp, k++ );
tmp.ang = Pi * dcmp( p[i+1].ang );
add( tmp, p[i+1], k++ );
}
}
sort( L, L + all, cmp );
solve();
}
return 0;
}