几何计算
大约 5 分钟
几何计算
距离、角度、交点、面积、空间索引等几何计算。
常用几何计算
距离计算
const { distance, Point2D } = vjcad;
const p1 = new Point2D(0, 0);
const p2 = new Point2D(100, 100);
// 使用 distance 函数
const dist = distance(p1, p2);
// 手动计算
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const dist2 = Math.sqrt(dx * dx + dy * dy);
// 直线长度
const line = new LineEnt([0, 0], [100, 100]);
console.log('长度:', line.Length);角度计算
const { getAngleBetweenPoints, radToDeg, degToRad, Point2D } = vjcad;
const origin = new Point2D(0, 0);
const target = new Point2D(100, 100);
// 获取角度(返回弧度,范围 0 到 2π)
const angleRad = getAngleBetweenPoints(origin, target);
const angleDeg = radToDeg(angleRad); // 转换为角度
// 角度转弧度
const rad = degToRad(45); // 45° → π/4
console.log(`角度: ${angleDeg}°`); // 45°中点计算
const { getMidPoint, Point2D } = vjcad;
const p1 = new Point2D(0, 0);
const p2 = new Point2D(100, 100);
const mid = getMidPoint(p1, p2);
console.log(`中点: (${mid.x}, ${mid.y})`); // (50, 50)
// 手动计算
const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2;交点计算
GeometryCalculator 类
const { GeometryCalculator, LineEnt, CircleEnt, ArcEnt, PolylineEnt } = vjcad;直线与直线
const line1 = new LineEnt([0, 0], [100, 100]);
const line2 = new LineEnt([0, 100], [100, 0]);
const intersections = GeometryCalculator.LineToLine(line1, line2);
intersections.forEach(pt => {
console.log(`交点: (${pt.x}, ${pt.y})`);
});直线与圆
const line = new LineEnt([0, 50], [100, 50]);
const circle = new CircleEnt([50, 50], 30);
const intersections = GeometryCalculator.LineToCircle(line, circle);
// 可能有 0、1 或 2 个交点圆与圆
const circle1 = new CircleEnt([30, 50], 25);
const circle2 = new CircleEnt([70, 50], 25);
const intersections = GeometryCalculator.CircleToCircle(circle1, circle2);
// 可能有 0、1 或 2 个交点圆弧与圆弧
const arc1 = new ArcEnt([0, 0], 50, 0, Math.PI / 2);
const arc2 = new ArcEnt([50, 0], 50, Math.PI / 2, Math.PI);
const intersections = GeometryCalculator.ArcToArc(arc1, arc2);多段线与多段线
const pline1 = new PolylineEnt();
pline1.setPoints([[0, 0], [100, 0], [100, 100]]);
const pline2 = new PolylineEnt();
pline2.setPoints([[50, -50], [50, 150]]);
const intersections = GeometryCalculator.PlineToPline(pline1, pline2);延长线交点
// 直线延长与直线延长的交点
const intersections = GeometryCalculator.LineExtToLineExt(line1, line2);
// 直线延长与圆的交点
const intersections = GeometryCalculator.LineExtToCircle(line, circle);边界框计算
单个实体边界框
const pline = new PolylineEnt();
pline.setPoints([[0, 0], [100, 0], [100, 60], [0, 60]]);
const bbox = pline.boundingBox();
console.log('最小点:', bbox.pt1); // Point2D
console.log('最大点:', bbox.pt2); // Point2D
console.log('宽度:', bbox.width);
console.log('高度:', bbox.height);
console.log('中心:', bbox.center); // Point2D多实体边界框
const { mergeBoundingBoxes, Engine } = vjcad;
// 方式1:使用 mergeBoundingBoxes
const bbox1 = entity1.boundingBox();
const bbox2 = entity2.boundingBox();
const merged = mergeBoundingBoxes([bbox1, bbox2]);
// 方式2:使用 Engine.getBoundsByEntities
const bbox = Engine.getBoundsByEntities([entity1, entity2], "WCS");边界框操作
// 判断两个边界框是否相交
function bboxIntersects(bbox1, bbox2) {
return !(
bbox1.pt2.x < bbox2.pt1.x || // bbox1 在左边
bbox1.pt1.x > bbox2.pt2.x || // bbox1 在右边
bbox1.pt2.y < bbox2.pt1.y || // bbox1 在下边
bbox1.pt1.y > bbox2.pt2.y // bbox1 在上边
);
}
// 判断点是否在边界框内
function pointInBbox(point, bbox) {
return point.x >= bbox.pt1.x && point.x <= bbox.pt2.x &&
point.y >= bbox.pt1.y && point.y <= bbox.pt2.y;
}点在多边形内判断
射线法
const { pointInPolygon, Point2D } = vjcad;
const polygon = [
new Point2D(0, 0),
new Point2D(100, 0),
new Point2D(100, 100),
new Point2D(0, 100)
];
const testPoint = new Point2D(50, 50);
const inside = pointInPolygon(testPoint, polygon);
console.log(inside ? '点在多边形内' : '点在多边形外');点与直线的位置关系
const { GeometryCalculator, Point2D } = vjcad;
const lineStart = new Point2D(0, 0);
const lineEnd = new Point2D(100, 0);
const point = new Point2D(50, 50);
// 返回值:-1=左侧, 0=线上, 1=右侧
const side = GeometryCalculator.witchSidePointToLine(lineStart, lineEnd, point);面积计算
多边形面积
const { calculatePolygonArea, Point2D } = vjcad;
const points = [
new Point2D(0, 0),
new Point2D(100, 0),
new Point2D(100, 60),
new Point2D(0, 60)
];
// 使用鞋带公式(Shoelace formula)
const doubleArea = calculatePolygonArea(points);
const area = Math.abs(doubleArea) / 2;
console.log('面积:', area); // 6000实体面积
// 圆的面积
const circle = new CircleEnt([50, 50], 30);
console.log('圆面积:', circle.area); // π × 30² ≈ 2827.43
// 闭合多段线面积
const pline = new PolylineEnt();
pline.setPoints([[0, 0], [100, 0], [100, 60], [0, 60]]);
pline.isClosed = true;
console.log('多段线面积:', pline.area); // 6000空间索引
用于大量实体的高效空间查询。
const { SpatialIndex } = vjcad;
// 创建空间索引
const spatialIndex = new SpatialIndex();
// 插入数据(必须包含 minX, minY, maxX, maxY 属性)
spatialIndex.insert({
minX: 10, minY: 10, maxX: 40, maxY: 40,
name: "区域A",
data: { /* 自定义数据 */ }
});
// 批量加载(性能最优)
const items = [
{ minX: 0, minY: 0, maxX: 50, maxY: 50, id: 1 },
{ minX: 30, minY: 30, maxX: 80, maxY: 80, id: 2 },
{ minX: 60, minY: 60, maxX: 100, maxY: 100, id: 3 }
];
spatialIndex.load(items);
// 区域查询
const searchBounds = { minX: 25, minY: 25, maxX: 75, maxY: 75 };
const found = spatialIndex.search(searchBounds);
console.log('找到:', found.length, '个');
// 碰撞检测
const hasCollision = spatialIndex.collides(searchBounds);
// 删除项目
spatialIndex.remove(item, (a, b) => a.id === b.id);
// 清空索引
spatialIndex.clear();
// 获取所有项目
const all = spatialIndex.all();几何变换
偏移
const { offsetLine, expandArc, LineEnt, ArcEnt, CircleEnt } = vjcad;
// 直线偏移
const line = new LineEnt([0, 0], [100, 0]);
const offsetUp = offsetLine(line, 20); // 向上偏移
const offsetDown = offsetLine(line, -20); // 向下偏移
// 圆弧偏移
const arc = new ArcEnt([50, 50], 30, 0, Math.PI);
const arcOut = expandArc(arc, 10); // 向外偏移
const arcIn = expandArc(arc, -10); // 向内偏移
// 圆偏移(改变半径)
const circle = new CircleEnt([50, 50], 30);
const newRadius = circle.radius + 10;
const newCircle = new CircleEnt(circle.center, newRadius);修剪和延伸
修剪和延伸通常通过交点计算 + 修改端点实现。
// 计算交点
const intersections = GeometryCalculator.LineToLine(targetLine, boundaryLine);
// 修剪:根据交点分割线段,删除不需要的部分
// 延伸:将端点延伸到交点位置打断
const { LineEnt, ArcEnt, getAngleBetweenPoints } = vjcad;
// 直线打断
function breakLine(line, breakPoint) {
const line1 = new LineEnt(line.startPoint, breakPoint);
const line2 = new LineEnt(breakPoint, line.endPoint);
line1.setDefaults();
line2.setDefaults();
return [line1, line2];
}
// 圆弧打断
function breakArc(arc, breakPoint) {
const breakAngle = getAngleBetweenPoints(arc.center, breakPoint);
const arc1 = new ArcEnt(arc.center, arc.radius, arc.startAngle, breakAngle);
const arc2 = new ArcEnt(arc.center, arc.radius, breakAngle, arc.endAngle);
arc1.setDefaults();
arc2.setDefaults();
return [arc1, arc2];
}坐标系转换
const { Engine, Point2D } = vjcad;
// Canvas 坐标 → 世界坐标
const canvasPoint = { x: 100, y: 200 };
const wcsPoint = Engine.CanvasToWcs(canvasPoint);
// 世界坐标 → 用户坐标
const ucsPoint = Engine.wcsToUcs(wcsPoint);
// 用户坐标 → 世界坐标
const wcsPoint2 = Engine.ucsToWcs(ucsPoint);
// 世界坐标 → 显示坐标
const dcsPoint = Engine.wcsToDcs(wcsPoint);坐标系类型
| 坐标系 | 说明 |
|---|---|
| WCS | 世界坐标系(绝对坐标) |
| UCS | 用户坐标系(可自定义原点和旋转) |
| DCS | 显示坐标系(屏幕像素坐标) |
| Canvas | 画布坐标(HTML Canvas 像素) |