AutoCAD Architecture Customization
Welcome to Autodesk’s AutoCAD Architecture Customization Forums. Share your knowledge, ask questions, and explore popular AutoCAD Architecture Customization topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

VB.NET - Access to Stylenames

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
helsinki_dave
2253 Views, 8 Replies

VB.NET - Access to Stylenames

Anyone reading this with interest will know that this is a pretty lonely path! ACA and .NET....total size of global audience..maybe three of us Smiley Sad

 

ACA is, of course, a fanatastic tool for urban design - blows the socks off Archicad (GDL anyone?), Revit (building sized projects only thanks!) and Autocad ( no location tool grip ).

 

But, if anyone has a few ideas about working with Styles and Property Sets, then feel free to chip in.

 

Question is, looking at the code below..which is kinda of stripped out from various sources..but shows the key ideas...is this really the way to access data on a propertysetdef? What I want the psetdef name and value on a certain style only...which, as we all know, is trickier than if VBA.

 

So to just get hold of the name of the psetdef, you need to go via ObjectIDCollection to fetch the Psets, then AecPropDB.Propertyset to fetch the the Psetdefs one by one, then use PropertyNameToId put the Property Definition into another variable, then use GetValueandUnitAt to put that variable into an ArrayList, then use a ValueUnitPair to pull that data into another variable, then create another final objectID (Val) which by means of val.GetType, and Val.ToString - I guess you could load those two values onto an array with two dimensions.

 

All I want to do is look in every single AECspace called Building in the drawing and pull off the an ID number from it and the area of the space. Seems all a little convaluted.

 

If anyone has a suggestion, then by all means!

 

 

 

 

Dim pname As String = "Gross_floor_area"

        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tm As AcadDb.TransactionManager = db.TransactionManager

        Dim dbobj As AcadDb.DBObject

        Dim trans As Transaction = tm.StartTransaction()

        Dim bt As BlockTable = tm.GetObject(db.BlockTableId, OpenMode.ForRead, False) 'open up the general block table

        Dim btr As BlockTableRecord = tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead, False) 'get every single object in the modelspace 

        Dim id As ObjectId

        For Each id In btr

            dbobj = tm.GetObject(id, OpenMode.ForRead, False, False)

            'test obj for type

            'Open each entity in turn using its ObjectId - only allows for AEC.database entity objects
            'Dim ent As AecDb.Entity = trans.GetObject(id, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)

            If TypeOf dbobj Is Space Then

                Dim Sspace As Space = tm.GetObject(dbobj.ObjectId, OpenMode.ForRead)

                Dim Sel_Space_Style As SpaceStyle = tm.GetObject(Sspace.StyleId, OpenMode.ForRead)

                Select Case Sel_Space_Style.Name

                    Case "Building"

                        Dim GFA_array As System.Collections.ArrayList = GetValuesFromPropertySetByName("Gross_Floor_Area", dbobj)

                    Case "Block"


                End Select


                Dim values As System.Collections.ArrayList = GetValuesFromPropertySetByName(pname, dbobj) 'using an array list to store the psetdefs that come back from the function
                Dim value_unit As AecPropDb.PropertyValueUnitPair
                For Each value_unit In values
                    ed.WriteMessage(vbCrLf + "Property with name = " + pname + " Entity ObjectId = " + id.ToString())


                    'ed.WriteMessage(vbCrLf + "Unit Type = " + value_unit.UnitType.InternalName + ", IsImperial = " + value_unit.UnitType.IsImperial.ToString() + ", Type = " + value_unit.UnitType.Type.ToString())

                    Dim val As Object = value_unit.Value
                    If Not val Is Nothing Then
                        ed.WriteMessage(vbCrLf + "DataType = " + val.GetType().ToString())
                        ed.WriteMessage(vbCrLf + "Value = " + val.ToString())
                    End If

                Next

            End If

        Next
        trans.Commit()
        trans.Dispose()
    End Sub
