Implementing Graham Scan to find the convex hull

algorithm, c++, computational-geometry, math, qt

Solution

I found the problem. It lies with the sentence:

Dot product divided by the norm to have the cos because sorting the angle is the same as sorting the cos in [0, Pi].

The lower the angle, the higher the cos, so I just had to change this line of code:

            if (dp(points[1], points[i+j]) < angle_temp)

to:

            if (dp(points[1], points[i+j]) > angle_temp)

and now it works perfectly!

Problem

I'm trying to implement the Graham Scan in C++ but it doesn't work and I can't find why. Any lead would be appreciated. After some tries it seems that I always have `m_M = 2` and the 2 points are the highest-y points, if that help. Cross product to know if it's a right turn or a left turn. ``` qreal Interpolation::ccw(QPointF pt1, QPointF pt2, QPointF pt3) { return (pt2.x()-pt1.x())*(pt3.y()-pt1.y()) - (pt2.y()-pt1.y())*(pt3.x()-pt1.x()); } ``` Dot product divided by the norm to have the `cos` because sorting the angle is the same as sorting the `cos in [0, Pi]`. ``` qreal Interpolation::dp(QPointF pt1, QPointF pt2) { return (pt2.x()-pt1.x())/qSqrt((pt2.x()-pt1.x())*(pt2.x()-pt1.x()) + (pt2.y()-pt1.y())*(pt2.y()-pt1.y())); } ``` The main function: ``` void Interpolation::ConvexHull() { QPointF points[m_N+1]; // My number of points QPointF pt_temp(m_pt[0]); qreal angle_temp(0); int k_temp(0); ``` Fill the array points with `points[1]` being the lower-y point: ``` for (int i(1); i < m_N; ++i) { if (m_pt[i].y() < pt_temp.y()) { points[i+1] = pt_temp; pt_temp = m_pt[i]; } else { points[i+1] = m_pt[i]; } } points[1] = pt_temp; ``` Sorting the points array by angle and doing `points[m_N] = points[0]` ``` for (int i(2); i <= m_N; ++i) { pt_temp = points[i]; angle_temp = dp(points[1], pt_temp); k_temp = i; for (int j(1); j <= m_N-i; ++j) { if (dp(points[1], points[i+j]) < angle_temp) { pt_temp = points[i+j]; angle_temp = dp(points[1], points[i+j]); k_temp = i+j; } } points[k_temp] = points[i]; points[i] = pt_temp; } points[0] = points[m_N]; ``` Executing the Graham scan ``` m_M = 1; // Number of points on the convex hull. for (int i(2); i <= m_N; ++i) { while (ccw(points[m_M-1], points[m_M], points[i]) <= 0) { if (m_M > 1) { m_M -= 1; } else if (i == m_N) { break; } else { i += 1; } } m_M += 1; pt_temp = points[m_M]; points[m_M] = points[i]; points[i] = points[m_M]; } ``` Saving the points to `m_convexHull` which should be the list of the points on the hull with `ConvexHull[m_M]=[ConvexHull[0]` ``` for (int i(0); i < m_M; ++i) { m_convexHull.push_back(points[i+1]); } m_convexHull.push_back(points[1]); } ```

Original source