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 }