Hi All,
Do we have any way to sum attribute value (integer) of many blocks fast?.
Thanks,
Solved! Go to Solution.
Solved by ditran7577. Go to Solution.
Solved by Hallex. Go to Solution.
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.
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,
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
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,
I don't know why,
It's working good on my A2010 Net.Framework 3.5
I use Autocad 2012 and VS2010. Please see attachment.
Thanks,
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
Can't find what you're looking for? Ask the community or share your knowledge.