二维几何常用模版(圆)

//用到的一些函数和类 看这里

定义圆的类

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

定义直线的类

struct Line{
     Vector v;
     Point p;
     Line(Vector V,Point P):v(V),p(P){}
     Point point(double t)
     {
         return p + v*t;
     }
};

求圆与直线的交点

方法一 将直线方程带入圆的方程,求解

int Get_Line_Circle_Intersection(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 Get_Line_Circle_Intersection2(Line L,Circle C,double & t1,double &t2,vector<Point> &sol)
{
    Point p = Get_Line_Projection(C.c,L.p,L.p+L.v);
    double distance = Distance_To_Line(C.c,L.p,L.p+L.v);
    if(dcmp(distance-C.r)>0)
       return 0;
    t1 = t2 =(p.x-L.p.x)/L.v.x;
    if(dcmp(distance-C.r)==0)
    {

        sol.push_back(p);
        return 1;
    }
    distance = sqrt(C.r*C.r-distance*distance);
// cout<<2*distance<<endl;
    distance  = distance/Length(L.v);
    t1 -= distance;
    t2 += distance;
// cout<<distance<<endl;
    sol.push_back(p-L.v*distance);
    sol.push_back(p+L.v*distance);
    return 2;
}

过定点求圆的切线

//过定点求圆的切线
int getTangents(Point p,Circle C,Vector *v)
{
    Vector u = C.c-p;
    double dist = Length(u);
    if(dcmp(dist-C.r)==-1)//没有切线,在圆内
        return 0;
    if(dcmp(dist-C.r)==0)//只有一个切线,点在圆上
    {
        v[0] = Rotate(u,pi/2);
        return 1;
    }
    double ang = asin(C.r/dist);
    v[0] = Rotate(u,-ang);
    v[1] = Rotate(u,+ang);
    return 2;
 }

两圆的公切线

 int getTangents(Circle A,Circle B,Point *a,Point *b)
 {
     int cnt = 0;
     if(A.r < B.r)
     {
         swap(A,B);swap(a,b);
     }
     int d2 = pow(A.c.x-B.c.x,2)+pow(A.c.y-B.c.y,2);
     int rdiff = A.r-B.r;
     int rsum = A.r+B.r;
     if(d2 < rdiff*rdiff)
        return 0;//内含

     double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
     if(d2==0&&A.r==B.r)
        return -1;//重合
     if(d2 == rdiff*rdiff)
     {
         a[cnt] = A.point(base);
         b[cnt] = B.point(base);
         cnt++;
         return 1;
     }
     //有外公切线
     double ang = acos((A.r-B.r)/sqrt(d2));
     a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang); cnt++;
     a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang); cnt++;
     if(d2==rsum*rsum)
     {
         a[cnt] = A.point(base);b[cnt] = B.point(pi+base);cnt++;
     }
     else if(d2 > rsum*rsum)
     {
         double ang = acos((A.r+B.r)/sqrt(d2));
         a[cnt] = A.point(base+ang);b[cnt] = B.point(base+ang+pi);cnt++;
         a[cnt] = A.point(base-ang);b[cnt] = B.point(base-ang+pi);cnt++;
     }
     return cnt;
 }

模版

#include <cstdio>//C语言io
#include <cstring>//以下是c语言常用头文件
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>//c++IO
#include <sstream>
#include <string>
#include <list>//c++常用容器
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>//c++泛型的一些函数
#include <functional>//用来提供一些模版
#define fo0(i,n) for(int i = 0;i < n; ++i)
#define fo1(i,n) for(int i = 1;i <= n; ++i)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
//......................................................

struct Point
{

    double x,y;
    Point(double x = 0,double y = 0):x(x),y(y) {}

};
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x + B.x,A.y + B.y);
}
Vector operator - (Vector A,Vector 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);
}
int dcmp(double x)
{
    if(fabs(x)<eps)
        return 0;
    else
        return x < 0?-1:1;
}
bool operator < (const Point &a,const Point &b)
{
    if(dcmp(a.x-b.x)==0)
        return a.y<b.y;
    else
        return a.x<b.x;
}

