AutoCAD大比例尺数字化制图系统中植被填充程序的开发
韦廖军 兰度
(南宁市勘测院 广西南宁 530021)
【摘 要】 在利用AutoCAD开发大比例尺数字化制图系统时,会涉及到如何开发植被填充程序的问题,本文介绍了两种开发植被填充程序的方法。
【关键词】 AutoCAD Vb AutoLisp 植被填充 CreatepolygonRgn PtInRegionh
0 引言
在利用AutoCAD开发大比例尺数字化制图系统时,植被填充程序的开发是一个必不可少的步骤。植被填充程序开发的难点在于植被填充范围的不规则,如何根据植被填充的不规则范围确定各个植被符号的插入位置坐标。笔者在开发实践中总结出两种行之有效的解决方法:
(一)利用Vb和AutoLisp相结合的方法来实现植被填充程序的开发。AutoLisp对AutoCAD图元的操作和数据的提取简单而直接,而Vb的Api函数非常丰富,其中有两个函数CreatePolygonRgn(生成一个区域)和PtInRegionh(判断点是否在区域内)非常有用,利用它们来编制植被填充程序,可以起到事半功倍的效果;因此可以考虑利用AutoLisp提取植被填充范围坐标和实现植被符号的插入,而利用Vb的Api函数根据植被填充范围坐标计算各个植被填充的插入位置坐标。
(二)利用AutoLisp编写实现判断点是否在区域内的功能(类似VB的PtInRegionh函数功能),所有数据在AutoLisp程序里面用表来处理,免去生成临时文件。
本文主要讲述第一种方法,第二种方法只给出判断点是否在区域内的子函数,其余程序实现方法与第一种方法类似。
1 第一种方法
(一)实现的方法及步骤
1.利用AutoLisp编程实现:在AutoCAD中绘制或者选取植被填充范围线,然后提取范围线坐标,并存入一个临时文本文件。
2.利用Vb编程实现:
(1)打开上一步骤所生成的文本文件,读取植被填充边界坐标,并存入一个数组。
(2)从边界坐标提取植被填充范围的坐标最大最小值,即确定包含植被填充不规则范围的矩形范围,根据规范要求的间距在矩形范围内内插规则方格网点(植被符号插入点)并存入另外一个数组B。
(3)利用CreatePolygonRgn函数,根据边界坐标生成一个区域PHRGN。
(4)利用PtInRegionh函数,剔除不在区域PHRGN内的方格网点,剩余的点即为所求的植被符号插入点。
3.利用AutoLisp编程实现:根据在上一步骤中求得的植被插入点在AutoCAD中批量插入植被符号。
(二)具体的编程代码及注释
以下就是根据上面的编程思路写出的的源程序代码和具体注释。
1.获取植被填充边界坐标子程序(用AutoLisp编写)
(DEFUN ZBZB()
(COMMAND "CMDECHO" 0)
(SETVAR "PLINETYPE" 1) ;;; PLINE 创建优化的多线
;;;;输入边界坐标.
(SETQ P NIL);;;;存贮边界范围坐标的表.
(PROMPT "\n植被填充:\n\t输入点:")
(SETQ P1 (GETPOINT))
(COMMAND "PLINE")
(COMMAND P1)
(SETQ P (APPEND (LIST P1) P))
(WHILE
(SETQ P2 (GETPOINT P1 "\n输入点:<回车结束>"))
(SETQ P (APPEND (LIST P2) P))
(COMMAND P2)
(SETQ P1 P2)
)
(COMMAND "C")
;;;;边界坐标写入文件.
(SETQ FIL (OPEN "C:/ZBHZ.TMP" "W")) ;;;;边界坐标写入文件C:/ZBHZ.TMP
(SETQ N (LENGTH P))
(SETQ I 0)
(REPEAT N
(SETQ Y (RTOS (CAR (NTH I P)) 2 3))
(SETQ X (RTOS (CADR (NTH I P)) 2 3))
(PRINC X FIL)
(PRINC "\n" FIL)
(PRINC Y FIL)
(PRINC "\n" FIL)
(SETQ I (1+ I))
)
(CLOSE FIL)
(PRINC)
)
2.计算植被符号插入点坐标子程序(用Vb编写)
Private PP() As POINTAPI
Private Xmin0,Xmax0,Ymin0,Ymax0 As Double
Private L As Double''''方格边长
Private p() As POINTAPI '''方格网点坐标
Private ZBJJ As Variant
Private Declare Function PtInRegion Lib "gdi32" (ByVal hRgn As Long,ByVal x As Long,ByVal y As Long) As Long
Private Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI,ByVal nCount As Long,ByVal
PolyFillMode As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private PHRGN As Long
Private PtInRgn As Long
Private Type POINTAPI
x As Long
y As Long
End Type
Private ltscale As Variant
Sub Main()
Dim nwith As Integer,nheight As Integer
Dim n As Integer,I As Integer
'''打开C:\ZBHZ.TMP读取边界坐标.
Open "C:\ZBHZ.TMP" For Input As #1
n = 0
Do While Not EOF(1)
Input #1,x
Input #1,y
n = n + 1
Loop
Close #1
ReDim PP(0 To n - 1) As POINTAPI
Open "C:\ZBHZ.TMP" For Input As #1
n = 0
Do While Not EOF(1)
Input #1,PP(n).x
Input #1,PP(n).y
n = n + 1
Loop
Close #1
On Error Resume Next
''''求包含植被边界范围的最小矩形x,y坐标
Xmin0 = PP(0).x: Ymin0 = PP(0).y
Xmax0 = Xmin0: Ymax0 = Ymin0
For I = 0 To n - 1
If PP(I).x <= Xmin0 Then
Xmin0 = PP(I).x
End If
If PP(I).x >= Xmax0 Then
Xmax0 = PP(I).x
End If
If PP(I).y <= Ymin0 Then
Ymin0 = PP(I).y
End If
If PP(I).y >= Ymax0 Then
Ymax0 = PP(I).y
End If
Next I
'''生成区域PHRGN
PHRGN = CreatePolygonRgn(PP(0),n,1)
Call FGW '''调用内插方格网点子程序
End Sub
'''内插方格网点子程序
Sub FGW()
Dim PPP(2) As Double
Dim I,J As Integer
Dim Xmin,Xmax,Ymin,Ymax As Double
Dim FIL As String
'''清除C:\ZBHZ.TMP文件数据
Open "C:\ZBHZ.TMP" For Append As #1
CLOSE #1
Open "C:\ZBHZ.TMP" For Append As #1
L = 10 '''设置植被填充间距
'''剔除植被填充区域外的方格网点.
nheight = Int((Ymax0 - Ymin0) / L) + 3
nwith = Int((Xmax0 - Xmin0) / L) + 3
ReDim p(0 To nwith - 1,0 To nheight - 1) As POINTAPI
For I = 0 To nwith - 2 Step 2
For J = 0 To nheight - 2 Step 2
p(I,J).x = (Int(Xmin0 / L) * L) + I * L
p(I,J).y = (Int(Ymin0 / L) * L) + J * L
PtInRgn = PtInRegion(PHRGN,p(I,J).x,p(I,J).y)
If PtInRgn > 0 Then
Print #1,p(I,J).x
Print #1,p(I,J).y
End If
p(I + 1,J).x = (Int(Xmin0 / L) * L) + (I + 1) * L
p(I + 1,J).y = (Int(Ymin0 / L) * L) + (J + 1) * L
PtInRgn = PtInRegion(PHRGN,p(I + 1,J).x,p(I + 1,J).y)
If PtInRgn > 0 Then
'''''把植被填充范围内的方格网点X,Y坐标数据写入C:\ZBHZ.TMP
Print #1,p(I + 1,J).x
Print #1,p(I + 1,J).y
End If
Next J
Next I
DeleteObject PHRGN'''删除区域
Close #1
End Sub
注:该子程序修改调试完毕之后需编译成可执行文件ZBHZ.EXE放在C盘根目录下
3.插入植被符号子程序(用AutoLisp编写)
(DEFUN ZBCR()
(SETQ OLDOSMODE (GETVAR "OSMODE"))
(COMMAND "OSMODE" 0)
(COMMAND "LINETYPE" "S" "CONTINUOUS" "")
;;;读入植被符号插入位置坐标数据
(SETQ FIL (OPEN "C:/ZBHZ.TMP" "R"))
(WHILE (SETQ X (READ-LINE FIL))
(IF (/= X NIL)
(SETQ X (ATOF X))
)
(SETQ Y (READ-LINE FIL))
(IF (/= Y NIL)
(SETQ Y (ATOF Y))
)
(SETQ P (LIST Y X))
(IF (/= P NIL)
;;;;插入植被符号,其中GS9410是已经定义的植被形符号名称,实际工作根据所需填充
;;;;符号不同更改其名称即可,缩放比例也是根据实际绘图比例设定。
(COMMAND "SHAPE" “GS9410”P0.50)
)
)
(CLOSE FIL)
(vl-file-delete "C:/ZBHZ.TMP") ;;;;删除临时文件 C:\ZBHZ.TMP
(COMMAND "OSMODE" OLDOSMODE)
(PRINC)
)
4.主程序(用AutoLisp编写)
(DEFUN C:ZBHZ()
(ZBZB);;;调用获取植被边界坐标子程序
(STARTAPP "C:/ZBHZ.EXE" "ZBHZ");;;;调用计算植被符号插入点坐标子程序
(ZBCR);;;;调用插入植被符号子程序
)
2 第二种方法
判断点是否在多边形区域内子函数如下:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;PTREGION() 子函数 <判断点是否在多边形区域内>
;;;需要参数 点:PT (X Y H)或者(X Y)多边形顶点坐标:PL ((X0 Y0) (X1 Y1) .....)
;;;返回值数据格式-- 区域内:IN 区域外:OUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun PTINREGION(PT PL / )
(setq PT (list (nth 0 PT) (nth 1 PT)))
(SETQ PL-NUM (LENGTH PL))
(SETQ PL-PT NIL)
(SETQ III 0)
(REPEAT PL-NUM
(SETQ PL-PT-JD (angle PT (NTH III PL)))
(if (= PL-PT nil)
(setq PL-PT (LIST PL-PT-JD))
(SETQ PL-PT (APPEND (LIST PL-PT-JD) PL-PT))
)
(SETQ III (1+ III))
)
(SETQ JDHE 0)
(SETQ INSIDE "OUT")
(SETQ III 0)
(REPEAT PL-NUM
(IF (/= III (- PL-NUM 1))
(PROGN
(SETQ JD (- (NTH (1+ III) PL-PT) (NTH III PL-PT)))
(IF (> JD PI)
(SETQ JD (- JD (* 2 PI)))
)
(IF (< JD (- 0 PI))
(SETQ JD (+ JD (* 2 PI)))
)
(IF (< (ABS (- (ABS JD) PI)) 0.0000000001)
(PROGN
(SETQ INSIDE "IN")
(:EXIT)
)
)
(SETQ JDHE (+ JDHE JD))
)
(PROGN
(SETQ JD (- (NTH 0 PL-PT) (NTH III PL-PT)))
(IF (> JD PI)
(SETQ JD (- JD (* 2 PI)))
)
(IF (< JD (- 0 PI))
(SETQ JD (+ JD (* 2 PI)))
)
(IF (< (ABS (- (ABS JD) PI)) 0.0000000001)
(PROGN
(SETQ INSIDE "IN")
(:EXIT)
)
)
(SETQ JDHE (ABS (+ JDHE JD)))
)
)
(SETQ III (1+ III))
)
(IF (< JDHE 0.0000000001)
(SETQ INSIDE "OUT")
(SETQ INSIDE "IN")
)
:EXIT
(SETQ INSIDE INSIDE)
)
;;;PTREGION() 子函数结束
附: CreatePolygonRgn,PtInRegion函数 VB声明
PtInRegionVB声明 |
| Declare Function PtInRegion Lib "gdi32" Alias "PtInRegion" (ByVal hRgn As Long,ByVal x As Long,ByVal y As Long) As Long |
说明 |
确定点是否在指定区域内 |
返回值 |
Long,若点在区域内为非零值,否则为0 |
参数表 |
参数 |
类型及说明 |
hRgn |
Long,区域句柄 |
x |
Long,以逻辑坐标表示的点的X坐标 |
y |
Long,以逻辑坐标表示的点的Y坐标 |
在vb里使用 |
在测试复杂图象时非常有用 |
| CreatePolygonRgn VB声明 |
| Declare Function CreatePolygonRgn Lib "gdi32" Alias "CreatePolygonRgn" (lpPoint As POINTAPI,ByVal nCount As Long,ByVal nPolyFillMode As Long) As Long |
| 说明 |
| 创建一个由一系列点围成的区域。windows在需要时自动将最后点与第一点相连以封闭多边形 |
| 返回值 |
| Long,执行成功为创建的区域句柄,失败则为0 |
| 参数表 |
| 参数 |
类型及说明 |
| lpPoint |
POINTAPI,nCount个POINTAPI结构中的第一个POINTAPI结构 |
| nCount |
Long,多边形的点数 |
| nPolyFillMode |
Long,描述多边形填充模式。可为ALTERNATE 或 WINDING常数。参考SetPolyFillMode函数对多边形填充模式的解释 |
| 注解 |
| 不用时一定要用DeleteObject函数删除该区域 |
3 结束语
数字化制图过程中,可用来实现填充植被等重复且规则出现的符号的方法是多种多样的。在这,笔者仅仅总结出实际工作过程中使用过的两种较为方便实现的方法来与同行探讨,希望能抛砖引玉,找出最简易方便的方法来提高制图软件的工作效率,进而推进数字化制图工作的长足进步。
【参考文献】
[1]
孙江宏,丁立伟,米 洁.Visual Lisp R14~2000编程与应用.科学出版社,1997
[2]
Visual Basic 6.0 程序设计参考手册.人民邮电出版社
【参考网站】
[1]
VB 爱好者乐园 http://www.vbgood.com
[2]
明经通道 http://www.vba.cn |