找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2591|回复: 10

[分享] 练习 修改的一个凸包程序

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-5-24 15:58:39 | 显示全部楼层 |阅读模式

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

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

×
用了 高飞版主 Lisp版的 Graham 扫描算法,用 Stack<T>维护一个凸包
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using Autodesk.AutoCAD.ApplicationServices;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using Autodesk.AutoCAD.Geometry;
  9. using Autodesk.AutoCAD.Runtime;
  10. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;[assembly: CommandClass(typeof(AutoCAD_CSharp_plug_in13.MyCommands))]namespace AutoCAD_CSharp_plug_in13
  11. {
  12.     public class MyCommands
  13.     {
  14.         private Point2d _p0;        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
  15.         {
  16.             return ((p2.X  - p3.X  )*(p2.Y   - p1.Y  ) - (p2.X  - p1.X )*(p2.Y   - p3.Y  )) > -1e-6;
  17.         }
  18.         //按角度
  19.         private double Cosine(Point2d pt)
  20.         {
  21.             double d = _p0.GetDistanceTo(pt);
  22.             return d == 0.0 ? 1.0 : Math.Round((pt.Y - _p0.Y)/d, 9);
  23.         }
  24.       
  25.         private Point2d[] ConvexHull(List<Point2d> pts)
  26.         {
  27.             _p0 = pts.OrderBy(p => p.X).ThenBy(p => p.Y).Last( );//最右边点
  28.             pts = pts.OrderByDescending(p => Cosine(p)).ThenBy(p => _p0.GetDistanceTo(p)).ToList();//按角度及距离排序
  29.             Stack<Point2d> outPoint2Ds = new Stack<Point2d>();
  30.             outPoint2Ds.Push(_p0);
  31.             outPoint2Ds.Push(pts[1]);
  32.             bool tf = true;
  33.             for (int i = 2; i < pts.Count ; i++)
  34.             {
  35.                 Point2d n = pts[i];
  36.                 Point2d p = outPoint2Ds.Pop();//出栈 car
  37.                 Point2d q = outPoint2Ds.Pop();//取第一个 cadr
  38.                 while (tf && Clockwise(n, p, q))
  39.                 {
  40.                     if (outPoint2Ds.Count > 1)
  41.                     {
  42.                         p = q;//出栈
  43.                         q = outPoint2Ds.Pop() ;//car
  44.                         
  45.                     }
  46.                     else
  47.                     {
  48.                         tf = false;
  49.                     }
  50.                 }
  51.                 outPoint2Ds.Push(q);
  52.                 outPoint2Ds.Push(p);
  53.                 outPoint2Ds.Push(n);
  54.                 tf = true;
  55.             }
  56.             return outPoint2Ds.ToArray() ;
  57.         }        [CommandMethod("Test")]
  58.         public void Test()
  59.         {
  60.             Document doc = AcAp.DocumentManager.MdiActiveDocument;
  61.             Database db = doc.Database;
  62.             Editor ed = doc.Editor;
  63.             TypedValue[] filter = new TypedValue[1] {new TypedValue(0, "POINT")};
  64.             PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
  65.             if (psr.Status != PromptStatus.OK) return;
  66.             using (Transaction tr = db.TransactionManager.StartTransaction())
  67.             using (Polyline pline = new Polyline())
  68.             {
  69.                 List<Point2d> pts = new List<Point2d>();
  70.                 foreach (SelectedObject so in psr.Value)
  71.                 {
  72.                     DBPoint dbPt = (DBPoint) tr.GetObject(so.ObjectId, OpenMode.ForRead);
  73.                     pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
  74.                 }
  75.                 Stopwatch watch = new Stopwatch();
  76.                 watch.Restart();
  77.                 Point2d [] npts = ConvexHull(pts);
  78.                 watch.Stop();
  79.                 ed.WriteMessage("\nTime = " + watch.Elapsed.TotalMilliseconds.ToString());
  80.                 for (int i = 0; i < npts.Length ; i++)
  81.                 {
  82.                     pline.AddVertexAt(i, npts[i], 0.0, 0.0, 0.0);
  83.                 }
  84.                 pline.Closed = true;
  85.                 pline.SetDatabaseDefaults();
  86.                 BlockTableRecord btr = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  87.                 btr.AppendEntity(pline);
  88.                 tr.AddNewlyCreatedDBObject(pline, true);
  89.                 tr.Commit();
  90.             }
  91.         }
  92.     }
  93. }
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 1268个

