坐标系统
大约 5 分钟
坐标系统
WebCAD 支持多种坐标系统,用于不同场景下的坐标计算和转换。理解坐标系统对于正确处理用户输入和实体定位至关重要。
坐标系类型
| 坐标系 | 英文全称 | 说明 | 用途 |
|---|---|---|---|
| WCS | World Coordinate System | 世界坐标系 | 实体存储、几何计算 |
| UCS | User Coordinate System | 用户坐标系 | 用户输入、相对定位 |
| DCS | Display Coordinate System | 显示坐标系 | 视图显示、缩放平移 |
| Canvas | Canvas Coordinate | 画布坐标 | 鼠标事件、屏幕像素 |
坐标系详解
WCS(世界坐标系)
世界坐标系是绝对参考坐标系,所有实体的几何数据都以 WCS 存储。
特点:
- 原点固定在 (0, 0)
- X 轴向右,Y 轴向上
- 单位通常为毫米或英寸
- 不受视图变换影响
import { LineEnt, Point2D } from 'vjcad';
// 实体坐标始终使用 WCS
const line = new LineEnt(
new Point2D(0, 0), // WCS 坐标
new Point2D(100, 100) // WCS 坐标
);
// 获取实体的 WCS 边界框
const bounds = line.boundingBox(); // 默认返回 WCS 边界框UCS(用户坐标系)
用户坐标系是可自定义的工作坐标系,方便在特定方向或位置进行绘图。
特点:
- 原点可以移动
- 可以旋转
- 用于简化特定角度的绘图
- 用户输入的相对坐标基于 UCS
import { Engine, Point2D } from 'vjcad';
// UCS 坐标转换为 WCS
const ucsPoint = new Point2D(50, 50); // UCS 坐标
const wcsPoint = Engine.trans.UcsToWcs(ucsPoint);
// WCS 坐标转换为 UCS
const wcsPoint2 = new Point2D(100, 100);
const ucsPoint2 = Engine.trans.WcsToUcs(wcsPoint2);DCS(显示坐标系)
显示坐标系是经过视图变换(缩放、平移)后的坐标系。
特点:
- 受视图缩放影响
- 受视图平移影响
- 原点在视图左下角
- 单位为像素
import { Engine, Point2D } from 'vjcad';
// WCS 转 DCS
const wcsPoint = new Point2D(100, 100);
const dcsPoint = Engine.trans.WcsToDcs(wcsPoint);
// DCS 转 WCS
const dcsPoint2 = new Point2D(500, 300);
const wcsPoint2 = Engine.trans.DcsToWcs(dcsPoint2);Canvas(画布坐标)
画布坐标是浏览器 Canvas 元素的像素坐标,原点在左上角。
特点:
- 原点在 Canvas 左上角
- Y 轴向下(与 WCS/DCS 相反)
- 单位为像素
- 用于处理鼠标事件
import { Engine, Point2D } from 'vjcad';
// 处理鼠标事件
canvas.addEventListener('click', (event) => {
// 获取 Canvas 坐标
const canvasPoint = new Point2D(event.offsetX, event.offsetY);
// 转换为 WCS 坐标
const wcsPoint = Engine.trans.CanvasToWcs(canvasPoint);
console.log(`世界坐标: (${wcsPoint.x}, ${wcsPoint.y})`);
});坐标转换
CoordinateTransform 类
CoordinateTransform 类提供所有坐标转换方法。
import { Engine, CoordinateTransform, Point2D } from 'vjcad';
// 获取坐标转换器
const trans: CoordinateTransform = Engine.trans;转换方法列表
| 方法 | 说明 | 输入 | 输出 |
|---|---|---|---|
WcsToUcs(point) | 世界坐标转用户坐标 | WCS | UCS |
UcsToWcs(point) | 用户坐标转世界坐标 | UCS | WCS |
WcsToDcs(point) | 世界坐标转显示坐标 | WCS | DCS |
DcsToWcs(point) | 显示坐标转世界坐标 | DCS | WCS |
WcsToCanvas(point) | 世界坐标转画布坐标 | WCS | Canvas |
CanvasToWcs(point) | 画布坐标转世界坐标 | Canvas | WCS |
UcsToDcs(point) | 用户坐标转显示坐标 | UCS | DCS |
DcsToUcs(point) | 显示坐标转用户坐标 | DCS | UCS |
完整转换示例
import { Engine, Point2D } from 'vjcad';
const trans = Engine.trans;
// 起始点(WCS)
const wcsPoint = new Point2D(100, 100);
console.log('WCS:', wcsPoint.x, wcsPoint.y);
// WCS -> UCS
const ucsPoint = trans.WcsToUcs(wcsPoint);
console.log('UCS:', ucsPoint.x, ucsPoint.y);
// WCS -> DCS
const dcsPoint = trans.WcsToDcs(wcsPoint);
console.log('DCS:', dcsPoint.x, dcsPoint.y);
// WCS -> Canvas
const canvasPoint = trans.WcsToCanvas(wcsPoint);
console.log('Canvas:', canvasPoint.x, canvasPoint.y);
// 反向转换
const wcsFromCanvas = trans.CanvasToWcs(canvasPoint);
console.log('WCS (from Canvas):', wcsFromCanvas.x, wcsFromCanvas.y);Engine 快捷方法
Engine 类提供常用的坐标转换快捷方法:
import { Engine, Point2D } from 'vjcad';
// Canvas 转 WCS(最常用)
const wcsPoint = Engine.canvasToWcs(new Point2D(500, 300));
// WCS 转 UCS
const ucsPoint = Engine.wcsToUcs(wcsPoint);
// UCS 转 WCS
const wcsPoint2 = Engine.ucsToWcs(ucsPoint);
// WCS 转 DCS
const dcsPoint = Engine.wcsToDcs(wcsPoint);使用场景
场景1:处理鼠标事件
import { Engine, Point2D, LineEnt } from 'vjcad';
// 鼠标点击绘制直线
let startPoint: Point2D | null = null;
canvas.addEventListener('click', (event) => {
// 将鼠标位置转换为 WCS
const canvasPoint = new Point2D(event.offsetX, event.offsetY);
const wcsPoint = Engine.canvasToWcs(canvasPoint);
if (!startPoint) {
startPoint = wcsPoint;
} else {
// 创建直线(使用 WCS 坐标)
const line = new LineEnt(startPoint, wcsPoint);
line.setDefaults();
Engine.addEntities(line);
startPoint = null;
}
});场景2:获取实体边界框
import { Engine, EntityBase, BoundingBox, CoordinateSystemType } from 'vjcad';
const entity: EntityBase = /* ... */;
// 获取 WCS 边界框(用于几何计算)
const wcsBounds = entity.boundingBox(CoordinateSystemType.WCS);
// 获取 DCS 边界框(用于屏幕显示)
const dcsBounds = entity.boundingBox(CoordinateSystemType.DCS);
// 判断实体是否在屏幕可见范围内
const screenBounds = /* 获取屏幕边界 */;
const isVisible = /* 判断 dcsBounds 是否与 screenBounds 相交 */;场景3:在特定位置显示 UI 元素
import { Engine, Point2D } from 'vjcad';
// 实体中心点(WCS)
const entityCenter = new Point2D(100, 100);
// 转换为 Canvas 坐标
const canvasPoint = Engine.trans.WcsToCanvas(entityCenter);
// 在该位置显示工具提示
showTooltip(canvasPoint.x, canvasPoint.y, '实体信息');场景4:计算屏幕距离
import { Engine, Point2D } from 'vjcad';
// 两个 WCS 点
const wcsPoint1 = new Point2D(0, 0);
const wcsPoint2 = new Point2D(100, 0);
// 转换为 DCS 计算屏幕距离
const dcsPoint1 = Engine.wcsToDcs(wcsPoint1);
const dcsPoint2 = Engine.wcsToDcs(wcsPoint2);
const screenDistance = Math.sqrt(
Math.pow(dcsPoint2.x - dcsPoint1.x, 2) +
Math.pow(dcsPoint2.y - dcsPoint1.y, 2)
);
console.log('屏幕距离(像素):', screenDistance);坐标系变换关系图
注意事项
实体坐标始终使用 WCS:创建和存储实体时,坐标必须是 WCS。
鼠标事件使用 Canvas 坐标:处理鼠标事件前,先转换为 WCS。
视图变换影响 DCS:缩放和平移会改变 WCS 到 DCS 的转换关系。
UCS 用于简化输入:当需要在特定角度绘图时,可以设置 UCS。
性能考虑:频繁的坐标转换可能影响性能,尽量缓存转换结果。
// 好的做法:缓存转换结果
const points = entities.map(e => e.position);
const dcsPoints = points.map(p => Engine.wcsToDcs(p)); // 批量转换
// 避免:在循环中重复转换
for (const entity of entities) {
// 每次循环都转换,效率低
const dcs = Engine.wcsToDcs(entity.position);
}下一步
- 撤销重做 - 了解撤销机制
- Point2D - 点的操作方法
- BoundingBox - 边界框计算