.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Sum ATT value of blockreference

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
ditran7577
746 Views, 8 Replies

Sum ATT value of blockreference

Hi All,

 

Do we have any way to sum attribute value (integer) of many blocks fast?. 

 

Thanks,

8 REPLIES 8
Message 2 of 9
norman.yuan
in reply to: ditran7577

Would you care to clarify what exactly you need to know?

 

Is it that you know a few ways of doing it but want to know which is fast or faster? Or you you just want to know whether it can be done (of course it can)? How much do you know .NET API programming? Or by "fast", you actually meant for quick, simple code, rather than running speed.

 

Yes, there is way to sum up value of ATT of one or more blocks. Yes, it could be fast or slow, deponding on the drawing size, block counts to be searched...It could be a fraction of seconds to who knows how long.

 

Basically, you would have code to identify one or more blocks by either asking user to select on drawing, or by searching drawing with certain criteria (block name, attribute tag...), then in a transaction, you open each block references, loop through its attribute collection and convert the targeting attribute value to a number and sum it up.

Message 3 of 9
ditran7577
in reply to: norman.yuan

Thank for reply. 

I have a large quantity of blocks. Each of block has 4 tag (Name-Detail-Description-Quantity). This code I  get blocks:

Public Sub SUM_AttBlk()
        Dim acName As String = ""
        Dim acQty As Integer=0
        Dim acDet As String = ""
        Dim acDes As String = ""

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tr As Transaction = db.TransactionManager.StartTransaction()
        Try
            Dim filList AsTypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")}
            Dim filter As New SelectionFilter(filList)
            Dim opts As New PromptSelectionOptions()
            opts.MessageForAdding = "Select block references: "
            Dim res As PromptSelectionResult = ed.GetSelection(opts, filter)
            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim selSet As SelectionSet = res.Value

            Dim idArray As ObjectId() = selSet.GetObjectIds() 

            For Each blkId As ObjectId In idArray

                Dim blkRef As BlockReference = tr.GetObject(blkId, OpenMode.ForRead)

                Dim attCol AsAttributeCollection = blkRef.AttributeCollection

                For Each attId As ObjectId In attCol
                    Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead),AttributeReference)
                    If (attRef.Tag = "NAME") Then
                        acName = attRef.TextString
                    ElseIf (attRef.Tag = "DETAIL") Then
                        acDet = attRef.TextString
                    ElseIf (attRef.Tag = "DES") Then
                        acDes = attRef.TextString
                    ElseIf (attRef.Tag = "QTY") Then
                        acQty = Convert.ToInt32(attRef.TextString)
                    End If
                Next
            Next
            tr.Commit()
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            MsgBox(("Exception: " + ex.Message + ex.ErrorStatus))
        Finally
            tr.Dispose()
        End Try
    End Sub

 

I want to sum them base on name and detail. If block has same name and detail we sum quantity.

Finally, display result on form. if blocks have same name and detail displayed uniquely.

 

Thanks,

Message 4 of 9
Hallex
in reply to: ditran7577

Try this pseudo-code snip

''gather your block attribute values into ArraylList
 Dim list As ArrayList = New ArrayList()
        For Each attId As ObjectId In attCol
                    Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead),AttributeReference)
                    If (attRef.Tag = "NAME") Then
                        acName = attRef.TextString
                    ElseIf (attRef.Tag = "DETAIL") Then
                        acDet = attRef.TextString
                    ElseIf (attRef.Tag = "DES") Then
                        acDes = attRef.TextString
                    ElseIf (attRef.Tag = "QTY") Then
                        acQty = Convert.ToInt32(attRef.TextString)
                    End If
                Next
list.Add(New Object() {acName, acDet, acDes,  acQty})
            Next
'then aplly Linq-based expression to do your job, e.g.:
Dim grop_query = (From el In list _
                   Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) _
                   Select dt = key, total = qty).ToList()
