找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 93|回复: 0

Graham's Scan法求解凸包问题

[复制链接]

1

主题

0

回帖

37

积分

管理员

积分
37
发表于 2024-6-21 10:11:25 | 显示全部楼层 |阅读模式
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <vector>
  4. #include <math.h>
  5. using namespace std;
  6. //二维点(或向量)结构体定义
  7. #ifndef 采用WINDEF采用
  8. struct POINT { int x; int y; };
  9. #endif
  10. typedef vector<POINT> PTARRAY;
  11. //判断两个点(或向量)是否相等
  12. bool operator==(const POINT &pt1, const POINT &pt2) {
  13.     return (pt1.x == pt2.x && pt1.y == pt2.y);
  14. }
  15. // 比较两个向量pt1和pt2分别与x轴向量(1, 0)的夹角
  16. bool CompareVector(const POINT &pt1, const POINT &pt2) {
  17.     //求向量的模
  18.     float m1 = sqrt((float)(pt1.x * pt1.x + pt1.y * pt1.y));
  19.     float m2 = sqrt((float)(pt2.x * pt2.x + pt2.y * pt2.y));
  20.     //两个向量分别与(1, 0)求内积
  21.     float v1 = pt1.x / m1, v2 = pt2.x / m2;
  22.     return (v1 > v2 || (v1 == v2 && m1 < m2));
  23. }
  24. //计算凸包
  25. void CalcConvexHull(PTARRAY &vecSrc) {
  26.     //点集中至少应有3个点,才能构成多边形
  27.     if (vecSrc.size() < 3) {
  28.         return;
  29.     }
  30.     //查找基点
  31.     POINT ptBase = vecSrc.front(); //将第1个点预设为最小点
  32.     for (PTARRAY::iterator i = vecSrc.begin() + 1; i != vecSrc.end(); ++i) {
  33.         //如果当前点的y值小于最小点,或y值相等,x值较小
  34.         if (i->y < ptBase.y || (i->y == ptBase.y && i->x > ptBase.x)) {
  35.             //将当前点作为最小点
  36.             ptBase = *i;
  37.         }
  38.     }
  39.     //计算出各点与基点构成的向量
  40.     for (PTARRAY::iterator i = vecSrc.begin(); i != vecSrc.end();) {
  41.         //排除与基点相同的点,避免后面的排序计算中出现除0错误
  42.         if (*i == ptBase) {
  43.             i = vecSrc.erase(i);
  44.         }
  45.         else {
  46.             //方向由基点到目标点
  47.             i->x -= ptBase.x, i->y -= ptBase.y;
  48.             ++i;
  49.         }
  50.     }
  51.     //按各向量与横坐标之间的夹角排序
  52.     sort(vecSrc.begin(), vecSrc.end(), &CompareVector);
  53.     //删除相同的向量
  54.     vecSrc.erase(unique(vecSrc.begin(), vecSrc.end()), vecSrc.end());
  55.     //计算得到首尾依次相联的向量
  56.     for (PTARRAY::reverse采用iterator ri = vecSrc.rbegin();
  57.         ri != vecSrc.rend() - 1; ++ri) {
  58.         PTARRAY::reverse采用iterator riNext = ri + 1;
  59.         //向量三角形计算公式
  60.         ri->x -= riNext->x, ri->y -= riNext->y;
  61.     }
  62.     //依次删除不在凸包上的向量
  63.     for (PTARRAY::iterator i = vecSrc.begin() + 1; i != vecSrc.end(); ++i) {
  64.         //回溯删除旋转方向相反的向量,使用外积判断旋转方向
  65.         for (PTARRAY::iterator iLast = i - 1; iLast != vecSrc.begin();) {
  66.             int v1 = i->x * iLast->y, v2 = i->y * iLast->x;
  67.             //如果叉积小于0,则无没有逆向旋转
  68.             //如果叉积等于0,还需判断方向是否相逆
  69.             if (v1 < v2 || (v1 == v2 && i->x * iLast->x > 0 &&
  70.                 i->y * iLast->y > 0)) {
  71.                     break;
  72.             }
  73.             //删除前一个向量后,需更新当前向量,与前面的向量首尾相连
  74.             //向量三角形计算公式
  75.             i->x += iLast->x, i->y += iLast->y;
  76.             iLast = (i = vecSrc.erase(iLast)) - 1;
  77.         }
  78.     }
  79.     //将所有首尾相连的向量依次累加,换算成坐标
  80.     vecSrc.front().x += ptBase.x, vecSrc.front().y += ptBase.y;
  81.     for (PTARRAY::iterator i = vecSrc.begin() + 1; i != vecSrc.end(); ++i) {
  82.         i->x += (i - 1)->x, i->y += (i - 1)->y;
  83.     }
  84.     //添加基点,全部的凸包计算完成
  85.     vecSrc.push采用back(ptBase);
  86. }
  87. int main(void) {
  88.     int nPtCnt = 100; //生成的随机点数
  89.     PTARRAY vecSrc, vecCH;
  90.     for (int i = 0; i < nPtCnt; ++i) {
  91.         POINT ptIn = { rand() % 20, rand() % 20 };
  92.         vecSrc.push采用back(ptIn);
  93.         cout << ptIn.x << ", " << ptIn.y << endl;
  94.     }
  95.     CalcConvexHull(vecSrc);
  96.     cout << "\nConvex Hull:\n";
  97.     for (PTARRAY::iterator i = vecSrc.begin(); i != vecSrc.end(); ++i) {
  98.         cout << i->x << ", " << i->y << endl;
  99.     }
  100.     return 0;
  101. }
  102. https://www.cnblogs.com/devymex/archive/2010/08/09/1795392.html
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|膜结构网

GMT+8, 2025-1-6 17:09 , Processed in 0.121151 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表