#End Region
#End Region
#Region "ImplementationMethods"
#Region "GetValuesFromPropertySetByName"
    ' <summary>
    ' Returns the values (PropertyValueUnitPair) of a property by name on a given object.
    ' </summary>
    ' <param name="pname">The property name to find on the object.</param>
    ' <param name="dbobj">The object to find the property on. </param>
    ' <returns> An array of the values </returns>
    Public Function GetValuesFromPropertySetByName(ByVal pname As String, ByVal dbobj As AcadDb.DBObject) As System.Collections.ArrayList

        Dim setIds As ObjectIdCollection = AecPropDb.PropertyDataServices.GetPropertySets(dbobj) 'use the objectidcollection- **setIds** is the pset collection!!

        Dim values As System.Collections.ArrayList = New System.Collections.ArrayList() 'values is only used to pick up the psetdef name and values then returns it since its a public function

        If setIds.Count = 0 Then
            Return values ' just return the empty collection...since there are no propertysets attached to this aecspace object
        End If

        Dim db As Database = HostApplicationServices.WorkingDatabase 'why are we starting up a transaction just now, I don't know...can't this be done further out?
        Dim tm As AcadDb.TransactionManager = db.TransactionManager
        Dim psId As ObjectId 'use this to pin down the pset with the correct psetdef in it
        For Each psId In setIds 'remember that setIds is the collection of psets

            Dim pset As AecPropDb.PropertySet = tm.GetObject(psId, OpenMode.ForRead, False, False) 'you must open each pset for read as you grab it

            '****bingo - pset if your object, now you can manipulate it***

            Dim pid As Integer 'pid will take the id number only for the psetdef

            Try 'this part hunts for pname in the propertyset - setids at this point is all you need if you just want to hunt for stylenames

                pid = pset.PropertyNameToId(pname) 'propertyname refers to a psetdef no a pset
                values.Add(pset.GetValueAndUnitAt(pid)) 'picks off the GFA and the value of it by integer ie PID. GetValueandUnit is a very special ACA function

                '*********Dim Psetvalue As Integer = pset.PropertySetDefinitionName(pname)

            Catch e As Autodesk.AutoCAD.Runtime.Exception
                ' most likely eKeyNotfound. in other words, the property set did not have the pname in it

            End Try

        Next

        Return values
    End Function

 

 

8 REPLIES 8
Message 2 of 9

Hi,

 

You can try this... DON'T run on a drawing without spaces --> needs further error-trapping

 

 

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.Aec.Arch.DatabaseServices
Imports DBTransMan = Autodesk.AutoCAD.DatabaseServices.TransactionManager

' This line is not mandatory, but improves loading performances

Namespace AutoCAD_Space

    ' This class is instantiated by AutoCAD once and kept alive for the 
    ' duration of the session. If you don't do any one time initialization 
    ' then you should remove this class.
    Public Class MyPlugin
        Implements IExtensionApplication

        Public Sub Initialize() Implements IExtensionApplication.Initialize
            Dim ed As Autodesk.AutoCAD.EditorInput.Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor()
            ed.WriteMessage("FindSpace loaded...")
        End Sub

        Public Sub Terminate() Implements IExtensionApplication.Terminate
            Console.WriteLine("Cleaning up...")
        End Sub
        <CommandMethod("FindSpace")> _
        Public Sub FSpace()
            Dim db As Database = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database
            Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
            Dim tm As DBTransMan = db.TransactionManager
            Dim ta As Transaction = tm.StartTransaction

            Dim res As PromptSelectionResult = ed.SelectAll
            Dim SS As SelectionSet = res.Value

            If SS.Count = 0 Then
                ed.WriteMessage("No object's found")
                GoTo ending
            End If

            Dim idarray() As Autodesk.AutoCAD.DatabaseServices.ObjectId = SS.GetObjectIds()
            Dim id As Autodesk.AutoCAD.DatabaseServices.ObjectId
            Dim SpaceObject As Autodesk.Aec.Arch.DatabaseServices.Space = Nothing
            Dim SpaceObjectStyle As SpaceStyle = Nothing

            For Each id In idarray
                Dim ent As Autodesk.AutoCAD.DatabaseServices.Entity = tm.GetObject(id, OpenMode.ForRead, True)
                If ent.ToString = "Autodesk.Aec.Arch.DatabaseServices.Space" Then
                    SpaceObject = ent
                    SpaceObjectStyle = tm.GetObject(SpaceObject.StyleId, OpenMode.ForRead, True)
                    If SpaceObjectStyle.Name.ToString = "Building" Then
                        ed.WriteMessage("Spacename: " & SpaceObject.Name.ToString & " SpaceStyleName: " & SpaceObjectStyle.Name.ToString & " ObjectID: " & id.ToString & " Area: " & SpaceObject.Area.ToString & " Volume: " & SpaceObject.BaseVolume.ToString)
                    Else
                        ed.WriteMessage("No spaces found with StyleName: 'Building', but the folowing spaces were found:")
                        ed.WriteMessage("Spacename: " & SpaceObject.Name.ToString & " SpaceStyleName: " & SpaceObjectStyle.Name.ToString & " ObjectID: " & id.ToString & " Area: " & SpaceObject.Area.ToString & " Volume: " & SpaceObject.BaseVolume.ToString)
                    End If
                Else
                    ed.WriteMessage("No Spaces Found!")
                End If
            Next id
            ta.Dispose()
