我写了一个C ++凸包算法的实现,它应该很简单。我的以下代码遵循the paperwork中的公式/方法。我使用称为“贾维斯进行曲”的方法。
它可以正常工作20000点,而性能却要差得多,但是如果我随机化输入点数组的顺序(使用using namespace std;
vector<Point> m_in;
inline double cross(const Point &a, const Point &b)
{
return (a.x * b.y) - (b.x * a.y);
}
// conterclockwise test
inline bool CCW(const Point &p, const Point &i, const Point &q)
{
// auto a = p.x,
// b = p.y,
// c = i.x,
// d = i.y,
// e = q.x,
// f = q.y;
// the same:
// return ((f - b) * (c - a)) > ((d - b) * (e - a));
// the same:
// Point va { c - a, d - b }; // i - p
// Point vb { e - a, f - b }; // q - p
// return cross(va, vb) > 0;
// the same, compact:
return cross(i - p, q - p) > 0;
}
void Reset(vector<Point> &in)
{
m_in = move(in);
}
vector<Line> GetLine() const
{
vector<Line> res;
Point l = m_in.front();
for(auto &i : m_in)
{
if(l.x < i.x)
{
l = i;
}
}
Point p = l;
for(auto &pi : m_in)
{
Point q = pi;
for(auto &i : m_in)
{
if(CCW(p, i, q))
{
q = i;
}
}
res.push_back(Line { p, q });
p = q;
}
return res;
}
),我会发现有时它会显示错误
对相同点的输入向量进行混洗后:
(绿线是针对给定的黑点计算出的凸包)
您可能会认为该错误与“最后”凸包线有关。但这有些不同,在这里可以观察到:
代码:
struct Point
{
double x, y;
friend Point operator+(const Point& a, const Point& b);
friend Point operator-(const Point& a, const Point& b);
friend bool operator!=(const Point& a, const Point& b);
};
struct Line
{
Point a;
Point b;
};
基于图片:
类型,要明确:
# Density overlayed with Scatter
#Set figure size
plt.figure(figsize=(10,6))
# Plots
sns.kdeplot(df.Attack,
df.Defense)
sns.lmplot(x='Attack',
y='Defense',
hue='Stage',
data=df,
fit_reg=False)
plt.title('Density vs Scatter')
最后,我看不到:此代码中的特定错误在哪里?
答案 0 :(得分:1)
第一个观察者:您如何在q
和i
之间进行选择。假设您已进行以下设置:
如果是i
,则要在q
上选择(i-p)^(q-p) < 0
。但是,您转向右侧。如果选择p = (0,0), q = (1,0), i = (0,1)
,就很容易看到它:
i
|
|
p-----q
然后(i-p)^(q-p) = (0,1)^(1,0) = 0 - 1 = -1 < 0
,并且应该选择i
上的q
。
还要注意,您是从x
最大的点开始的,而不是从最小的点开始的。
但是所有这些都没有关系。该算法可以正常工作。。您可以here找到它。它会为您的混洗数组提供正确的答案。
答案 1 :(得分:1)
更正CCW测试代码:
inline bool CCW(const Point &p, const Point &i, const Point &q)
{
return cross(i - p, q - p) < 0.0;
}
请勿手动遍历输入数组以找到最低的X坐标。使用std::sort()
通过X坐标对输入数组进行排序。这不会破坏该方法的纸面描述。
void Reset(vector<Point> &in)
{
sort(in.begin(), in.end(), [](const Point &a, const Point &b) { return a.x < b.x; });
m_in = move(in);
}
重写代码,使其使用迭代器(算法描述中令人困惑的行是q = p + 1
,而这实际上并未在OP的代码中实现)。尝试保存原始的语法方法,因为没有人喜欢在其他地方广泛监督的C风格或C ++ 98示例。
vector<Line> GetLine() const
{
vector<Line> res;
if(m_in.empty())
{
return res;
}
auto l = m_in.begin(),
r = m_in.end() - 1;
auto p = l;
do
{
auto q = p + 1;
if(q > r) {
q = l;
}
for(auto i = l; i <= r; i++)
{
if(CCW(*p, *i, *q)) {
q = i;
}
}
res.push_back(Line{*p, *q});
p = q;
}
while(p != l);
return res;
}
如果您有兴趣,可以在Github上找到我应用的完整代码。