Author Topic: Problem with function to add annotative blocks  (Read 8885 times)

0 Members and 1 Guest are viewing this topic.

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Problem with function to add annotative blocks
« on: August 13, 2010, 02:43:59 PM »
I try to add blocks into AutoCAD with attributes and I am almost there! But it does weird things with annotative blocks.

The function is this:

Code: [Select]
  Public Shared Function hzInsertBlock(ByVal pntInsert As Geometry.Point3d,
                                       ByVal strBlockName As String,
                                       ByVal dScale As Double,
                                       ByVal strLayerName As String) As DatabaseServices.ObjectId

    ' TODO: Check block if is dynamic and do other things

    Dim retVal As DatabaseServices.ObjectId = Nothing

    Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
    ' Get the current document editor
    Dim ed As Editor = doc.Editor
    ' Get the current database
    Using db As Database = HostApplicationServices.WorkingDatabase
      ' Get the current transaction
      Dim tr As Transaction = db.TransactionManager.StartTransaction
      ' using transaction
      Using tr
        Try
          ' Open current space for write
          Dim myBT As BlockTable = doc.Database.BlockTableId.GetObject(OpenMode.ForRead)
          Dim myBTR As BlockTableRecord = CType(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

          ' Annotation Scales
          Dim ocm As ObjectContextManager = db.ObjectContextManager
          Dim occ As ObjectContextCollection = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES")

          ' Insert Block
          Dim myBlockDef As BlockTableRecord = myBT(strBlockName).GetObject(OpenMode.ForRead)
          Dim myBlockRef As New DatabaseServices.BlockReference(pntInsert, myBT(strBlockName))

          Dim obj As ObjectId = myBTR.AppendEntity(myBlockRef)
          tr.AddNewlyCreatedDBObject(myBlockRef, True)

          ' Set Attribute Value
          Dim myAttColl As DatabaseServices.AttributeCollection
          Dim myEnt As DatabaseServices.Entity
          Dim myBTREnum As BlockTableRecordEnumerator
          myAttColl = myBlockRef.AttributeCollection
          myBTREnum = myBlockDef.GetEnumerator
          While myBTREnum.MoveNext
            myEnt = myBTREnum.Current.GetObject(OpenMode.ForWrite)
            If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
              Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
              Dim myAttRef As New DatabaseServices.AttributeReference
              myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
              myAttColl.AppendAttribute(myAttRef)
              tr.AddNewlyCreatedDBObject(myAttRef, True)
            End If
          End While

          ' Set Layer
          myBlockRef.Layer = strLayerName

          ' Set Scale
          myBlockRef.ScaleFactors = New Geometry.Scale3d(dScale, dScale, dScale)

          ' Set Current Annotative Scale if block is Annotative
          If myBlockRef.Annotative = AnnotativeStates.True Then
            Dim AnnoObj As DBObject = tr.GetObject(obj, OpenMode.ForRead)
            Internal.ObjectContexts.AddContext(AnnoObj, occ.CurrentContext)
          End If

          ' Set return value
          retVal = myBlockRef.ObjectId
          ' Commit transaction
          tr.Commit()
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
          ed.WriteMessage("Error: {0}" & vbLf & "Stack trace: {1}", ex.Message, ex.StackTrace)
        End Try
      End Using ' dispose transaction
    End Using ' dispose database

    ' return
    Return retVal

  End Function

For filling the attributes I have a different function. Above is the function that will place a block and takes the attributes from the definition and adds it to the reference. There are two problems. One problem is that the attribute is always the size of the original, even while I add the current scale 1:500 or 1:250 to the block, the other problem is that the first placed block has the attribute at the right position, all others will have the attributes one textline lower. See image.
The red one is the only correct one.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #1 on: August 13, 2010, 03:53:33 PM »
Looking at the code real quick I can tell where you got some of it from. You can learn some stuff from that book, but pay attention to how the guys or girls on the site write their code. Alot of the stuff from that book seems like he just tries different things intellisense pops up until something works.
I am about to starve to death, but I will post after I get back from lunch.

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #2 on: August 13, 2010, 05:41:59 PM »
A portion of the function comes from Jerry Winters. There are not many books about VB.NET and AutoCAD so it is a good point to start from. Though it is very simple and straight to the point, I realise it is not very helpful when I want more complex stuff. And that is the reason I read and post on The Swamp, to learn :-)

I tried a lot with this code but I keep getting these problems. I hope someone will find out why.


The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #3 on: August 13, 2010, 06:15:43 PM »
I was trying to keep his name out of it, but what do you learn from 4 sentences then 10 pages of code with 2 or 3 lines changed.
I would rather have 10 pages of good explanation and a couple pages of code.
I do not know how some of these guys have picked up all of their knowledge, but I know I have a tough time trying find resources to get a good understanding of the API.
 

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #4 on: August 13, 2010, 07:06:02 PM »
Are these blocks you created that you inserting

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #5 on: August 14, 2010, 01:40:26 AM »
The block I use is annotative. It is just one circle with one attribute.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #6 on: August 14, 2010, 02:29:32 AM »
See if this helps at all

