Overkill on selection set

Overkill on selection set

jwe03
Advocate Advocate
6,058 Views
15 Replies
Message 1 of 16

Overkill on selection set

jwe03
Advocate
Advocate

Hello, I'm trying to execute the overkill command on a specific selection set.

Is that possible? 

If not, what is the alternative.

 

The goal is to remove duplicates from specific layers and objects types.

 

Thanks.

0 Likes
Accepted solutions (1)
6,059 Views
15 Replies
Replies (15)
Message 2 of 16

ActivistInvestor
Mentor
Mentor

Yes. You can use the command line version (e.g., "-OVERKILL"), to script the command from the Editor's Command() method, the LISP (command) function, etc..

 


@jwe03 wrote:

Hello, I'm trying to execute the overkill command on a specific selection set.

Is that possible? 

If not, what is the alternative.

 

The goal is to remove duplicates from specific layers and objects types.

 

Thanks.


 

0 Likes
Message 3 of 16

jwe03
Advocate
Advocate

Hi, thank you for your reply
is there any way to that from vb.net?

0 Likes
Message 4 of 16

_gile
Consultant
Consultant

Hi, Here's a little example:

Public Sub Test() 
    Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor 
    Dim ss As PromptSelectionResult = ed.GetSelection() 
    If ss.Status = PromptStatus.OK Then 
        ed.Command("_-overkill", ss.Value, "", "") 
    End If 
End Sub

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 16

jwe03
Advocate
Advocate

Gilles Chanteau, always helpful Smiley Happy
Thank you.

0 Likes
Message 6 of 16

jwe03
Advocate
Advocate

Hello Gilles,

 

I have tested your code and it does not seem to work.

I got the following error:

Autodesk.AutoCAD.Runtime.Exception: eInvalidInput
at Autodesk.AutoCAD.EditorInput.Editor.Command(Object[] parameter)

 

This is my code:

 

Public Shared Function overkill()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor


Dim tvsPolyline(1) As TypedValue

tvsPolyline.SetValue(New TypedValue(0, "LWpolyline"), 0)
tvsPolyline.SetValue(New TypedValue(8, "0"), 1)

Dim sfPolyline As SelectionFilter = New SelectionFilter(tvsPolyline)
Dim srPolyline As PromptSelectionResult = ed.SelectAll(sfPolyline)

 

If srPolyline.Status = PromptStatus.OK Then ed.Command("_-overkill", srPolyline.Value, "", "")

 

End Function

 

 

Regards,

Jad.

0 Likes
Message 7 of 16

_gile
Consultant
Consultant

Hi,

 

I don't know much about VB, but it seems to me your method should be a Sub (none returned value) instead of a Function.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 8 of 16

jwe03
Advocate
Advocate

Hi, 

You're right it should be a sub, but this is not the cause of the issue.

 

If there is a way to actually select entities on the scene based on a selection set, then this well be solved.

But till now i have not found a way to do so

 

Regards,

Jad.

0 Likes
Message 9 of 16

_gile
Consultant
Consultant

@jwe03 wrote:

Hi, 

You're right it should be a sub, but this is not the cause of the issue.

 

If there is a way to actually select entities on the scene based on a selection set, then this well be solved.

But till now i have not found a way to do so

 

Regards,

Jad.


Are you sure?

 

I made the effort to wrote and test the following VB code and it works fine.

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

Public Class Commands

    <CommandMethod("Test")>
    Public Shared Sub overkill()

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

        Dim tvsPolyline(1) As TypedValue

        tvsPolyline.SetValue(New TypedValue(0, "LWpolyline"), 0)
        tvsPolyline.SetValue(New TypedValue(8, "0"), 1)

        Dim sfPolyline As SelectionFilter = New SelectionFilter(tvsPolyline)
        Dim srPolyline As PromptSelectionResult = ed.SelectAll(sfPolyline)

        If srPolyline.Status = PromptStatus.OK Then ed.Command("_-overkill", srPolyline.Value, "", "")

    End Sub

End Class


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 10 of 16

ActivistInvestor
Mentor
Mentor

@jwe03 wrote:

Hi, 

You're right it should be a sub, but this is not the cause of the issue.

 

If there is a way to actually select entities on the scene based on a selection set, then this well be solved.

But till now i have not found a way to do so

 

Regards,

Jad.


Where is your code being called from?

 

