明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 4634|回复: 10

地形图上的植被符号自动避让程序

    [复制链接]
发表于 2012-5-20 23:15:25 | 显示全部楼层 |阅读模式
本帖最后由 caddog 于 2012-5-20 23:20 编辑

    有地形图测绘经验的朋友有没有这样的体会:对于纯地形区域,在内业整饰时很大一部分时间都花在调整植被符号和高程注记对等高线等地物的压盖、遮挡上。基于此,编写了这么一个小程序,欲实现对植被符号位置的自动调整。以便大家从繁琐的重复劳动中解放出来。
    程序的原理是以植被符号(图块)的插入点为中心,在0、45、90、135、180、225、270、315度共八个方向上按用户指定的移动步长及限定的移动距离求出一系列备用点,再分别用这些点结合植被符号(图块)的BOUNDINGBOX(我称为外接矩形好不好?)判定是否有地物被压盖。若无,则将图块移至此位置,若全都有压盖,则不处理。
    程序执行的效果尚可。就是速度有点见不得人。主要慢在判断是否有压盖上。我使用的方法是用图块的外接矩形作为范围进行“窗交”或“圈交”选择,看能不能选到图元,若不能,则说明没有压盖了。我也知道这样的方式很慢,但苦于没有更好的方法来实现。还请各位高手不吝赐教!
    下面上代码:
  1. ;;;---------------------------------------------------
  2. ;;;函数:围绕指定的基点,以指定的角度旋转点集
  3. ;;;---------------------------------------------------
  4. (defun move:Rotate(pts basePoint rad / x)
  5.   (mapcar '(lambda(x)
  6.          (polar basePoint (+ rad (angle basePoint x)) (distance basePoint x)))
  7.       pts)
  8.   )
  9. ;;;---------------------------------------------------
  10. ;;;函数:用于创建图块的BOUNDBOX四个角点相对于其插入点
  11. ;;;     的偏移量表.
  12. ;;;ps   拣懒,没传递参数
  13. ;;;---------------------------------------------------
  14. (defun move:bulidEnRota (/ MAXPOINT MINPOINT PT-REC X)
  15.   (if (/= 0 enRo) ;_如果有旋转
  16.     (vla-put-Rotation (vlax-ename->vla-object en1) 0) ;_先将图块转回0度来
  17.     )
  18.   ;;求boundbox
  19.   (vla-GetBoundingBox   (vlax-ename->vla-object en1)    'minpoint  'maxpoint)
  20.   (setq minpoint (3DPOINT->2DPOINT (vlax-safearray->list minpoint))
  21.     maxpoint (3DPOINT->2DPOINT (vlax-safearray->list maxpoint)))
  22.   ;;把块旋转回去得
  23.   (vla-put-Rotation (vlax-ename->vla-object en1) enRo)
  24.   ;;下面求出四个角点相对于插入点之增量
  25.   (setq pt-rec (list minpoint (list (car minpoint)(cadr maxpoint)) maxpoint (list (car maxpoint)(cadr minpoint))))
  26.   (setq pt-rec
  27.      (mapcar '(lambda(x)
  28.             (list (- (car x)(car inspt))(- (cadr x)(cadr inspt)))
  29.             )
  30.          pt-rec))
  31.   ;;将增量表放入一个表中,用块名进行索引
  32.   (setq #EnRota (cons (cons (cdr(assoc 2 ent1)) pt-rec) #EnRota))
  33.   )


  34. ;;;-------------------------------------------------------------------------
  35. ;;;程序功能: 移动植被符号(形和块都可以),以使其不压盖地物(主要是针对等高线)
  36. ;;;          程序将以用户给定的距离在0/45/90/135/180/225/270/315度共8个方向上
  37. ;;;          依次移动植被并检查是否存在压盖情况.若无,则将植被符号移至此新坐标,
  38. ;;;          若在用户限定条件内都存在压盖,则不处理.
  39. ;;;判断是否压盖的方法也许不是很合理,速度很慢.2000多个点要花去7/8分钟....
  40. ;;;不知道还有没有更加科学的方法呢?
  41. ;;;-------------------------------------------------------------------------

  42. (defun c:MPlant  (/           $LEN    %LEN     #LI      #MOVE       #VALUEMAX
  43.           #VALUEMIN        %ID     ANGL      EN1       ENLAYER
  44.           ENT1     INSPT    MAXPOINT MINPOINT NEWPT       SS1
  45.           STEP     STEPMAX    STEPMOVE #ENROTA #ROTA ENLAYER ENNAME ENRO PTS-REC)
  46.   ;;移动步长、移动范围
  47.   (setq #EnRota nil);_此表记录所有块的boundingBox矩形四个角点相对于其插入点的增量
  48.   (setq step (getreal "\n请输入移动步长(米)<0.1>"))
  49.   (if (not step)(setq step 0.1))
  50.   (setq stepMax (getreal "\n请输入最大可移动距离(米)<1.5>"))
  51.   (if (not stepMax)(setq stepMax 1.5))
  52.   (setq    stepMove step
  53.     angl 0)

  54.   (setq ss1 (ssget '((0 . "insert,shape")))) ;_选取块/形
  55.   (setq    %id  0
  56.     %len (sslength ss1);_图元个数
  57.     $len (itoa %len))
  58.   (repeat %len
  59.     (setq en1 (ssname ss1 %id);_图元名
  60.       %id (1+ %id))
  61.     (setq ent1      (entget en1)
  62.       enLayer (cdr (assoc 8 ent1));_获取图层
  63.       enRo      (cdr (assoc 50 ent1));_获取旋转角度
  64.       enName  (cdr (assoc 2 ent1));_获取块名
  65.       insPt (3DPOINT->2DPOINT (cdr (assoc 10 ent1))));_获取插入点
  66.     ;;;看#EnRota中是否有定义,若无则需要调用程序处理
  67.     ;;;即使没有旋转,也应该求出其四个角点之增量不是?
  68.     (if (not (setq #Rota (cdr (assoc enName #EnRota))))
  69.     ;_若有定义,则直接返回表.若无,则调用函数建立之
  70.     (progn
  71.       (move:bulidEnRota)
  72.       (setq #Rota (cdr (assoc enName #EnRota)))
  73.       )
  74.       );_end if

  75.    
  76.     ;;下面根据图块的插入点求出其BOUNDingBOX的四个角点坐标
  77.     (setq pts-Rec (mapcar '(lambda(x)
  78.                  (list
  79.                    (+ (car x)(car insPt))
  80.                    (+ (cadr x)(cadr insPt))
  81.                    0.0
  82.                    )
  83.                  )#Rota))
  84.     ;;移动视口至图块所在位置并适当缩放.
  85.     ;;因为在调试时发现把视口缩得太小,有些会出现漏移,可能是由于做"_C"选择时出现了问题.故改为如此
  86.     (vla-ZoomCenter
  87.       (acad-object)
  88.       (vlax-3d-point insPt)
  89.       (vlax-make-variant (* 5 stepMax) vlax-vbDouble)
  90.       )
  91.     (if    (ssget "_c"
  92.            (nth 0 pts-Rec)
  93.            (nth 2 pts-Rec)
  94.            (list '(-4 . "<NOT")
  95.              (cons 8 enLayer)
  96.              '(-4 . "NOT>")));_本图层的东东不选(为了防止选中自身)
  97.       ;;若有压盖,则处理
  98.       (progn
  99.     ;;开始求取移动的坐标.根据移动步长及移动范围,求八个方向上的坐标.
  100.     (setq #move nil
  101.           #li   nil)
  102.     (repeat    (fix (/ stepMax step))
  103.       (repeat 8
  104.         (setq #li (cons (polar insPt angl stepMove) #li))
  105.         (setq angl (+ angl (/ pi 4.0)))
  106.         ) ;_end repeat fix...
  107.       (setq    stepMove (+ stepMove step)
  108.         #move     (cons (REVERSE #li) #move)
  109.         angl     0
  110.         #li     nil
  111.         ) ;_end setq
  112.       ) ;_end repeat 8
  113.     (setq #move    (REVERSE #move)
  114.           stepMove step)
  115.    
  116.     ;;根据图块的旋转角度求对其BOUNDBOX进行旋转
  117.     ;;点集已经有了,下面就是循环/框选看有没有压盖,如果是旋转过的块,要用CP的方式来进行
  118.     ;;可以使用vl-some函数吧
  119.     (setq newpt nil)
  120.     (if (= enRo 0.0)      
  121.         (setq newPt
  122.            (vl-some
  123.              '(lambda (x)
  124.             ;;求出bound坐标
  125.             (setq pts-Rec (mapcar '(lambda(y)
  126.                (list
  127.                  (+ (car y)(car x))
  128.                  (+ (cadr y)(cadr x))
  129.                  0.0
  130.                  )
  131.                )#Rota))
  132.             (if
  133.               ;;选择时排除了块所在的图层
  134.               (not (ssget "c"
  135.                       (nth 0 pts-Rec)
  136.                       (nth 2 pts-Rec)
  137.                       (list '(-4 . "<NOT")
  138.                         (cons 8 enLayer)
  139.                         '(-4 . "NOT>"))))
  140.                x
  141.                nil
  142.                )
  143.             )
  144.              (apply 'append #move)
  145.              ) ;_end vl-some
  146.           );_end progn
  147.       ;;否则,即旋转角度不为0
  148.       (progn        
  149.         (setq newPt
  150.            (vl-some
  151.              (function(lambda (x)
  152.             ;;求出bound坐标
  153.             (setq pts-Rec (mapcar '(lambda(y)
  154.                (list
  155.                  (+ (car y)(car x))
  156.                  (+ (cadr y)(cadr x))
  157.                  0.0
  158.                  )
  159.                )#Rota))
  160.             (setq pts-Rec (move:Rotate pts-Rec x enRo));_求出旋转后的boundingBox
  161.             (if
  162.               ;;选择时排除了块所在的图层,选择时用的"圈交"方式
  163.               (not (ssget "_cp"
  164.                       pts-Rec                  
  165.                       (list '(-4 . "<NOT")
  166.                         (cons 8 enLayer)
  167.                         '(-4 . "NOT>"))))
  168.                x
  169.                nil
  170.                )
  171.             ));_end function
  172.              (apply 'append #move)
  173.              ) ;_end vl-some
  174.           )
  175.         );_end progn
  176.       );_end if =0 rota
  177.       
  178.    
  179.      ;_end setq
  180.     ;;如果有符合要求的点,则将块移到该点
  181.     (if newpt
  182.       (entmod (subst (cons 10 newpt) (assoc 10 ent1) ent1))
  183.       )
  184.     ) ;_end progn 若有压盖则处理
  185.       ) ;_end if 若有....

  186.     (setvar "modemacro" (strcat "正处理: " (itoa %id) "/" $len))

  187.     ) ;_end repeat
  188.   (setvar "modemacro" "")
  189.   (princ "\n完成!")
  190.   (princ)

  191.   ) ;_end defun

还用到了几个CAD自带帮助里的函数,一起上来哈:
  1. (VL-LOAD-COM)
  2. (SETQ *acad-object* nil)        ; Initialize global variable
  3. (DEFUN acad-object  ()
  4.   (COND    (*acad-object*)            ; Return the cached object
  5.     (T
  6.      (SETQ *acad-object* (VLAX-GET-ACAD-OBJECT))
  7.      )
  8.     ) ;_ 结束cond

  9.   ) ;_ 结束defun

  10. (SETQ *active-document* nil)        ; Initialize global variable
  11. (DEFUN active-document    ()
  12.   (COND    (*active-document*)        ; Return the cached object
  13.     (T
  14.      (SETQ *active-document* (VLA-GET-ACTIVEDOCUMENT (acad-object)))
  15.      )
  16.     ) ;_ 结束cond

  17.   ) ;_ 结束defun

  18. (SETQ *model-space* nil)        ; Initialize global variable
  19. (DEFUN model-space  ()
  20.   (COND    (*model-space*)            ; Return the cached object
  21.     (T
  22.      (SETQ *model-space* (VLA-GET-MODELSPACE (active-document)))
  23.      )
  24.     ) ;_ 结束cond


  25.   ) ;_ 结束defun
  26. ;;; 函数: 3dPoint->2dPoint                    
  27. ;;;--------------------------------------------------
  28. ;;; 说明:本函数有一个参数,表示一个三维点            
  29. ;;;        (由三个整数或实数组成的表), 函数将它        
  30. ;;;        转换为二维点(由两个实数组成的表)。        
  31. ;;;        本函数并不检查参数 3dpt,而是            
  32. ;;;        总认为它是一个有效点。               
  33. ;;;---------------------------------------------------
  34. ;;; 要添加的功能:加上一些参数检查功能,            
  35. ;;;       这样即使传给它空值或不是三维点的值,        
  36. ;;;       函数也不会导致程序崩溃。               
  37. ;;;----------------------------------------------------
  38. (DEFUN 3dPoint->2dPoint     (3dpt)
  39.   (LIST (FLOAT (CAR 3dpt)) (FLOAT (CADR 3dpt)))

  40.   ) ;_ 结束defun

发表于 2012-5-21 00:34:52 | 显示全部楼层
同行有高程点文字避让的程序不?发上来学习学习。论坛有一个就是慢了点。
发表于 2012-5-21 09:54:07 | 显示全部楼层
谢谢楼主
论坛里避让类的程序大都也是通过ssget来选择判断 同求更好的方法
发表于 2012-5-21 20:53:31 | 显示全部楼层
画个框框求交点。
发表于 2012-5-22 08:06:28 | 显示全部楼层
本帖最后由 mandala 于 2012-5-22 08:06 编辑

可以考虑将所有符号的外接矩形范围统一设为一个大略值。通常符号的大小不会相差太大。
发表于 2012-9-1 00:50:45 | 显示全部楼层
很是不错,不知道效果怎么样啊
发表于 2012-12-8 14:46:50 | 显示全部楼层
来学习一下了
不知效果怎样呢
发表于 2013-1-17 12:16:59 | 显示全部楼层
支持楼主的源码无私分享      如果是源码加动画那就更好了!  
发表于 2013-1-22 22:51:01 | 显示全部楼层
感谢提供。一定仔细研究学习
发表于 2013-1-23 10:24:39 来自手机 | 显示全部楼层
很好,测绘高手啊!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-5-20 02:24 , Processed in 0.190075 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表