找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1242|回复: 1

[分享] Sorting an AutoCAD Point2dCollection or Point3dCollection using .NET

[复制链接]

已领礼包: 1268个

财富等级: 财源广进

发表于 2014-5-5 13:08:40 来自手机 | 显示全部楼层 |阅读模式

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

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

×
http://through-the-interface.typepad.com/through_the_interface/2011/01/sorting-an-autocad-point2dcollection-or-point3dcollection-using-net.html
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-6-23 00:31:05 | 显示全部楼层
留存
Sorting an AutoCAD Point2dCollection or Point3dCollection using .NET
Thanks to Virupaksha Aithal, from DevTech India, for providing the technical response to an ADN member than inspired this post.
When working with the Point2d and Point3d objects from AutoCAD’s .NET API it’s common to use the in-built collection types, Point2dCollection and Point3dCollection. Neither of these objects provides the capability to sort their contents (and, in any case, sorting would mean different things to different people when it comes to containers of objects with multiple data entries).
So how can you sort one of these collections?
The answer is fairly straightforward: you convert them to a .NET array, sort them using standard .NET capabilities and then recreate an AutoCAD collection.
The below C# code does this for collections of both Point2d and Point3d objects.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System.Collections.Generic;
using System;

namespace PointSort
{
  internal class sort2dByX : IComparer<Point2d>
  {
    public static bool IsZero(double a)
    {
      return Math.Abs(a) < Tolerance.Global.EqualPoint;
    }

    public static bool IsEqual(double a, double b)
    {
      return IsZero(b - a);
    }

    public int Compare(Point2d a, Point2d b)
    {
      if (IsEqual(a.X, b.X)) return 0; // ==
      if (a.X < b.X) return -1; // <
      return 1; // >
    }
  }

  internal class sort3dByX : IComparer<Point3d>
  {
    public static bool IsZero(double a)
    {
      return Math.Abs(a) < Tolerance.Global.EqualPoint;
    }

    public static bool IsEqual(double a, double b)
    {
      return IsZero(b - a);
    }

    public int Compare(Point3d a, Point3d b)
    {
      if (IsEqual(a.X, b.X)) return 0; // ==
      if (a.X < b.X) return -1; // <
      return 1; // >
    }
  }

  public class Commands
  {
    private double DeNormalize(double a, double max)
    {
      // Random numbers are from 0 to 1.0, so we
      // multiply it out to be within our range
      // (this will create a value from -max to max)

      return (2 * a - 1) * max;
    }

    public Point2d Random2dPoint(Random rnd, double max)
    {
      double x = rnd.NextDouble(),
            y = rnd.NextDouble();

      return new Point2d(
        DeNormalize(x, max),
        DeNormalize(y, max)
      );
    }

    public Point3d Random3dPoint(Random rnd, double max)
    {
      double x = rnd.NextDouble(),
            y = rnd.NextDouble(),
            z = rnd.NextDouble();

      return new Point3d(
        DeNormalize(x, max),
        DeNormalize(y, max),
        DeNormalize(z, max)
      );
    }

    public Point2dCollection Random2dPoints(int num, double max)
    {
      Point2dCollection pts = new Point2dCollection(num);
      Random rnd = new Random();
      for (int i = 0; i < num; i++)
      {
        pts.Add(Random2dPoint(rnd, max));
      }
      return pts;
    }

    public Point3dCollection Random3dPoints(int num, double max)
    {
      Point3dCollection pts = new Point3dCollection();
      Random rnd = new Random();
      for (int i = 0; i < num; i++)
      {
        pts.Add(Random3dPoint(rnd, max));
      }
      return pts;
    }

    public void PrintPoints(Editor ed, Point2dCollection pts)
    {
      foreach (Point2d pt in pts)
      {
        ed.WriteMessage("{0}\n", pt);
      }
    }

    public void PrintPoints(Editor ed, Point3dCollection pts)
    {
      foreach (Point3d pt in pts)
      {
        ed.WriteMessage("{0}\n", pt);
      }
    }

    [CommandMethod("PTS")]
    public void PointSort()
    {
      Document doc =
          Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;

      Point2dCollection pts2d = Random2dPoints(20, 1000.0);
      Point2d[] raw = pts2d.ToArray();
      Array.Sort(raw, new sort2dByX());
      Point2dCollection sorted2d = new Point2dCollection(raw);

      ed.WriteMessage("\n2D points before sort:\n\n");
      PrintPoints(ed, pts2d);
      ed.WriteMessage("\n\n2D points after sort:\n\n");
      PrintPoints(ed, sorted2d);

      Point3dCollection pts3d = Random3dPoints(20, 1000.0);
      Point3d[] raw3d = new Point3d[pts3d.Count];
      pts3d.CopyTo(raw3d, 0);
      Array.Sort(raw3d, new sort3dByX());
      Point3dCollection sorted3d = new Point3dCollection(raw3d);

      ed.WriteMessage("\n3D points before sort:\n\n");
      PrintPoints(ed, pts3d);
      ed.WriteMessage("\n\n3D points after sort:\n\n");
      PrintPoints(ed, sorted3d);
    }
  }
}

  Some notes on this implementation:
  • For the purposes of this example, we’re assuming “sorting” means to sort on the X value of each point
    • It should be obvious how to change the implementation to use different sort criteria
  • To test the sorting, we’re populating the collections with a set of randomly-generated points
    • We create 20 points in each collection, each with coordinates in the range of –1000 to 1000
    • I’ve kept the number of points in each collection low, just to keep the post to a reasonable length and still be able to include the results
  • Converting to a .NET array is a little different for 2D and 3D collections
    • Point2dCollection has the ToArray() method
    • Point3dCollection has the CopyTo() method
