唯杰地图 logo唯杰地图
VJMAP
EN

query-cases

vjmap/references/backend/query-cases.md 10.8 KB233 行
原文

本文回答:查询 + 处理的典型综合用例:自动分割子图、自动标注、自动提表格、自动提取中心线、工程剖面图。

案例里所有 name='xx' 实体类型、字段(s4, n6, n7, ...)含义、conditionQueryFeature 完整参数 ⇒ 见 query-features(主查询文档)。本文只描述算法思路 + 关键代码。

这些案例展示了"查询 + 空间算法 + 后续绘制/导出"的思路。完整 demo 可在官方示例 https://vjmap.com/demo/ 搜关键词查看。

一、自动分割子图(queryCase1)

需求:一张"总图"里含多个独立子图,要把每个子图分别取出。

思路:

  1. 查询所有横竖直线 / 闭合多段线(name='1'、name='2' and n6=1,类型 ID 与字段含义见 query-features 第三、四节)。
  2. 按包围关系判断每个子图的轮廓(找最外层未被包含的矩形)。
  3. 对每个轮廓调用 svc.composeNewMap({ clipbounds }),生成仅含该范围的新图。

关键 SQL:

// 所有"线段"类(直线、二三维多段线)
const cond = `name='1' or name='2' or name='3' or name='4'`;
const lines = await svc.conditionQueryFeature({
  condition: cond,
  fields: "objectid,points,envelop",
  limit: 100000
});

组合裁剪:

for (const outline of outlines) {
  const composed = await svc.composeNewMap([{
    mapid, version,
    clipbounds: outline.bounds.toArray()
  }]);
  // composed.fileid 可用于上传 / 创建新图
}

完整算法(找四线组合矩形、横竖线判断)见原文 https://vjmap.com/guide/queryCase1.html。

二、根据测点编号自动标注位置(queryCase2)

需求:工程图里的"点号 + 坐标"文字 / 测点符号,自动把测点编号关联到真实坐标位置。

两种模式:

A. 文字本身就是 编号 X=xxx Y=yyy 格式 —— 直接正则解析

// name='13' = AcDbText(单行文本)
const q = await svc.conditionQueryFeature({
  condition: "name='13'",
  fields: "text,location",
  limit: 100000
});
for (const t of q.result) {
  const m = t.text.match(/^(\d+)\s+X=(\S+)\s+Y=(\S+)/);
  if (!m) continue;
  const [, id, x, y] = m;
  new vjmap.Marker({ color: "#3e3" })
    .setLngLat(map.toLngLat([+x, +y]))
    .setPopup(new vjmap.Popup().setHTML(id))
    .addTo(map);
}

B. 文字只有点号,旁边有图形符号(圆 / 三角填充) —— 用空间临近匹配

// 1) 查所有以 J / DZ 开头的文字,长度 2-12(s4=text)
//    name='12'/'13'/'26'/'27' = 多行/单行/属性注记/块属性 文字类
const texts = await svc.conditionQueryFeature({
  condition: `(name='12' or name='13' or name='26' or name='27')
              and LENGTH(s4) >= 2 and LENGTH(s4) <= 12
              and (s4 like 'J%' or s4 like 'DZ%')`,
  fields: "objectid,text,location",
  limit: 100000
});

// 2) 查所有 hatch(name='11'),按尺寸区分圆 / 三角
const hatches = await svc.conditionQueryFeature({
  condition: `name='11'`,
  includegeom: true,
  limit: 100000
});

// 3) 对每个 hatch 在距离阈值内找最近的文字 → 建立关联

字段说明:name 类型 ID 见 query-features 第三节;s4 在文字类实体上 = text,详细对应表见 query-features 第四节。

三、自动识别图纸提取信息(queryCase3)

需求:批量识别图纸里的固定模式对象(如停车场的车位、图纸编号块、圆圈内文字…)。

五种识别方式:

  1. 属性数据匹配:通过实体类型+图层+颜色+面积+填充符号+是否同一块等组合一次查出。

    // 查 "0" 图层、面积 = 12720000 的多段线
    await svc.conditionQueryFeature({
      condition: `name='2' and layerindex=0 and n5=12720000`,
      limit: 100000
    });
    

    name 类型 ID 与 n5 在每种实体上的含义见 query-features 第三、四节。

  2. 属性 + 业务规则:先查易识别对象(如"圆"),再用空间邻近找关联文字。

  3. 业务逻辑代码:复杂场景(如自动分割子图,见第一节)。

  4. 图像相似性:WMS 出图后用 SIFT / 哈希比对(适用于"非块化的重复符号")。

  5. AI 深度学习:自定义训练目标检测模型,处理任意对象。

属性块抽取的常用做法:

// 表达式查询:查"图纸编号"块(gInAttrs5 对应 s5=blockname)
const blockQ = await svc.exprQueryFeature({
  expr: `return gInFeatureType == 'AcDbBlockReference' && gInAttrs5 == '图纸编号'`,
  fields: "objectid,blockname,positon,s4"   // fields 可写属性名或原始列名;块的 s4 列 = attributeDef
});
// 解析每条的 s4 -> KV 对

详细方法见原文 https://vjmap.com/guide/queryCase3.html。

