欧拉公式 和 计算几何模板

欧拉公式

学习向量旋转的时候用到的,在百度知道查到了公式的证明过程,做个记录。

证明过程

\(y=e^x,y=\sin x,y=\cos x\)用幂级数展开,有

\[e^x=\exp(x)=1+{x}+\frac{x^2}{2!}+\frac{x^3}{3!}+\frac{x^4}{4!}+\dots+\frac{x^n}{n}+\dots \\ \sin x=x-\frac{x^3}{3!}+\frac{x^5}{5!}-\frac{x^7}{7!}+\dots+(-1)^{k-1}\frac{x^{2k-1}}{(2k-1)!}+\dots \\ \cos x=1-\frac{x^2}{2!}+\frac{x^4}{4!}-\frac{x^6}{6!}+\dots+(-1)^k\frac{x^{2k}}{(2k)!}+\dots \]

将式中的\(x\)换为\(ix\),就得到了

\[e^{ix}=\cos x+i \sin x \]

将等式里的\(x\)替换为\(-x\),得到

\[e^{-ix}=\cos x-i \sin x \]

然后采用两式相加减的方法得到

\[\sin x=\frac{e^{ix}-e^{-ix}}{2i} \\ \cos x=\frac{e^{ix}+e^{-ix}}{2} \\ \tan x=\frac{e^{ix}-e^{-ix}}{ie^{ix}+ie^{-ix}} \]

此时三角函数定义域已推广至整个复数集。

辅助内容

幂级数

\[c_0+c_1x+c_2x^2+\dots+c_nx^n+\dots=\sum_{n=0}^{\infty}c_nx^n \\ c_0+c_1(x-a)+c_2(x-a)^2+\dots+c_n(x-a)^n+\dots=\sum_{n=0}^{\infty}c_n(x-a)^n \]

他们的各项都是正整数幂的幂级数,其中\(c_0,c_1,\dots,c_n,\dots\)以及\(a\)都是常数,这种级数称为幂级数。

泰勒展开式(幂级数展开法)

\[f(x)=f(a)+f'(a)(x-a)+\frac{f''(a)}{2!}(x-a)^2+\dots+\frac{f^{(n)}(a)}{n!}(x-a)^n+R_n(x) \]

实用幂级数

\[e^x=1+x+\frac{x^2}{2!}+\frac{x^3}{3!}+\dots+\frac{x^n}{n!}+\dots \\ \ln(x+1)=x-\frac{x^2}{2}+\frac{x^3}{3}+\dots+(-1)^{n-1}\frac{x^n}{n}+\dots \]

向量基础

const double eps=1e-10;
int dcmp(double x)
{
    if(fabs(x)<eps)
        return 0;
    else
        return x<0?-1:1;
}

struct Point
{
    double x,y;
    
	Point(double x=0,double y=0)
    :x(x),y(y){}
    
    bool operator<(co Point&rhs)co // edit 1
    {
        return dcmp(x-rhs.x)?x<rhs.x:y<rhs.y;
    }
    
    bool operator==(co Point&rhs)co
    {
        return dcmp(x-rhs.x)==0&&dcmp(y-rhs.y)==0;
    }
    
    double angle()
    {
    	return atan2(y,x);
	}
};
typedef Point Vector;

Vector operator+(Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}

Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}

Vector operator*(Vector A,double p) 
{
    return Vector(A.x*p,A.y*p);
}

Vector operator/(Vector A,double p)
{
    return Vector(A.x/p,A.y/p);
}

double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}

double Length(Vector A)
{
    return sqrt(Dot(A,A));
}

double Angle(Vector A,Vector B)
{
    return acos(Dot(A,B)/Length(A)/Length(B));
}

double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

double Area2(Point A,Point B,Point C)
{
    return Cross(B-A,C-A);
}

Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}

Vector Normal(Vector A)
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}

Point LineLineIntersection(Point P,Vector v,Point Q,Vector w)
{
    Vector u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}

double DistanceToLine(Point P,Point A,Point B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2))/Length(v1);
}

double DistanceToSegment(Point P,Point A,Point B)
{
    if(A==B)
        return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0)
        return Length(v2);
    if(dcmp(Dot(v1,v3))>0)
        return Length(v3);
    return DistanceToLine(P,A,B);
}

Point PointLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));
}

bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
            c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}

bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}

double PolygonArea(Point*p,int n)
{
    double area=0;
    for(int i=1;i<n-1;++i)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2;
}

凸包(水平序)

\(x\)排序后始终找前进方向右边的点,用个栈维护,上凸壳下凸壳分别做一遍。

时间复杂度是排序的\(O(n \log n)\)

动图