ending:

        End Sub
    End Class

End Namespace

 Maybe this help's...

 

Regards,

 

Wouter

 

Message 3 of 9

..and the clouds did part and the sun did shine!!

 

SpaceObjectStyle = tm.GetObject(SpaceObject.StyleId, OpenMode.ForRead, True)

 

...quick, to the point, does the job nicely.

 

I also really like the way you just grab the biggest net in the belly of the boat , and blast the drawing with ed.SelectAll

 

Why not, rather than cycling through every ObjectId in the Block Table Record.

 

Thanks a bundle for taking the time to write out an solution!

 

With the Building Space picked out, reading off the property sets on it is totally different from VBA. Thanks to a couple of sesssions on Autodesk University, there is some code floating about on how Autodesk envisage that this is done.

 

The following code is really interesting in the way it builds collections. I know we're warned about these in the few existing help files on the net, but things such as ObjectIdCollection are like a shot out of the blue.

 

I notice in your code you collect Ids in something called idarray()

 

Have you figured out why ACA introduces ObejctIdCollection, then, for example, in the code below, and uses this to collect Id's?

 

I have a feeling that what you guys (ie experienced pro's) don't get bogged down with this kind of question in your mind and charge on with what you know works - collecting objects in a fail safe way, and not trying too hard to re-learn new classes etc until you hit a brick wall.

 

#Region "GetValuesFromPropertySetByName"
    ' <summary>
    ' Returns the values (PropertyValueUnitPair) of a property by name on a given object.
    ' </summary>
    ' <param name="pname">The property name to find on the object.</param>
    ' <param name="dbobj">The object to find the property on. </param>
    ' <returns> An array of the values </returns>
    Public Function GetValuesFromPropertySetByName(ByVal pname As String, ByVal dbobj As AcadDb.DBObject) As System.Collections.ArrayList

        Dim setIds As ObjectIdCollection = AecPropDb.PropertyDataServices.GetPropertySets(dbobj)

        Dim values As System.Collections.ArrayList = New System.Collections.ArrayList()

        If setIds.Count = 0 Then
            Return values ' just return emtpy collection...
        End If


        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tm As AcadDb.TransactionManager = db.TransactionManager
        Dim psId As ObjectId
        For Each psId In setIds
            Dim pset As AecPropDb.PropertySet = tm.GetObject(psId, OpenMode.ForRead, False, False) 'As AecPropDb.PropertySet
            Dim pid As Integer
            Try
                pid = pset.PropertyNameToId(pname)
                values.Add(pset.GetValueAndUnitAt(pid))
            Catch e As Autodesk.AutoCAD.Runtime.Exception
                ' most likely eKeyNotfound.

            End Try

        Next

        Return values
    End Function
#End Region

 

Message 4 of 9

Glad that my awnser helped you out.. and thank you for seeing me as a pro Smiley Wink, but i have to disappoint you.. im am not a .NET pro... just a enthausiast that has some experience in programming..

 

Happy coding Smiley Happy

 

Regards,

 

Wouter

Message 5 of 9
Jeffrey_H
in reply to: wouterbleumink

Just to throw this in

 

If you take look at this link

http://www.theswamp.org/index.php?topic=37089.0

 

Using Editor.SelectAll even with a filter has to itterate through all the objects.

The fastest method seems to be itterate yourself and by looking at the link you can see other options, but the basic idea is to check a property of the ObjectId to see if it is the type object you want then open the object.

That way you skip a bunch useless and sometimes expensive cycles opening and closing objects you do not need to.

 

Here this uses ObjectId.ObjectClass.Name which ObjectClass gets the RxClass of the object and checks to see if the name is "AecDbSpace" first then opens it.

Then it prints Space Name, Area, and Style Name It uses

 

using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using AecDbSrvcs = Autodesk.Aec.DatabaseServices;
using ArchDbSrvcs = Autodesk.Aec.Arch.DatabaseServices;
[assemblyCommandClass(typeof(MEPExamplesCS.MyCommands))]

namespace MEPExamplesCS
{

    public class MyCommands
    {

        [CommandMethod("GetSpaceDataCS")]
        public void GetSpaceDataCS() 
        {

            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;       

            using (Transaction trx = db.TransactionManager.StartTransaction())
            {

                BlockTableRecord mdlSpace = SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForRead) as BlockTableRecord;
                
                foreach (ObjectId objId in mdlSpace)
                {

                    if (objId.ObjectClass.Name == "AecDbSpace")
                    {
                        ArchDbSrvcs.Space spce = (ArchDbSrvcs.Space)trx.GetObject(objId, OpenMode.ForRead);
                        ArchDbSrvcs.SpaceStyle spceStyle = (ArchDbSrvcs.SpaceStyle)trx.GetObject(spce.StyleId, OpenMode.ForRead);
                        ed.WriteMessage(String.Format("\nThis Space Name: {0} Area: {1} and is on Stlye: {2}",
                                                      spce.Name, spce.Area, spceStyle.Name));
                    }

                }
            
            }

            
        }

    
    }

}

 

 

 

