TheSwamp

Code Red => .NET => Topic started by: kdub on July 06, 2019, 09:44:14 PM

Title: Selection Set by Fence
Post by: kdub on July 06, 2019, 09:44:14 PM

Some days you have so much fun you forget about the wonderful sun shining outside

Title: Re: Selection Set by Fence
Post by: kdub on July 06, 2019, 10:08:13 PM
During a discussion elsewhere about a month ago I mistakenly thought that a Fence selection did not keep the SelectionSet in order of selection.
That, combined with the OP's requirement for being able to multi-select and force the selectionset to retain a specific order, led to a play day for me.

This could probably be combined with a keyword trap to allow single selections as well as Fence selections to be added to the SelectionSet .. but it would probably get messy.

Just to prove I was wrong about the Selection set (not) being ordered : ...


edit kdub: spelling police :)
Title: Re: Selection Set by Fence
Post by: kdub on July 06, 2019, 10:16:53 PM
Some Code

Code - C#: [Select]
  1.  
  2.    public class Commands
  3.     {
  4.         [CommandMethod("TEST", CommandFlags.Modal)]
  5.         public void Test()
  6.         {
  7.             Active.Editor.WriteMessage(" Get on with it !!");
  8.         }
  9.  
  10.         /// <summary>SelectionSet with filter by Fence.</summary>
  11.         // This command does a simple selection and ignores all
  12.         // entities other than red circles.
  13.         [CommandMethod("SSetF", CommandFlags.Modal)]
  14.         public void SSGetFilterByFence()
  15.         {
  16.             // DxfCode.Start (equal to 0) - This is for 'Entity Name'
  17.             // DxfCode.Color is for ACI color - 1 = Red
  18.             TypedValue[] filterValues = new[] {
  19.                 new TypedValue((int)DxfCode.Start, "CIRCLE"),
  20.                 new TypedValue((int)DxfCode.Color, 1)
  21.             };
  22.             SelectionFilter selectionFilter = new SelectionFilter(filterValues);
  23.  
  24.             Active.WriteMessage("\nFence point: (Enter when Done)");
  25.             Point3dCollection pointCollection = InteractivePolyLine.CollectPointsInteractive();
  26.  
  27.             if (pointCollection.Count != 0) {
  28.                 try {
  29.                     SelectionSet ss;
  30.                     PromptSelectionResult selectionResult = Active.Editor.SelectFence(pointCollection, selectionFilter);
  31.                     if (selectionResult.Status == PromptStatus.OK) {
  32.                         ss = selectionResult.Value;
  33.                         if (ss != null) {
  34.                             Active.WriteMessage($"\nThe SelectionSet has {ss.Count} entities.");
  35.                             OutputCircleData(ss);
  36.                         }
  37.                         else {
  38.                             Active.WriteMessage("\nThe SelectionSet has null value");
  39.                         }
  40.                     }
  41.                     else { Active.WriteMessage("\nFence selection failed!"); }
  42.  
  43.                 }
  44.                 catch (System.Exception ex) {
  45.                     Active.WriteMessage(Environment.NewLine + ex.ToString());
  46.                 }
  47.             }
  48.         }
  49.  
  50.  
  51.         /// <summary>SelectionSet with filter.</summary>
  52.         // This command does a simple selection and ignores all
  53.         // entities other than red circles.
  54.         // Use any of the conventional selection Keywords at the commandLine
  55.  
  56.         [CommandMethod("SSetA", CommandFlags.Modal)]
  57.         public void SSGetFilterAnyMeans()
  58.         {
  59.             // DxfCode.Start (equal to 0) - This is for 'Entity Name'
  60.             // DxfCode.Color is for ACI color - 1 = Red
  61.             TypedValue[] filterValues = new[] {
  62.                 new TypedValue((int)DxfCode.Start, "CIRCLE"),
  63.                 new TypedValue((int)DxfCode.Color, 1)
  64.             };
  65.             SelectionFilter selectionFilter = new SelectionFilter(filterValues);
  66.  
  67.             // Set the selection options
  68.             PromptSelectionOptions selectionOptions = new PromptSelectionOptions {
  69.                 MessageForAdding = "Select Red Circles by Any means:",
  70.                 AllowDuplicates = true
  71.             };
  72.  
  73.             // Make the selection:
  74.             PromptSelectionResult selectionResult = Active.Editor.GetSelection(selectionOptions, selectionFilter);
  75.  
  76.             if (!(selectionResult.Status == PromptStatus.OK))
  77.                 return;
  78.  
  79.             SelectionSet ss = selectionResult.Value;
  80.             OutputCircleData(ss);
  81.         }
  82.  
  83.         /// <summary>Outputs the circle data.</summary>
  84.         /// <param name="ss">The SelectionSet of Circles.</param>
  85.         private void OutputCircleData(SelectionSet ss)
  86.         {
  87.             ObjectId[] idarray = ss.GetObjectIds();
  88.             // start a transaction
  89.             using (Transaction tr = Active.Database.TransactionManager.StartTransaction()) {
  90.                 try {
  91.                     foreach (var id in idarray) {
  92.                         var circle = (Circle)tr.GetObject(id, OpenMode.ForRead, true);
  93.                         Active.WriteMessage(
  94.                             $"\nYou selected: {circle.GetType().FullName} with Radius = {circle.Radius }");
  95.                     }
  96.                 }
  97.                 finally {
  98.                     tr.Dispose();
  99.                 }
  100.             }
  101.         }
  102.  
  103.  


Code - C#: [Select]
  1.  
  2.    /// <summary>
  3.     /// Provides easy access to several "active" objects in the
  4.     /// AutoCAD runtime environment.
  5.     /// Thanks to : Scott McFarlane - Programming AutoCAD with C#: Best Practices
  6.     /// </summary>
  7.     public static class Active
  8.     {
  9.         public static Document Document => cadApp.DocumentManager.MdiActiveDocument;
  10.         public static Database Database => Document.Database;
  11.         public static Editor Editor => Document.Editor;
  12.  
  13.         public static void WriteMessage(
  14.             string message)
  15.             => Editor.WriteMessage(message);
  16.  
  17.         public static void WriteMessage(
  18.             string message, params object[] parameter)
  19.             => Editor.WriteMessage(message, parameter);
  20.     }
  21.  
  22.  
  23.     /// <summary></summary>
  24.     /// <seealso cref="Autodesk.AutoCAD.Runtime.IExtensionApplication" />
  25.     public class Initialization : IExtensionApplication
  26.     {
  27.         public void Initialize()
  28.         {
  29.             cadApp.Idle += OnIdle;
  30.         }
  31.  
  32.         private void OnIdle(object sender, EventArgs e)
  33.         {
  34.             var doc = Active.Document;
  35.             if (doc != null) {
  36.                 cadApp.Idle -= OnIdle;
  37.                 Active.WriteMessage("\nSelectionTesting loaded.\n");
  38.                 Active.WriteMessage("Enter \"TEST\" at the CommandLine.\n");
  39.                 Active.WriteMessage("Enter \"SSetA\" at the CommandLine to Select Red Circles\n");
  40.                 Active.WriteMessage("Enter \"SSetF\" at the CommandLine to Select Red Circles by FENCE\n");
  41.             }
  42.         }
  43.  
  44.         public void Terminate()
  45.         { }
  46.     }
  47.  

The  CollectPointsInteractive() method is also used by
        [CommandMethod("TestPOLY", CommandFlags.Modal)]
        public void InteractivePolylineTest()

       
Code - C#: [Select]
  1.     public class InteractivePolyLine
  2.     {
  3.         /// <summary>Collects the points interactively, Temporarily joining vertexes.</summary>
  4.         /// <returns>Point3dCollection</returns>
  5.         public static Point3dCollection CollectPointsInteractive()
  6.         {
  7.             Point3dCollection pointCollection = new Point3dCollection();
  8.             Color color = Active.Database.Cecolor;
  9.             PromptPointOptions pointOptions = new PromptPointOptions("\nSelect vertex: ") {
  10.                 AllowNone = true
  11.             };
  12.  
  13.             // Get the start point
  14.             PromptPointResult pointResult = Active.Editor.GetPoint(pointOptions);
  15.             while (pointResult.Status == PromptStatus.OK) {
  16.                 pointCollection.Add(pointResult.Value);
  17.  
  18.                 // Select subsequent points
  19.                 pointOptions.UseBasePoint = true;
  20.                 pointOptions.BasePoint = pointResult.Value;
  21.                 pointResult = Active.Editor.GetPoint(pointOptions);
  22.                 if (pointResult.Status == PromptStatus.OK) {
  23.                     // Draw a temporary segment
  24.                     Active.Editor.DrawVector(
  25.                       pointCollection[pointCollection.Count - 1], // start point
  26.                       pointResult.Value,          // end point
  27.                       color.ColorIndex,
  28.                       false);                     // highlighted?
  29.                 }
  30.             }
  31.             if (pointResult.Status == PromptStatus.None) {
  32.                 return pointCollection;
  33.             }
  34.             else {
  35.                 return new Point3dCollection();
  36.             }
  37.         }
  38.  
  39.         /// <summary> Generates an interactive Polyline.</summary>
  40.         [CommandMethod("TestPOLY", CommandFlags.Modal)]
  41.         public void InteractivePolylineTest()
  42.         {
  43.             Point3dCollection pointCollection = CollectPointsInteractive();
  44.  
  45.             if (pointCollection.Count != 0) {
  46.                 // Get the current UCS
  47.                 Matrix3d ucs = Active.Editor.CurrentUserCoordinateSystem;
  48.                 Point3d origin = new Point3d(0, 0, 0);
  49.                 Vector3d normal = new Vector3d(0, 0, 1).TransformBy(ucs);
  50.  
  51.                 // Create a temporary plane
  52.                 Plane plane = new Plane(origin, normal);
  53.  
  54.                 // Create the polyline
  55.                 Polyline pline = new Polyline(pointCollection.Count) {
  56.                     Normal = normal
  57.                 };
  58.                 foreach (Point3d pt in pointCollection) {
  59.                     pline.AddVertexAt(pline.NumberOfVertices,
  60.                     plane.ParameterOf(pt.TransformBy(ucs)),
  61.                     0, 0, 0
  62.                     );
  63.                 }
  64.  
  65.                 // Add the polyline to modelspace
  66.                 using (Transaction tr = Active.Database.TransactionManager.StartTransaction()) {
  67.                     var bt = (BlockTable)tr.GetObject(Active.Database.BlockTableId, OpenMode.ForRead);
  68.  
  69.                     var btrMS = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
  70.  
  71.                     ObjectId plineId = btrMS.AppendEntity(pline);
  72.                     tr.AddNewlyCreatedDBObject(pline, true);
  73.                     tr.Commit();
  74.  
  75.                     Active.WriteMessage("\nPolyline entity is: " + plineId.ToString());
  76.                 }
  77.             }
  78.             Active.Editor.Regen();
  79.         }
  80.     }
  81.  
  82.  
Title: Re: Selection Set by Fence
Post by: MickD on July 07, 2019, 12:51:11 AM
I know it's a throwback to vba but I have used ThisDrawing (or ThisDrg for short) in the same way you have used Active, it just seems to read well :)
Title: Re: Selection Set by Fence
Post by: kdub on July 07, 2019, 10:54:33 PM
I know it's a throwback to vba but I have used ThisDrawing (or ThisDrg for short) in the same way you have used Active, it just seems to read well :)

I like it too Mick
.. but not because it reminds me of VBA :)

I'm getting into the habit of using it without conciously forcing it. That was difficult after years of declaring and assigning the values over and over and over again. Intellisence saves the typing.

As an aside, I've noticed I'm using longer variable names that read better ( for me) ie: reducing the use of abbreviations for variables (except for the regularly accepted ones ; tr, bt, id, ent etc.
I find it makes code easier for me to read when I come back to it ... I don't need to pause mentally to expand/translate abbreviations.
Title: Re: Selection Set by Fence
Post by: kdub on July 08, 2019, 12:50:11 AM
This is getting anal-retentive.

Code - C#: [Select]
  1.             var selectionResult = Active.Editor.SelectFence(pointsCollection);
  2.             if (selectionResult.Status == PromptStatus.OK) {
  3.                 Active.WriteMessage($"\n{selectionResult.Value.Count} object{(selectionResult.Value.Count > 1 ? "s" : "")} selected.");
  4.             }
  5.  

Time to go for a ride and smell the countryside.
Title: Re: Selection Set by Fence
Post by: Atook on July 08, 2019, 12:13:48 PM
Quote
{(selectionResult.Value.Count > 1 ? "s" : "")}
:idea:

It's a nice little detail, I like it! Show's you're paying attention!