Code: [Select]
<CommandMethod("InsertBlockWithAttributes")> _
   Public Sub InsertBlockWithAttributes()
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Using tr As Transaction = db.TransactionManager.StartTransaction
            Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
            Dim btrMS As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

            ''''''Check to see if blocktablerecods exists if not exits
            ''''' and if does opens models space for write'''''''
            If Not bt.Has("C") Then
                Exit Sub
            Else
                btrMS.UpgradeOpen()
            End If
            Dim btr As BlockTableRecord = bt("C").GetObject(OpenMode.ForRead)

            '''' Creating an instance to produce random Numbers'''''
            Dim randomNumber As New Random
            '''''''Numbers between 5 and 100'''''''
            Dim x As Double = randomNumber.Next(5, 100)
            Dim y As Double = randomNumber.Next(5, 100)
            Dim bref As New BlockReference(New Point3d(x, y, 0), btr.ObjectId)

            btrMS.AppendEntity(bref)
            tr.AddNewlyCreatedDBObject(bref, True)

            For Each objId As ObjectId In btr

                Dim ent As Entity = objId.GetObject(OpenMode.ForRead)

                If TypeOf ent Is AttributeDefinition Then
                    Dim attDef As AttributeDefinition = CType(ent, AttributeDefinition)
                    Dim attRef As New AttributeReference
                    attRef.SetAttributeFromBlock(attDef, bref.BlockTransform)
                    ''''''Random Number Less than 100''''
                    attRef.TextString = randomNumber.Next(100).ToString
                    bref.AttributeCollection.AppendAttribute(attRef)
                    tr.AddNewlyCreatedDBObject(attRef, True)
                End If
            Next
            
            tr.Commit()
        End Using
    End Sub

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #7 on: August 14, 2010, 02:33:58 AM »
Could post a drawing with block

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #8 on: August 14, 2010, 09:09:31 AM »
Drawing attached with one annotative block.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

fixo

  • Guest
Re: Problem with function to add annotative blocks
« Reply #9 on: August 14, 2010, 11:25:17 AM »
Perhaps it will helps:
Code: [Select]
myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
[color=red]myAttRef.AdjustAlignment(db)[/color]
              myAttColl.AppendAttribute(myAttRef)
              tr.AddNewlyCreatedDBObject(myAttRef, True)

And also use foreach instead of Enumerator

~'J'~

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #10 on: August 14, 2010, 11:48:08 AM »
All i did was change the name of the block in the code and the circle was not showing up until you change annotation scale because of the ANNOAUTOSCALE
So I added code to fix that I will see if someone else will explain it because I am not sure I fully understand that part yet.

By the way you can type "ins" then hit tab a couple of times and the command will pop up
If you did not know the tab button goes through all comands alphabetically so netload just type "ne" tab
Also add Imports Autodesk.AutoCAD.Internal

Code: [Select]
<CommandMethod("InsertBlockWithAttributes")> _
   Public Sub InsertBlockWithAttributes()
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Using tr As Transaction = db.TransactionManager.StartTransaction
            Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
            Dim btrMS As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)
            If Not bt.Has("exampleblock") Then
                Exit Sub
            Else
                btrMS.UpgradeOpen()
            End If
            Dim btr As BlockTableRecord = bt("exampleblock").GetObject(OpenMode.ForRead)
            Dim randomNumber As New Random
            Dim x As Double = randomNumber.Next(5, 100)
            Dim y As Double = randomNumber.Next(5, 100)
            Dim bref As New BlockReference(New Point3d(x, y, 0), btr.ObjectId)
            btrMS.AppendEntity(bref)
            tr.AddNewlyCreatedDBObject(bref, True)
            If btr.Annotative = AnnotativeStates.True Then
                Dim ocm As ObjectContextManager = db.ObjectContextManager
                Dim occ As ObjectContextCollection = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES")
                ObjectContexts.AddContext(bref, occ.CurrentContext)
            End If
            For Each objId As ObjectId In btr
                Dim ent As Entity = objId.GetObject(OpenMode.ForRead)
                If TypeOf ent Is AttributeDefinition Then
                    ent.UpgradeOpen()
                    Dim attDef As AttributeDefinition = CType(ent, AttributeDefinition)
                    Dim attRef As New AttributeReference
                    attRef.SetAttributeFromBlock(attDef, bref.BlockTransform)
                    attRef.TextString = randomNumber.Next(100).ToString
                    bref.AttributeCollection.AppendAttribute(attRef)
                    tr.AddNewlyCreatedDBObject(attRef, True)
                End If
            Next
            tr.Commit()
        End Using
    End Sub

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Problem with function to add annotative blocks
« Reply #11 on: August 14, 2010, 02:24:08 PM »
Did that help at all?

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #12 on: August 14, 2010, 02:44:26 PM »
Did that help at all?

I just started to check this out (it took a while before the kids are going to bed, or sleep, whatever comes first :-) )

Your first solution is not working for annotative blocks. My function is working however the attributes won't follow the annotative scale of the block.