You can also find your answers @ TheSwamp
Message 6 of 9
Jeffrey_H
in reply to: Jeffrey_H

Sorry here is VB

 

I am more familiar with the Vanallia Acad API, and although have used MEP I have avoided learning its API due to lack of documentation. It would be nice just to get a sentence about a each class and it's properties and methods. I decided to start learning it so I will see you guys around.

 

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports AecDbSrvcs = Autodesk.Aec.DatabaseServices
Imports ArchDbSrvcs = Autodesk.Aec.Arch.DatabaseServices
<AssemblyCommandClass(GetType(MEPExamplesVB.MyCommands))> 

Namespace MEPExamplesVB

    Public Class MyCommands

      

        <CommandMethod("GetSpaceDataVB")> _
        Public Sub GetSpaceDataVB()

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

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim mdlSpace As BlockTableRecord = SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForRead)

                For Each objId As ObjectId In mdlSpace

                    If objId.ObjectClass.Name = "AecDbSpace" Then
                        Dim spce As ArchDbSrvcs.Space = trx.GetObject(objId, OpenMode.ForRead)
                        Dim spceStyle As ArchDbSrvcs.SpaceStyle = trx.GetObject(spce.StyleId, OpenMode.ForRead)
                        ed.WriteMessage(String.Format("{0}This Space Name: {1} Area: {2} and is on Stlye: {3}", _
                                                      vbCrLf, spce.Name, spce.Area, spceStyle.Name))
                    End If
                Next
            End Using

        End Sub

   
    End Class

End Namespace

 

 

You can also find your answers @ TheSwamp
Message 7 of 9

Thanks Jeff for the 'cycling through' routine - I haven't come across this line before:

 

Dim mdlSpace As BlockTableRecord = SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForRead)

 

It's really interesting that you use SymbolUtilityServices.GetBlockModelSpaceId. How on earth did you crack that one!

 

The different techniques of getting hold of ObjectId's really blows my mind. It's a long way from the VBA ThisDrawing.Modelspace days!

 

You're bang on that there precious little help on ACA and AMEP. We really are in 'burning platform' territory - but we can't do in Revit or ArchiCAD what we are doing in here with property sets and location grips in a city sized ACA project.

 

I'm finding it really hard to aggregate data arriving in an Arrayllist as a PropertiesValueUnitPair but I'll take that question over to the Swamp.

 

Thanks again!

Message 8 of 9

To help migrating your software from VBA to .NET you can use the following to be able to use the ThisDrawing method:

 

 

Public Shared ReadOnly Property ThisDrawing() As AcadDocument
            Get
                Return Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.AcadDocument
            End Get
        End Property

 Hope this helps..

 

Regards

 

Message 9 of 9
Jeffrey_H
in reply to: helsinki_dave


@helsinki_dave wrote:

Thanks Jeff for the 'cycling through' routine - I haven't come across this line before:

 

Dim mdlSpace As BlockTableRecord = SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForRead)

 

It's really interesting that you use SymbolUtilityServices.GetBlockModelSpaceId. How on earth did you crack that one!

 


 

Not a whole lot cracking to it or actually none.

That is the thing when it comes to the API, it is just finding the methods and properties you need.

That one just saves a line.

I either just stumbled across it in arxdoc.chm or I think I picked it up from Thorsten(kaefer) at the Swamp

 

You can also find your answers @ TheSwamp

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost