唯杰地图 logo唯杰地图
VJMAP
EN

几何计算

vjcad/references/autodraw/geometry.md 6.6 KB242 行
原文

距离、角度、交点、面积、空间索引、坐标系转换。


距离计算

const { distance, Point2D } = vjcad;

const p1 = new Point2D(0, 0);
const p2 = new Point2D(100, 100);
const dist = distance(p1, p2);

// 直线长度
const line = new LineEnt([0, 0], [100, 100]);
console.log('长度:', line.Length);

角度计算

const { getAngleBetweenPoints, radiansToDegrees, degreesToRadians, Point2D } = vjcad;

const origin = new Point2D(0, 0);
const target = new Point2D(100, 100);

const angleRad = getAngleBetweenPoints(origin, target);  // 弧度,范围 0 到 2π
const angleDeg = radiansToDegrees(angleRad);             // 转换为角度
const rad = degreesToRadians(45);                        // 45° → π/4

中点计算

const { getMidPoint, Point2D } = vjcad;

const mid = getMidPoint(new Point2D(0, 0), new Point2D(100, 100));
// mid: { x: 50, y: 50 }

交点计算

const { GeometryCalculator, LineEnt, CircleEnt, ArcEnt, PolylineEnt } = vjcad;

// 直线与直线
const ptsLL = GeometryCalculator.LineToLine(line1, line2);

// 直线与圆(0、1 或 2 个交点)
const ptsLC = GeometryCalculator.LineToCircle(line, circle);

// 圆与圆
const ptsCC = GeometryCalculator.CircleToCircle(circle1, circle2);

// 圆弧与圆弧
const ptsAA = GeometryCalculator.ArcToArc(arc1, arc2);

// 多段线与多段线
const ptsPP = GeometryCalculator.PlineToPline(pline1, pline2);

// 延长线交点
const ptsLLExt = GeometryCalculator.LineExtToLineExt(line1, line2);
const ptsLCExt = GeometryCalculator.LineExtToCircle(line, circle);

面积计算

const { calculatePolygonArea, Point2D } = vjcad;

// 多边形面积(鞋带公式)
const points = [
    new Point2D(0, 0),
    new Point2D(100, 0),
    new Point2D(100, 60),
    new Point2D(0, 60)
];
const doubleArea = calculatePolygonArea(points);
const area = Math.abs(doubleArea) / 2;  // 6000

// 圆面积
console.log(circle.area);  // π × r²

// 闭合多段线面积:仅对无凸度、闭合、不自交的多段线有效,否则返回 -1(如圆角矩形)
pline.isClosed = true;
console.log(pline.area);

边界框

// 单个实体
const bbox = entity.boundingBox();
// { pt1(最小点), pt2(最大点), width, height, center }

// 多实体组合范围
const { Engine, mergeBoundingBoxes } = vjcad;
const combined = Engine.getBoundsByEntities([e1, e2], "WCS");
const merged = mergeBoundingBoxes([bbox1, bbox2]);

点在多边形内判断

const { pointInPolygon, Point2D } = vjcad;

const polygon = [
    new Point2D(0, 0), new Point2D(100, 0),
    new Point2D(100, 100), new Point2D(0, 100)
];
const inside = pointInPolygon(new Point2D(50, 50), polygon);

点与直线的位置关系

const { GeometryCalculator, Point2D } = vjcad;

// 返回:1=行进方向左侧, 0=线上, -1=右侧(源码注释写反,以实现为准;本例返回 1)
const side = GeometryCalculator.witchSidePointToLine(
    new Point2D(0, 0), new Point2D(100, 0), new Point2D(50, 50)
);

几何变换

偏移

const { offsetLine, expandArc } = vjcad;

// 正值偏到行进方向右侧、负值偏到左侧(实现用 angle - 90°;源码注释"正值向左/向上"写反)
const offsetRight = offsetLine(line, 20);   // 从左向右画的线 → 向下偏移
const offsetLeft = offsetLine(line, -20);   // 从左向右画的线 → 向上偏移
const arcOut = expandArc(arc, 10);          // 圆弧向外偏移
const arcIn = expandArc(arc, -10);          // 圆弧向内偏移

点旋转

const { rotatePointAroundCenter, Point2D } = vjcad;

// 签名是 rotatePointAroundCenter(centerPoint, pointToRotate, angle)——中心在前
const rotated = rotatePointAroundCenter(
    new Point2D(0, 0),     // 旋转中心(第 1 参)
    new Point2D(100, 0),   // 要旋转的点(第 2 参)
    Math.PI / 4            // 旋转角度(弧度)
);
// ⚠️ 必须传 Point2D 实例:传裸数组 [x,y] 不报错但返回 {x:null,y:null},
// 错误静默——结果取 .x/.y 前先判 null。

空间索引

用于大量实体的高效空间查询。

const { SpatialIndex } = vjcad;

const spatialIndex = new SpatialIndex();

// 批量加载(性能最优)
const items = [
    { minX: 0, minY: 0, maxX: 50, maxY: 50, id: 1 },
    { minX: 30, minY: 30, maxX: 80, maxY: 80, id: 2 },
];
spatialIndex.load(items);

// 区域查询
const found = spatialIndex.search({ minX: 25, minY: 25, maxX: 75, maxY: 75 });

// 碰撞检测
const hasCollision = spatialIndex.collides({ minX: 0, minY: 0, maxX: 10, maxY: 10 });

// 插入/删除/清空
spatialIndex.insert(item);
spatialIndex.remove(item, (a, b) => a.id === b.id);
spatialIndex.clear();

两个索引类,别混:

  • SpatialIndex:rbush 通用空间索引(d.ts 里声明为 any)。项形态是 {minX,minY,maxX,maxY, ...任意字段} 纯对象;load/search/collides/insert/remove(item, eqFn)/clear。
  • SpatialIndexManager(Engine.spatialIndexManager):按文档维护实体索引(rbush + 实体映射),吃 BoundingBox 实例(new BoundingBox(pt1: Point2D, pt2: Point2D),自动算 minX/maxX…):load(entities?, doc?) / search(bounds, entityArray?, doc?) / collides(bounds, doc?) / insert(entity) / remove(entity) / setEnabled(bool)。要自己存任意对象用前者;要对图内实体做空间查询用后者。

坐标系转换

const { Engine } = vjcad;

Engine.canvasToWcs(canvasPoint);   // Canvas → 世界坐标
Engine.wcsToUcs(wcsPoint);        // 世界 → 用户坐标
Engine.ucsToWcs(ucsPoint);        // 用户 → 世界坐标
Engine.wcsToDcs(wcsPoint);        // 世界 → 显示坐标
坐标系 说明
WCS 世界坐标系(绝对坐标)
UCS 用户坐标系(可自定义原点和旋转)
DCS 显示坐标系(屏幕像素坐标)
Canvas 画布坐标(HTML Canvas 像素)

常用数学工具

// 注意:这些是 vjcad 顶层导出函数(src/utils/ 展开导出),
// 不是 MathUtils./AngleUtils. 命名空间成员
vjcad.degreesToRadians(45);          // 角度 → 弧度
vjcad.radiansToDegrees(Math.PI);     // 弧度 → 角度
vjcad.randInt(1, 100);               // 随机整数
vjcad.roundToDecimalPlace(3.14159, 2);  // 3.14

vjcad.normalizeAngle(angle);         // 归一化弧度到 [0, 2π)
vjcad.polarToCartesian(centerPt, angle, distance);  // 极坐标 → Point2D(参数顺序:中心、角度、距离)