Author Topic: Anonymous Aggravation - Newbie Info/Code Request  (Read 2222 times)

0 Members and 1 Guest are viewing this topic.

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Anonymous Aggravation - Newbie Info/Code Request
« on: October 26, 2011, 10:47:17 AM »
It appears that the copied and/or dynamic blocks (DB's for short) visibility states are not recognized by a block replace routine in a otherwise powerful AutoCAD add-on called ToolPac by www.dotsoft.com.

As a fledgling VB.NET programmer, I would like to find out what would be needed, in the form of general comments or code snippet form, to handle those annoying anonymous blocks (and/or DB's visibility states)?  :x
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

kaefer

  • Guest
Re: Anonymous Aggravation - Newbie Info/Code Request
« Reply #1 on: October 27, 2011, 01:36:26 PM »
It appears that the copied and/or dynamic blocks (DB's for short) visibility states are not recognized by a block replace routine in a otherwise powerful AutoCAD add-on called ToolPac by www.dotsoft.com.

As a fledgling VB.NET programmer, I would like to find out what would be needed, in the form of general comments or code snippet form, to handle those annoying anonymous blocks (and/or DB's visibility states)?  :x

I wouldn't want to ruin Mr. Dotson's business, but if his block replacement tool works how I imagine it to work, there's very little complexity to it except in the very special case of dynamic block references.

Now, if I understand you correctly, you want to preserve the values of your dynamic properties when switching definitions for a given set of block references, otherwise you wouldn't worry about those anonymous blocks. As far as I can ascertain, that's not quite trivial, because we would have to ensure that the property on a reference with the old definition will be supported under the new definition too. It's not sufficient to merely read the dynamic properties, store them in some container, and write them back after changing the definition. An example for this way to copy properties can be found here.

Now we have to read the property descriptors from the BlockTableRecord as well. There may be a better way but this function will do:
Code: [Select]
    Function PropDescDictFromBtr(ByRef btr As BlockTableRecord, ByRef tr As Transaction) _
        As Dictionary(Of String, BlockParameterPropertyDescriptor)
        Dim pddict = New Dictionary(Of String, BlockParameterPropertyDescriptor)
        Dim exdict = CType(tr.GetObject(btr.ExtensionDictionary, OpenMode.ForRead), DBDictionary)
        If exdict.Contains("ACAD_ENHANCEDBLOCK") Then
            Dim eg = CType(tr.GetObject(exdict.GetAt("ACAD_ENHANCEDBLOCK"), OpenMode.ForRead), EvalGraph)
            For Each i In eg.GetAllNodes()
                Dim bp = TryCast(eg.GetNode(CUInt(i), OpenMode.ForRead, tr), BlockParameter)
                If bp <> Nothing Then
                    For Each pd As BlockParameterPropertyDescriptor In bp.PropertyDescription
                        If Not pddict.ContainsKey(pd.PropertyName) Then
                            pddict.Add(pd.PropertyName, pd)
                        End If
                    Next
                End If
            Next
        End If
        Return pddict
    End Function

The command sub loops simply through a SelectionSet and tries to combine those two approaches outlined above:
Code: [Select]
    <CommandMethod("BlockReplace", CommandFlags.UsePickSet)> _
    Public Sub DynPropBlockReplace()
        Dim dm = Application.DocumentManager
        Dim ed = dm.MdiActiveDocument.Editor
        Dim db = dm.MdiActiveDocument.Database

        Dim psr = ed.GetSelection(New SelectionFilter(New TypedValue() {New TypedValue(DxfCode.Start, "INSERT")}))
        If psr.Status <> PromptStatus.OK OrElse psr.Value.Count <= 0 Then Return
        Dim pr = ed.GetString(New PromptStringOptions(Microsoft.VisualBasic.vbCrLf +
                                                      "Enter block name: ") With {.AllowSpaces = True})
        If pr.Status <> PromptStatus.OK OrElse pr.StringResult = "" Then Return
        Using tr = db.TransactionManager.StartTransaction()
            Dim bt = CType(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
            If Not bt.Has(pr.StringResult) Then
                ed.WriteMessage(Microsoft.VisualBasic.vbCrLf +
                                "Block name ""{0}"" not defined ", pr.StringResult)
            Else
                Dim btr = CType(tr.GetObject(bt(pr.StringResult), OpenMode.ForRead), BlockTableRecord)
                If Not btr.IsDynamicBlock Then
                    For Each id In psr.Value.GetObjectIds()
                        CType(tr.GetObject(id, OpenMode.ForWrite), BlockReference).BlockTableRecord = bt(pr.StringResult)
                    Next
                Else
                    Dim pddict = PropDescDictFromBtr(btr, tr)
                    For Each id In psr.Value.GetObjectIds()
                        Dim br = CType(tr.GetObject(id, OpenMode.ForWrite), BlockReference)
                        Dim dict = New Dictionary(Of String, DynamicBlockReferenceProperty)()
                        If br.IsDynamicBlock Then
                            For Each prop As DynamicBlockReferenceProperty In br.DynamicBlockReferencePropertyCollection
                                If Not prop.ReadOnly AndAlso Not dict.ContainsKey(prop.PropertyName) Then
                                    dict.Add(prop.PropertyName, prop)
                                End If
                            Next
                        End If
                        br.BlockTableRecord = bt(pr.StringResult)
                        If br.IsDynamicBlock Then
                            For Each prop As DynamicBlockReferenceProperty In br.DynamicBlockReferencePropertyCollection
                                If Not prop.ReadOnly AndAlso
                                    dict.ContainsKey(prop.PropertyName) AndAlso
                                    prop.PropertyTypeCode = dict(prop.PropertyName).PropertyTypeCode AndAlso
                                    pddict.ContainsKey(prop.PropertyName) AndAlso
                                    prop.PropertyTypeCode = pddict(prop.PropertyName).PropertyType Then
                                    prop.Value = dict(prop.PropertyName).Value
                                End If
                            Next
                        End If
                    Next
                    btr.UpdateAnonymousBlocks()
                End If
            End If
            tr.Commit()
        End Using
    End Sub

Note that you will need a reference to the Autodesk.AutoCAD.Internal.DatabaseServices namespace.

Have fun!

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Re: Anonymous Aggravation - Newbie Info/Code Request
« Reply #2 on: November 02, 2011, 01:25:43 PM »
Yours are very interesting comments and from an apparent seasoned code master (at least in my eyes), too.
I will review and will be back with questions. It may be a while (a few weeks) as I am production/CAD manager/newbie programmer all rolled into one.

Perhaps that is part of the cause for my current bout with obesity. Perhaps not.
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Re: Anonymous Aggravation - Newbie Info/Code Request
« Reply #3 on: November 03, 2011, 11:06:24 AM »
Quote
Note that you will need a reference to the Autodesk.AutoCAD.Internal.DatabaseServices namespace.

On any given AutoCAD (or any other coding project), how do you know how many and which type of namespaces to reference?
Are there any rules of thumb, etc.?
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Anonymous Aggravation - Newbie Info/Code Request
« Reply #4 on: November 03, 2011, 12:07:01 PM »
I start with the core requirements.  As I develop the program flow (code is my end product, not my starting point), I identify the methods and properties needed, and locate the required references for them.  Sometimes when implementing the actual code something doesn't work as planned, requiring additional references and/or not requiring others.  As part of final debugging I go through the references and look for those that are no longer needed - not critical, but that sort of thing bugs me.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}