财富等级: 财源广进

发表于 2014-5-24 16:57:37 | 显示全部楼层
命令: TEST
选择对象: 指定对角点: 找到 143208 个

选择对象:

Time = 309.4958

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

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-24 18:11:53 来自手机 | 显示全部楼层
好像 q 先不用出栈,减少入栈、出栈次数
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-25 15:29:13 | 显示全部楼层
本帖最后由 csharp 于 2014-5-25 17:32 编辑

为什么有时候不对,多数时候对呢?
入栈和出栈不对,再修改
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-26 11:46:33 | 显示全部楼层
终于找到原因了,原来是 Math.Round 舍多了!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 2476个

财富等级: 金玉满堂

发表于 2014-5-26 14:55:18 | 显示全部楼层
C#程序怎么用?和LISP一样吗??
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-26 15:06:21 | 显示全部楼层
刚试了试
命令: NETLOAD
命令: TEST
选择对象: 指定对角点: 找到 145152 个

选择对象:

Time = 200.7578

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

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-26 17:53:41 | 显示全部楼层
最终版
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using Autodesk.AutoCAD.ApplicationServices;
  7. using Autodesk.AutoCAD.DatabaseServices;
  8. using Autodesk.AutoCAD.EditorInput;
  9. using Autodesk.AutoCAD.Geometry;
  10. using Autodesk.AutoCAD.Interop.Common;
  11. using Autodesk.AutoCAD.Runtime;
  12. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  13. using Exception = System.Exception;

  14. [assembly: CommandClass(typeof(AutoCAD_CSharp_plug_in13.MyCommands))]

  15. namespace AutoCAD_CSharp_plug_in13
  16. {
  17.     public class MyCommands
  18.     {
  19.       
  20.         private Point2d _p0;

  21.         private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
  22.         {
  23.             return ((p2.X  - p3.X  )*(p2.Y   - p1.Y  ) - (p2.X  - p1.X )*(p2.Y   - p3.Y  )) > -1e-6;
  24.         }
  25.         //按角度
  26.         private double Cosine(Point2d pt)
  27.         {
  28.             double d = _p0.GetDistanceTo(pt);
  29.             return d == 0.0 ? 1.0 : (pt.Y - _p0.Y) / d;//sin
  30.         }
  31.       
  32.         private Point2d[] ConvexHull(List<Point2d> pts)
  33.         {
  34.             _p0 = pts.OrderBy(p => p.X).ThenBy(p => p.Y).Last( );//最右边点
  35.             pts = pts.OrderByDescending(p => Cosine(p)).ThenBy
  36.                 (p => _p0.GetDistanceTo(p)).ToList();//按角度及距离排序

  37.             Stack<Point2d> outPoint2Ds = new Stack<Point2d>();

  38.             outPoint2Ds.Push(_p0);
  39.             outPoint2Ds.Push(pts[1]);

  40.             bool tf = true;
  41.             for (int i = 2; i < pts.Count ; i++)
  42.             {
  43.                 Point2d n = pts[i];

  44.                 Point2d p = outPoint2Ds.Pop();
  45.                 Point2d q = outPoint2Ds.Peek()  ;

  46.                 while (tf && Clockwise(n, p, q))
  47.                 {
  48.                   
  49.                     if (outPoint2Ds.Count > 1)
  50.                     {
  51.                         outPoint2Ds.Pop();
  52.                         p = q;
  53.                         q = outPoint2Ds.Peek() ;
  54.                        
  55.                     }
  56.                     else
  57.                     {
  58.                         tf = false;
  59.                     }
  60.                 }
  61.                 outPoint2Ds.Push(p);
  62.                 outPoint2Ds.Push(n);
  63.                 tf = true;
  64.             }
  65.             return outPoint2Ds.ToArray() ;
  66.         }

  67.         [CommandMethod("Test")]
  68.         public void Test()
  69.         {
  70.             Document doc = AcAp.DocumentManager.MdiActiveDocument;
  71.             Database db = doc.Database;
  72.             Editor ed = doc.Editor;
  73.             TypedValue[] filter = new TypedValue[1] {new TypedValue(0, "POINT")};
  74.             PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
  75.             if (psr.Status != PromptStatus.OK) return;
  76.             using (Transaction tr = db.TransactionManager.StartTransaction())
  77.             using (Polyline pline = new Polyline())
  78.             {
  79.                 List<Point2d> pts = new List<Point2d>();
  80.                 Stopwatch watch = new Stopwatch();
  81.                 watch.Restart();
  82.                 foreach (SelectedObject so in psr.Value)
  83.                 {
  84.                     //DBPoint dbPt = (DBPoint) tr.GetObject(so.ObjectId, OpenMode.ForRead);
  85.                     DBPoint dbPt = (DBPoint) so.ObjectId.GetObject(OpenMode.ForRead);
  86.                     pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
  87.                 }
  88.                 watch.Stop();
  89.                 ed.WriteMessage("\nGet Points Used Time = " + watch.Elapsed.TotalSeconds.ToString());
  90.                 watch.Restart();
  91.                 Point2d [] npts = ConvexHull(pts);
  92.                 watch.Stop();
  93.                 ed.WriteMessage("\nGet Hull Used Time = " + watch.Elapsed.TotalSeconds.ToString());
  94.                 for (int i = 0; i < npts.Length ; i++)
  95.                 {
  96.                     pline.AddVertexAt(i, npts[i], 0.0, 0.0, 0.0);
  97.                 }
  98.                 pline.Closed = true;
  99.                 pline.SetDatabaseDefaults();
  100.                 BlockTableRecord btr = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  101.                 btr.AppendEntity(pline);
  102.                 tr.AddNewlyCreatedDBObject(pline, true);
  103.                 tr.Commit();
  104.             }
  105.         }
  106.     }
  107. }