四、自动提取表格数据(queryCase4)

需求:CAD 图里手工画的表格(线条 + 文字),识别行列并导出 JSON / CSV / Excel。

思路:

  1. 查所有水平 / 垂直直线(name='1',详见 query-features);过滤纯横竖(vjmap.isZero(dx) / vjmap.isZero(dy))。
  2. 查所有文字(name='12' or name='13' or name='26' or name='27')。
  3. 线段聚类:水平线按 Y 排序,相邻容差内归同一行;垂直线按 X 排序归同一列。
  4. 交点 = 单元格顶点,确定每个 cell 的边界。
  5. 文字插入点 vs 单元格边界,定位归属。
  6. 合并单元格:相邻 cell 共用边线缺失则视为合并。

后台已封装为命令 extractTable(execCommand 传的命令名;参数:tol 容差、tableEdgeMinPoint 最少点、tableTextMinCount 最少文本、cellEmptyRatio 空值比例…,全部字段见 SDK IExtractTable)。MCP 工具:extractTable(见 ai-features)。

// SDK 封装:内部 execCommand("extractTable", param, "_null", "v1"),mapid/version/layer 缺省取当前图
const r = await svc.cmdExtractTable({
  mapid, version,
  bounds: "x1,y1,x2,y2",   // 空表示全图
  tol: 0,                   // 0=自动求容差
  tableEdgeMinPoint: 12,
  tableTextMinCount: 4,
  findChildMapRects: false  // 同时返回子图范围
});

⚠️ 这类分析命令(extractTable/extractCenterLines/objectDetection)从参数里读 mapid/version,URL 段固定 "_null","v1";照普通命令把 mapid 放 URL、参数里不带,会报 param error, mapid is empty(几何渲染图则静默返回 {})。

五、自动提取中心线(queryCase5)

需求:墙体 / 道路 / 巷道由一对平行线组成,取它们的中心线(把"具象图形"转"抽象拓扑")。

思路:

  1. 分页查询所有直线 / 多段线(name='1' or name='2',分页见 query-features 第六节)。
  2. 对每条直线找到"平行配对"(角度容差 + 距离对,可同时配多组距离支持不同墙厚)。
  3. 中点连线 → 中心线。
  4. 后处理:合并端点、连接断口、过滤短线、合并共线段。

后台命令 extractCenterLines:

await svc.execCommand("extractCenterLines", {
  mapid, version,                // 必须放参数里(见上节 ⚠️)
  bounds: "x1,y1,x2,y2",
  minSpaceDistance: "2.5,3.5",   // 最小距离对(多组)
  maxSpaceDistance: "7.5,8.5",   // 最大距离对
  collinearTolerance: 1.0,        // 共线容差
  duplicateTolerance: 0.2,
  maxGapDistance: 5,              // 允许断开
  paralleSlopeAngleTolerance: 5,  // 平行角度误差(度)
  mergeSlopeAngleTolerance: 3,
  bMergeLine: true,
  bCenterGeoJson: true
}, "_null", "v1");                // 官方路由 /map/cmd/extractCenterLines/_null/v1

进阶:用高程注记给中心线插值赋值,再生成 3D 管道。

六、工程剖面图(综合 03)

需求:给定一条剖面线,抽取穿过的所有实体,按高程排版形成剖面。

思路:

  1. conditionQueryFeature({ bounds: 剖面线点列 }) 拿到穿越实体。
  2. 每个实体按投影 X 值排序。
  3. 用 vjmapext 的实体绘制 API 生成新图。

七、查找面积最大子实体(多种查询组合)

在 query-expression 第七节示例里展示了:

  1. 表达式查询全部块(name='10' = AcDbBlockReference)。
  2. 构造 objectid LIKE 'xxx_%' 条件查询每个块的子实体。
  3. 在客户端按块聚合取 area 最大值(n5 字段,含义见 query-features 第四节)。

八、选择技巧总结

  • 几何模式 + conditionQueryFeature:快,支持空间谓词(相交/包含)。完整接口见 query-features。
  • 内存模式 + exprQueryFeature:不入库,适合"临时查看 + 简单过滤"。
  • 几何模式 + exprQueryFeature:某些复杂逻辑在 SQL 里写不出时的回退方案。
  • 全文搜索:在所有图中按文字 / 图层名 / 块名 搜索。
  • 后台命令:extractTable / extractCenterLines / objectDetection 等已封装的复杂流程,直接用最省事。

九、常见坑

  1. 把几何查询当成小数据量 → 大图查 100 万条很慢。分页 + 只要必要字段(见 query-features 第十一节)。
  2. 自动分割子图时 clipbounds 稍小 → 边界线条缺失。bounds.scale(1.02) 稍放大。
  3. 表格提取后行列对齐错乱 → 由于 CAD 用户画线不精确,需要做容差聚类(距离 < tol 视为同一行)。
  4. 中心线不连续 → 平行线有断开,调大 maxGapDistance;或图里有干扰元素,先用图层切换/手动框选缩范围。
  5. 属性识别失败 → 先 console.log 一两条数据看 s3..s5 / n5..n10 的真实值(不同类型字段含义不同,见 query-features 第四节)。

十、相关文档