bool operator == (const Point &a,const Point &b)
{
    return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);
}
double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
    return sqrt(A.x*A.x+A.y*A.y);
}
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);
}
//调用前确保直线有唯一交点,当且仅当Cross(v,w)非0
Point Get_Line_Intersection(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 angle(Vector v)
{
    return atan2(v.y,v.x);
}

double Distance_To_Line(Point P,Point A,Point B)//点到直线的距离
{
    Vector v1 = B-A,v2 = P-A;
    return fabs(Cross(v1,v2)/Length(v1));
}
double Distance_To_Segment(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(v1);
    else if(dcmp(Dot(v1,v3))>0)
        return Length(v3);
    else
        return fabs(Cross(v1,v2))/Length(v1);
}
Point Get_Line_Projection(Point P,Point A,Point B)//求投影点
{
    Vector v = B- A;
    return A + v*(Dot(v,P-A)/Dot(v,v));
}
//线段相交判定 相交不在线段的端点
bool Segment_Proper_Intersection(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,a2-b1),c4 = Cross(b2-b1,a1-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;
}
//多边形的有向面积
//1
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;
}
//2
double PolygonArea2(Point *p,int n)
{
    double area = 0;
    for(int i = 0; i <= n-1; ++i)
    {
        if(i!=n-1)
            area += Cross(p[i],p[i+1]);
        else
            area += Cross(p[n-1],p[0]);
    }
    return area/2;
}
Point Get(Point A,Point B,double rad1,double rad2)
{
    return Get_Line_Intersection(A,Rotate(B-A,rad1/3),B,Rotate(A-B,-rad2/3));
}
struct Circle
{
    Circle() =  default;
    Point c;
    double r;
    Circle(Point c,double r):c(c),r(r) {}
    Point point(double a)
    {
        return Point (c.x+cos(a)*r,c.y+sin(a)*r);
    }
};
struct Line
{
    Line() = default;
    Vector v;
    Point p;
    Line(Vector V,Point P):v(V),p(P) {}
    Point point(double t)
    {
        return p + v*t;
    }
};
int Get_Line_Circle_Intersection(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 Get_Line_Circle_Intersection2(Line L,Circle C,double & t1,double &t2,vector<Point> &sol)
{
    Point p = Get_Line_Projection(C.c,L.p,L.p+L.v);
    double distance = Distance_To_Line(C.c,L.p,L.p+L.v);
    if(dcmp(distance-C.r)>0)
        return 0;
    t1 = t2 =(p.x-L.p.x)/L.v.x;
    if(dcmp(distance-C.r)==0)
    {

        sol.push_back(p);
        return 1;
    }
    distance = sqrt(C.r*C.r-distance*distance);
// cout<<2*distance<<endl;
    distance  = distance/Length(L.v);
    t1 -= distance;
    t2 += distance;
// cout<<distance<<endl;
    sol.push_back(p-L.v*distance);
    sol.push_back(p+L.v*distance);
    return 2;
}

//过定点求圆的切线
int getTangents(Point p,Circle C,Vector *v)
{
    Vector u = C.c-p;
    double dist = Length(u);
    if(dcmp(dist-C.r)==-1)
        return 0;
    if(dcmp(dist-C.r)==0)
    {
        v[0] = Rotate(u,pi/2);
        return 1;
    }
    double ang = asin(C.r/dist);
    v[0] = Rotate(u,-ang);
    v[1] = Rotate(u,+ang);
    return 2;
}
//求两圆的公切线
int getTangents(Circle A,Circle B,Point *a,Point *b)
{
    int cnt = 0;
    if(A.r < B.r)
    {
        swap(A,B);
        swap(a,b);
    }
    int d2 = pow(A.c.x-B.c.x,2)+pow(A.c.y-B.c.y,2);
    int rdiff = A.r-B.r;
    int rsum = A.r+B.r;
    if(d2 < rdiff*rdiff)
        return 0;//内含

    double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    if(d2==0&&A.r==B.r)
        return -1;//重合
    if(d2 == rdiff*rdiff)
    {
        a[cnt] = A.point(base);
        b[cnt] = B.point(base);
        cnt++;
        return 1;
    }
    //有外公切线
    double ang = acos((A.r-B.r)/sqrt(d2));
    a[cnt] = A.point(base+ang);
    b[cnt] = B.point(base+ang);
    cnt++;
    a[cnt] = A.point(base-ang);
    b[cnt] = B.point(base-ang);
    cnt++;
    if(d2==rsum*rsum)
    {
        a[cnt] = A.point(base);
        b[cnt] = B.point(pi+base);
        cnt++;
    }
    else if(d2 > rsum*rsum)
    {
        double ang = acos((A.r+B.r)/sqrt(d2));
        a[cnt] = A.point(base+ang);
        b[cnt] = B.point(base+ang+pi);
        cnt++;
        a[cnt] = A.point(base-ang);
        b[cnt] = B.point(base-ang+pi);
        cnt++;
    }
    return cnt;
}
//...........................
//求三角形的外切圆
Circle Circumscribed_Circle(Point A,Point B,Point C)
{
    Vector v1 = Normal(A-B);
    Vector  v2 = Normal(A-C);
    Point c = Get_Line_Intersection((A+B)/2,v1,(A+C)/2,v2);
    return Circle(c,Length(c-A));
}
Circle CircumscribedCircle2(Point p1,Point p2,Point p3)
{
    double Bx=p2.x-p1.x,By=p2.y-p1.y;
    double Cx=p3.x-p1.x,Cy=p3.y-p1.y;

    double D=2*(Bx*Cy-By*Cx);

    double cx=(Cy*(Bx*Bx+By*By)-By*(Cx*Cx+Cy*Cy))/D+p1.x;
    double cy=(Bx*(Cx*Cx+Cy*Cy)-Cx*(Bx*Bx+By*By))/D+p1.y;

    Point p=Point(cx,cy);

    return Circle(p,Length(p-p1));
}
//求三角形的内切圆
int get_Circle_Cricle_Intersection(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 = angle(C2.c-C1.c);
    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;
}
//Circle Inscribed_Circle(Point p1,Point p2,Point p3)
//{
// double a = Length(p2-p3);
// double b = Length(p3-p1);
// double c = Length(p1-p2);
// Point p = (p1*a+p2*b+p3*c)/(a+b+c);
// return Circle(p,Distance_To_Line(p,p1,p2));
//}
Circle Inscribled_Circle(Point p1,Point p2,Point p3)
{
    double a=Length(p2-p3);
    double b=Length(p3-p1);
    double c=Length(p1-p2);

    Point I=(p1*a+p2*b+p3*c)/(a+b+c);

    return Circle(I,Distance_To_Line(I, p1, p2));

}
Point read_point(void)
{
    Point p;
    scanf("%lf%lf",&p.x,&p.y);
    return p;
}
全部评论

相关推荐

牛客263158796号:我领羊一面后十天不挂也不推进 今天问hr说等前序的第一批意向发完看情况再看是否推进
点赞 评论 收藏
分享
10-15 16:27
门头沟学院 C++
LeoMoon:建议问一下是不是你给他付钱😅😅
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务