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

0 Members and 1 Guest are viewing this topic.

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: 6144
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: 6144
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