Line.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Optional.h>
  8. #include <AK/StdLibExtras.h>
  9. #include <LibGfx/Forward.h>
  10. #include <LibGfx/Point.h>
  11. #include <LibGfx/Rect.h>
  12. #include <math.h>
  13. #include <stdlib.h>
  14. namespace Gfx {
  15. template<typename T>
  16. class Line {
  17. public:
  18. Line() { }
  19. Line(Point<T> a, Point<T> b)
  20. : m_a(a)
  21. , m_b(b)
  22. {
  23. }
  24. template<typename U>
  25. Line(U a, U b)
  26. : m_a(a)
  27. , m_b(b)
  28. {
  29. }
  30. template<typename U>
  31. explicit Line(Line<U> const& other)
  32. : m_a(other.a())
  33. , m_b(other.b())
  34. {
  35. }
  36. bool intersects(Line const& other) const
  37. {
  38. return intersected(other).has_value();
  39. }
  40. Optional<Point<T>> intersected(Line const& other) const
  41. {
  42. auto cross_product = [](Point<T> const& p1, Point<T> const& p2) {
  43. return p1.x() * p2.y() - p1.y() * p2.x();
  44. };
  45. auto r = m_b - m_a;
  46. auto s = other.m_b - other.m_a;
  47. auto delta_a = other.m_a - m_a;
  48. auto num = cross_product(delta_a, r);
  49. auto denom = cross_product(r, s);
  50. if (denom == 0) {
  51. if (num == 0) {
  52. // Lines are collinear, check if line ends are touching
  53. if (m_a == other.m_a || m_a == other.m_b)
  54. return m_a;
  55. if (m_b == other.m_a || m_b == other.m_b)
  56. return m_b;
  57. // Check if they're overlapping
  58. if (!(m_b.x() - m_a.x() < 0 && m_b.x() - other.m_a.x() < 0 && other.m_b.x() - m_a.x() && other.m_b.x() - other.m_a.x())) {
  59. // Overlapping
  60. // TODO find center point?
  61. }
  62. if (!(m_b.y() - m_a.y() < 0 && m_b.y() - other.m_a.y() < 0 && other.m_b.y() - m_a.y() && other.m_b.y() - other.m_a.y())) {
  63. // Overlapping
  64. // TODO find center point?
  65. }
  66. return {};
  67. } else {
  68. // Lines are parallel and not intersecting
  69. return {};
  70. }
  71. }
  72. auto u = static_cast<float>(num) / static_cast<float>(denom);
  73. if (u < 0.0f || u > 1.0f) {
  74. // Lines are not parallel and don't intersect
  75. return {};
  76. }
  77. auto t = static_cast<float>(cross_product(delta_a, s)) / static_cast<float>(denom);
  78. if (t < 0.0f || t > 1.0f) {
  79. // Lines are not parallel and don't intersect
  80. return {};
  81. }
  82. // TODO: round if we're dealing with int
  83. return Point<T> { m_a.x() + static_cast<T>(t * r.x()), m_a.y() + static_cast<T>(t * r.y()) };
  84. }
  85. float length() const
  86. {
  87. return m_a.distance_from(m_b);
  88. }
  89. Point<T> closest_to(Point<T> const& point) const
  90. {
  91. if (m_a == m_b)
  92. return m_a;
  93. auto delta_a = point.x() - m_a.x();
  94. auto delta_b = point.y() - m_a.y();
  95. auto delta_c = m_b.x() - m_a.x();
  96. auto delta_d = m_b.y() - m_a.y();
  97. auto len_sq = delta_c * delta_c + delta_d * delta_d;
  98. float param = -1.0;
  99. if (len_sq != 0)
  100. param = static_cast<float>(delta_a * delta_c + delta_b * delta_d) / static_cast<float>(len_sq);
  101. if (param < 0)
  102. return m_a;
  103. if (param > 1)
  104. return m_b;
  105. // TODO: round if we're dealing with int
  106. return { static_cast<T>(m_a.x() + param * delta_c), static_cast<T>(m_a.y() + param * delta_d) };
  107. }
  108. Line<T> shortest_line_to(Point<T> const& point) const
  109. {
  110. return { closest_to(point), point };
  111. }
  112. float distance_to(Point<T> const& point) const
  113. {
  114. return shortest_line_to(point).length();
  115. }
  116. Point<T> const& a() const { return m_a; }
  117. Point<T> const& b() const { return m_b; }
  118. void set_a(Point<T> const& a) { m_a = a; }
  119. void set_b(Point<T> const& b) { m_b = b; }
  120. String to_string() const;
  121. private:
  122. Point<T> m_a;
  123. Point<T> m_b;
  124. };
  125. template<>
  126. inline String IntLine::to_string() const
  127. {
  128. return String::formatted("[{},{} -> {}x{}]", m_a.x(), m_a.y(), m_b.x(), m_b.y());
  129. }
  130. template<>
  131. inline String FloatLine::to_string() const
  132. {
  133. return String::formatted("[{},{} {}x{}]", m_a.x(), m_a.y(), m_b.x(), m_b.y());
  134. }
  135. }