If it is from a button on a paletteSet or some other modeless element, then that would explain eInvalidInput.

 

The Command() method can only be called from a registered command handler.

 

 

Message 11 of 16

jwe03
Advocate
Advocate

Spot on, im calling the function from a button in a user form. Here's the code:

 

Private Sub OverkillButton_Click(sender As Object, e As EventArgs) Handles OverkillButton.Click


Annotate.overkill()

End Sub

 

'In the annotate class, you have the following function:

Public Shared Function overkill()

 

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim tvsPolyline(1) As TypedValue

tvsPolyline.SetValue(New TypedValue(0, "LWpolyline"), 0)
tvsPolyline.SetValue(New TypedValue(8, "0"), 1)

 

Dim sfPolyline As SelectionFilter = New SelectionFilter(tvsPolyline)
Dim srPolyline As PromptSelectionResult = ed.SelectAll(sfPolyline)

 

If srPolyline.Status = PromptStatus.OK Then ed.Command("_-overkill", srPolyline.Value, "", "")

 

End Function

 

 

What do you suggest should be done in this case?

I need to research more about what is meant by "a registered command handler" as well.

0 Likes
Message 12 of 16

jwe03
Advocate
Advocate

As mentioned above, it seems that the problem is because im calling the function/sub from a button in a userform.

Thank you for your efforts.

0 Likes
Message 13 of 16

ActivistInvestor
Mentor
Mentor

@jwe03 wrote:

Spot on, im calling the function from a button in a user form. Here's the code:

 

Private Sub OverkillButton_Click(sender As Object, e As EventArgs) Handles OverkillButton.Click


Annotate.overkill()

End Sub

 

'In the annotate class, you have the following function:

Public Shared Function overkill()

 

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim tvsPolyline(1) As TypedValue

tvsPolyline.SetValue(New TypedValue(0, "LWpolyline"), 0)
tvsPolyline.SetValue(New TypedValue(8, "0"), 1)

 

Dim sfPolyline As SelectionFilter = New SelectionFilter(tvsPolyline)
Dim srPolyline As PromptSelectionResult = ed.SelectAll(sfPolyline)

 

If srPolyline.Status = PromptStatus.OK Then ed.Command("_-overkill", srPolyline.Value, "", "")

 

End Function

 

 

What do you suggest should be done in this case?

I need to research more about what is meant by "a registered command handler" as well.


You need to also show how the form is shown (modeless or modal).

 

It's fairly obvious that the form is modeless, but you need to confirm that.

0 Likes
Message 14 of 16

jwe03
Advocate
Advocate

Yes you're right, the user form is modeless. 

I created it using the visual basic wizard not through code. So, i guess this is the default behavior. And I need it to be like that in my application

Is there a way to work around that?

 

0 Likes
Message 15 of 16

ActivistInvestor
Mentor
Mentor

@jwe03 wrote:

Yes you're right, the user form is modeless. 

I created it using the visual basic wizard not through code. So, i guess this is the default behavior. And I need it to be like that in my application

Is there a way to work around that?

 


I don't have VB.NET code to show how to work around it, but the way to do that is to define a CommandMethod that does not use the CommandFlags.Session flag, and in that method, call the Editor's Command() method to do what you need. From the click handler of your button, use the Document's SendStringToExecute() method to run the command method you defined.

 

In AutoCAD 2016 or later you can also use ExecuteInCommandContextAsync(), which is really just a gift-wrapped version of that very same method. If you need to run your code on AutoCAD 2015 or earlier, you can just use the method I described which does the same thing as ExecuteInCommandContextAsync().

 

See the code below and the attached file. If you find it's too complicated or more than you need, then you can find a less-complete/complicated version of it in >this post<.

 

For anyone who may be struggling with this and other context-related issues, the code below is the usage sample portion of the attached file, which is a more complete version of the code in the post I referred to above.

 

I honestly don't know if this will convert to VB without errors but you can always give it a try.

 

////////////////////////////////////////////////////////////////////////
/// USAGE EXAMPLE
/// 
/// The above code is API, and everything that
/// follows is example code demonstrating the
/// use of the API code.

/// All example code is accessed from buttons
/// on a PaletteSet that can be activated using 
/// the DCPALETTE command.
/// 

