1 Commits
E4 ... E3

Author SHA1 Message Date
aad4ce9375 If two points intersect 2024-09-06 16:55:52 +02:00
3 changed files with 59 additions and 35 deletions

View File

@ -116,46 +116,69 @@ void Tour::insertNearest(Point p) {
nearest->next = newNode; nearest->next = newNode;
} }
Node *findbestNodeTSP(Node *const start, Point &point) { enum class Orientation { COLLINEAR, CLOCKWISE, COUNTER_CLOCKWISE };
auto calcHeuristic = [&point](Node *const insertAt) -> double {
double distanceWithNewPoint = insertAt->point.distanceTo(point) +
point.distanceTo(insertAt->next->point);
double originalDistance = insertAt->point.distanceTo(insertAt->next->point);
return distanceWithNewPoint - originalDistance; // 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
double optimalH = Q_INFINITY; // Calculate the calcOrientation of the triplet (p, q, r)
Node *optimalNode; 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);
Node *node = start; if (val == 0)
do { return Orientation::COLLINEAR;
double h = calcHeuristic(node); return (val > 0) ? Orientation::CLOCKWISE : Orientation::COUNTER_CLOCKWISE;
if (h < optimalH) { }
optimalH = h; // True if q lies on the segment p-r
optimalNode = node; 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) &&
node = node->next; q.y <= std::max(p.y, r.y) && q.y >= std::min(p.y, r.y));
} while (node != start); }
// 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);
return optimalNode; // 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;
} }
void Tour::insertOptimalHeuristic(Point p) { bool Tour::pointsCross(Point &p1, Point &p2) {
if (m_startNode == nullptr) { if (m_startNode == nullptr || m_startNode->next == m_startNode)
m_startNode = new Node(p); return false;
m_startNode->next = m_startNode; // Make it cirkular Node *n1 = m_startNode, *n2 = m_startNode->next;
return; do {
} Point &q1 = n1->point, &q2 = n2->point;
if (m_startNode->next == nullptr) { if (doesPointsIntersect(p1, p2, q1, q2))
auto newNode = new Node(p, m_startNode); return true;
m_startNode->next = newNode;
return;
}
Node *bestNode = findbestNodeTSP(m_startNode, p); n1 = n2;
auto *newNode = new Node(p, bestNode->next); n2 = n2->next;
bestNode->next = newNode; } while (n1 != m_startNode);
return false;
} }
void Tour::insertSmallest(Point p) { void Tour::insertSmallest(Point p) {

View File

@ -24,10 +24,11 @@ public:
double distance() const; double distance() const;
void insertNearest(Point p); void insertNearest(Point p);
void insertSmallest(Point p); void insertSmallest(Point p);
void insertOptimalHeuristic(Point p);
private: private:
Node* m_startNode; Node* m_startNode;
bool pointsCross(Point &p1, Point &p2);
}; };
#endif // TOUR_H #endif // TOUR_H

View File

@ -49,7 +49,7 @@ int main(int argc, char *argv[]) {
auto timeStart = std::chrono::high_resolution_clock::now(); auto timeStart = std::chrono::high_resolution_clock::now();
while (input >> x >> y) { while (input >> x >> y) {
Point p(x, y); Point p(x, y);
tour.insertOptimalHeuristic(p); tour.insertNearest(p);
//uncomment the 4 lines below to animate //uncomment the 4 lines below to animate
//tour.draw(scene); //tour.draw(scene);
//std::chrono::milliseconds dura(50); //std::chrono::milliseconds dura(50);