边界框
大约 5 分钟
边界框
BoundingBox 表示一个轴对齐的矩形边界框(AABB),用于表示实体的包围范围、碰撞检测、选择框判断等。
创建边界框
import { BoundingBox, Point2D } from 'vjcad';
// 通过两个角点创建边界框
const bbox = new BoundingBox(
new Point2D(0, 0), // 第一个角点
new Point2D(100, 100) // 第二个角点
);
// 角点顺序无关,会自动计算 min/max
const bbox2 = new BoundingBox(
new Point2D(100, 100),
new Point2D(0, 0)
);
// bbox2.minX = 0, bbox2.maxX = 100
// 创建空边界框(默认为原点)
const emptyBox = new BoundingBox();属性
坐标属性
| 属性 | 类型 | 说明 |
|---|---|---|
pt1 | Point2D | 第一个角点(构造时传入) |
pt2 | Point2D | 第二个角点(构造时传入) |
minX | number | 最小 X 坐标 |
maxX | number | 最大 X 坐标 |
minY | number | 最小 Y 坐标 |
maxY | number | 最大 Y 坐标 |
const bbox = new BoundingBox(new Point2D(10, 20), new Point2D(100, 80));
console.log(bbox.minX); // 10
console.log(bbox.maxX); // 100
console.log(bbox.minY); // 20
console.log(bbox.maxY); // 80尺寸属性
| 属性 | 类型 | 说明 |
|---|---|---|
width | number | 宽度(maxX - minX) |
height | number | 高度(maxY - minY) |
center | Point2D | 中心点 |
const bbox = new BoundingBox(new Point2D(0, 0), new Point2D(100, 60));
console.log(bbox.width); // 100
console.log(bbox.height); // 60
console.log(bbox.center); // Point2D(50, 30)角点获取器
| 属性 | 说明 | 坐标 |
|---|---|---|
minPoint | 最小点(左下) | (minX, minY) |
maxPoint | 最大点(右上) | (maxX, maxY) |
BL | Bottom Left(左下) | (minX, minY) |
BR | Bottom Right(右下) | (maxX, minY) |
TL | Top Left(左上) | (minX, maxY) |
TR | Top Right(右上) | (maxX, maxY) |
point1 | 第一个角点(左下) | (minX, minY) |
point2 | 第二个角点(右下) | (maxX, minY) |
point3 | 第三个角点(右上) | (maxX, maxY) |
point4 | 第四个角点(左上) | (minX, maxY) |
const bbox = new BoundingBox(new Point2D(0, 0), new Point2D(100, 80));
// 使用方向命名
console.log(bbox.BL); // Point2D(0, 0) - 左下
console.log(bbox.BR); // Point2D(100, 0) - 右下
console.log(bbox.TL); // Point2D(0, 80) - 左上
console.log(bbox.TR); // Point2D(100, 80) - 右上
// 使用数字命名(逆时针顺序)
console.log(bbox.point1); // Point2D(0, 0)
console.log(bbox.point2); // Point2D(100, 0)
console.log(bbox.point3); // Point2D(100, 80)
console.log(bbox.point4); // Point2D(0, 80)状态属性
| 属性 | 类型 | 说明 |
|---|---|---|
hasSizeBounds | boolean | 是否有实际尺寸 |
isSinglePointBounds | boolean | 是否退化为单点 |
const normalBox = new BoundingBox(new Point2D(0, 0), new Point2D(100, 100));
console.log(normalBox.hasSizeBounds); // true
const pointBox = new BoundingBox(new Point2D(50, 50), new Point2D(50, 50));
console.log(pointBox.isSinglePointBounds); // true方法
move() - 移动边界框
将边界框从一个位置移动到另一个位置:
const bbox = new BoundingBox(new Point2D(0, 0), new Point2D(100, 100));
// 将边界框移动 (50, 30)
bbox.move(new Point2D(0, 0), new Point2D(50, 30));
console.log(bbox.minX); // 50
console.log(bbox.minY); // 30
console.log(bbox.maxX); // 150
console.log(bbox.maxY); // 130isPointInBox() - 点包含检测
判断点是否在边界框内(包含边界):
const bbox = new BoundingBox(new Point2D(0, 0), new Point2D(100, 100));
console.log(bbox.isPointInBox(new Point2D(50, 50))); // true - 内部
console.log(bbox.isPointInBox(new Point2D(0, 0))); // true - 边界上
console.log(bbox.isPointInBox(new Point2D(100, 100))); // true - 边界上
console.log(bbox.isPointInBox(new Point2D(150, 50))); // false - 外部边界框合并
使用 mergeBoundingBoxes() 函数将多个边界框合并为一个包含所有边界框的最小边界框:
import { mergeBoundingBoxes, BoundingBox, Point2D } from 'vjcad';
const bbox1 = new BoundingBox(new Point2D(0, 0), new Point2D(50, 50));
const bbox2 = new BoundingBox(new Point2D(30, 30), new Point2D(100, 80));
const bbox3 = new BoundingBox(new Point2D(-20, 10), new Point2D(40, 60));
// 合并多个边界框
const merged = mergeBoundingBoxes([bbox1, bbox2, bbox3]);
console.log(merged.minX); // -20
console.log(merged.minY); // 0
console.log(merged.maxX); // 100
console.log(merged.maxY); // 80获取实体边界框
所有实体都有 boundingBox() 方法,返回该实体在世界坐标系(WCS)中的边界框:
import { LineEnt, CircleEnt, Point2D } from 'vjcad';
// 直线的边界框
const line = new LineEnt(new Point2D(0, 0), new Point2D(100, 50));
const lineBbox = line.boundingBox();
console.log(lineBbox.width); // 100
console.log(lineBbox.height); // 50
// 圆的边界框
const circle = new CircleEnt(new Point2D(50, 50), 30);
const circleBbox = circle.boundingBox();
console.log(circleBbox.minX); // 20 (50 - 30)
console.log(circleBbox.maxX); // 80 (50 + 30)边界框相交检测
检测两个边界框是否相交
function boxesIntersect(box1: BoundingBox, box2: BoundingBox): boolean {
return !(
box1.maxX < box2.minX ||
box1.minX > box2.maxX ||
box1.maxY < box2.minY ||
box1.minY > box2.maxY
);
}
// 使用示例
const box1 = new BoundingBox(new Point2D(0, 0), new Point2D(50, 50));
const box2 = new BoundingBox(new Point2D(40, 40), new Point2D(100, 100));
const box3 = new BoundingBox(new Point2D(60, 60), new Point2D(100, 100));
console.log(boxesIntersect(box1, box2)); // true - 有重叠
console.log(boxesIntersect(box1, box3)); // false - 无重叠检测边界框是否完全包含另一个
function boxContains(outer: BoundingBox, inner: BoundingBox): boolean {
return (
outer.minX <= inner.minX &&
outer.maxX >= inner.maxX &&
outer.minY <= inner.minY &&
outer.maxY >= inner.maxY
);
}边界框操作
扩展边界框
function expandBox(box: BoundingBox, margin: number): BoundingBox {
return new BoundingBox(
new Point2D(box.minX - margin, box.minY - margin),
new Point2D(box.maxX + margin, box.maxY + margin)
);
}
// 使用示例
const bbox = new BoundingBox(new Point2D(10, 10), new Point2D(90, 90));
const expanded = expandBox(bbox, 5);
// expanded: (5, 5) - (95, 95)计算边界框的交集
function boxIntersection(box1: BoundingBox, box2: BoundingBox): BoundingBox | null {
const minX = Math.max(box1.minX, box2.minX);
const minY = Math.max(box1.minY, box2.minY);
const maxX = Math.min(box1.maxX, box2.maxX);
const maxY = Math.min(box1.maxY, box2.maxY);
// 检查是否有有效交集
if (minX > maxX || minY > maxY) {
return null;
}
return new BoundingBox(
new Point2D(minX, minY),
new Point2D(maxX, maxY)
);
}使用场景
视图缩放到范围
import { Engine, mergeBoundingBoxes } from 'vjcad';
// 缩放视图以显示所有选中实体
function zoomToSelection() {
const selectedEntities = Engine.getSelectedEntities();
if (selectedEntities.length === 0) return;
// 获取所有实体的边界框
const boxes = selectedEntities
.map(e => e.boundingBox())
.filter(box => box.hasSizeBounds);
if (boxes.length === 0) return;
// 合并为总边界框
const merged = mergeBoundingBoxes(boxes);
// 缩放视图
Engine.zoomToExtent(merged);
}快速碰撞检测
先用边界框进行粗略碰撞检测,再进行精确检测可以提高性能:
function quickCollisionCheck(entity1: EntityBase, entity2: EntityBase): boolean {
const box1 = entity1.boundingBox();
const box2 = entity2.boundingBox();
// 边界框不相交,肯定不碰撞
if (!boxesIntersect(box1, box2)) {
return false;
}
// 边界框相交,需要精确检测
return preciseCollisionCheck(entity1, entity2);
}选择框实现
import { GeometryUtils } from 'vjcad';
function selectEntitiesInBox(
selectionBox: BoundingBox,
entities: EntityBase[],
mode: 'Window' | 'Cross'
): EntityBase[] {
return entities.filter(entity => {
const entityBox = entity.boundingBox();
if (mode === 'Window') {
// 窗口模式:实体必须完全在选择框内
return boxContains(selectionBox, entityBox);
} else {
// 交叉模式:实体与选择框相交即可
return boxesIntersect(selectionBox, entityBox);
}
});
}从点数组计算边界框
import { calculateBoundingBoxFromPoints, Point2D } from 'vjcad';
const points = [
new Point2D(10, 20),
new Point2D(50, 80),
new Point2D(30, 10),
new Point2D(90, 50)
];
const bbox = calculateBoundingBoxFromPoints(points);
console.log(bbox.minX); // 10
console.log(bbox.maxX); // 90
console.log(bbox.minY); // 10
console.log(bbox.maxY); // 80