Author Topic: Filtering a selection set by class?  (Read 12789 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
Filtering a selection set by class?
« on: October 01, 2012, 03:58:45 PM »
This is related to my previous post about using a pickfirst selection set with a command.
http://www.theswamp.org/index.php?topic=42871.0
My new question is does anyone know how to filter a selection set using the class of the object vs dxf codes?  Most examples for filters that I have seen using PromptSelectionOptions look something like the following where the selection set is filtering Text.
 
Code: [Select]
       
Dim filter As New SelectionFilter(New TypedValue() {New TypedValue(DxfCode.Start, "TEXT")})
Dim result As PromptSelectionResult = ed.GetSelection(filter)

All of the examples that I have seen from autodesk where they are filtering AEC objects use PromptEntityResults, .GetEntity, and PromptEntityOptions.  In the PromptEntityOptions they are using code to filter objects similar to this.
 
Code: [Select]

    Dim optEnt As New PromptEntityOptions(
      vbLf & "Select an AEC object to attach a property set")
    optEnt.SetRejectMessage(
      vbLf & "Selected entity is NOT an AEC object, try again...")
    ' "Geo" is the base class for AEC object.
    ' Use this if you want to apply to all the AEC objects.
    optEnt.AddAllowedClass(GetType(Geo), False)
    ' If you are interested in only Door object, use this instead.
    'optEnt.AddAllowedClass(GetType(Door), False) 
 
    Dim resEnt As PromptEntityResult = ed.GetEntity(optEnt)
    If resEnt.Status <> PromptStatus.OK Then
      ed.WriteMessage("Selection error - aborting")
      Exit Sub
    End If

I was wondering if there was a similiar way to filter by class using PromptSelectOptions.  As far as I know there are not DXF codes for AEC objects and according to Autodesk, there never will be and they have systematically removed any codes that might be there now.  Can you filter by Class? If not, does anyone know of a method using the GetSelection that will allow you to filter AEC objects? 
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Filtering a selection set by class?
« Reply #1 on: October 01, 2012, 04:25:15 PM »
What is the name shown for an AEC object when selected and LIST'ed in the Editor? It will be something like this: Command: li
LIST 1 found

                  AECC_TIN_SURFACE  Layer: "C-TOPO"
                            Space: Model space
                   Handle = 158e3a

which is a C3D surface. To filter for a C3D surface with selection set, the DXF name is AECC_TIN_SURFACE. All selectable objects will have a DXFName, even if they don't contain the 'normal' DXF data.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #2 on: October 01, 2012, 06:05:40 PM »
Thank you Jeff!  That worked perfectly.  I also searched google and figured out how to use conditional statements and create a multiple typed value selection set.  Here is the code that worked for me.
 
Code: [Select]
    ' <summary>
 
    ' Tests the PickSet Flag on duct and duct fittings
 
    ' </summary>
 
    <Autodesk.AutoCAD.Runtime.CommandMethod("PropertySetTools", "TestPickfirst", CommandFlags.Modal + CommandFlags.UsePickSet)> _
 
    Public Sub Command_TestPickFirst()
 
 
 
 
 
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
 
            Dim ed As Editor = doc.Editor
 
            Dim db As Database = doc.Database
 
            'Create an array of DXF Names to use in a filter
 
        Dim AECB_TypedValues() As TypedValue = {New TypedValue(DxfCode.Operator, "<OR"), _
 
                                                New TypedValue(DxfCode.Start, "AECB_DUCTFITTING"), _
 
                                                New TypedValue(DxfCode.Start, "AECB_DUCT"), _
 
                                                New TypedValue(DxfCode.Operator, "OR>")}
 
            'Create the filter and set it equal to the DXF Names created previously
 
            Dim filter As New SelectionFilter(AECB_TypedValues)
 
            'Create a Prompt Selection Option
 
            Dim pso As New PromptSelectionOptions
 
            'Create a message to display if no fittings are picked before the command is ran
 
            pso.MessageForAdding = vbLf + "Select fittings: "
 
            'Get the fittings from the pickfirst selection or from the message
 
            Dim result As PromptSelectionResult = ed.GetSelection(pso, filter)
 
            'Display the number of objects selected
 
            If result.Status = PromptStatus.OK Then
 
                ed.WriteMessage(String.Format("{0} objects selected", result.Value.Count.ToString))
 
            End If
 
End Sub
 
 

My next question would be do you happen to know how to filter a classification?  Classifications of AEC objects are stored in extension dictionaries.  I am just not sure how to go about using that in the dxf filter.
 
Thanks again for the response.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

IDabble

  • Guest
Re: Filtering a selection set by class?
« Reply #3 on: October 01, 2012, 06:41:23 PM »
That's some handy information to have!
I never thought it could be that easy.   :-o
Thanks Jeff_M for sharing that and thanks Keith Brown for asking that question!

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Filtering a selection set by class?
« Reply #4 on: October 01, 2012, 06:53:07 PM »
Thank you Jeff!  That worked perfectly.
You're welcome! Note that you can combine same DXF values into one, like so:
Code: [Select]
        Dim AECB_TypedValues() As TypedValue = {New TypedValue(DxfCode.Start, "AECB_DUCT,AECB_DUCTFITTING")}

Or you can use wildcards, assuming you want all of the objects with AECB_DUCT in the DXFname:
Code: [Select]
        Dim AECB_TypedValues() As TypedValue = {New TypedValue(DxfCode.Start, "AECB_DUCT*")}

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Filtering a selection set by class?
« Reply #5 on: October 01, 2012, 07:19:50 PM »
Oh, and as for the filtering by the classification, I don't think that's directly possible with the base filter object. I think you will need to get the SS then loop through it to test whether to keep it in the SS or not.

TheMaster

  • Guest
Re: Filtering a selection set by class?
« Reply #6 on: October 02, 2012, 05:35:56 AM »
Oh, and as for the filtering by the classification, I don't think that's directly possible with the base filter object. I think you will need to get the SS then loop through it to test whether to keep it in the SS or not.

You can do that, but it may be better to use the SelectionAdded event to filter within the selection process rather than after it completes. With SelectionAdded you can filter objects while the user is selecting them, just as AutoCAD does with objects on locked layers, etc.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #7 on: October 02, 2012, 02:25:03 PM »
How does the event handler interact with my code?  My command will either accept a selection set from the user as the command is being ran or will prompt the user to select some objects.  Once the selection begins the event handler should fire off correct?  I can do some manipulations of the selection set from the event handler but from there how would i pass the selection set back to my code?  In other words, how does my command routine get the information back from the event handler?
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

BlackBox

  • King Gator
  • Posts: 3770
Re: Filtering a selection set by class?
« Reply #8 on: October 02, 2012, 02:32:28 PM »
Take the 'meat' out of your CommandMethod and make it a separate Method... Then, presumably, either the CommandMethod, or Event Handler could call the newly separated Method, supplying a valid selection set as a parameter, etc..
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Filtering a selection set by class?
« Reply #9 on: October 02, 2012, 02:33:54 PM »
Hi,

Here's an example of an extension method called SelectByClass which extents the Editor class.

C#
Code - C#: [Select]
  1.     public static class SelectionExtensions
  2.     {
  3.         private static List<RXClass> classes;
  4.  
  5.         public static PromptSelectionResult SelectByClass(this Editor ed, params Type[] types)
  6.         {
  7.             classes = types.Select(t => RXClass.GetClass(t)).ToList();
  8.             ed.SelectionAdded += new SelectionAddedEventHandler(OnSelectionAdded);
  9.             PromptSelectionResult psr = ed.GetSelection();
  10.             ed.SelectionAdded -= new SelectionAddedEventHandler(OnSelectionAdded);
  11.             return psr;
  12.         }
  13.  
  14.         static void OnSelectionAdded(object sender, SelectionAddedEventArgs e)
  15.         {
  16.             ObjectId[] ids = e.AddedObjects.GetObjectIds();
  17.             for (int i = 0; i < ids.Length; i++)
  18.             {
  19.                 if (!classes.Contains(ids[i].ObjectClass))
  20.                     e.Remove(i);
  21.             }
  22.         }
  23.     }

Using example:
Code - C#: [Select]
  1. PromptSelectionResult psr = ed.SelectByClass(typeof(Circle), typeof(Line));

VB
Code - vb.net: [Select]
  1.     Module SelectionExtensions
  2.  
  3.         Dim classes As List(Of RXClass)
  4.  
  5.         <System.Runtime.CompilerServices.Extension()> _
  6.         Public Function SelectByClass(ed As Editor, ParamArray types As Type()) As PromptSelectionResult
  7.             classes = types.Select(Function(t) RXClass.GetClass(t)).ToList()
  8.             AddHandler ed.SelectionAdded, AddressOf OnSelectionAdded
  9.             Dim psr As PromptSelectionResult = ed.GetSelection
  10.             RemoveHandler ed.SelectionAdded, AddressOf OnSelectionAdded
  11.             Return psr
  12.         End Function
  13.  
  14.         Private Sub OnSelectionAdded(sender As Object, e As SelectionAddedEventArgs)
  15.             Dim ids As ObjectId() = e.AddedObjects.GetObjectIds()
  16.             For i As Integer = 0 To ids.Length - 1
  17.                 If Not classes.Contains(ids(i).ObjectClass) Then
  18.                     e.Remove(i)
  19.                 End If
  20.             Next
  21.         End Sub
  22.  
  23.     End Module

Using example:
Code - vb.net: [Select]
  1. Dim psr As PromptSelectionResult = ed.SelectByClass(GetType(Circle), GetType(Line))
Speaking English as a French Frog

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #10 on: October 02, 2012, 02:58:02 PM »
Take the 'meat' out of your CommandMethod and make it a separate Method... Then, presumably, either the CommandMethod, or Event Handler could call the newly separated Method, supplying a valid selection set as a parameter, etc..

Maybe I am just blind but I don't see how to make that work.  If i put the method inside of the event handler, how will it know that my command is being ran?  I really only want the event handler to run when my command is in progress  As my overall project increases in size I will need the event handler to filter out several different types of objects depending on the command in progress.  For example, one command will select a mvpart that is of type VAV_Box, and another command will select a mvpart that is of type Boiler.  I can use the dxf name filter to filter out everything but the mvparts but I will need the event handler to filter out vav_boxes OR boilers depending on the command that is in progress.  The amount of different items that the event handler will need to filter is unknown at this time.  Can i create different event handlers to handle this and start up the event handler at the beginning of my command and then turn it off at the end?  If I can do this then it seems pretty straight forward from here but will the handler still fire on a selection in progress when the event handler is started?  This would be the case when a selection was made before the command was started. Does this make sense?  It seems like I have two different events that needs each other in order to work correctly hence my confusion.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #11 on: October 02, 2012, 03:00:31 PM »
Gile,

Could I use the same method to filter based on another value other than type.  Say for instance Classifications, or anything for that matter?
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Filtering a selection set by class?
« Reply #12 on: October 02, 2012, 03:08:19 PM »
I do not know anything about Classifications, but you certainly can with changing the arguments type in the SelectByClass() method and the if statement (filtering) in the event handler.
Speaking English as a French Frog

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #13 on: October 02, 2012, 03:26:45 PM »
Classifications are used in Autocad Architecture and Autocad MEP.  They might be used in other programs but I am not sure.  I am still investigating how to programmatically set a classification or even get a classification.  I currently do not know how to do this using .net but I know that it can be done.  I just need to investigate it and ask the right people how they did it in the past.  There is precious little documentation for Autocad Architecture or Autocad MEP and finding answers can sometimes be difficult.  But once I figure out how to get/set classifications then I should be able to pass the classification as you have done with types, and then just check for the right classification within the if statement of the event handler.

hmmm...  off to start a new post on how to get/set classifications.   :lmao:   
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

BlackBox

  • King Gator
  • Posts: 3770
Re: Filtering a selection set by class?
« Reply #14 on: October 02, 2012, 04:23:52 PM »
By 'classifications' do you mean entity types (DXF 0), such as "AECB_DUCTFITTING", and "AECB_DUCT"?
« Last Edit: October 03, 2012, 12:00:03 AM by RenderMan »
"How we think determines what we do, and what we do determines what we get."