File indexing completed on 2024-05-12 04:42:47

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "convexhull_p.h"
0007 
0008 #include <QDebug>
0009 #include <QLineF>
0010 #include <QPolygonF>
0011 
0012 using namespace KPublicTransport;
0013 
0014 static double orientation(QPointF p, QPointF q, QPointF r)
0015 {
0016     return (q.y() - p.y()) * (r.x() - q.x()) - (r.y() - q.y()) * (q.x() - p.x());
0017 }
0018 
0019 // see https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
0020 QPolygonF ConvexHull::compute(const std::vector<QPointF> &points)
0021 {
0022     QPolygonF hull;
0023     if (points.size() < 3) {
0024         return hull;
0025     }
0026 
0027     // find left-most point
0028     const auto it = std::min_element(points.begin(), points.end(), [](auto lhs, auto rhs) {
0029         return lhs.x() < rhs.x();
0030     });
0031     hull.push_back(*it);
0032     auto p = std::distance(points.begin(), it);
0033 
0034     while (true) {
0035         auto q = (p + 1) % points.size();
0036         for (std::size_t r = 0; r < points.size(); ++r) {
0037             if (q == r) {
0038                 continue;
0039             }
0040 
0041             auto o = orientation(points[p], points[q], points[r]);
0042             if (o < 0.0) {
0043                 q = r;
0044             } else if (o == 0.0) {
0045                 if (QLineF(points[p], points[r]).length() > QLineF(points[p], points[q]).length()) {
0046                     q = r;
0047                 }
0048             }
0049         }
0050         p = q;
0051         hull.push_back(points[p]);
0052 
0053         if (hull.isClosed()) {
0054             break;
0055         }
0056     }
0057 
0058     return hull;
0059 }