问题

给定三角形 3 个点的坐标,在给定一个点 (x, y) ,判断该点是否在三角形中。

解法

面积比较

判断 求一点是否在三角形内 - 图1 的面积与 求一点是否在三角形内 - 图2 是否相等。若相等则 O 在内部,反之则在外部。
求一点是否在三角形内 - 图3

如何求三角形的面积?

海伦公式:
求一点是否在三角形内 - 图4

  1. interface IPointer {
  2. x: number;
  3. y: number;
  4. }
  5. var pointInTriangle = function (
  6. o: IPointer,
  7. a: IPointer,
  8. b: IPointer,
  9. c: IPointer
  10. ): boolean {
  11. var ab = getDistance(a, b),
  12. bc = getDistance(b, c),
  13. ac = getDistance(a, c),
  14. ao = getDistance(a, o),
  15. bo = getDistance(b, o),
  16. co = getDistance(c, o),
  17. area = getTriangleArea(ab, bc, ac),
  18. area1 = getTriangleArea(ab, ao, bo),
  19. area2 = getTriangleArea(ac, ao, co),
  20. area3 = getTriangleArea(bc, bo, co);
  21. // 两点距离 == 直线长度
  22. function getDistance(p1: IPointer, p2: IPointer) {
  23. var x1 = p1.x,
  24. x2 = p2.x,
  25. y1 = p1.y,
  26. y2 = p2.y,
  27. result;
  28. result = Math.abs(Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)));
  29. return result;
  30. }
  31. // 三角形面积
  32. function getTriangleArea(a: number, b: number, c: number) {
  33. // 海伦公式
  34. var p = (a + b + c) / 2,
  35. area = Math.sqrt(p * (p - a) * (p - b) * (p - c));
  36. return area;
  37. }
  38. function isPointInTriangle(
  39. area1: number,
  40. area2: number,
  41. area3: number,
  42. area: number
  43. ) {
  44. return Math.abs(area1 + area2 + area3 - area) < 0.0001; // 这种计算时会有精度问题,会存在在误差。
  45. }
  46. return isPointInTriangle(area1, area2, area3, area);
  47. };

向量叉乘

如果有一个 点 O求一点是否在三角形内 - 图5 内,那么沿着三角形的边界逆时针走,点 O 一定保持在边界的左边,也就是说 点 O 在边 求一点是否在三角形内 - 图6求一点是否在三角形内 - 图7求一点是否在三角形内 - 图8 的左边。
求一点是否在三角形内 - 图9

如何判断点在一个边的左侧?

二维向量的叉积公式:
求一点是否在三角形内 - 图10

:::info 由于输入的 3个点不一定是逆时针的顺序,比如输入的三点的坐标是 A C B,那就不行了。
所以假设依次输入的点分别为 求一点是否在三角形内 - 图11
求一点是否在三角形内 - 图12求一点是否在三角形内 - 图13 的右侧,则表示输入的点的顺序是顺时针,即 A C B 的输入,此时将 求一点是否在三角形内 - 图14调换位置即可保证是逆时针顺序。
求一点是否在三角形内 - 图15 :::

  1. interface IPointer {
  2. x: number;
  3. y: number;
  4. }
  5. var pointInTriangle = function (
  6. o: IPointer,
  7. a: IPointer,
  8. b: IPointer,
  9. c: IPointer
  10. ): boolean {
  11. // 计算向量
  12. function getVector(p1: IPointer, p2: IPointer, p3: IPointer) {
  13. return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
  14. }
  15. function isPointInTriangle(
  16. p1: IPointer,
  17. p2: IPointer,
  18. p3: IPointer,
  19. o: IPointer
  20. ): boolean {
  21. return getVector(p1, p2, p3) < 0
  22. ?
  23. isPointInTriangle(p1, p3, p2, o) // 三角形三点输入顺序为顺时针
  24. : getVector(p1, p2, o) > 0 &&
  25. getVector(p2, p3, o) > 0 &&
  26. getVector(p3, p1, o) > 0
  27. }
  28. return isPointInTriangle(a, b, c, o);
  29. };