Source: model/Triplet.js

  1. /**
  2. * @file Class Triplet.
  3. * @version March 12, 2017
  4. *
  5. * @author Olivier Pirson --- http://www.opimedia.be/
  6. * @license GPLv3 --- Copyright (C) 2017 Olivier Pirson
  7. */
  8. /**
  9. * A triplet of points.
  10. */
  11. class Triplet {
  12. /**
  13. * Constructs a triplet (a, b, c) of points.
  14. *
  15. * @param {Point} a
  16. * @param {Point} b
  17. * @param {Point} c
  18. */
  19. constructor(a, b, c) {
  20. assert(a instanceof Point, a);
  21. assert(b instanceof Point, b);
  22. assert(c instanceof Point, c);
  23. this._a = a;
  24. this._b = b;
  25. this._c = c;
  26. }
  27. /**
  28. * Returns the first point.
  29. *
  30. * @returns {Point}
  31. */
  32. get a() { return this._a; }
  33. /**
  34. * Returns the second point.
  35. *
  36. * @returns {Point}
  37. */
  38. get b() { return this._b; }
  39. /**
  40. * Returns the third point.
  41. *
  42. * @returns {Point}
  43. */
  44. get c() { return this._c; }
  45. /**
  46. * Returns a new triplet, copied of this.
  47. *
  48. * @returns {Triplet}
  49. */
  50. copy() {
  51. return new Triplet(this.a, this.b, this.c);
  52. }
  53. /**
  54. * Returns the cross product of the vector ab and bc.
  55. *
  56. * @returns {number}
  57. */
  58. crossProductMagnitude() {
  59. const a = this.a;
  60. const b = this.b;
  61. const c = this.c;
  62. return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
  63. }
  64. /**
  65. * Returns true iff a, b and c are on the same line.
  66. *
  67. * @returns {boolean}
  68. */
  69. isCollinear() {
  70. return isFloat0(this.orientation());
  71. }
  72. /**
  73. * Returns true iff p is in the triangle formed by the triplet.
  74. *
  75. * Cf. http://stackoverflow.com/a/2049593/1333666
  76. *
  77. * @param {Point} p
  78. *
  79. * @returns {boolean}
  80. */
  81. isIn(p) {
  82. assert(p instanceof Point, p);
  83. const ps = [this.a, this.b, this.c];
  84. sortRadiallyAroundFirst(ps);
  85. const a = ps[0];
  86. const b = ps[1];
  87. const c = ps[2];
  88. const orient1 = (new Triplet(p, a, b)).isLeftOn();
  89. const orient2 = (new Triplet(p, b, c)).isLeftOn();
  90. const orient3 = (new Triplet(p, c, a)).isLeftOn();
  91. return (orient1 === orient2) && (orient2 === orient3);
  92. }
  93. /**
  94. * Returns true iff c is left to ab.
  95. *
  96. * @returns {boolean}
  97. */
  98. isLeft() {
  99. return (this.orientation() > 0);
  100. }
  101. /**
  102. * Returns true iff c is left to ab or collinear.
  103. *
  104. * @returns {boolean}
  105. */
  106. isLeftOn() {
  107. return (this.orientation() >= 0);
  108. }
  109. /**
  110. * Returns true iff c is right to ab.
  111. *
  112. * @returns {boolean}
  113. */
  114. isRight() {
  115. return (this.orientation() < 0);
  116. }
  117. /**
  118. * Returns true iff c is right to ab or collinear.
  119. *
  120. * @returns {boolean}
  121. */
  122. isRightOn() {
  123. return (this.orientation() <= 0);
  124. }
  125. /**
  126. * Returns the orientation of the point c compared to ab.
  127. *
  128. * If -1 then c is on the right,
  129. * else if 0 then c is on the same line that ab,
  130. * else if 1 then c is on the left.
  131. *
  132. * @returns {number} -1, 0 or 1
  133. */
  134. orientation() {
  135. const magnitude = this.crossProductMagnitude();
  136. return Math.sign(magnitude);
  137. }
  138. /**
  139. * Returns a string representation of the triplet.
  140. *
  141. * Each number is represented with at most precision figures after the decimal point.
  142. *
  143. * @returns {String}
  144. */
  145. toString(precision=2) {
  146. assert(Number.isInteger(precision), precision);
  147. assert(precision >= 0, precision);
  148. return (this.a.toString(precision)
  149. + ":" + this.b.toString(precision)
  150. + ":" + this.c.toString(precision));
  151. }
  152. }