几何计算
距离、角度、交点、面积、空间索引、坐标系转换。
距离计算
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(参数顺序:中心、角度、距离)