From b91b886173361fc41c114971205835c010e1b5fa Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Fri, 6 Sep 2024 16:54:53 +0200 Subject: [PATCH] If two points intersect --- src/Tour.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/Tour.h | 2 ++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/Tour.cpp b/src/Tour.cpp index 0139e2f..6436112 100755 --- a/src/Tour.cpp +++ b/src/Tour.cpp @@ -52,7 +52,7 @@ void Tour::draw(QGraphicsScene *scene) const { return; Node *node = m_startNode; - do{ + do { node->point.draw(scene); node->point.drawTo(node->next->point, scene); node = node->next; @@ -116,6 +116,71 @@ void Tour::insertNearest(Point p) { nearest->next = newNode; } +enum class Orientation { COLLINEAR, CLOCKWISE, COUNTER_CLOCKWISE }; + +// I'm not going to pretend that I came up with this on my own. +// The description for the algorithms is found both in the +// linear algebra course, and on this wiki +// https://en.wikipedia.org/w/index.php?title=Line-line_intersection&oldid=1229564037 + +// Calculate the calcOrientation of the triplet (p, q, r) +inline Orientation calcOrientation(const Point &p, const Point &q, const Point &r) { + int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + + if (val == 0) + return Orientation::COLLINEAR; + return (val > 0) ? Orientation::CLOCKWISE : Orientation::COUNTER_CLOCKWISE; +} +// True if q lies on the segment p-r +inline bool isOnSegment(const Point &p, const Point &q, const Point &r) { + return (q.x <= std::max(p.x, r.x) && q.x >= std::min(p.x, r.x) && + q.y <= std::max(p.y, r.y) && q.y >= std::min(p.y, r.y)); +} +// Check if the two line segments p1q1 and p2q2 intersect +bool doesPointsIntersect(const Point &p1, const Point &q1, const Point &p2, + const Point &q2) { + Orientation o1 = calcOrientation(p1, q1, p2); + Orientation o2 = calcOrientation(p1, q1, q2); + Orientation o3 = calcOrientation(p2, q2, p1); + Orientation o4 = calcOrientation(p2, q2, q1); + + // General case: line segments intersect if they have different orientations + if (o1 != o2 && o3 != o4) + return true; + + // Special cases + // p1, q1, p2 are collinear and p2 lies on segment p1q1 + if (o1 == Orientation::COLLINEAR && isOnSegment(p1, p2, q1)) + return true; + // p1, q1, q2 are collinear and q2 lies on segment p1q1 + if (o2 == Orientation::COLLINEAR && isOnSegment(p1, q2, q1)) + return true; + // p2, q2, p1 are collinear and p1 lies on segment p2q2 + if (o3 == Orientation::COLLINEAR && isOnSegment(p2, p1, q2)) + return true; + // p2, q2, q1 are collinear and q1 lies on segment p2q2 + if (o4 == Orientation::COLLINEAR && isOnSegment(p2, q1, q2)) + return true; + + return false; +} + +bool Tour::pointsCross(Point &p1, Point &p2) { + if (m_startNode == nullptr || m_startNode->next == m_startNode) + return false; + Node *n1 = m_startNode, *n2 = m_startNode->next; + do { + Point &q1 = n1->point, &q2 = n2->point; + if (doesPointsIntersect(p1, p2, q1, q2)) + return true; + + n1 = n2; + n2 = n2->next; + } while (n1 != m_startNode); + + return false; +} + void Tour::insertSmallest(Point p) { if (m_startNode == nullptr) { m_startNode = new Node(p); diff --git a/src/Tour.h b/src/Tour.h index 14e3f0f..dd4d510 100755 --- a/src/Tour.h +++ b/src/Tour.h @@ -27,6 +27,8 @@ public: private: Node* m_startNode; + + bool pointsCross(Point &p1, Point &p2); }; #endif // TOUR_H