由于我的极差记忆力,我打算把这个破玩意先记下来。因为以后会有改动(Delaunay三角网生成算法),我不想把一个好的东西改坏了。。。
好吧……
凸包生成算法,:
1.先在指定的宽(width
)高(height
)范围内生成一堆随机点;
1.1. 生成N个不重复的正整数,使用洗牌算法让生成的数字不重复;
1.2. 将每个数字分解成坐标。可以设想一个二维数组,每个数字依次填进数组内。那么,对于数字A来说,它能够生成的坐标则为:
x = A % width;
y = (A% width== 0) ? A / width : A / width+ 1);
2. 对所有随机点进行排序;
2.1.找到 y 值最小的点
pointYmin
;
2.2. 计算每个离散点
pt
、
pointYmin
、和X轴组成角的弧度
radian
(或者角度
angle
也可以)。其中,点
pointYmin
为角心;
2.3. 依照上面计算出的弧度进行排序。
3. 开始找凸包
3.1.(我懒得写了……) https://www.cnblogs.com/aiguona/p/7232243.html
3.2. 大体上就是,首先离散点集之中入栈两个点,然后需要计算每三个点
ptA
(栈内点,次顶点),
ptO
(栈内点,栈顶点),
ptB
(栈外点,当前点)之间的逆时针夹角,如果夹角是小于180(π)的,那么则
ptB
入栈,否则
ptO
出栈。直到所有离散点都计算完成。
以下是代码……C++11
File: stdinc.h
#include <cmath>
#include <random>
#include <stdarg.h>
#include <string>
#include <exception>
#include <vector>
#include <stack>
#include <map>
#include <set>
#pragma once
#ifdef _DEBUG
#define ErrorThrow(errMsg) { LogThrow::ErrorOccur(errMsg, __FILE__, __LINE__);}
#include <cassert>
#else
#define ErrorThrow(errMsg) {}
#endif // _DEBUG
#include <iostream>
static const double PI = 3.14159265358980/*...80... -> ...7932384626...*/;
static const double precision = 1000.0;
static const double doubleESP = 1e-008;
namespace LogThrow
{
#include <windows.h>
static void ErrorOccur(const std::string& errMsg, const std::string& fileName, int line)
{
std::string msg("[ERROR] " + errMsg + '\n' + "File: " + fileName + '\n' + "Line: " + std::to_string(line));
std::logic_error(msg.c_str());
MessageBox(NULL, msg.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
ExitProcess(0);
}
};
namespace MyMathTools
{
inline static bool LessThan(double a, double b)
{
if (a - b < doubleESP)
{
return true;
}
return false;
}
inline static bool IsEqual(double a, double b)
{
if (std::abs(a - b) <= doubleESP)
{
return true;
}
return false;
}
};
File: Point2D.cpp
#include "stdinc.h"
#pragma once
//Point & Vector
template<typename T>
class Point2D
{
private:
public:
typedef std::vector<const Point2D<int>> Points;
T x, y;
public:
Point2D(T nx, T ny) :x(nx), y(ny)
{
}
Point2D() :Point2D{ 0, 0 }
{
}
Point2D(const Point2D& np) :Point2D{ np.x, np.y }
{
}
void Init(T x, T y)
{
this->x = x;
this->y = y;
}
void Transposition()
{
T total = x + y;
x = total - x;
y = total - y;
}
void operator= (const Point2D& np/*new point*/)
{
Init(np.x, np.y);
}
bool operator== (const Point2D& pointOther)
{
if ((pointOther.x == this->x) &&
(pointOther.y == this->y))
{
return true;
}
return false;
}
friend std::ostream& operator<<(std::ostream& out, const Point2D& pt)
{
out << "(" << pt.x << "," << pt.y << ")";
return out;
}
public:
//[min, max)
/*const */Point2D& RandomPoint(int maxX, int maxY)
{
if (maxX <= 0 || maxY <= 0)
{
std::logic_error("The less then 0!");
}
std::random_device rd;
std::mt19937 mt(rd());
this->x = mt() % maxX;
this->y = mt() % maxY;
//I can modify the left value.
return *this;
}
template<typename T1, typename T2>
static double Distance(const Point2D<T1>& ptA, const Point2D<T2>& ptB)
{
double cutX = ptB.x - ptA.x;
double cutY = ptB.y - ptA.y;
return std::pow((cutX * cutX + cutY * cutY), .5);
}
template<typename T1>
double Distance(const Point2D<T1>& ptOther)
{
return Point2D::Distance<T, T1>(*this, ptOther);
}
//Without repetition: Shuffle algorithm.
static void RandomPoints(int count, int maxX, int maxY, std::vector<const Point2D<int>>& __out points)
{
//auto LcmFunc = [maxX, maxY](int numA, int numB)
//{
// int max = (maxX > maxY) ? maxX : maxY;
// int min = maxX + maxY - max;
// long lcm = -1;