int ConvexHull(Point*p,int n,Point*ch)
{
	sort(p,p+n);
	int m=0;
	for(int i=0;i<n;++i)
	{
		while(m>1&&dcmp(Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0)
			--m;
		ch[m++]=p[i];
	}
	int k=m;
	for(int i=n-2;i>=0;--i)
	{
		while(m>k&&dcmp(Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0)
			--m;
		ch[m++]=p[i];
	}
	if(n>1)
		m--;
	return m;
}

半平面交

atan2(y,x)的值域是\((-\pi,\pi]\),返回相当于\(x+yi\)的幅角。

半平面交维护的是点集,用双端队列维护。时间复杂度为排序的\(O(n \log n)\)

struct Line
{
	Point P;
	Vector v;
	
	Line(Point P=0,Vector v=0)
	:P(P),v(v){}
	
	double angle()co
	{
		return atan2(v.y,v.x);
	}
	
	bool operator<(co Line&rhs)co
	{
		return angle()<rhs.angle();
	}
};

bool OnLeft(co Line&L,co Point&p)
{
	return Cross(L.v,p-L.P)>0;
}

Point LineLineIntersection(co Line&a,co Line&b)
{
	Vector u=a.P-b.P;
	double t=Cross(b.v,u)/Cross(a.v,b.v);
	return a.P+a.v*t;
}

co double INF=1e8;
co double eps=1e-6;

vector<Point>HalfplaneIntersection(vector<Line>L)
{
	int n=L.size();
	sort(L.begin(),L.end());
	
	int first,last;
	vector<Point>p(n);
	vector<Line>q(n);
	vector<Point>ans;
	
	q[first=last=0]=L[0];
	for(int i=1;i<n;++i)
	{
		while(first<last&&!OnLeft(L[i],p[last-1]))
			--last;
		while(first<last&&!OnLeft(L[i],p[first]))
			++first;
		q[++last]=L[i];
		if(fabs(Cross(q[last].v,q[last-1].v))<eps)
		{
			--last;
			if(OnLeft(q[last],L[i].P))
				q[last]=L[i];
		}
		if(first<last)
			p[last-1]=LineLineIntersection(q[last-1],q[last]);
	}
	while(first<last&&!OnLeft(q[first],p[last-1]))
		--last;
	if(last-first<=1)
		return ans;
	p[last]=LineLineIntersection(q[last],q[first]);
	
	for(int i=first;i<=last;++i)
		ans.push_back(p[i]);
	return ans;
}

struct Circle
{
	Point c;
	double r;
	
	Circle(Point c=0,double r=0)
	:c(c),r(r){}
	
	Point point(double a)
	{
		return Point(c.x+cos(a)*r,c.y+sin(a)*r);
	}
};

int LineCircleIntersection(Line L,Circle C,double&t1,double&t2,vector<Point>&sol)
{
	double a=L.v.x,b=L.p.x-C.c.x,c=L.v.y,d=L.p.y-C.c.y;
	double e=a*a+c*c,f=2*(a*b+c*d),g=b*b+d*d-C.r*C.r;
	double delta=f*f-4*e*g;
	if(dcmp(delta)<0)
		return 0;
	if(dcmp(delta)==0)
	{
		t1=t2=-f/(2*e);
		sol.push_back(L.point(t1));
		return 1;
	}
	t1=(-f-sqrt(delta))/(2*e);
	t2=(-f+sqrt(delta))/(2*e);
	sol.push_back(L.point(t1));
	sol.push_back(L.point(t2));
	return 2;
}

int CircleCircleIntersection(Circle C1,Circle C2,vector<Point>&sol)
{
	double d=Length(C1.c-C2.c);
	if(dcmp(d)==0)
	{
		if(dcmp(C1.r-C2.r)==0)
			return -1;
		return 0;
	}
	if(dcmp(C1.r+C2.r-d)<0)
		return 0;
	if(dcmp(fabs(C1.r-C2.r)-d)>0)
		return 0;
	
	double a=(C2.c-C1.c).angle();
	double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
	Point p1=C1.point(a-da),p2=C1.point(a+da);
	
	sol.push_back(p1);
	if(p1==p2)
		return 1;
	sol.push_back(p2);
	return 2;
}

co double PI=acos(-1);

int PointCircleTangent(Point p,Circle C,vector<Vector>&sol)
{
	Vector u=C.c-p;
	double dist=Length(u);
	if(dcmp(dist-C.r)<0)
		return 0;
	if(dcmp(dist-C.r)==0)
	{
		sol.push_back(Rotate(u,PI/2));
		return 1;
	}
	double ang=asin(C.r/dist);
	sol.push_back(Rotate(u,-ang));
	sol.push_back(Rotate(u,ang));
	return 2;
}

int CircleCircleTangent(Circle A,Circle B,vector<pair<Point,Point> >&sol)
{
	int cnt=0;
	if(dcmp(A.r-B.r)<0) // notice the result here
		swap(A,B);
	double d=Length(A.c-B.c);
	double rdiff=A.r-B.r;
	double rsum=A.r+B.r;
	if(dcmp(d-rdiff)<0)
		return 0;
	
	double base=(B.c-A.c).angle();
	if(dcmp(d)==0&&dcmp(A.r-B.r)==0)
		return -1;
	if(dcmp(d-rdiff)==0)
	{
		sol.push_back(make_pair(A.point(base),B.point(base)));
		++cnt;
		return 1;
	}
	
	double ang=acos((A.r-B.r)/d);
	sol.push_back(make_pair(A.point(base+ang),B.point(base+ang)));
	++cnt;
	sol.push_back(make_pair(A.point(base-ang),B.point(base-ang)));
	++cnt;
	if(dcmp(d-rsum)==0)
	{
		sol.push_back(make_pair(A.point(base),B.point(base+PI)));
		++cnt;
	}
	else if(dcmp(d-rsum)>0)
	{
		double ang=acos((A.r+B.r)/d);
		sol.push_back(make_pair(A.point(base+ang),B.point(base+ang+PI)));
		++cnt;
		sol.push_back(make_pair(A.point(base-ang),B.point(base-ang+PI)));
		++cnt;
	}
	return cnt;
}

posted on 2018-12-15 13:51  autoint  阅读(1030)  评论(0)    收藏  举报

导航