'just to display result of query:
            Dim sb As New StringBuilder
            For Each grp In grop_query
                Dim keys() As String = grp.dt.Split(","c)
                'Console.WriteLine(keys(0) + vbTab + keys(1)) 'ok
                sb.AppendLine(keys(0) & vbTab & keys(1) & vbTab & grp.total)' description is ommited, add them if you need
            Next
            MsgBox("Block info:" & vbLf & sb.ToString)
' You have instead to pull this data in the table data list (of string) or in arralist

 Not tested, just from the top of my head Smiley Happy

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 5 of 9
ditran7577
in reply to: ditran7577

Hi Hallex,

There is an err in this line:

Dim grop_query = (From el In List Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) Select dt = key, total = qty).ToList()

 

Err Description:

"Too few type arguments to 'System.Collections.Generic.List(of T)

 

What happen?

 

Thanks,

 

 

Message 6 of 9
Hallex
in reply to: ditran7577

I don't know why,

It's working good on my A2010 Net.Framework 3.5

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 7 of 9
ditran7577
in reply to: Hallex

I use Autocad 2012 and VS2010. Please see attachment.

Thanks,

Message 8 of 9
Hallex
in reply to: ditran7577

Here is complete working code

I've used blocks "Panel" for test

Change them to your suit:

        <CommandMethod("summa", CommandFlags.UsePickSet)> _
        Public Shared Sub SUM_AttBlk()
            Dim acName As String = ""
            Dim acQty As Integer = 0
            Dim acDet As String = ""
            Dim acDes As String = ""

            Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
            Dim db As Database = HostApplicationServices.WorkingDatabase
            Dim tr As Transaction = db.TransactionManager.StartTransaction()
            Try
                Dim filList As TypedValue() = New TypedValue(1) {New TypedValue(0, "INSERT"), New TypedValue(2, "Panel")}
                Dim filter As New SelectionFilter(filList)
                Dim opts As New PromptSelectionOptions()
                opts.MessageForAdding = "Select block references: "
                Dim res As PromptSelectionResult = ed.GetSelection(opts, filter)
                If res.Status <> PromptStatus.OK Then
                    Return
                End If

                Dim selSet As SelectionSet = res.Value

                ' Dim blockData As List(Of Object()) = New List(Of Object())
                Dim blockData As New ArrayList
                Dim idArray As ObjectId() = selSet.GetObjectIds()

                For Each blkId As ObjectId In idArray

                    Dim blkRef As BlockReference = tr.GetObject(blkId, OpenMode.ForRead)

                    Dim attCol As AttributeCollection = blkRef.AttributeCollection

                    For Each attId As ObjectId In attCol
                        Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference)
                        If (attRef.Tag = "NAME") Then
                            acName = attRef.TextString
                        ElseIf (attRef.Tag = "DETAIL") Then
                            acDet = attRef.TextString
                        ElseIf (attRef.Tag = "DES") Then
                            acDes = attRef.TextString
                        ElseIf (attRef.Tag = "QTY") Then
                            acQty = Convert.ToInt32(attRef.TextString)
                        End If
                        Dim tmpData() As Object = New Object(3) {}
                        tmpData(0) = acName
                        tmpData(1) = acDet
                        tmpData(2) = acDes
                        tmpData(3) = acQty

                    Next
                    blockData.Add(New Object() {acName, acDet, acDes, acQty})
                Next
                Dim grop_query = (From el In blockData _
               Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) _
               Select dt = key, total = qty).ToList()
                Dim sb As New StringBuilder
                For Each grp In grop_query
                    Dim keys() As String = grp.dt.Split(","c)
                    'Console.WriteLine(keys(0) + vbTab + keys(1)) 'ok
                    sb.AppendLine(keys(0) & vbTab & keys(1) & vbTab & grp.total)
                Next
                MsgBox("Block info:" & vbLf & sb.ToString)
           
                tr.Commit()
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                MsgBox("Exception: " + ex.Message + vbLf + ex.ErrorStatus)
                tr.Abort()
            Finally
                tr.Dispose()
            End Try
        End Sub

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 9 of 9
ditran7577
in reply to: Hallex

Hi Hallex,

 

 

How to display acDes value after query?

 

Thanks,

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost