Author Topic: Filtering a selection set by class?  (Read 12899 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: 4096
  • 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: 4096
  • 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: 4096
  • 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."

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #15 on: October 02, 2012, 05:49:14 PM »
Renderman....no....classifications are not considered types.  Inside of Autocad MEP you can assign classifications to any type of object.  Consider the PipeFitting Classification List inside of Autocad MEP.  It consists of Pipe, Coupling, Elbow, Takeoff, Cross, Transition, Tee, and Connector.  One of those classifications is assigned to every pipe fitting.  You can then filter a AEC schedule to only schedule a fitting based on its classification.  MEP has the ability to create ANY classification list with an seemingly unlimited amount of items in the list.  I have created a list for OMNI Classifications with over 8000 items in the list.

The same theory applies to every AEC object type.  What I am attempting to do is to be able to select a certain type of MvPart.  For our purpose today lets say VAV Boxes.  I would like to create a filter that only selects VAV Boxes.  From my previous code I know that I can use DXF Names to filter out everything but Mvparts.  I now need to filter the mvparts to only get VAV Boxes.  To do this I need to look at the MvPart Type Classification List and only select MvParts that have a value of VAV Box.

What you have shown will only filter the MvPart.  Not the classifications. 

There are several posts on the AEC Developer Blog about classifications and .NET

Here a couple:

http://adndevblog.typepad.com/aec/2012/07/recursively-listing-classification-definitions.html
http://adndevblog.typepad.com/aec/2012/07/how-to-set-a-classification-in-a-property-set-definition.html

Those two posts show how to print out the classifications in a drawing and how to create a property set based on a classification.
And here is a link to the help file explaining classifications

http://exchange.autodesk.com/autocadmep/enu/online-help/search#WScedd0d2069f88934137c60dfa2566d240-7fae.htm

Hopefully that helps people to understand a little better on what a classification actually is in Autocad MEP and Autocad Architecture.

Here is a link to a post that has some code concerning classifications.  I need to study this to find out how to check if my entity has the correct classification attached to it.

http://www.theswamp.org/index.php?topic=38110.msg433644#msg433644


And lastly I am hoping that Jeff pops into this thread as he has had some experience programming Autocad MEP and has dealt with classifications in some way.




Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Filtering a selection set by class?
« Reply #16 on: October 02, 2012, 05:56:45 PM »
I remeber dooing some things with classifications in the past but since they did not update the horrible documentation if you want to call it that as they deployed 2010 crap docs with 2011 & 2012 I gave up but I will see if I can dig up.
 
 
 

BlackBox

  • King Gator
  • Posts: 3770
Re: Filtering a selection set by class?
« Reply #17 on: October 02, 2012, 05:57:35 PM »
Many thanks for clarifying, Keith... I'll dig through those links when time permits.
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Filtering a selection set by class?
« Reply #18 on: October 02, 2012, 06:00:37 PM »
From here
http://www.theswamp.org/index.php?topic=38110.msg433644#msg433644
 
might be something you can use
 
Code - Visual Basic: [Select]
  1.  
  2.      <CommandMethod("GetClassificationWithDefinition")> _
  3.     Public Sub GetClassificationWithDefinition()
  4.         Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  5.         Dim db As Database = doc.Database
  6.         Dim ed As Editor = doc.Editor
  7.         Dim classficationDefId As ObjectId
  8.         Using trx As Transaction = db.TransactionManager.StartTransaction()
  9.             Dim classDefDictionary As New DictionaryClassificationDefinition(db)
  10.             Dim objectIds As Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection = classDefDictionary.Records
  11.             For Each objId As ObjectId In objectIds
  12.                 Dim classDef As ClassificationDefinition = trx.GetObject(objId, OpenMode.ForRead)
  13.                 If classDef.Name = "Category" Then
  14.                     classficationDefId = classDef.ObjectId
  15.                     Exit For
  16.                 End If
  17.             Next
  18.  
  19.             Dim mdlSpace As BlockTableRecord = SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForRead)
  20.             For Each objId As ObjectId In mdlSpace
  21.                 If objId.ObjectClass.Name = "AecDbSpace" Then
  22.                     Dim spce As ArchDbSrvcs.Space = trx.GetObject(objId, OpenMode.ForRead)
  23.                     Dim cls As Classification = trx.GetObject(ClassificationDefinition.GetClassification(spce, classficationDefId), OpenMode.ForRead)
  24.                     ed.WriteMessage(String.Format("{0}This Classification is: {1} ", vbCrLf, cls.Name))
  25.                 End If
  26.             Next
  27.  
  28.             trx.Commit()
  29.         End Using
  30.     End Sub
  31.  

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #19 on: October 02, 2012, 06:25:35 PM »
I just finished looking at that post and your code when you posted it in this thread.   ;D

I am pretty sure that your code inserted into Gile's extension method will work for me.  I know the type of object (AECB_MvPart), the ClassificationDefinition (MvPart Type), and the classification (VAV Box).  Using these three pieces of information I should be able to plug them into Gile's code and create a handy new filter for myself.
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 #20 on: October 03, 2012, 01:22:27 AM »
Here is the final code that I came up with to get a selection set of mvparts of a certain classification.  I went with the method of filtering by DXF Name, and then iterating over the selection set and removing items that were not of the classification that I wanted.
Code - Visual Basic: [Select]
  1.     <Autodesk.AutoCAD.Runtime.CommandMethod("PropertySetTools", "MvPartPickFirst", CommandFlags.Modal + CommandFlags.UsePickSet)> _
  2.     Public Sub Command_MvPartPickFirst()
  3.  
  4.         Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  5.         Dim ed As Editor = doc.Editor
  6.         Dim db As Database = doc.Database
  7.         Dim ClassificationDefId As ObjectId
  8.  
  9.         Using Tr As Transaction = db.TransactionManager.StartTransaction
  10.  
  11.  
  12.             Dim ClassDefDictionary As New DictionaryClassificationDefinition(db)
  13.             Dim ObjectIds As ObjectIdCollection = ClassDefDictionary.Records
  14.             For Each ObjId As ObjectId In ObjectIds
  15.                 Dim classdef As ClassificationDefinition = Tr.GetObject(ObjId, OpenMode.ForRead)
  16.                 If classdef.Name = "MvPart Type" Then
  17.                     ClassificationDefId = classdef.ObjectId
  18.                 End If
  19.             Next
  20.  
  21.             Dim filter As New SelectionFilter(New TypedValue() {New TypedValue(DxfCode.Start, "AECB_MvPart")})
  22.  
  23.             'Create a Prompt Selection Option
  24.            Dim pso As New PromptSelectionOptions
  25.  
  26.             'Create a message to display if no fittings are picked before the command is ran
  27.            pso.MessageForAdding = vbLf + "Select VAV Boxes: "
  28.  
  29.             'Get the fittings from the pickfirst selection or from the message
  30.            Dim result As PromptSelectionResult = ed.GetSelection(pso, filter)
  31.  
  32.             Dim ObjIdColl As ObjectIdCollection = New ObjectIdCollection()
  33.  
  34.             'filter the items by classification
  35.            If result.Status = PromptStatus.OK Then
  36.                 ObjIdColl = New ObjectIdCollection(result.Value.GetObjectIds())
  37.                 For i As Integer = 0 To result.Value.Count - 1
  38.                     Dim VavBox As MultiViewPart = Tr.GetObject(result.Value(i).ObjectId, OpenMode.ForRead)
  39.                     Dim cls As Classification = Tr.GetObject(ClassificationDefinition.GetClassification(VavBox, ClassificationDefId), OpenMode.ForRead)
  40.                     If Not (cls.Name.ToString = "VAV_Box") Then
  41.                         ObjIdColl.RemoveAt(i)
  42.                     End If
  43.                 Next
  44.                 ed.WriteMessage(String.Format(vbCrLf + "{0} MvParts selected.", ObjIdColl.Count.ToString()))
  45.             End If
  46.         End Using
  47.     End Sub
  48.  

Next step is to impliment Gile's extension method so the objects that I remove do not actually get selected.  Thank you to everyone that helped out with suggestions and code.  And if you see anything that is blatantly wrong and needs corrected or just something to improve the code, please let me know.
« Last Edit: April 28, 2015, 12:26:16 PM by Keith Brown »
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

TheMaster

  • Guest
Re: Filtering a selection set by class?
« Reply #21 on: October 05, 2012, 05:42:09 AM »
Here is the final code that I came up with to get a selection set of mvparts of a certain classification.  I went with the method of filtering by DXF Name, and then iterating over the selection set and removing items that were not of the classification that I wanted.
Code: [Select]
    <Autodesk.AutoCAD.Runtime.CommandMethod("PropertySetTools", "MvPartPickFirst", CommandFlags.Modal + CommandFlags.UsePickSet)> _
    Public Sub Command_MvPartPickFirst()

        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        Dim db As Database = doc.Database
        Dim ClassificationDefId As ObjectId

        Using Tr As Transaction = db.TransactionManager.StartTransaction


            Dim ClassDefDictionary As New DictionaryClassificationDefinition(db)
            Dim ObjectIds As ObjectIdCollection = ClassDefDictionary.Records
            For Each ObjId As ObjectId In ObjectIds
                Dim classdef As ClassificationDefinition = Tr.GetObject(ObjId, OpenMode.ForRead)
                If classdef.Name = "MvPart Type" Then
                    ClassificationDefId = classdef.ObjectId
                End If
            Next

            Dim filter As New SelectionFilter(New TypedValue() {New TypedValue(DxfCode.Start, "AECB_MvPart")})

            '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 VAV Boxes: "

            'Get the fittings from the pickfirst selection or from the message
            Dim result As PromptSelectionResult = ed.GetSelection(pso, filter)

            Dim ObjIdColl As ObjectIdCollection = New ObjectIdCollection()

            'filter the items by classification
            If result.Status = PromptStatus.OK Then
                ObjIdColl = New ObjectIdCollection(result.Value.GetObjectIds())
                For i As Integer = 0 To result.Value.Count - 1
                    Dim VavBox As MultiViewPart = Tr.GetObject(result.Value(i).ObjectId, OpenMode.ForRead)
                    Dim cls As Classification = Tr.GetObject(ClassificationDefinition.GetClassification(VavBox, ClassificationDefId), OpenMode.ForRead)
                    If Not (cls.Name.ToString = "VAV_Box") Then
                        ObjIdColl.RemoveAt(i)
                    End If
                Next
                ed.WriteMessage(String.Format(vbCrLf + "{0} MvParts selected.", ObjIdColl.Count.ToString()))
            End If
        End Using
    End Sub

Next step is to impliment Gile's extension method so the objects that I remove do not actually get selected.  Thank you to everyone that helped out with suggestions and code.  And if you see anything that is blatantly wrong and needs corrected or just something to improve the code, please let me know.

A few comments:

1.  Your first For Each loop looks like it continues to run even after finding the element you're looking for.

2.  Calling RemoveAt() on any dynamic container or collection object iteratively in a loop is wasteful.

ObjectIdCollection is actually an array (in native code) that can dynamically grow in size without much pain. However, the same cannot be said for dynamically shrinking in size. When you remove an element, all the elements beyond the one removed must be shifted (make sense?).  It would be far more efficient to just build a new collection containing the qualifying items.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Filtering a selection set by class?
« Reply #22 on: October 08, 2012, 07:33:42 AM »
A few comments:

1.  Your first For Each loop looks like it continues to run even after finding the element you're looking for.

2.  Calling RemoveAt() on any dynamic container or collection object iteratively in a loop is wasteful.

ObjectIdCollection is actually an array (in native code) that can dynamically grow in size without much pain. However, the same cannot be said for dynamically shrinking in size. When you remove an element, all the elements beyond the one removed must be shifted (make sense?).  It would be far more efficient to just build a new collection containing the qualifying items.

Item #1 Makes alot of sense.  I missed that in my excitement of finally getting the code to work.  Item #2 also makes sense.  I initially had alot of problems with this section as I was using result.value.count as my loop counter but I was programmatically removing elements from the loop each time through.  When the loop came around again, the count was different it was reporting incorrect values.  My solution was to create a new collection and remove the elements from the new selection instead.  Of course your idea to create a new selection and ADD elements as they are found is much more efficient and easier to read.  When I am finished looping through the entire collection I would just set Result to equal the new collection?

Thank you for the advice and constructive criticism.  It is actually very educational and well received.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013