SorryToPerson logo
返回
算法2026-04-18·9 分钟

算法知识库:几何算法实现

JavaScript/TypeScript 实现几何相关算法,如点线位置关系、凸包、多边形面积等。

几何算法实现

1. 点和向量定义

ts
interface Point {
  x: number;
  y: number;
}

interface Vector {
  x: number;
  y: number;
}

2. 向量叉积

ts
function cross(o: Point, a: Point, b: Point): number {
  return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}

3. 点到直线距离

ts
function pointToLineDistance(p: Point, a: Point, b: Point): number {
  const numerator = Math.abs((b.y - a.y) * p.x - (b.x - a.x) * p.y + b.x * a.y - b.y * a.x);
  const denominator = Math.sqrt((b.y - a.y) ** 2 + (b.x - a.x) ** 2);
  return numerator / denominator;
}

4. 判断点是否在多边形内

ts
function isPointInPolygon(point: Point, polygon: Point[]): boolean {
  let inside = false;
  const n = polygon.length;

  for (let i = 0, j = n - 1; i < n; j = i, i += 1) {
    if (polygon[i].y > point.y !== polygon[j].y > point.y && point.x < ((polygon[j].x - polygon[i].x) * (point.y - polygon[i].y)) / (polygon[j].y - polygon[i].y) + polygon[i].x) {
      inside = !inside;
    }
  }

  return inside;
}

5. 计算多边形面积

ts
function polygonArea(points: Point[]): number {
  let area = 0;
  const n = points.length;

  for (let i = 0; i < n; i += 1) {
    const j = (i + 1) % n;
    area += points[i].x * points[j].y;
    area -= points[j].x * points[i].y;
  }

  return Math.abs(area) / 2;
}

6. 凸包算法 (Graham 扫描)

ts
function convexHull(points: Point[]): Point[] {
  if (points.length <= 1) return points;

  // 找到最底部的点
  let minY = Infinity;
  let minIndex = 0;

  for (let i = 0; i < points.length; i += 1) {
    if (points[i].y < minY || (points[i].y === minY && points[i].x < points[minIndex].x)) {
      minY = points[i].y;
      minIndex = i;
    }
  }

  // 以最底部点为基准排序
  const p0 = points[minIndex];
  points.sort((a, b) => {
    const angleA = Math.atan2(a.y - p0.y, a.x - p0.x);
    const angleB = Math.atan2(b.y - p0.y, b.x - p0.x);
    if (angleA !== angleB) return angleA - angleB;
    return (a.x - p0.x) ** 2 + (a.y - p0.y) ** 2 - (b.x - p0.x) ** 2 - (b.y - p0.y) ** 2;
  });

  // 移除共线点
  const stack: Point[] = [];
  for (const point of points) {
    while (stack.length >= 2 && cross(stack[stack.length - 2], stack[stack.length - 1], point) <= 0) {
      stack.pop();
    }
    stack.push(point);
  }

  return stack;
}

7. 线段相交检测

ts
function doIntersect(a: Point, b: Point, c: Point, d: Point): boolean {
  const d1 = cross(a, b, c);
  const d2 = cross(a, b, d);
  const d3 = cross(c, d, a);
  const d4 = cross(c, d, b);

  if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {
    return true;
  }

  return false;
}

8. 实现要点

  • 使用叉积判断方向和位置关系。
  • 凸包算法处理点集排序和栈操作。
  • 射线法判断点在多边形内。
  • 面积计算使用鞋带公式。
算法几何JavaScript