namespace InvokeExample
{
   using Autodesk.AutoCAD.ApplicationServices;
   using Application = Autodesk.AutoCAD.ApplicationServices.Application;
   using System.Windows.Forms;
   using Autodesk.AutoCAD.Geometry;
   using System.Drawing;


   /// <summary>
   /// A specialization of System.Windows.Forms.Button whose 
   /// Click event handler executes in the document context.
   /// </summary>

   public class CommandButton : Button
   {
      protected override void OnClick(EventArgs e)
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;
         if(doc!=null)
            doc.Invoke(() => base.OnClick(e));
      }
   }

   /// <summary>
   /// An example UserControl hosted by the included PalletteSet.
   /// </summary>

   public class MyUserControl : UserControl
   {
      Button button1;
      Button button2;
      Button button3;
      Button button4;
      CommandButton commandButton1;

      public MyUserControl()
      {
         this.Dock = DockStyle.Fill;

         button1 = new Button();
         button1.Text = "Draw a Circle";
         button1.AutoSize = true;
         button1.Click += button1_Click;
         this.Controls.Add(button1);

         button2 = new Button();
         button2.Text = "Copy objects to new Document";
         button2.Click += button2_Click;
         this.Controls.Add(button2);

         button3 = new Button();
         button3.Text = "Draw rectangles in each open Document";
         button3.Click += button3_Click;
         this.Controls.Add(button3);

         commandButton1 = new CommandButton();
         commandButton1.Text = "Draw Circles using CommandButton";
         commandButton1.Click += commandButton1_Click;
         this.Controls.Add(commandButton1);

         button4 = new Button();
         button4.Text = "Batch process drawing files";
         button4.Click += button4_Click;
         this.Controls.Add(button4);

         // Bind the UserControl's Enabled property to the
         // EditorStateView's HasQuiescentDocument property,
         // to automatically enable/disable the UserControl
         // when a quiescent document is/is not active. 

         this.DataBindings.Add("Enabled", EditorStateView.Instance, "HasQuiescentDocument");
      }

      protected override void OnLayout(LayoutEventArgs e)
      {
         this.SuspendLayout();
         base.OnLayout(e);
         int top = 0;
         foreach(Control control in this.Controls)
         {
            control.Height = control.GetPreferredSize(new Size(1, 1)).Height;
            control.SetMargins(margin, Alignment.Horizontal);
            control.Center(Alignment.Horizontal);
            top = top == 0 ? margin : top + control.Height + margin;
            control.Top = top;
         }
         this.ResumeLayout(false);
      }

      const int margin = 6;

      /// The click handler for button1 on the UserControl calls 
      /// the Invoke() method and passes a delegate that will 
      /// execute in the document context, asynchronously. 
      /// 
      /// When the button is clicked the delegate executes and 
      /// calls the Editor's Command() method to draw a circle.

      void button1_Click(object sender, EventArgs e)
      {
         /// Ask the ContextManager if its possible to
         /// use the Invoke() method at this point:

         Document doc = Application.DocumentManager.MdiActiveDocument;

         if(doc != null && doc.CanInvoke())
         {

            /// The call to Invoke() is usually the last statement
            /// in the event handler, as any code that follows it
            /// will execute <em>before</em> the delegate runs.

            doc.Invoke(delegate()
            {
               /// The code within this delegate runs in the 
               /// document context, making it possible to use 
               /// the Command() method, so let's draw a circle:

               doc.Editor.Command("._CIRCLE", "10,10", "5");

            });

            /// Code appearing here runs in the application context
            /// <em>before</em> the code in the above delegate runs.
            /// Do not place code here that depends on side-effects
            /// of code in the above delegate, or that must run after 
            /// the above delegate executes.
         }
      }

      /// <summary>
      /// The click handler for the "Copy objects to new Document"
      /// button demonstrates how to use the OnEndInvoke() method to
      /// execute code in the application context, after the delegate
      /// passed to Invoke() (which runs in the document context) has
      /// returned. It also shows how you can chain together Invoke()
      /// and OnEndInvoke() delegates to repeatedly switch between the
      /// document and application contexts to perform more complex 
      /// operations involving multiple open documents, and operations 
      /// that involve opening, activating, and closing documents.
      /// 
      /// The button click handler will prompt for a selection of
      /// objects, and then issue the COPYBASE command to copy the 
      /// selected objects to the clipboard.
      /// 
      /// Then, it creates a new document, acivates it, and issues
      /// the PASTEORIG command to paste the copied objects into the
      /// new document. 
      /// 
      /// Finally, it switches back to the original document from
      /// which the objects were copied.
      /// </summary>

      void button2_Click(object sender, EventArgs e)
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;

         if(doc != null && doc.CanInvoke())
         {
            PromptSelectionResult psr;

            /// Prevent the user from switching documents while
            /// they are selecting objects:
            
            Application.DocumentManager.DocumentActivationEnabled = false;

            try
            {
               /// Set the focus to the drawing view:

               doc.Editor.SetFocus();

               /// Get a selection set of objects from the user:
               
               psr = doc.Editor.GetSelection();
               if(psr.Status != PromptStatus.OK)
                  return;
            }
            finally
            {
               /// enable document activation:
               
               Application.DocumentManager.DocumentActivationEnabled = true;
            }

            // all code in this method up to this point
            // runs in the application context.

            doc.Invoke(delegate()
            {
               // this code runs in the document context:
               doc.Editor.Command("._COPYBASE", Point3d.Origin, psr.Value, "");
               doc.OnEndInvoke(delegate()
               {
                  // this code runs in the application context:
                  Document newDoc = Application.DocumentManager.Add("acad");
                  newDoc.Invoke(delegate()
                  {
                     // this code runs in the document context:
                     newDoc.Editor.Command("._PASTEORIG");
                     newDoc.OnEndInvoke(delegate()          
                     {
                        // this code runs in the application context:
                        Application.DocumentManager.MdiActiveDocument = doc;

                     });
                  });
               });
            });
         }
      }

      /// <summary>
      /// The third button click handler shows how to use the
      /// ForEach() extension method of the DocumentCollection,
      /// to execute a delegate in the document context multiple
      /// times, once for each open document. 
      /// 
      /// The delegate accepts a single argument of type Document,
      /// which is the Document that it is being invoked in, and
      /// uses that argument to work with the document. 
      /// 
      /// The delegate must not close the document or switch to 
      /// another document.
      /// 
      /// The example draws 2 rectangles in every open document.
      /// </summary>

      void button3_Click(object sender, EventArgs e)
      {
         Application.DocumentManager.ForEach(
            delegate(Document doc)
            {
               doc.Editor.Command("._RECTANG", "8,8", "12,10");
               doc.Editor.Command("._RECTANG", "7,7", "13,11");
            }
         );
      }

      /// <summary>
      /// The Click event handler for commandButton1 demonstrates 
      /// the use of the included CommandButton class, whose click 
      /// event handler executes in the document context. 
      /// 
      /// The handler draws 2 circles using the Command() method.
      /// 
      /// Notice that unlike the other button event handlers, 
      /// there's no use of the Invoke() method at all. Rather, 
      /// the code in the click handler can quite simply assume
      /// it's running in the document context, thereby making 
      /// the task of switching to the document context totally
      /// transparent to the programmer.
      /// </summary>

      void commandButton1_Click(object sender, EventArgs e)
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;
         doc.Editor.Command("._CIRCLE", "8,8", "4");
         doc.Editor.Command("._CIRCLE", "8,8", "2");
      }

      /// <summary>
      /// The click event for button4 demonstrates how to use
      /// the second overload of the ForEach() extension method 
      /// to batch-process multiple DWG files selected from a 
      /// file dialog.
      /// </summary>
      /// <remarks>
      /// Each file in the argument list is sequentially opened
      /// and the delegate invoked with the Document representing
      /// the open file. When the delegate returns, the document
      /// is closed, and processing proceeds to the next file.
      /// 
      /// The process performed on each file:
      /// 
      ///   1. Switch to model space
      ///   2. Zoom Extents
      ///   3. Save the file
      ///   
      /// The delegate that performs the processing of each file
      /// executes in the document context, allowing the use of
      /// the Command() method. The delegate must save the file
      /// if necessary, as it will not be saved automatically,
      /// and any changes made by the delegate will be discarded.
      /// </remarks>

      void button4_Click(object sender, EventArgs e)
      {
         OpenFileDialog ofd = new OpenFileDialog();
         ofd.AddExtension = true;
         ofd.Filter = "Drawing files|*.dwg";
         ofd.FilterIndex = 0;
         ofd.Multiselect = true;
         ofd.DefaultExt = ".dwg";
         if(ofd.ShowDialog() == DialogResult.OK && ofd.FileNames.Length > 0)
         {
            Application.DocumentManager.ForEach(ofd.FileNames,
               delegate(Document doc) 
               {
                  doc.Editor.Command("._TILEMODE", "1");
                  doc.Editor.Command("._ZOOM", "_E");
                  doc.Save();
               }
            );
         }
      }


   }


   /// A PaletteSet that hosts the above UserControl
   /// 
   /// This PaletteSet also demonstrates best-practices
   /// for consuming a PaletteSet, which is by deriving
   /// a class from the PaletteSet class, and placing all 
   /// of the initialization code in the constructor of 
   /// the derived class, rather than in some other place 
   /// (like a command handler). The practice is identical
   /// to the way Windows Forms are consumed, serving to 
   /// make a PaletteSet a self-contained component having 
   /// no dependence on any other code or component.
   /// 
   /// The custom PaletteSet class also uses the Singleton
   /// pattern to marshal and manage the single reference
   /// to the PaletteSet, which helps to simplify its use.
   /// The command method that shows the PaletteSet is also
   /// incorporated into the custom class, if you follow
   /// this pattern, remember that command methods that are 
   /// added to a PaletteSet class must be static methods.

   public class DCPaletteSet : PaletteSet
   {
      /// <summary>
      /// Static singleton instance:
      /// </summary>
      static DCPaletteSet instance;

      MyUserControl control;

      public DCPaletteSet() : base("MyPaletteSet")
      {
         control = new MyUserControl();
         Add("MyUserControl", control);
         this.DockEnabled = DockSides.None;
         this.Visible = true;
         this.Dock = DockSides.None;
      }

      protected override void Dispose(bool disposing)
      {
         if(instance == this)
            instance = null;
         if(control != null)
         {
            control.Dispose();
            control = null;
         }
         base.Dispose(disposing);
      }

      /// <summary>
      /// A command to create/show the example PaletteSet
      /// </summary>

      [CommandMethod("DCPALETTE", CommandFlags.Session)]
      public static void ShowCommand()
      {
         if(instance == null)
            instance = new DCPaletteSet();
         instance.Visible = true;
      }
   }

   /// <summary>
   /// WinForm Control support extension methods:
   /// </summary>
   public static class MyControlExtensions
   {

      public static void Center(this Control control, Alignment alignment)
      {
         Control parent = control.Parent;
         if(parent != null)
         {
            if(alignment.HasFlag(Alignment.Horizontal))
               control.Left = (parent.Width - control.Width) / 2;
            if(alignment.HasFlag(Alignment.Vertical))
               control.Top = (parent.Height - control.Height) / 2;
         }
      }

      public static void SetMargins(this Control control, int value, Alignment alignment)
      {
         Control parent = control.Parent;
         if(parent != null)
         {
            if(alignment.HasFlag(Alignment.Horizontal))
               control.Width = parent.Width - (value * 2);
            if(alignment.HasFlag(Alignment.Vertical))
               control.Height = parent.Height - (value * 2);
         }
      }
   }

   [Flags]
   public enum Alignment
   {
      Horizontal = 1,
      Vertical = 2,
      Both = 4
   }
}

 

Message 16 of 16

jwe03
Advocate
Advocate
Accepted solution

Hello, 

 

This did not directly solve my problem, but it helped and i finally got the solution. I researched on command definitions and there is one called transparent. This allows the command to be executed while another command is running. As you suggested, I created a command and made the subroutine call this command. Below is my code:

 

    <CommandMethod("CustomOverkill", CommandFlags.Transparent)> _
    Public Shared Sub customOverKill()

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

        Dim tvsPolyline(0) As TypedValue

        tvsPolyline.SetValue(New TypedValue(8, "0"), 0)

        Dim sfPolyline As SelectionFilter = New SelectionFilter(tvsPolyline)
        Dim srPolyline As PromptSelectionResult = ed.SelectAll(sfPolyline)


        If srPolyline.Status = PromptStatus.OK Then ed.Command("_-overkill", srPolyline.Value, "", "")

    End Sub

    Public Shared Sub overkill()

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        doc.LockDocument()
        doc.SendStringToExecute("CustomOverkill" & vbCr, True, False, False)

    End Sub

Thanks a lot for your help !!! Smiley Happy

0 Likes