命令:  TEST

选择对象: 指定对角点: 找到 580608 个

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

使用道具 举报

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-26 18:06:23 | 显示全部楼层
  1.                 foreach (ObjectId  so in psr.Value.GetObjectIds() )
  2.                 {
  3.                     //DBPoint dbPt = (DBPoint) tr.GetObject(so.ObjectId, OpenMode.ForRead);
  4.                     DBPoint dbPt = (DBPoint) so.GetObject(OpenMode.ForRead);
  5.                     pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
  6.                 }

再改进一句后的效果
命令: TEST

选择对象: 指定对角点: 找到 580608 个

选择对象:

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

使用道具 举报

已领礼包: 3758个

财富等级: 富可敌国

发表于 2014-7-18 23:01:31 | 显示全部楼层
应该将
   watch.Restart();
改为
   watch.Reset();
   watch.Start();
谢谢分享!{:soso_e163:}{:soso_e179:}{:soso_e179:}{:soso_e179:}
试了一下。的确很快。
选择对象: 指定对角点: 找到 1002072 个
选择对象:
Get Points Used Time = 9.9183639
Get Hull Used Time = 3.3560182
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 3758个

财富等级: 富可敌国

发表于 2014-7-18 23:14:56 | 显示全部楼层
本帖最后由 dnbcgrass 于 2014-7-18 23:19 编辑

速度比Lee Mac那个Convex Hull.vlx快10倍以上!:lol
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-22 00:04 , Processed in 0.407577 second(s), 51 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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