计算几何基础

1.多边形面积计算

double S(Point p[],int n)
{
    double ans = 0;
    p[n] = p[0];
    for(int i=1;i<n;i++)
       ans += cross(p[0],p[i],p[i+1]);
    if(ans < 0) ans = -ans;
    return ans / 2.0;
}


2.求凸包

bool cmp(Point A,Point B)
{
    double k = cross(MinA,A,B);
    if(k<0) return 0;
    if(k>0) return 1;
    return dist(MinA,A)<dist(MinA,B);
}

void Graham(Point p[],int n)
{
    for(int i=1;i<n;i++)
       if(p[i].y<p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x))
            swap(p[i],p[0]);
    MinA = p[0];
    p[n] = p[0];
    sort(p+1,p+n,cmp);
    stack[0] = p[0];
    stack[1] = p[1];
    top = 2;
    for(int i=2;i<n;i++)
    {
        while(top >= 2 && cross(stack[top-2],stack[top-1],p[i])<=0) top--;
        stack[top++] = p[i];
    }
}

3.任意多边形求重心

Point Gravity(Point p[],int n)
{
    Point O,t;
    O.x = O.y = 0;
    t.x = t.y = 0;
    p[n] = p[0];
    double A = 0;
    for(int i=0; i<n; i++)
        A += cross(O,p[i],p[i+1]);
    A /= 2.0;
    for(int i=0; i<n; i++)
    {
        t.x += (p[i].x + p[i+1].x) * cross(O,p[i],p[i+1]);
        t.y += (p[i].y + p[i+1].y) * cross(O,p[i],p[i+1]);
    }
    t.x /= 6*A;
    t.y /= 6*A;
    return t;
}


4.求线段交点的坐标

bool Segment_crossing(Segment u,Segment v)   /** 判断线段是否相交 */
{
         return((max(u.a.x,u.b.x)>=min(v.a.x,v.b.x))&&
           (max(v.a.x,v.b.x)>=min(u.a.x,u.b.x))&&
           (max(u.a.y,u.b.y)>=min(v.a.y,v.b.y))&&
           (max(v.a.y,v.b.y)>=min(u.a.y,u.b.y))&&
           (cross(v.a,u.b,u.a)*cross(u.b,v.b,u.a)>=0)&&
           (cross(u.a,v.b,v.a)*cross(v.b,u.b,v.a)>=0));
}

/**求直线交点的坐标,如果没有交点返回NULL,否则返回交点p的地址*/
Point* CrossPoint(Segment u,Segment v)
{
    Point p;
    if(Segment_crossing(u,v))
    {
        p.x=(cross(v.b,u.b,u.a)*v.a.x-cross(v.a,u.b,u.a)*v.b.x)/(cross(v.b,u.b,u.a)-cross(v.a,u.b,u.a));
        p.y=(cross(v.b,u.b,u.a)*v.a.y-cross(v.a,u.b,u.a)*v.b.y)/(cross(v.b,u.b,u.a)-cross(v.a,u.b,u.a));
        return &p;
    }
    return NULL;
}


5.三角形外接圆的半径与圆心

Point Circle_Point(Point A,Point B,Point C)
{
    double a=dist(B,C);
    double b=dist(A,C);
    double c=dist(A,B);
    double p=(a+b+c)/2.0;
    double S=sqrt(p*(p-a)*(p-b)*(p-c));
    R=(a*b*c)/(4*S);    //三角形外接圆的半径为R

    double t1=(A.x*A.x+A.y*A.y-B.x*B.x-B.y*B.y)/2;
    double t2=(A.x*A.x+A.y*A.y-C.x*C.x-C.y*C.y)/2;
    Point center;
    center.x=(t1*(A.y-C.y)-t2*(A.y-B.y))/((A.x-B.x)*(A.y-C.y)-(A.x-C.x)*(A.y-B.y));
    center.y=(t1*(A.x-C.x)-t2*(A.x-B.x))/((A.y-B.y)*(A.x-C.x)-(A.y-C.y)*(A.x-B.x));
    return center;
}


6.旋转卡壳求凸包的直径,也就是平面最远点对,p[]为凸包的点集

double rotating_calipers(Point p[],int n)
{
    int k = 1;
    double ans = 0;
    p[n] = p[0];
    for(int i=0;i<n;i++)
    {
        while(fabs(cross(p[i],p[i+1],p[k])) < fabs(cross(p[i],p[i+1],p[k+1])))
             k = (k+1) % n;
        ans = max(ans, max(dist(p[i],p[k]),dist(p[i+1],p[k])));
    }
    return ans;
}


7.求凸包的宽度

double rotating_calipers(Point p[],int n)
{
    int k = 1;
    double ans = 0x7FFFFFFF;
    p[n] = p[0];
    for(int i=0;i<n;i++)
    {
        while(fabs(cross(p[i],p[i+1],p[k])) < fabs(cross(p[i],p[i+1],p[k+1])))
             k = (k+1) % n;
        double tmp = fabs(cross(p[i],p[i+1],p[k]));
        double d   = dist(p[i],p[i+1]);
        ans = min(ans,tmp/d);
    }
    return ans;
}


8. 求线段与圆的交点

#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>

using namespace std;
const double eps = 1e-8;

struct Point
{
    double x, y;
};

struct Segment
{
    Point s, t;
};

struct Circle
{
    Point c;
    double r;
};

vector<Point> LineToCircle(Segment line, Circle circle)
{
    vector<Point> v;
    v.clear();

    double fd = sqrt((line.s.x - line.t.x) * (line.s.x - line.t.x)
                   + (line.s.y - line.t.y) * (line.s.y - line.t.y));
    Point d;

    d.x = (line.t.x - line.s.x) / fd;
    d.y = (line.t.y - line.s.y) / fd;

    Point e;
    e.x = circle.c.x - line.s.x;
    e.y = circle.c.y - line.s.y;

    double a = e.x * d.x + e.y * d.y;
    double a2 = a * a;

    double e2 = e.x * e.x + e.y * e.y;
    double r2 = circle.r * circle.r;

    v.push_back(line.s);
    if(r2 - e2 + a2 > -eps)
    {

        double f = sqrt(r2 - e2 + a2);
        double t = a - f;

        if((t > -eps) && (t - fd) < eps)
        {
            Point tmp;
            tmp.x = line.s.x + t * d.x;
            tmp.y = line.s.y + t * d.y;
            v.push_back(tmp);
        }

        t = a + f;
        if((t > -eps) && (t - fd) < eps)
        {
            Point tmp;
            tmp.x = line.s.x + t * d.x;
            tmp.y = line.s.y + t * d.y;
            v.push_back(tmp);
        }
    }
    v.push_back(line.t);
    return v;
}

int main()
{
    Segment line;
    Circle circle;

    line.s.x = -1.0;
    line.s.y = -1.0;
    line.t.x = 1.0;
    line.t.y = 1.0;

    circle.c.x = 0.0;
    circle.c.y = 0.0;
    circle.r = 2.0;

    vector<Point> p = LineToCircle(line, circle);

    for(int i = 0; i < p.size(); i++)
        printf("%lf %lf\n", p[i].x, p[i].y);
    return 0;
}

现在有这样一个问题,平面上给定n个点,确定一对平行线,使得所有的点都在平行线之间,求这对平行线的最近距

离。这个问题实际上就是求点集的凸包宽度。

 

 

你可能感兴趣的:(计算几何基础)