计算几何__凸包算法

 

 
/*

凸包算法总结:

凸包是指覆盖平面坐标系内若干点的面积最小的凸多边形。求凸包的第一步是确定:

凸包的定点都在给定的点中。通过几何方法反证很容易得到这一结论。所以,只要

从所有点中挑选若干正确的点,按顺序(顺时针或逆时针)排列,就相当与求得了凸

包。一种简便的方法是"包裹法"(Gift-Wrapping)。将y坐标最低的点作为凸包的第

一个顶点H1(易证,所有点中xy坐标取到最大或最小值的点一定是凸包顶点之一)

找到满足条件的点,该点与水平线的叉积为正且夹角最小,作为凸包的第二个顶点

H2。再求与线段H1H2叉积为正且夹角最小的点,。。。。依此类推。

*/

 

//计算几何中的凸包问题程序(graham算法)

#i nclude <stdio.h>

#i nclude <stdlib.h>

#i nclude <math.h>

#define MAXN 10000

 

/* 顶点的类型定义 */

typedef struct {

       double x;

       double y;

       double arCos;

}Point1;

int n;     // 顶点的个数

Point1 points[MAXN];     // 顶点数组

int stack[MAXN];  //

 

/*主函数*/

int main()

{

       void Init();

       void Make();

       Init();    //程序数据的读入

       Make();    //程序算法过程

       while(1);

       return 0;

}

 

/*数据读入函数*/

void Init()

{

       FILE *in;   // 采用读文件的方式,读入数据

       int i;

       in = fopen("281.txt", "r");

       fscanf(in, "%d", &n);

       for(i = 0; i < n; ++i)

              fscanf(in, "%lf%lf", &points[i].x, &points[i].y);

       fclose(in);   // 关闭文件

}

 

/*算法实现函数*/

void Make()

{

       int Multi(Point1, Point1, Point1);   //计算两个向量的积

       double Angle(int);      //计算其余顶点与第一顶点的角度,为排序做准备

       void QSort(int, int);     //对顶点进行快速排序

       void Swap(int, int);     

       int i, j, t;

       double min = 32767.0;

       for(i = 0; i < n; ++i){     //找第一个顶点,做为算法的起始顶点

              if(points[i].y < min) {

                     j = i;

                     min = points[i].y;

              }

    }

       Swap(0, j);

       for(i = 1; i < n; ++i){     //计算除第一顶点外的其余顶点到第一点的线段与x轴的夹角

              points[i].arCos = Angle(i);

       }

       QSort(1, n-1);       //根据所得到的角度进行快速排序.

       for(i = 0; i <= 2; ++i) stack[i] = i;   //将前3个顶点压栈

       t = 2;

       while(i < n) {

              /*如果新的点,与最近入栈中的2点构成了一个"", 则将栈顶元素出栈. 直到把栈检查完*/

              while(Multi(points[stack[t-1]], points[stack[t]], points[i]) && t >= 1) 

                     t--;    

              t++;        // 将新点压栈

              stack[t] = i;

              i++;

       }

       /*打印结果*/

       for(i = 0; i <=t; ++i)

              printf("<%.2lf, %.2lf>/n",points[stack[i]].x, points[stack[i]].y);

}

int Multi(Point1 px, Point1 py, Point1 pz)

{

       double k;

       k = (py.x-px.x)*(pz.y-py.y) - (pz.x-py.x)*(py.y-px.y);  // 计算两个向量的向量积,

       // 判断3个点所成的角是不是一个"".

       if(k < 0) return 1;

       return 0;

}

 

/*角度计算函数*/

double Angle(int i)

{

       double j, k, m, n;

       j = fabs(points[i].x - points[0].x);

       k = fabs(points[i].y - points[0].y);

       m = sqrt(j*j+k*k);     //得到顶点i 到第一顶点的线段长度.

       n = acos(j/m);      //得到该线段与x轴的角度

       //强悍

       return n;

}

 

void QSort(int top, int bot)

{

    //快排

       int Loc(int, int);

       int pos;

      

       if(top < bot) {

              pos = Loc(top, bot);

              QSort(top, pos-1);

              QSort(pos+1, bot);

       }

}

 

int Loc(int top, int bot)

{

       void Swap(int, int);

       double x = points[top].arCos;

       int j, k;

       j = top+1;

       k = bot;

       while(1) {

              while(j < bot && points[j].arCos < x) j++;

              while(k > top && points[k].arCos > x) k--;

             

              if(j >= k) break;

             

              Swap(j, k);

       }

       Swap(top, k);

       return k;

}

 

void Swap(int px, int py)

{

       Point1 k;

       k = points[px];

       points[px] = points[py]; //注意

       points[py] = k;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值