题意:给出矩形的长和宽,该矩形中心点在(0,0).
问将矩形逆时针旋转a度以后,和原先矩形的重叠面积?
先求出旋转后的四个顶点.可以得到4条直线.
求出这4条直线和原先矩形的交点.
这些交点构成组成的凸多边形显然就是重叠的部分.
将交点极角排序后,利用叉积求出面积可.注意斜率为0时特判一下.
#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
typedef pair<ld,ld> ii;
const int N=2e3+5;
const ld pi=acos(-1.0);
ld w,h,a,X,Y;
ld x[N],y[N];
ld getx(ld x,ld y)
{
return x*cos(a)-y*sin(a);
}
ld gety(ld x,ld y)
{
return x*sin(a)+y*cos(a);
}
void init()
{
a*=pi/180.0;
X=w/2.0,Y=h/2.0;
x[1]=getx(-X,Y),y[1]=gety(-X,Y);
x[2]=getx(-X,-Y),y[2]=gety(-X,-Y);
x[3]=getx(X,-Y),y[3]=gety(X,-Y);
x[4]=getx(X,Y),y[4]=gety(X,Y);
}
struct node{
ld x,y;
node(){}
node(ld a,ld b){
x=a,y=b;
}
}p[N];
node operator-(const node&v1,const node&v2){
return node(v2.x-v1.x,v2.y-v1.y);
}
ld product(node a,node b){
return a.x*b.y-a.y*b.x;
}
map<ii,int> mp;
int cnt=0;
bool check(ld x,ld y)
{
if(mp[ii(x,y)])
return false;
return x>=-X&&x<=X&&y<=Y&&y>=-Y;
}
bool cmp(node a,node b)
{
if(atan2(a.y,a.x)!=atan2(b.y,b.x))
return atan2(a.y,a.x)<atan2(b.y,b.x);
return a.x<b.x;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>w>>h>>a;
if(a==0||a==180)
{
ld res=w*h;
cout<<fixed<<setprecision(15)<<res<<'\n';
return 0;
}
init();
for(int i=1;i<=4;i++)
{
int j=(i==4?1:i+1);
if(x[j]==x[i]) continue;
ld k=(y[j]-y[i])/(x[j]-x[i]);
//y-y[i]=k(x-x[i]).
for(int o1=0;o1<2;o1++)
{
for(int o2=0;o2<2;o2++)
{
ld rx=X,ry=Y;
if(o1==0) rx=-rx;
if(o2==0) ry=-ry;
ld nx=(ry-y[i]+k*x[i])/k,ny=k*(rx-x[i])+y[i];
if(check(nx,ry))
p[++cnt]=node(nx,ry),mp[ii(nx,ry)]=true;
if(check(rx,ny))
p[++cnt]=node(rx,ny),mp[ii(rx,ny)]=true;
}
}
}
sort(p+1,p+1+cnt,cmp);
// for(int i=1;i<=cnt;i++)
// cout<<p[i].x<<' '<<p[i].y<<'\n';
ld res=0;
for(int i=2;i<cnt;i++)
{
node p1=p[i]-p[1],p2=p[i+1]-p[1];
res+=fabs(product(p1,p2));
}
res/=2.0;
cout<<fixed<<setprecision(15)<<res<<'\n';
return 0;
}
标程的解法: 只有两种情况:一种是平行四边形,一种利用对称性和相似来考虑.
#include<iostream>
#include<math.h>
#include<stdio.h>
using namespace std;
const double pi = acos(-1.0);
int main()
{
double w,h,t;cin>>w>>h>>t;
if(w<h)swap(w,h);
if(t>=90)t=180-t;
t=t*pi/180;
double x1,y1,x2,y2;
y2 = (h-tan(t)*w/(1+1.0/cos(t)))/(1+1/cos(t)-tan(t)*tan(t)/(1+1/cos(t)));
x2 = tan(t)*y2;
y1 = (w-y2*tan(t))/(1+1/cos(t));
x1 = y1*tan(t);
//cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
//cout<<tan(t)<<endl;
if(tan(t/2)<h/w)
{
double ans = w*h - x1*y1 - x2*y2;
printf("%.16f\n",ans);
}
else
{
double x = h / sin(t);
printf("%.10f\n",w*h-(w-x)*h);
}
}
极角排序是根据坐标系内每一个点与x轴所成的角,逆时针比较,。按照角度从小到大的方式排序。