> **本文回答**：选择 CAD 实体 —— 点选 / 框选 / 多边形选，高亮与对象 ID。

## 一、前提

选择 **CAD 原始实体**（区别于 Draw / GeoJSON 要素）必须：

- `svc.openMap({ mapopenway: vjmap.MapOpenWay.GeomRender })`
  - 内存模式（`Memory`）不存实体 → 无法选择
- 后端要返回 geom 字段

## 二、点选：hover 高亮 + click 查询

### 栅格样式

```js
map.enableLayerClickHighlight(svc, (e) => {
  if (!e) return;
  console.log(`name=${e.name}, id=${e.objectid}, layer=${e.layerindex}`);
});
```

### 矢量样式

```js
const layers = svc.getMapLayers();
const { entTypeIdMap } = await svc.getConstData();

map.enableVectorLayerHoverHighlight((event, feature, layer) => {
  const prop = feature.properties;
  console.log(`feature=${feature.id}, layer=${layers[prop.layer].name}, type=${entTypeIdMap[prop.type]}`);
});
```

### 主动查询一点

```js
map.on("click", async (e) => {
  const pt = map.fromLngLat(e.lngLat);
  const q = await svc.pointQueryFeature({
    x: pt.x, y: pt.y,
    pixelsize: 5,
    zoom: map.getZoom()
  });
  console.log(q);
});
```

## 三、框选 (Rectangle)

```js
const r = await vjmap.Draw.actionDrawRectangle(map, {
  api: { getSnapFeatures: snapObj }
});
if (r.cancel) return;

const [p1, p2, p3, p4] = map.fromLngLat(r.features[0].geometry.coordinates[0]);
const bounds = [p1.x, p1.y, p3.x, p3.y];

const features = await getHighlightEntities(map, bounds, /*useGeomCoord*/ true);
```

**推荐：用 `conditionQueryFeature` 内置的范围参数**（官方示例 `22hightselentity.js` 的做法；`bounds` 就是上面 `map.fromLngLat` 得到的地图坐标，无需手写空间 SQL）：

```js
const res = await svc.conditionQueryFeature({
  condition: "",          // 可再叠加属性条件
  bounds,                 // [x1, y1, x2, y2]；多边形传点数组 [[x, y], ...]
  isContains: true,       // true = 完全包含；false（默认）= 相交
  includegeom: true,      // 返回几何
  realgeom: true,         // 每条都返回真实几何（否则多条时只给外包矩形）
  fields: "",
  limit: 100000
});
```

手写空间 SQL 的参考实现如下（`getHighlightEntities` 不是包内导出函数，需自己写）：

```js
async function getHighlightEntities(map, [x1, y1, x2, y2], useGeomCoord, disableHighlight, includeWholeEntity, disabledSet) {
  const svc = map.getService();
  // ⚠️ ST_MakeEnvelope 所有形态都返回 0——该谓词在后端
  // 不被支持，老资料里的 `geom::geometry && ST_MakeEnvelope(...)` 配方已失效。
  // 可用配方：ST_Intersects(geom, ST_GeomFromText(wkt, 0))，坐标必须是**实体坐标域**
  const wkt = `POLYGON((${x1} ${y1}, ${x2} ${y1}, ${x2} ${y2}, ${x1} ${y2}, ${x1} ${y1}))`;
  const res = await svc.conditionQueryFeature({
    condition: `ST_Intersects(geom, ST_GeomFromText('${wkt}', 0))`,
    fields: "objectid,name,envelop,layer,color",
    geom: true,
    limit: 100000
  });
  // 根据 res.result 生成 GeoJSON features, 再高亮
  return { features: ... };
}

// ⚠️ 三个坐标/语法坑位：
// 1) geom 条件里的 WKT 必须是**实体坐标域**（envelop 字段同一空间，百万级 CAD 原始
//    坐标），不是 drawBounds/鼠标 lngLat 的显示域——两域不重叠，混用必 0 命中。
// 2) ST_Intersects/ST_Within 第二参必须写 ST_GeomFromText('...', 0)——
//    把裸 WKT 字符串直接传参会使空间条件退化为永真，返回**全表**（554 条）。
// 3) 简单矩形框选（显示域）用 `rectQueryFeature({x1,y1,x2,y2})` 更稳——
//    它用的是地图显示坐标域，与鼠标框选一致。
```

