基于AutoCAD的多段线点坐标提取
2016-08-22李玲
■ 李玲
(广西壮族自治区地理国情监测院广西南宁530023)
基于AutoCAD的多段线点坐标提取
■李玲
(广西壮族自治区地理国情监测院广西南宁530023)
本文主要介绍AutoCAD不同类型的多段线数据存储结构及相应的点坐标提取算法。
多段线坐标凸度弧段逆时针顺时针样条拟合
1 引言
在AutoCAD中,实现要素的制图表现或提取坐标信息的过程中,我们不可避免地要读取要素骨架线(点)的图形信息特别是空间信息,以确定相辅的点、线、文本的空间位置。AutoCAD中点、线段、文本、插入块等的坐标提取都相对简单,相对于其他实体,多点线段也称多段线或称复合线(以下统称多段线)在AutoCAD中有不同的表现形式和存储结构,其线上的结点坐标提取也较为复杂。
自R14版本的AutoCAD开始,多线段由原来的POLYLINE分化为LWPOLYLINE和POLYLINE,两种类型的多段线在AUTOCAD中的存储结构不一致,表现形式也多种多样:
LWPOLYLINE为简单实体,其实体存储列表中可以通过简单的函数获取。LWPOLYLINE多段线上每个结点的高程一致,整根线段的标高由其实体存储列表中的组码38对应的数据项决定,实体存储列表中组码70对应的数据项为LWPOLYLINE的特征值,设特征值的二进制形式如下:
其中,当X0值为1时LWPOLYLINE为闭合线,当X7值为1 时LWPOLYLINE整段线线型规范化表示。在表现形式上,LWPOLYLINE可分为:折线LWPOLYLINE——结点与结点间以直线段相连接;含弧段的LWPOLYLINE——结点与结点间或以直线段相连,或以弧段相连。LWPOLYLINE也称超轻线,存储所占字节相对POLYLINE较小,但LWPOLYLINE一经曲线光滑处理(算法分拟合和样条拟合两种)后,其数据类型就会转换成POLYLINE。
POLYLINE为复杂实体:多段线为主实体,有相应的实体存储列表,线上的每个结点为子实体,在图形中各自有相应的实体存储列表。每个结点允许有不同的高程值,因此,POLYLINE也称三维多段线。整根POLYLINE的结点搜索要通过由主实体引导的每个子实体存储列表的循环来完成。POLYLINE主实体存储列表中组码70对应的数据项为POLYLINE的特征值,设特征值的二进制形式如下:
其中,当X0值为1时POLYLINE为闭合线,当X7值为1时POLYLINE整段线线型规范化表示,当X1为1时POLYLINE为拟合法生成的光滑曲线,当X2为1时POLYLINE为样条拟合法生成的光滑曲线。在表现形式上,POLYLINE可分为:折线POLYLINE——结点间以直线段相连,拟合POLYLINE——由拟合法生成的光滑曲线,样条POLYLINE——样条拟合法生成的光滑曲线。
LWPOLYLINE和POLYLINE不同的存储结构和多种表现形式导致在点坐标提取中要详细分析,分别处理。
2 LWPOLYLINE的点坐标提取
如前所述,LWPOLYLINE在表现形式上,可分为:折线LWPOLYLINE——结点与结点间以直线段相连接和含弧段的LWPOLYLINE——结点与结点间或以直线段相连,或以弧段相连。在地形图的数据采集中,许多要素如围墙、铁路、房屋、道路等通常用LWPOLYLINE多段线表示,而在要素的骨架线采集中,经常需要在多段线中加入弧段:如弧形阳台,弧形围墙等等。
我们先来看看LWPLOLYLINE的数据结构。
如图1为一LWPOLYLINE多段线,结点1,2间为直线段,结点2,3间为弧段a1,其圆心为点c1,结点3,4间为弧段,其圆心为c2,结点4,5间为直线段。在AUTOCAD中获取此多段线的实体存储列表如下:
((-1.<图元名:4009a500>)(0."LWPOLYLINE")(330.<图元名:4008cc10>)(5."118")(100."AcDbEntity")(67.0)(410."Model") (8."0")(100."AcDbPolyline")(90.5)(70.0)(43.1.0)(38.0.0)(39. 0.0)(10 80.7448 199.489)(40.1.0)(41.1.0)(42.0.0)(10 127.561 129.576)(40.1.0)(41.1.0)(42.0.366517)(10 215.933 104.344)(40. 1.0)(41.1.0)(42.-0.366517)(10 311.471 77.0665)(40.1.0)(41.1.0) (42.0.0)(10 383.645 100.228)(40.1.0)(41.1.0)(42.0.0)(210 0.0 0.0 1.0))
其中,组码10对应的数据项记录了多段线的几个结点(1,2,3,4,5)的点坐标,组码42对应的数据项的值为弧段凸度(Bugle),其值为0时表示前后两结点组成直线段(如1,2结点),其值大于0时表示前后两结点组成前进方向右边的(可以理解为顺时针)弧段(如2,3结点),其值小于0时表示前后两结点组成前进方向左边的(可以理解为逆时针)弧段(如3,4结点)。
在获取LWPOLYLINE结点坐标时,我们要根据多段线的存储结构作相应的处理。
2.1折线LWPOLYLINE的点坐标提取
提取折线LWPOLYLINE中的点坐标方法很简单,只需循环读取多段线存储列表中组码为10对应的数据项即可。假设实体列表赋值为EN,则读取结点坐标并赋值到PLIST结点列表的LISP程序代码为:
(SETQ I 0 LEN(LENGTH EN))
(WHILE(
(SETQ VN(LIST(NTH I EN))P(CDR(ASSOC 10 VN)))
(IF P(SETQ PLIST(CONS P PLIST)))
(SETQ I(1+I))
);End of While
程序代码段1折线LWPOLYLINE中的点坐标提取
2.2含弧段的LWPOLYLINE的点坐标提取
当骨架线中含有弧段时,我们需要在不失真的情况下按一定间隔提取弧段上的点坐标。由前面的数据分析,我们知道多段线的存储列表中仅记录连接弧线段的前后两个的坐标和此弧段的凸度。因此,为了提取弧段上的点坐标,我们必须先了解AUTOCAD中关于凸度的定义。
凸度也称弓弦比,其绝对值为弦高和弦长之比的两倍,即2× H/D之值(如图2),当凸度值为1.0或-1.0时,弧段为半圆。凸度值为0时表示前后两结点组成直线段,值大于0时表示前后两结点组成前进方向右边的(可以理解为顺时针)弧段,值小于0时表示前后两结点组成前进方向左边的(可以理解为逆时针)弧段。
如图2,假设我们知道一多段线LWPOLYLINE线上的两结点坐标分别为P1和P2,采集方向从P1点到P2点,P1和P2两结点间的凸度值为Bulge,因为Bulge的绝对值等于2×H/D,则H/D= Bulge的绝对值/2.0,而弦长D为结点P1和P2的距离,可用函数(DISTANCE P1 P2)轻易求出,因此H的值也能求出。
下面我们根据H和D的值求圆心C0的坐标和弧段半径r:
在三角形△P1C0P2中利用勾股定律,有r 2=(D/2)2+(r-H)2,求出r=(D/H/8.0+H/D/2.0)×D。
圆心C0的求取要根据弧段的方向(顺时针或逆时针)来判断,设弦P1P2的中点坐标为MidP,P1到P2的方位角为ANG,ang90为PI/2.0,ang_90为-PI/2.0,则逆时针弧段的圆心坐标C0可用函数(POLAR midp(+ang ang90)(-r h))求得,顺时针弧段的圆心坐标C0可用函数(POLAR midp(+ang ang_90)(-r h))求得。
求得圆心C0和半径r之后,弧段内插点的坐标就容易求出来了。如图2,设C0到P1的方位角为ang1,C0到P2的方位角为ang2,ang1到ang2的弧度增量为dispang,以ang=ang1为起始角度,按dispang弧度大小递增,即ang=(+ang dispang),则结点P1与P2间的弧段内插点坐标为P=(polar cent ang r),循环提取内插点坐标直至ang>=ang2。
弧度增量dispang的绝对值大小与提取精度有关,值太小则点太密,导出的弧段点太密,值太大则导出的弧段严重失真。弧段提取的循环方式与弧段的方向(顺时针还是逆时针)和方位角ang1与ang2之间的大小关系密切相关,我们将在下面内容中分逆时针弧段和顺时针弧段详细讨论。
由以上的分析,我们知道,多段线上的弧段信息对于我们提取结点坐标来说至关重要,因此,我们在获取LWPOLYLINE中的结点坐标的同时,也要获取与结点相关的弧段凸度Bulge的信息。在多段线LWPOLYLINE实体存储列表中,组码10对应的数据项记录了多段线的几个结点(1,2,3,4,5)的点坐标,组码42对应的数据项的值为弧段凸度(Bugle)。将程序代码段1修改如下(提取出来的结点列表赋值为PLIST,凸度列表赋值为BULGE_LIST):
(SETQ EN(ENTGET ENAME))
(SETQ I 0 LEN(LENGTH EN))
(WHILE(
(SETQ VN(LIST(NTH I EN)))
(SETQ BULGE(CDR(ASSOC 42 VN)))
(SETQ P(CDR(ASSOC 10 VN)))
(IF P(SETQ PLIST(APPEND PLIST(LIST P))))
(IF BULGE(SETQ BULGE_LIST(APPEND BULGE_LIST(LIST BULGE))))
(SETQ I(1+I))
);End of While
(IF(/=(LOGAND(CDR(ASSOC 70 VN))1)0);判断多段线是否闭合
(SETQ PLIST(APPEND PLIST(LIST(NTH 0PLIST))) BULGE_LIST(APPEND BULGE_LIST(LIST 0)))
);闭合多段线添加第一个结点
程序代码段2点列表和凸度列表的提取
2.2.1逆时针弧段的点提取
如图3所示,假设我们知道一多段线LWPOLYLINE线上的两结点(第i点和第i+1结点)坐标分别为P1和P2,采集方向从P1点到P2点,P1和P2两结点间的凸度值为Bulge。设已求出半径r和圆心C0,并设程序代码段2提取出来的结点列表赋值为PLIST,凸度列表赋值为BULGE_LIST,则Bulge=(nth i Bulge_list),p1=(nth i plist),p2=(nth(1+i)plist)。
设ang1、ang2分别为圆心C0到结点P1、圆心C0到结点P2的方位角,当弧段提取间隔为0.5米的时候,相应的弧度增量大小绝对值为dispang=(/0.5 r)。
当ang1
(SETQ ANG ANG1)
(WHILE(<(+ANG DISPANG)ANG2)
(SETQ ANG(+ANG DISPANG))
(SETQ P(POLAR C0 ANG R))
(SETQ BULGE_PLIST(APPEND BULGE_PLIST(LIST P)))
);While end
程序代码段3逆时针弧段点坐标提取
当ang1>ang2时,如图4所示,将ang1改为(-ang1(*pi 2.0)),程序代码段3不变。
2.2.2顺时针弧段的点提取
当Bulge<0,ang1>ang2时(如图5),以ang=ang2为起始角度,ang=(+ang dispang),则P1与P2间的间隔点为p=(polar cent ang r),循环直至ang>=ang1,然后将取得的弧段内插点列表转置。循环部分的程序代码如下(设Bulge_Plist为存储结点P1和结点P2间弧段内插点的点列表):
(SETQ ANG ANG2)
(WHILE(<(+ANG DISPANG)ANG1)
(SETQ ANG(+ANG DISPANG)
(SETQ P(POLAR C0 ANG R))
(SETQ BULGE_PLIST(APPEND BULGE_PLIST(LIST P)))
);While end
(SETQ BULGE_PLIST(REVERSE BULGE_PLIST));/*转置结点列表
程序代码段4顺时针弧段点坐标提取
当ang1 尽管LWPOLYLINE的存储字节小,但某些情况下它不能满足我们的成图需要,当我们需要光滑曲线时,我们要将LWPOLYLINE按拟合或样条拟合进行光滑处理,变成POLYLINE。 由前面的数据分析,我们了解POLYLINE为复杂实体:多段线为主实体,有相应的实体存储列表,线上的每个结点为子实体,在图形中各自有相应的实体存储列表。每个结点允许有不同的高程值。在表现形式上,POLYLINE分为:折线POLYLINE——结点间以直线段相连,拟合POLYLINE——由拟合法生成的光滑曲线,样条POLYLINE——样条拟合法生成的光滑曲线。 POLYLINE主实体存储列表中组码70对应的数据项为特征值,由前所述,特征值二进制形式中的X1值为1时表示POLYLINE为拟合法生成的光滑曲线,X2值为1时POLYLINE为样条拟合法生成的光滑曲线。我们可以通过对特征值的数值分析以区分POLYLINE的表现形式。 我们来看看拟合法生成的光滑曲线与样条拟合法生成的光滑曲线的区别。如图7,设折线3为一LWPOLYLINE,则曲线1为其经拟合法后生成的光滑曲线,曲线2为其经样条拟合法后生成的光滑曲线。曲线1和曲线2两者之间有本质上的区别:拟合法生成的光滑曲线仍通过原折线采集点,但在原折线两采集结点分别插入弧段;而样条拟合法后生成的光滑曲线以原折线结点作控制点光滑内插,偏离了原折线采集点。 我们在提取POLYLINE的结点坐标时,要根据其不同的表现形式,按不同的算法提取。 3.1折线POLYLINE的点坐标提取 我们知道POLYLINE为复杂实体,其每个结点在AUTOCAD中作为子实体,有相应的存储列表对应。整根POLYLINE多段线的结点提取可以通过由主实体引导的每个结点存储列表的组码为10对应的数据项的循环搜索来完成。假如一POLYLINE实体名赋值为Ename,则它的第一个结点子实体Vname可通过 (entnext ename)获取,下一个结点子实体则通过(entnext Vname)获取,循环直到子实体类型为"SEQEND"时结束。 实体名为ename的POLYLINE的点坐标提取程序代码为(点坐标提取列表赋值为Plist): (SETQ V(ENTNEXT ENAME)VN(ENTGET V))(WHILE(= (CDR(ASSOC 0 VN))"VERTEX") (SETQ PLIST(APPEND PLIST(LIST(CDR(ASSOC 10 VN))))) (SETQ V(ENTNEXT V)VN(ENTGET V)) );END WHILE 程序代码段5折线POLYLINE的点坐标提取 3.2拟合POLYLINE的点坐标提取 如图8所示,加粗线为LWPOLYLINE多段线,细实线为其经拟合后生成的光滑曲线。拟合后生成的光滑曲线,其数据结构中,除记录原折线上的结点1,2,3外,还新增了控制点C1,C2。拟合后的曲线以结点1,c1,2,c2,3为控制点分别在两结点间内插弧段,形成光滑曲线。 结点1,2,3为原结点,其结点实体列表(VN1)为: ((-1.<图元名:400ab090>)(0."VERTEX")(330.<图元名: 400ab080>)(5."292")(100."AcDbEntity")(67.0)(410."Model")(8. "JJ")(62.3)(100."AcDbVertex")(100."AcDb2dVertex")(10-146.87 491.48 0.0)(40.0.0)(41.0.0)(42.0.1182)(70.0)(50.0.0)) 结点C1,C2为曲线拟合后插入结点,其结点实体列表(VN2)为: ((-1.<图元名:400ab0d0>)(0.“VERTEX”)(330.<图元名: 400ab080>)(5.“29A”)(100.“AcDbEntity”)(67.0)(410.“Model”)(8.“JJ”)(62.3)(100.“AcDbVertex”)(100.“AcDb2dVertex”)(10 233.201 422.065 0.0)(40.0.0)(41.0.0)(42.0.313944)(70.1)(50. 0.0)) 对比以上两个列表,组码70对应的数据项的值分别为0和1,这是原结点与曲线拟合插入结点的根本区别。 如果仅提取原结点,那么在程序代码段5中只需加上对70组码对应的数据项的判断,仅提取数据项值为0对应的结点坐标即可。修改后的程序代码为: (SETQ V(ENTNEXT ENAME)VN(ENTGET V)) (WHILE(=(CDR(ASSOC 0 VN))"VERTEX")(IF(= (CDR(ASSOC 70 VN))0) (SETQ PLIST(APPEND PLIST(LIST(CDR(ASSOC 10 VN))))) );End of If (SETQ V(ENTNEXT V)VN(ENTGET V)) );END WHILE 程序代码段6拟合曲线原折线点坐标提取 如果需要不失真地提取拟合曲线上的点坐标,则需要将曲线拟合后内插的弧段按一定间隔提取坐标点。 这与含弧段的LWPolyLine的点提取算法大致相同,不同的是结点列表和凸度列表的提取方法不一样,只需将2.2节中的程序代码段2修改为(提取出来的结点列表赋值为PLIST,凸度列表赋值为BULGE_LIST): (SETQ V(ENTNEXT ENAME)VN(ENTGET V)) (WHILE(=(CDR(ASSOC 0 VN))"VERTEX") (SETQ BULGE(CDR(ASSOC 42 VN))) (SETQ P(CDR(ASSOC 10 VN))) (IF P(SETQ PLIST(APPEND PLIST(LIST P)))) (IF BULGE(SETQ BULGE_LIST(APPEND BULGE_LIST (LIST BULGE)))) (SETQ V(ENTNEXT V)VN(ENTGET V)) );End Of While (IF(/=(LOGAND(CDR(ASSOC 70 VN))1)0);判断多段线是否闭合 (SETQ PLIST(APPENDPLIST(LIST(NTH 0PLIST))) BULGE_LIST(APPEND BULGE_LIST(LIST 0)));闭合多段线添加第一个结点 程序代码段7拟合POLYLINE结点列表和凸度列表的提取 其余算法和程序代码与2.2节中的一致。 3.3样条POLYLINE的点坐标提取 如图9所示,加粗线为原LWPOLYLINE线,细实线为其经样条曲线化后生成的POLYLINE。圆框点为原结点,也称样条曲线控制点,其结点实体列表为: ((-1.<图元名:400a2740>)(0."VERTEX")(330.<图元名: 400a2720>)(5."180")(100."AcDbEntity")(67.0)(410."Model")(8. "GCD")(62.3)(100."AcDbVertex")(100."AcDb2dVertex")(10 172.918 144.49 0.0)(40.0.0)(41.0.0)(42.0.0)(70.16)(50.0.0)) 方框点为样条曲线拟合插入点,其结点实体列表为: ((-1.<图元名:400a2780>)(0."VERTEX")(330.<图元名: 400a2720>)(5."188")(100."AcDbEntity")(67.0)(410."Model")(8. "GCD")(62.3)(100."AcDbVertex")(100."AcDb2dVertex")(10 172.918 144.49 0.0)(40.0.0)(41.0.0)(42.0.0)(70.8)(50.0.0)) 对比两个列表,70组码的值分别为16和8,如果是三维POLYLINE样条拟合后生成的POLYLINE,则70组码的值分别为48和40,这是原结点与样条曲线拟合插入点的根本区别。 分析70组码对应的数据项,将其值按二进制形式表示为: 则X3值为1时,结点为原结点,X2值为1时结点为样条曲线拟合插入点。 如果仅提取原结点,那么在程序代码段7中只需加上对组码70对应的数据项的值的判断,仅提取数据项中X3值为1对应的结点坐标即可。修改后的程序代码为: (SETQ V(ENTNEXT ENAME)VN(ENTGET V)) (WHILE(=(CDR(ASSOC 0 VN))"VERTEX") (IF(/=(LOGAND(CDR(ASSOC 70 VN))16)0) ((SETQ PLIST(APPEND PLIST(LIST(CDR(ASSOC 10 VN)))) ) );End of If (SETQ V(ENTNEXT V)VN(ENTGET V)) );END WHILE 程序代码段8样条曲线原折线点坐标提取 如果要不失真地提取样条曲线点坐标,则提取数据项中X2值为1对应的结点坐标即可。程序代码为: (SETQ V(ENTNEXT ENAME)VN(ENTGET V)) (WHILE(=(CDR(ASSOC 0 VN))"VERTEX") (IF(/=(LOGAND(CDR(ASSOC 70 VN))8)0) ((SETQ PLIST(APPEND PLIST(LIST(CDR(ASSOC 10 VN)))) ) );End of If (SETQ V(ENTNEXT V)VN(ENTGET V)) );END WHILE 程序代码段9样条曲线不失真点坐标提取 在国土系统的征地或规划设计、土地整治等项目中经常需要在AutoCAD中提取多段线的坐标信息,以上论文中所介绍的几种不同类别的多段线点坐标信息提取,都可用于实际工作中,将文中程序代码段中收集整理好的PLIST列表,输出到文本文件中,便可得到想要的坐标文件。 [1]AutoCAD开发帮助.AutoDesk公司 [2]Visual LISP中文版开发人员手册.AutoDesk公司 The algorithm of polyline coordinate extraction in AutoCAD Li Ling (Geographical conditions Monitoring Institute of Guangxi Zhuang People Autonomous Region,Guangxi,Jianzheng Road,Nanning 530023) To describes the different types of AutoCAD polyline data storage structure and the corresponding point coordinate extraction algorithm. Polylines Coordinate Crown Arc Clockwise Counterclockwise Spline fitting G633.55[文献码]B 1000-405X(2016)-3-312-1 李玲,女,硕士,高级工程师,研究方向为地理信息系统的开发与应用。3 POLYLINE的点坐标提取
4 结束语