The solution of fixo did not do the trick, it is working code but it doesn't affect my function good or bad. Meanwhile I found the solution of the lowered attributes, accidentally there was a linefeed character in the value, so AutoCAD showed the text on the second line and on the first line there was a carriage return and line feed. Btw, maybe a cool trick to write multiline attributes without having Mtext :-)

But... there is still the problem that the attribute won't scale down or up with the block...
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #13 on: August 14, 2010, 03:30:33 PM »
As suggested I tried to use ForEach instead of Getenumerator and the code is as follows:

Code: [Select]
  Public Shared Function hzInsertBlock(ByVal pntInsert As Geometry.Point3d,
                                       ByVal strBlockName As String,
                                       ByVal dScale As Double,
                                       ByVal strLayerName As String) As DatabaseServices.ObjectId

    ' TODO: Check block if is dynamic and do other things

    Dim retVal As DatabaseServices.ObjectId = Nothing

    Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
    ' Get the current document editor
    Dim ed As Editor = doc.Editor
    ' Get the current database
    Using db As Database = HostApplicationServices.WorkingDatabase
      ' Get the current transaction
      Dim tr As Transaction = db.TransactionManager.StartTransaction
      ' using transaction
      Using tr
        Try
          ' Open current space for write
          Dim myBT As BlockTable = doc.Database.BlockTableId.GetObject(OpenMode.ForRead)
          Dim myBTR As BlockTableRecord = CType(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

          ' Annotation Scales
          Dim ocm As ObjectContextManager = db.ObjectContextManager
          Dim occ As ObjectContextCollection = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES")

          ' Insert Block
          Dim myBlockDef As BlockTableRecord = myBT(strBlockName).GetObject(OpenMode.ForRead)
          Dim myBlockRef As New DatabaseServices.BlockReference(pntInsert, myBT(strBlockName))

          Dim obj As ObjectId = myBTR.AppendEntity(myBlockRef)
          tr.AddNewlyCreatedDBObject(myBlockRef, True)

          ' Set Attribute Value
          'Dim myAttColl As DatabaseServices.AttributeCollection
          'Dim myEnt As DatabaseServices.Entity
          'Dim myBTREnum As BlockTableRecordEnumerator
          'myAttColl = myBlockRef.AttributeCollection
          'myBTREnum = myBlockDef.GetEnumerator
          'While myBTREnum.MoveNext
          '  myEnt = myBTREnum.Current.GetObject(OpenMode.ForWrite)
          '  If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
          '    Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
          '    Dim myAttRef As New DatabaseServices.AttributeReference
          '    myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
          '    myAttColl.AppendAttribute(myAttRef)
          '    tr.AddNewlyCreatedDBObject(myAttRef, True)
          '  End If
          'End While

          For Each objId As ObjectId In myBTR
            Dim ent As Entity = objId.GetObject(OpenMode.ForRead)
            If TypeOf ent Is AttributeDefinition Then
              ent.UpgradeOpen()
              Dim attDef As AttributeDefinition = CType(ent, AttributeDefinition)
              Dim attRef As New AttributeReference
              attRef.SetAttributeFromBlock(attDef, myBlockRef.BlockTransform)
              myBlockRef.AttributeCollection.AppendAttribute(attRef)
              tr.AddNewlyCreatedDBObject(attRef, True)
            End If
          Next

          ' Set Layer
          myBlockRef.Layer = strLayerName

          ' Set Current Annotative Scale if block is Annotative
          If myBlockRef.Annotative = AnnotativeStates.True Then
            Dim AnnoObj As DBObject = tr.GetObject(obj, OpenMode.ForRead)
            Internal.ObjectContexts.AddContext(AnnoObj, occ.CurrentContext)
          End If

          ' Set Scale
          myBlockRef.ScaleFactors = New Geometry.Scale3d(dScale, dScale, dScale)

          ' Set return value
          retVal = myBlockRef.ObjectId
          ' Commit transaction
          tr.Commit()
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
          ed.WriteMessage("Error: {0}" & vbLf & "Stack trace: {1}", ex.Message, ex.StackTrace)
        End Try
      End Using ' dispose transaction
    End Using ' dispose database

    ' return
    Return retVal

  End Function


But now I don't get any attribute assigned to the block :-(
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

huiz

  • Swamp Rat
  • Posts: 913
  • Certified Prof C3D
Re: Problem with function to add annotative blocks
« Reply #14 on: August 14, 2010, 03:38:04 PM »
All i did was change the name of the block in the code and the circle was not showing up until you change annotation scale because of the ANNOAUTOSCALE
So I added code to fix that I will see if someone else will explain it because I am not sure I fully understand that part yet.

By the way you can type "ins" then hit tab a couple of times and the command will pop up
If you did not know the tab button goes through all comands alphabetically so netload just type "ne" tab
Also add Imports Autodesk.AutoCAD.Internal



Your sub is working well, I'll put it together with what I have now, and I hope to get a working function. But still I hope someone can explain why in my code the attributes won't scale.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.