实际项目可引入 vjmapext 用 `mapcadLayer.inputManager.getSelections(...)`（vjmapext 没有名为 `selectEntities` 的导出函数）。

## 四、多边形选（Polygon）

```js
const r = await vjmap.Draw.actionDrawPolygon(map, { api: { getSnapFeatures: snapObj } });
if (r.cancel) return;
const ring = map.fromLngLat(r.features[0].geometry.coordinates[0]);

// 推荐：内置多边形范围查询（官方 22hightselentitypoly.js）
const hit = await svc.conditionQueryFeature({
  condition: "", bounds: ring.map(p => [p.x, p.y]), isContains: true,
  includegeom: true, realgeom: true, fields: "", limit: 100000
});

// 或手写空间 SQL：

// 转 WKT
const wkt = `POLYGON((${ring.map(p => `${p.x} ${p.y}`).join(",")}))`;
const res = await svc.conditionQueryFeature({
  condition: `ST_Within(geom, ST_GeomFromText('${wkt}', 0))`,
  fields: "objectid,name,envelop",
  geom: true,
  limit: 100000
});
```

## 五、连续选择（`actionSelect` 风格）

参考 [draw-action.md](draw-action.md#七选择实体不是-draw-的实体而是-cad-实体) 的 `selectFeatures` 函数。关键点：

- 循环里每次 `actionDrawRectangle / actionDrawPoint`
- 右键 → `map.fire("keyup", { keyCode: 13 })` 触发结束
- 累积所选要素

## 六、高亮方式

1. **内置点击高亮**：`map.enableLayerClickHighlight(svc, cb)` 内部用 `<prefix>-source`（默认 `highlight-source`）存高亮要素——**注意 `vjmap.HighlightFeatureStyle`/`highlight_feature_source` 并不是真实导出名**，要自定义样式就对 `highlight-source` 这个 source 自己配 layer。
2. **自己画**：对选中 features 建一个 `new vjmap.Polygon / vjmap.Polyline`，`addTo(map)`。
3. **矢量样式用 feature-state**：
   ```js
   map.setFeatureState({ source: "layer-src", sourceLayer: "...", id: 123 }, { selected: true });
   // 样式中用 ["feature-state", "selected"]
   ```

## 七、清除选择

没有内置的 `clearHighlight` 方法，按高亮的实现方式分别清：

```js
// 1) 内置点击高亮（enableLayerClickHighlight 用 <prefix>-source 存高亮要素，默认前缀 "highlight"）
// 只清当前高亮、保留点击高亮模式：
map.getSource("highlight-source")
   ?.setData({ type: "FeatureCollection", features: [] });
// 彻底关掉：会连同 highlight-source 及其线/面图层一起删除并解绑 click（之后无需再 setData）
map.disableLayerClickHighlight();

// 2) feature-state 方式：逐条或整块清
map.removeFeatureState({ source: "layer-src", sourceLayer: "..." });        // 省 id = 清整个 source
map.removeFeatureState({ source: "layer-src", sourceLayer: "...", id }, "selected");

// 3) 自己画的高亮图层/实体
map.removeSourceEx("my-sel");   // vjmap 扩展：连同用到它的 layer 一起移除
```

## 八、批量 objectid 查询

```js
const ids = [10, 20, 30];
const res = await svc.conditionQueryFeature({
  condition: `objectid in (${ids.join(",")})`,
  fields: "objectid,name,envelop",
  geom: true
});
```

## 九、图层显示过滤

选择前限制"只能选某图层"：

```js
const disableSet = new Set(["LAYER_A", "LAYER_B"]);
const features = await getHighlightEntities(map, bounds, true, undefined, undefined, disableSet);
```

## 十、常见坑

1. **内存模式选不了** → 切换 `MapOpenWay.GeomRender` 或 `mapopenway: "GeomRender"`。
2. **框大了查询超时** → 后端 `limit` 加保护。
3. **栅格 + 矢量两套样式共存时 hover 不对**：查看 `map.hasVectorLayer()` 决定走哪条分支。
4. **PostGIS envelope 查询速度慢** → 服务端 `geom` 字段建 GIST 索引（内置）。
