# 查询与选择

实体查询、过滤、选择集操作、边界框。

---

## 获取所有实体

```javascript
const { Engine } = vjcad;
// getEntities() 不带过滤 = [...currentSpace.items]，含已删除（isAlive=false）实体
const allEntities = Engine.getEntities(e => e.isAlive);   // 或 Engine.currentSpace.aliveItems
```

---

## 按类型获取

```javascript
const { Engine } = vjcad;

const lines   = Engine.getEntitiesByType('LINE');
const circles = Engine.getEntitiesByType('CIRCLE');
const arcs    = Engine.getEntitiesByType('ARC');
const plines  = Engine.getEntitiesByType('PLINE');
const texts   = Engine.getEntitiesByType('TEXT');
const mtexts  = Engine.getEntitiesByType('MTEXT');
const inserts = Engine.getEntitiesByType('INSERT');
const hatches = Engine.getEntitiesByType('HATCH');
```

> `getEntitiesByType` / `getEntities(filter)` 同样不过滤已删除实体；需要时在条件里加 `e.isAlive`，如 `Engine.getEntities(e => e.isAlive && e.type === 'LINE')`。

---

## 按条件过滤

```javascript
const { Engine } = vjcad;

// 按颜色
const redEntities = Engine.getEntities(ent => ent.color === 1);

// 按图层
const layerA = Engine.getEntities(ent => ent.layer === "图层A");

// 组合条件
const redLines = Engine.getEntities(ent =>
    ent.type === "LINE" && ent.color === 1
);

// 自定义复杂条件
const largeCircles = Engine.getEntities(ent =>
    ent.type === "CIRCLE" && ent.radius > 50
);

// 排除某些实体
const visible = Engine.getEntities(ent =>
    ent.layer !== "隐藏图层"
);

// 带扩展数据的实体
const withXData = Engine.getEntities(ent =>
    ent.hasExtData?.() && ent.extDataAppName === "MY_APP"
);
```

---

## 选择集操作

```javascript
const { Engine } = vjcad;

// 设置选择集
Engine.ssSetFirst([entity1, entity2]);

// 获取当前选择集
const selected = Engine.ssGetFirst();
console.log(`选中 ${selected.length} 个实体`);

// 清空选择集
Engine.ssSetFirst([]);

// 选择所有存活实体（不过滤会把已删除实体也塞进选择集）
Engine.ssSetFirst(Engine.getEntities(e => e.isAlive));
```

---

## 边界框

### 单个实体

```javascript
const bbox = entity.boundingBox();
// 返回 BoundingBox 类实例：{ pt1, pt2, minX, minY, maxX, maxY, width, height, center, ... }
// （返回纯 {minX,minY,maxX,maxY} 字面量的是 GLine/GArc/GCircle/GEllipse 几何原语，不是实体）

const w = bbox.width, h = bbox.height;
console.log(`宽度: ${w}, 高度: ${h}`);
console.log(`中心: (${bbox.center.x}, ${bbox.center.y})`);
```

### 多实体组合范围

```javascript
const { Engine } = vjcad;

// 方式1：Engine API
const combined = Engine.getBoundsByEntities([ent1, ent2], "WCS");

// 方式2：mergeBoundingBoxes（返回 BoundingBox 类实例）
const { mergeBoundingBoxes } = vjcad;
const merged = mergeBoundingBoxes([
    entity1.boundingBox(),   // 实体 boundingBox() 本就返回 BoundingBox 实例，可直接传
    entity2.boundingBox()
]);
```

### 判断相交与包含

> ⚠️ **`BoundingBox` 的 `pt1`/`pt2` 是纯数据字段**：`minX/minY/maxX/maxY` 仅在**构造时**从 pt1/pt2 快照一次，事后赋 `bb.pt1 = pt` 不会重算 min/max——`isPointInBox`/`width`/`center` 等仍按旧值返回。事后调整请用 `minPoint`/`maxPoint` setter 或直接写 `minX..maxY` 字段（`new BoundingBox()` + 赋 pt1/pt2 后 `isPointInBox(中点)=false`）。

```javascript
// 判断两个边界框是否相交
function bboxIntersects(bbox1, bbox2) {
    return !(
        bbox1.pt2.x < bbox2.pt1.x ||
        bbox1.pt1.x > bbox2.pt2.x ||
        bbox1.pt2.y < bbox2.pt1.y ||
        bbox1.pt1.y > bbox2.pt2.y
    );
}

// 判断点是否在边界框内
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;
}
```

---

## 屏幕范围内的实体

```javascript
const { Engine } = vjcad;

// 获取屏幕边界（世界坐标系）
const bounds = Engine.getScreenBoundsWcs();
// 返回: BoundingBox 类实例——{ pt1, pt2, minX, minY, maxX, maxY, width, height, center, ... }

// 获取屏幕内的实体
const screenEntities = Engine.getScreenEntities();
const expandedEntities = Engine.getScreenEntities(1.5);  // 扩展 1.5 倍范围
```
