道路指定桩号处管线标高查询程序的编制思路

两天前,有道路专业的同事找我帮忙解决一个问题:

既有一个 *.dwg 文件,存储了大量片区管线资料,管线按实际位置以空间直线(LINE)而非空间多段线(POLYLINE)的形式存储,不同类型的管线分图层存储,现需要沿道路中心线按给定桩号间隔读取道路宽度范围内所有管线的标高或埋深,希望能有比较便捷的程序进行处理。

说实话,这个问题在 AutoCAD 中的解决方法并不是很困难,只是过程相对繁琐,并且算法处理不好时,时间复杂度会比较高,如果是 O(n2)O(n^2) 级别的时间复杂度则是不能接受的。就在我基本考虑好这个问题并准备编写代码时,需求 变了!!!用户希望自行在管线上选取一点读出管线在该位置的标高并标注在图中。这个需求大大降低了程序编制的难度(程序员碰到这种产品经理或用户真要开心死了)。当天吃完午饭后午休时间,用了二十分钟不到的时间,我写完了这段代码(主程序代码都不超过 20 行)。考虑到前面的需求已经进行了一定程度的思索,我在这里把程序编制的思路写下来,以便将来遇到类似的问题可以用得上,同时也测试一下 hexonext 主题下 markdownmermaid 图形生成静态网页的情况。

程序需要解决的问题及对策

道路中线与道路路面的表达

道路中心线与道路路面的表达在我自己编写的 BRTools 中已经有了解决办法,道路中心线用连成一体的轻量化多段线(LWPOLYLINE)进行表达,路面信息可以通过竖曲线扩展数据和超高扩展数据进行表达,简言之,对于给定的道路中心线,能够得到任一道路里程点切线和法线方向,加上道路竖曲线、超高信息,就能够得到路面上任一位置的高程。这里,BRTools 对超高的处理不是太完善,变宽路面好像没有考虑(毕竟这是十年前编写的东西,我又不是学道路专业的,真的记不清楚了),可能需要再进行一些补充。

与指定桩号相关的所有管线的选取

这个问题是完成整个程序编写的关键,需求变更时把这一步由用户自行选择就大大降低了问题的复杂程度。如果需求仍然是由道路桩号决定,那么就需要求取各种管线与道路里程点的法平面之交点。空间直线段与某平面的交点可以通过坐标变换的方式容易求取,假设空间直线段起终点在世界坐标系(WCS)中坐标表分别为变量 ptspte,平面的法向量为 normal,该平面上的某点坐标变量为 ptm,则:

1
2
3
(setq pts (trans pts 0 normal) 
pte (trans pte 0 normal)
ptm (trans ptm 0 normal))

则将 ptspteptm 均转换成为以 normal 为法线的对象坐标系(OCS)坐标,若 ptm 的 Z 坐标介于 ptspte 的 Z 坐标之间,则该线段与平面必然存在交点。容易理解但啰嗦的写法是:

1
2
3
(or 
(< (caddr pts) (caddr ptm) (caddr pte))
(> (caddr pts) (caddr ptm) (caddr pte)))

不太容易理解但好扩展的炫技写法是:

1
2
3
4
5
(apply 'or 
(mapcar
'(lambda(x)
(cons x (mapcar 'caddr (list pts ptm pte))))
(list '> '<)))

若上面表达式值为 T,则直线段与平面的交点坐标为:

1
2
3
4
5
6
7
8
(trans 
(inters
pts
pte
(list (car pts) (cadr pts) (caddr ptm))
(list (car pte) (cadr pte) (caddr ptm))
T)
normal 0)

这个很好理解,就是空间直线段与其在平面上的投影的交点。

目前为止,道路中心线某一里程点的法平面很容易确定,因此只需要遍历所有管线,判断其是否与法平面相交,若相交则求取交点,并结合管线的其他信息存储在一个表中。这时存在一个问题,管线的图元数量巨大,且对于某一里程点来说,大部分管线是不与道路里程点的法平面相交的,为了避免这些无意义的计算与判断,必须进行过滤选择。AutoLisp 中的 ssget 函数提供了很多过滤功能,其中 f 选项可以通过两点画线相交的方式进行过滤选择。我从前不确定这种选择方式是否在图形屏幕区以外的部分能够将图元选择上,所以一直都不常使用这种过滤方式,如今进行一下测试,即使是不在 AutoCAD 图形屏幕区范围内的图元也能够被选中,那么问题就相对简单了,只需要

1
(setq ss (ssget "f" (list pt1 pt2) (list (0 . "LINE") (cons 8 layer))))

就可以将 pt1pt2 两点连线划中的位于 layer 图层的 LINE 图元全部选中,置于 ss 选择集中。pt1pt2 可以考虑使用道路中心线正负法向距离为道路半宽的点。至此,程序的主要问题就解决了。

程序的大概框图

其实本文没有什么值得记录的意义,我只是想在这里尝试一下 hexonext 主题下 markdown 中的 mermaidflow 图形生成静态网页的情况。现在看来,实现没有问题,需要做的事情是装两个插件:

1
npm install --save hexo-filter-flowchart

以及

1
npm install hexo-filter-mermaid-diagrams

这个程序的框图可以表现为:

嗯,说老实话,flow 的效果实在是太 丑陋 了,赶明儿个用 graph 写写试试。

感谢拨冗阅读本文,若有些许收获,不妨捐赠以资鼓励。