找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 5224|回复: 42

[研讨] 对于面域两两求交集的代码进行优化。

[复制链接]
发表于 2013-5-28 14:46:09 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 wowan1314 于 2013-5-28 21:22 编辑

                           关于面域两两求交集代码的优化。
最近大家都在讨论代码执行效率问题,收益颇丰。故而想对以前一个程序进行优化。
由于实际工作中这个程序处理的样本数量不是很大。
所以此代码的优化重点不是mapcar/while/foreach这些函数的优化,更应该是算法的优化。感谢lispboy的提醒。
可能用VL处理面域会好些。但是我还没认识几个VL函数呢。 算法就更不了解了。。  这个程序还是留待以后来优化吧。
  1. ;============================={  消火栓保护范围粗查  }==========================================;;YY-JC
  2. (DEFUN C:T11 (/ TT YY_BJING XHS_SS AL N SSS REG_SS DIAN AAS AA AA2 TIME1 SS Q AA1 TIME2 NN QQ AAA YY_SHEZHI YY_NBJING)
  3.   (defun TT (Q QQ / AAA)
  4.     (setq AAA (ssadd))
  5.     (command "_.copy" Q "" "0,0" "@")
  6.     (ssadd (entlast) AAA)
  7.     (command "_.copy" QQ "" "0,0" "@")
  8.     (ssadd (entlast) AAA)
  9.     (command "_.intersect" AAA "")
  10.     AAA
  11.   )
  12. (IF (<= YY_BJING 0) (SETQ YY_BJING 25000))
  13.   (PRINC (strcat "\n选择消火栓<半径为" (rtos YY_BJING) ">:"))
  14. (setq XHS_ss (ssget '((2 . "*给排水*933*,*给排水*934*"))))  ;;;根据块名过滤
  15. ;;据块画圆
  16. (setq AL (sslength XHS_ss))
  17. (setq N 0)
  18. (setq sss (entlast))
  19. (setq reg_ss (ssadd))
  20. (repeat AL
  21. (setq DIAN (TRANS (CDR (ASSOC 10 (ENTGET(ssname XHS_ss N)))) 0 1))
  22. (command "_.CIRCLE" DIAN (rtos YY_BJING))
  23. (setq N (1+ N))
  24. (setq SSS (entnext SSS))
  25. (ssadd SSS reg_ss)
  26.   )
  27. ;;圆转化面域
  28. (setq AAS (ssadd) AA NIL)
  29.   (setq sss (entlast))
  30.   (command "region" reg_ss "")
  31.   (while (setq sss (entnext sss))
  32.       (ssadd sss AAS)(SETQ AA (CONS SSS AA))
  33.   )
  34. ;;两两差集
  35. (SETQ AA2 AA)
  36. (setvar "cmdecho" 0)
  37. (setvar "nomutt" 1);面域的回显无法关闭
  38. ;;利用WHILE求
  39. (setq time1 (get-utime))
  40. (setq SS (ssadd))
  41. (WHILE AA
  42.   (SETQ  Q   (CAR AA)
  43.   AA1 (CDR AA)
  44.   AA  (CDR AA)
  45.   )
  46.   (WHILE AA1
  47.     (ssadd (ssname (TT Q (CAR AA1)) 0) SS)
  48.     (SETQ AA1 (CDR AA1))
  49.   )
  50. )
  51. (setq time2 (get-utime))
  52. (princ "\nwhile方法:")
  53. (princ (- time2 time1))
  54. (princ "s")
  55. ;|
  56. ;;利用repeat求
  57. (setq time3 (get-utime)
  58.       AA    AAS
  59. )
  60. (setq AL (sslength AA))
  61. (setq SS (ssadd))
  62. (setq N 0)
  63. (repeat  AL
  64.   (setq NN (1+ N))
  65.   (setq Q (ssname AA N))
  66.   (repeat (- AL NN)
  67.     (setq QQ (ssname AA NN))
  68.     (setq NN (1+ NN))
  69.     (ssadd (ssname (TT Q QQ) 0) SS)
  70.   )
  71.   (setq N (1+ N))
  72. )
  73. (setq time4 (get-utime))
  74. (princ "\nrepeat方法:")
  75. (princ (- time4 time3))
  76. (princ "s")
  77. |;
  78. ;|
  79. ;;利用FOREACH求
  80. (setq time5 (get-utime)
  81.       AA    AA2
  82. )
  83. (setq SS (ssadd))
  84. (FOREACH Q AA
  85.   (SETQ  AA1 (CDR AA)
  86.   AA  (CDR AA)
  87.   )
  88.   (FOREACH QQ AA1
  89.     (ssadd (ssname (TT Q QQ) 0) SS)
  90.   )
  91. )
  92. (setq time6 (get-utime))
  93. (princ "\nFOREACH方法:")
  94. (princ (- time6 time5))
  95. (princ "s")
  96. |;
  97. ;|
  98. ;;利用MAPCAR求
  99. (setq time7 (get-utime)
  100.       AA    AA2
  101. )
  102. (setq SS  (ssadd)
  103.       AA1 AA
  104. )
  105. (MAPCAR  '(lambda (A)
  106.      (SETQ AA1 (CDR AA1))
  107.      (MAPCAR '(lambda (B) (ssadd (ssname (TT A B) 0) SS)) AA1)
  108.    )
  109.   AA
  110. )
  111. (setq time8 (get-utime))
  112. (princ "\nMAPCAR方法:")
  113. (princ (- time8 time7))
  114. (princ "s")
  115. |;
  116. ;;合并填充
  117. (setvar "nomutt" 0)
  118.   (command "_.union" SS "")
  119.   (SETQ SS (ENTLAST))
  120.   (command "_.bhatch" "s" SS "" "P" "ANSI31" "2000" "0" "")
  121.   (setq AAA (entlast))
  122. ;;暂停后删除
  123.   (princ (strcat "\n左>右>键退出或[重设半径(S)" (rtos YY_BJING) "]或[删圆(D)]:"))
  124.    (initget "S s D d")
  125.    (SETQ YY_SHEZHI (GETPOINT))
  126.     (if (OR (= YY_SHEZHI "S") (= YY_SHEZHI "s"))
  127.     (PROGN
  128.     (setq YY_NBJING (getreal (strcat "\n输入保护半径<" (rtos YY_BJING) ">:")))
  129.     (if (> YY_NBJING 0)(setq YY_BJING YY_NBJING))))
  130.     (if (OR (= YY_SHEZHI "D") (= YY_SHEZHI "d")) (PROGN (command "_.erase" AAS "")(GETPOINT)))
  131.   (command "_.erase" SS "")
  132.   (command "_.erase" AAA "")
  133.   (command "_.erase" AAS "")
  134.   (princ)
  135. )
  136. ;;测时间函数
  137. (defun get-utime () (* 86400.0 (getvar "tdusrtimer")))
上面代码对程序速度影响最大的是------两两求差集部分。。 所以主要是该部分的优化,写了四种方法。速度基本一致。
测试选择了48个块,分别运行。其执行时间如下:
while方法:5.062s
repeat方法:5.0s
foreach方法:5.018s
mapcar方法:5.032s
基本保持在5s左右。毫无变化。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 51个

财富等级: 招财进宝

发表于 2013-5-28 14:49:49 | 显示全部楼层
本帖最后由 Lispboy 于 2013-5-28 14:51 编辑

葛老的帖子里面,必须有我的,先座下沙发。
48个啊才,换48万先。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-28 14:55:54 | 显示全部楼层
Lispboy 发表于 2013-5-28 14:49
葛老的帖子里面,必须有我的,先座下沙发。
48个啊才,换48万先。

:o  48就能测出来了,何必那么多。那么多的话就等着卡死算了。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 3255个

财富等级: 富可敌国

发表于 2013-5-28 14:56:13 | 显示全部楼层
这几个函数 我也一直在思考着,感觉对于单个图元或者对象的处理 lisp比vlisp快,vlisp比command快,批量还是用command最快,这应该算一个思路:lol
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 51个

财富等级: 招财进宝

发表于 2013-5-28 14:59:48 | 显示全部楼层
pengfei2010 发表于 2013-5-28 14:56
这几个函数 我也一直在思考着,感觉对于单个图元或者对象的处理 lisp比vlisp快,vlisp比command快,批量还 ...

COMMAND是能别用就尽量别用。AUTOLISP和VLISP比较,主要是看你做啥。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 51个

财富等级: 招财进宝

发表于 2013-5-28 15:01:36 | 显示全部楼层
wowan1314 发表于 2013-5-28 14:55
48就能测出来了,何必那么多。那么多的话就等着卡死算了。

你不是要测效率吗,比时间吗,当然样本数多才准确,另外,就是同样的数量,你多几个回车,结果可能也差别不少。电脑主板上哪个地方有灰啥的都可能不顺畅尼。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-28 15:10:59 | 显示全部楼层
Lispboy 发表于 2013-5-28 15:01
你不是要测效率吗,比时间吗,当然样本数多才准确,另外,就是同样的数量,你多几个回车,结果可能也差别 ...

有道理哦。函数的效率是要在大量的样本做基础才可以测出的。

这几个函数本身是有区别的。但是样本太少,就分不出了。

那么这个程序的优化,我是走错路了。 应该在算法上优化吧!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 51个

财富等级: 招财进宝

发表于 2013-5-28 15:18:29 | 显示全部楼层
wowan1314 发表于 2013-5-28 15:10
有道理哦。函数的效率是要在大量的样本做基础才可以测出的。

这几个函数本身是有区别的。但是样本太少 ...

有的函数适合跑长跑的,有的适合跑短跑的。
while 为什么比 repeat foreach 慢,主要是while 多了条件测试。
他们为啥有比mapcar慢,因为mapcar是亲儿子。葛老找个大点数量的在测试看看时间,
对同一个函数的,应该程序加上多运行几次取平均时间。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2013-5-28 15:19:59 | 显示全部楼层
Region 操作所用的时间把别的效率都"遮盖了",Cad对Region的操作本来就是费时间的

点评

对的。这个程序处理的是小表。 所以不是哪些循环函数的优化了。 而是求面域差集用command还是VL函数的区别,以及两两求差集的算法优化.  发表于 2013-5-28 15:23
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 3255个

财富等级: 富可敌国

发表于 2013-5-28 15:20:26 | 显示全部楼层
Lispboy 发表于 2013-5-28 15:18
有的函数适合跑长跑的,有的适合跑短跑的。
while 为什么比 repeat foreach 慢,主要是while 多了条件测 ...

mapcar是亲儿子。楼主这话什么意思哇?呵呵

点评

那是lispboy的意思。咋来问我? 不过我猜应该是mapcar是lisp亲生的,其他是衍生的  发表于 2013-5-28 15:35
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 40个

财富等级: 招财进宝

发表于 2013-5-28 15:27:49 | 显示全部楼层
wowan1314 发表于 2013-5-28 15:10
有道理哦。函数的效率是要在大量的样本做基础才可以测出的。

这几个函数本身是有区别的。但是样本太少 ...

应该是VL的比COMMAND快。楼主可以修改下用下VL的在测试下。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 40个

财富等级: 招财进宝

发表于 2013-5-28 15:29:04 | 显示全部楼层
pengfei2010 发表于 2013-5-28 15:20
mapcar是亲儿子。楼主这话什么意思哇?呵呵

葛老,人家mm问你呢,你知道详情?:P
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2013-5-28 15:32:58 | 显示全部楼层
如果用Vl处理面域,最好在cad启动的时候就把那个 geom3d.arx (高版本好像是 acGeomUI.arx)加载,省得运行时耽误时间,这个文件是加载一次,后面就不耽误了

点评

还有这么一说呀! 多些提醒。  发表于 2013-5-28 15:36
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 40个

财富等级: 招财进宝

发表于 2013-5-28 16:13:15 | 显示全部楼层
本帖最后由 newer 于 2013-5-28 16:15 编辑
wowan1314 发表于 2013-5-28 15:10
有道理哦。函数的效率是要在大量的样本做基础才可以测出的。

这几个函数本身是有区别的。但是样本太少 ...

处理面域的部分先不谈
程序本身你代码还可以优化,看到你两层选择集循环,中间夹杂着SSADD SSNAME这些,效率肯定要打折扣,另外两层选择集找实体,是否有重复的计算?

推荐你先把选择集给转成实体表,然后就可以用那些MAPCAR函数了。

  1. (defun ss2entl (ss / el i len)
  2.   (if (= 'PICKSET (type ss))
  3.     (progn
  4.       (setq i -1
  5.             len (sslength ss)
  6.       )
  7.       (repeat len
  8.         (setq el (cons (ssname ss (setq i (1+ i))) el))
  9.       )
  10.     )
  11.   )
  12.   el
  13. )


得到选集实体名表后

下面代码生成 表中一个实体 和在这个实体之后 的所有实体的表,避免了同样表两次嵌套循环重复计算
  1. (defun entPair(el)
  2.    (mapcar '(lambda(x)(cons x (cdr (member x el)))) el)
  3. )

拿实体位置当实体,就是 表 (1 2 3 4 5) ---> ((1 2 3 4 5)(2 3 4 5)(3 4 5)(4 5)(5))

然后你在对上面生成的表用mapcar 算 面域。

不知道我表达清楚没,别用嵌套的选择集,别重复计算,多用mapcar,别用WHILE

楼主按这个思路测试下,看看时间。
通过上面的改造表,你把N*N的算法编程了N级的了,而且都是用ACAD的MAPCAR ,CDR这些高效率的处理表的函数。

点评

不过我怎么觉的还是要算N*N次呀!一次都不能少。我嵌套两个mapcar一样效果撒。而SSADD是为了建选择集的。它放到mapcar外面的话就又多一个循环!  发表于 2013-5-28 16:57
1、没重复计算,计算完一个我就把表CDR一次。 2、entPair函数非常好!没想到可以这样弄。  发表于 2013-5-28 16:50
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-28 16:27:19 | 显示全部楼层
本帖最后由 wowan1314 于 2013-5-28 18:06 编辑
newer 发表于 2013-5-28 16:13
处理面域的部分先不谈
程序本身你代码还可以优化,看到你两层选择集循环,中间夹杂着SSADD SSNAME这些, ...

多谢指导。。 待会好好学习。

我现在把求交集用下面的函数替代。发现速度极快,原来5s现在变成1s了。

但是CAD也直接“异常错误。。。  死掉了。  好像超过25个就死掉了。  呵呵发现是这句(command "_.union" SS "")导致的错误!莫非VL求出的差集不适合用COMMAND来求并集?
  (defun TT1 (Q QQ)
    (setq Q (vlax-invoke-method Q 'Copy))
    (setq QQ (vlax-invoke-method QQ 'Copy))
    (VLA-BOOLEAN Q acIntersection QQ)
   Q
  )
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-4-25 17:22 , Processed in 0.251124 second(s), 64 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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