无需人工标注位置,一键在Web端CAD图上根据测点编号自动标注位置
CAD图如下图所示
在后台数据库中只有测点编号及测点值的信息,如下列列表
测点编号 测点类型 测点值
DZ129-2 类型1 值1
DZ128-2 类型1 值2
DZ127-2 类型1 值3
J28 类型2 值5
J26 类型2 值6
J27 类型2 值7
J29 类型2 值8
.......
那怎么把上面的测点值在CAD图相应位置展示出来呢?如下图
因为后台数据库中没有测点坐标信息,传统的方法一般是事先人工在地图上手工标注每个测点对应的位置,然后把位置信息保存至后台数据库。下次再从数据中获取位置信息和测点信息显示在地图上。这个方法的缺点也很明显,如果测点多时,人工标注每个测点对应的位置是一件费时费力的事情。
实现
规律分析
要找出测点编号对应的地理位置就得知道每个类型的测点的规律或规则是什么。
如上例图的两种不同的测点:
测点类型1
规律为:每个测点旁边有一个填充的三角形测点符号
测点类型2
规律为:每个测点旁边有一个填充的红色的圆形符号
根据规律查找对应的图形符号
查找方法有多种,如图像识别,图形分析等。因为图像识别干扰因素多,同时性能慢。而图形分析速度快,准确率高。这里我们采用图形分析来查找。
步骤为:
(1) 遍历图中所有实体类型
(2)通过实体类型和实体范围大小来确定是否满足条件
根据图形符号搜索旁边对应的测点编号,并建立关联关系
步骤为:
(1) 搜索符号旁边一定范围(如可设置为符号范围的几倍),设置旁边最近的文字
(2) 根据文字的内容规则去排查非测点编号名称(如此图中测点编号是以 DZ或J开头的,长度也有限制)
(3) 在所有满足条件的测点编号名称中查找一个距离最近的做为最终的测点编号名称
(4) 把测点编号名称和图形符号的坐标建立关联关系。
关键代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | const queryMapText = async () => { let query = await svc.conditionQueryFeature({ // 查询所有文字(包括单行文本,多行文本、块注记文字,属性文字) 具体类型数字参考文档"服务端条件查询和表达式查询-支持的cad实体类型" 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: "" , limit: 100000 // 全部查吧 }) if (query.error) { message.error(query.error) } else { query.result.forEach(rst => { rst.position = vjmap.GeoPoint.fromString(rst.location); // 获取坐标 }) return query.result; } } // 获取图中的文字信息 let mapAllText = await queryMapText(); console.log(mapAllText); // 查找所有hatch const queryHatch = async () => { let query = await svc.conditionQueryFeature({ condition: `(name= '11' ) `, // 类型为hatch fields: "" , includegeom: true , limit: 100000 // 全部查吧 }) if (query.error) { message.error(query.error) } else { query.result.forEach(rst => { rst.geoBounds = vjmap.GeoBounds.fromString(rst.bounds); // 获取范围 let w = rst.geoBounds.width(); let h = rst.geoBounds.height(); // 如果半径为2,则是圆,旁边是J_的 if (vjmap.isZero(w - 2, 0.1) && vjmap.isZero(h - 2, 0.1)) { rst.type = "circle_20" ; } else { if (rst.geom.geometries[0].type == "Polygon" && rst.geom.geometries[0].coordinates[0].length == 5) { // 如果是三角形填充 if (vjmap.isZero(w - 2.5, 1) && vjmap.isZero(h - 2.5, 1)) { rst.type = "triangle" ; } } } }) return query.result; } } // 获取图中的文字信息 let mapAllCircleHatch = await queryHatch(); console.log(mapAllCircleHatch); // 圆旁边是文字J开头的 let dataCircleTextG = mapAllCircleHatch.filter(rst => rst.type == "circle_28" ) dataCircleTextG.forEach(circle => { // 查找距离最近的一个以J开头的文字 let texts = mapAllText.filter(t => t.text.substr(0, 1) == "J" ) let findTexts = texts.filter(t => t.position.distanceTo(circle.geoBounds.center()) <= 2.8 * 3) // 查找符合条件的文字 // 找一个距离最近的 if (findTexts.length > 0) { findTexts = findTexts.sort((a, b) => a.position.distanceTo(circle.geoBounds.center()) - b.position.distanceTo(circle.geoBounds.center()) ) drawDatas.push({ point: circle.geoBounds.center(), name: findTexts[0].text, color: "#0f0" }) } }) // 三角形旁边是文字DZ开头的 let dataTriangleTextDz = mapAllCircleHatch.filter(rst => rst.type == "triangle" ) dataTriangleTextDz.forEach(tri => { // 查找距离最近的一个以DZ开头的文字 let texts = mapAllText.filter(t => t.text.substr(0, 2) == "DZ" ) let findTexts = texts.filter(t => t.position.distanceTo(tri.geoBounds.center()) <= 2.8 * 3) // 查找符合条件的文字 // 找一个距离最近的 if (findTexts.length > 0) { findTexts = findTexts.sort((a, b) => a.position.distanceTo(tri.geoBounds.center()) - b.position.distanceTo(tri.geoBounds.center()) ) drawDatas.push({ point: tri.geoBounds.center(), name: findTexts[0].text, color: "#f0f" }) } }) console.log(drawDatas) // 把数据显示到图上 let symbols; const showDataInMap = (datas)=> { let geoDatas = [] for ( let i = 0; i < datas.length; i++) { const pt = datas[i].point; const data = { point: map.toLngLat(pt), properties: { name: datas[i].name, textColor: datas[i].color } } geoDatas.push(data); } if (symbols) { symbols.remove(); // 如果有先删除了 } symbols = new vjmap.Symbol({ data: geoDatas, iconImage: "stretchTextBackImg" , iconAnchor: "bottom" , iconOpacity: 0.5, iconOffset: [-2, -10], textTranslate: [-2, -6], textAnchor: "bottom" , textField: [ 'get' , 'name' ], textFont: [ 'Arial Unicode MS Regular' ], textSize: 14, textColor: [ 'get' , 'textColor' ], iconTextFit: "both" , iconAllowOverlap: true , textAllowOverlap: true }); symbols.addTo(map); } showDataInMap(drawDatas); |
最效效果
上面的案例代码已开源,出于对用户数据保密的需要,案例代码用唯杰地图官网的示例图进行了替换,思路一致。访问 (https://vjmap.com/demo/#/demo/map/service/22findtextbyrules
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)