Something I will say about the above code... It’s code like this that makes me yearn for a more dynamic environment (I’m writing this in “classic”, statically-typed C#). There are several duplicate classes with basically the same implementation but taking different types: plenty of code that just feels redundant.
It would be interesting to rework this IronPython, to see what that it brings (or even to see if using the dynamic keyword would help – I should really install VS 2010 and give it a try). This is also exactly the kind of problem that F# excels at solving, so I’ll expect I’ll be giving that a try, too, before too long, just to see how much code can be ripped out.
Here are some sample results from  running the PTS command:
Command: PTS
2D points before sort:

(546.62044884014,333.683370302284)
(273.865409788613,671.008432130799)
(786.237089795171,-664.37283328938)
(-951.588503062533,-221.942868652727)
(-362.490728200642,-93.6347987007512)
(-938.590817124858,-889.46122764119)
(628.55356355596,-180.880018128492)
(485.986099339084,329.109809980313)
(525.820961001246,-659.813289372164)
(-902.095012321181,-931.107034874664)
(683.452251219867,931.710177069395)
(110.748492698534,-899.346025613763)
(47.6774876227963,-794.155224130561)
(-993.500254113926,438.08932389975)
(994.927220044158,-722.431948279232)
(198.020555636855,462.94129894252)
(-693.78015850381,-930.635690656787)
(-330.415913523369,497.267734025264)
(-855.102567866027,951.917634323201)
(520.609316192851,-779.07530860001)


2D points after sort:

(-993.500254113926,438.08932389975)
(-951.588503062533,-221.942868652727)
(-938.590817124858,-889.46122764119)
(-902.095012321181,-931.107034874664)
(-855.102567866027,951.917634323201)
(-693.78015850381,-930.635690656787)
(-362.490728200642,-93.6347987007512)
(-330.415913523369,497.267734025264)
(47.6774876227963,-794.155224130561)
(110.748492698534,-899.346025613763)
(198.020555636855,462.94129894252)
(273.865409788613,671.008432130799)
(485.986099339084,329.109809980313)
(520.609316192851,-779.07530860001)
(525.820961001246,-659.813289372164)
(546.62044884014,333.683370302284)
(628.55356355596,-180.880018128492)
(683.452251219867,931.710177069395)
(786.237089795171,-664.37283328938)
(994.927220044158,-722.431948279232)

3D points before sort:

(-282.271111981138,909.546242053409,285.631638618946)
(371.393521023632,762.584686168742,-119.380790330181)
(386.957248387373,-908.643945077734,648.815548815213)
(494.069362754966,93.28737999,323.425575775758)
(494.450510244095,586.600064107496,680.753123797827)
(489.99652056489,712.608007580325,660.061542717768)
(132.996848380657,-910.9989078301,-602.627639473708)
(564.335921576403,-454.319581135325,78.9875290724391)
(276.740193961533,837.884722202031,922.783010603293)
(-314.830172487921,370.544476141475,-925.548076594969)
(865.08049995875,-543.389787684842,101.277599624022)
(-267.499718473991,616.808070622761,558.13882665622)
(-782.131620581323,-289.302226756374,373.464381961834)
(832.297310155024,-629.765324122163,523.183570021383)
(614.174030541523,-112.834495079161,366.034026893803)
(-234.866094419205,43.4879246370345,265.665525228561)
(-255.009830582426,195.9628114458,-851.765022544081)
(374.128198891007,532.42736753655,-900.2289231402)
(-385.354406845455,153.392966442459,363.865823188734)
(-793.355890453493,-905.346672937901,924.69996396671)


3D points after sort:

(-793.355890453493,-905.346672937901,924.69996396671)
(-782.131620581323,-289.302226756374,373.464381961834)
(-385.354406845455,153.392966442459,363.865823188734)
(-314.830172487921,370.544476141475,-925.548076594969)
(-282.271111981138,909.546242053409,285.631638618946)
(-267.499718473991,616.808070622761,558.13882665622)
(-255.009830582426,195.9628114458,-851.765022544081)
(-234.866094419205,43.4879246370345,265.665525228561)
(132.996848380657,-910.9989078301,-602.627639473708)
(276.740193961533,837.884722202031,922.783010603293)
(371.393521023632,762.584686168742,-119.380790330181)
(374.128198891007,532.42736753655,-900.2289231402)
(386.957248387373,-908.643945077734,648.815548815213)
(489.99652056489,712.608007580325,660.061542717768)
(494.069362754966,93.28737999,323.425575775758)
(494.450510244095,586.600064107496,680.753123797827)
(564.335921576403,-454.319581135325,78.9875290724391)
(614.174030541523,-112.834495079161,366.034026893803)
(832.297310155024,-629.765324122163,523.183570021383)
(865.08049995875,-543.389787684842,101.277599624022)

  Update
Thanks to Dan Smith for provide a refactored version of the code: if you use multiple inheritance – in the case of our “comparer” classes – and generics/LINQ – in the case of the point generation piece – then it’s certainly possible to factor out the redundant code in good old C#. (You will have to target .NET Framework 3.5 or higher to get this to build.)
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System.Collections.Generic;
using System.Linq;
using System;

namespace PointSort
{
  internal class sortByX
  {
    protected static bool IsZero(double a)
    {
      return Math.Abs(a) < Tolerance.Global.EqualPoint;
    }

    protected static bool IsEqual(double a, double b)
    {
      return IsZero(b - a);
    }

    protected int Compare(double aX, double bX)
    {
      if (IsEqual(aX, bX)) return 0; // ==
      if (aX < bX) return -1; // <
      return 1; // >
    }
  }

  internal class sort2dByX : sortByX, IComparer<Point2d>
  {
    public int Compare(Point2d a, Point2d b)
    {
      return base.Compare(a.X, b.X);
    }
  }

  internal class sort3dByX : sortByX, IComparer<Point3d>
  {
    public int Compare(Point3d a, Point3d b)
    {
      return base.Compare(a.X, b.X);
    }
  }

  public class Commands
  {
    private double DeNormalize(double a, double max)
    {
      // Random numbers are from 0 to 1.0, so we
      // multiply it out to be within our range
      // (this will create a value from -max to max)

      return (2 * a - 1) * max;
    }

    public Point2d Random2dPoint(Random rnd, double max)
    {
      double x = rnd.NextDouble(),
            y = rnd.NextDouble();

      return new Point2d(
        DeNormalize(x, max),
        DeNormalize(y, max)
      );
    }

    public Point3d Random3dPoint(Random rnd, double max)
    {
      double x = rnd.NextDouble(),
            y = rnd.NextDouble(),
            z = rnd.NextDouble();

      return new Point3d(
        DeNormalize(x, max),
        DeNormalize(y, max),
        DeNormalize(z, max)
      );
    }

    TPoint[] RandomPoints<TPoint>(
      int num, double max, Func<Random, double, TPoint> generator
    )
    {
      var pts = new TPoint[num];
      var rnd = new Random();

      for (int i = 0; i < num; i++)
      {
        pts = generator(rnd, max);
      }
      return pts;
    }

    public Point2dCollection Random2dPoints(int num, double max)
    {
      var pts = RandomPoints<Point2d>(num, max, Random2dPoint);
      return new Point2dCollection(pts);
    }

    public Point3dCollection Random3dPoints(int num, double max)
    {
      var pts = RandomPoints<Point3d>(num, max, Random3dPoint);
      return new Point3dCollection(pts);
    }

    public void PrintPoints(Editor ed, Point2dCollection pts)
    {
      foreach (Point2d pt in pts)
      {
        ed.WriteMessage("{0}\n", pt);
      }
    }

    public void PrintPoints(Editor ed, Point3dCollection pts)
    {
      foreach (Point3d pt in pts)
      {
        ed.WriteMessage("{0}\n", pt);
      }
    }

    [CommandMethod("PTS")]
    public void PointSort()
    {
      Document doc =
          Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;

      Point2dCollection pts2d = Random2dPoints(20, 1000.0);
      Point2d[] raw = pts2d.ToArray();
      Array.Sort(raw, new sort2dByX());
      Point2dCollection sorted2d = new Point2dCollection(raw);

      ed.WriteMessage("\n2D points before sort:\n\n");
      PrintPoints(ed, pts2d);
      ed.WriteMessage("\n\n2D points after sort:\n\n");
      PrintPoints(ed, sorted2d);

      Point3dCollection pts3d = Random3dPoints(20, 1000.0);
      Point3d[] raw3d = new Point3d[pts3d.Count];
      pts3d.CopyTo(raw3d, 0);
      Array.Sort(raw3d, new sort3dByX());
      Point3dCollection sorted3d = new Point3dCollection(raw3d);

      ed.WriteMessage("\n3D points before sort:\n\n");
      PrintPoints(ed, pts3d);
      ed.WriteMessage("\n\n3D points after sort:\n\n");
      PrintPoints(ed, sorted3d);
    }
  }
}

  It’s still more verbose than I’d like, given the relatively low complexity of the problem, so I’ll still give IronPython and F# a go to see how they compare, when I get the chance.


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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-17 22:27 , Processed in 0.228023 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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