Burst Blocks

Burst Blocks

SRSDS
Advisor Advisor
3,637 Views
11 Replies
Message 1 of 12

Burst Blocks

SRSDS
Advisor
Advisor

I've been searching and there are answers on this

but just curious to know why this doesn't work

 

        Dim filter(0) As TypedValue
        filter(0) = New TypedValue(DxfCode.Start, "INSERT")
        Dim sf As SelectionFilter = New SelectionFilter(filter)
        Dim psr As PromptSelectionResult
        psr = Application.DocumentManager.MdiActiveDocument.Editor.SelectAll(sf)
        Do
            If psr.Status = PromptStatus.OK Then
                Dim IdCollection As ObjectIdCollection = New ObjectIdCollection(psr.Value.GetObjectIds)
                Dim objids(IdCollection.Count - 1) As ObjectId
                For i As Integer = 0 To IdCollection.Count - 1
                    objids(i) = IdCollection(i)
                Next
                ed.SetImpliedSelection(objids)
                Application.DocumentManager.MdiActiveDocument.SendStringToExecute("BURST ", True, False, False)
            Else Exit Do
            End If
        Loop
0 Likes
Accepted solutions (3)
3,638 Views
11 Replies
Replies (11)
Message 2 of 12

dgorsman
Consultant
Consultant

Rather than trying to create a scripting engine to call commands, I'd recommend going through the API documentation to understand what makes up a block reference (and definition), and why they are organized that way.  From there you can work out how BURST operates "behind the scenes" and look at duplicating/modifying/enhancing the process to your own needs.  That kind of deep-level knowledge is highly useful for many other tasks you'll run into.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 3 of 12

_gile
Consultant
Consultant

Hi,

 

You cannot call the BURST "command" with SendStringToExecute() or Command() methods because it is a LISP defined command.

You can try using the COM SendCommand() method.

 

            var psr = ed.GetSelection(new SelectionFilter(new[] { new TypedValue(0, "INSERT") }));
            if (psr.Status == PromptStatus.OK)
            {
                ed.SetImpliedSelection(psr.Value);
                dynamic acadDoc = doc.GetAcadDocument();
                acadDoc.SendCommand("burst ");
            }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 4 of 12

SRSDS
Advisor
Advisor

Still a bumbling newbie, sorry.

How do i define/import Dynamic. There's no intelliprompt for a solution.

 

Untitled.png 

0 Likes
Message 5 of 12

SRSDS
Advisor
Advisor
Accepted solution

I think I might have found the solution in an AutoCAD devblog here:

https://adndevblog.typepad.com/autocad/2015/06/programmatically-mimic-the-burst-command.html

I skimmed over the link in another post. Sorry for the trouble.

 

0 Likes
Message 6 of 12

_gile
Consultant
Consultant

With VB, I think you have to use the Object type for late binding.

It also seems to me the GetAcadDocument() extension method does not work as expected with VB (crappy language...).

Dim acadDoc As Object = DocumentExtension.GetAcadDocument(Application.DocumentManager.MdiActiveDocument)

Anyway, I really agree with @dgorsman: scripting with .NET looks like chasing mosquitoes with a bazooka.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 12

kerry_w_brown
Advisor
Advisor

@SRSDS wrote:

I think I might have found the solution in an AutoCAD devblog here:

https://adndevblog.typepad.com/autocad/2015/06/programmatically-mimic-the-burst-command.html

 

<<<<

Sam,

If you work through Balaji's code you'll learn a lot.

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 8 of 12

_gile
Consultant
Consultant
Accepted solution

I tried to make a version more finalized than Balaji's example which also takes into account the multiline attributes.

The code uses the C# 7 local functions feature.

 

        [CommandMethod("XPLODEBLOCK")]
        public static void ExplodeBlock()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var psr = ed.GetSelection(new SelectionFilter(new[] { new TypedValue(0, "INSERT") }));
            if (psr.Status != PromptStatus.OK)
                return;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                // local functions
                void append(Entity ent)
                {
                    var id = curSpace.AppendEntity(ent);
                    tr.AddNewlyCreatedDBObject(ent, true);
                }

                DBText appendDBText(DBText source)
                {
                    var text = new DBText
                    {
                        Normal = source.Normal,
                        Thickness = source.Thickness,
                        Oblique = source.Oblique,
                        Rotation = source.Rotation,
                        Height = source.Height,
                        WidthFactor = source.WidthFactor,
                        TextString = source.TextString,
                        TextStyleId = source.TextStyleId,
                        IsMirroredInX = source.IsMirroredInX,
                        IsMirroredInY = source.IsMirroredInY,
                        HorizontalMode = source.HorizontalMode,
                        VerticalMode = source.VerticalMode,
                        Position = source.Position
                    };
                    if (source.Justify != AttachmentPoint.BaseLeft)
                    {
                        text.Justify = source.Justify;
                        text.AlignmentPoint = source.AlignmentPoint;
                    }
                    text.SetPropertiesFrom(source);
                    append(text);
                    return text;
                }

                MText appendMtext(MText source)
                {
                    var mtext = new MText
                    {
                        Contents = source.Contents,
                        FlowDirection = source.FlowDirection,
                        Attachment = source.Attachment,
                        TextHeight = source.TextHeight,
                        TextStyleId = source.TextStyleId,
                        Width = source.Width,
                        Rotation = source.Rotation,
                        Location = source.Location,
                        Normal = source.Normal,
                        LineSpacingStyle = source.LineSpacingStyle,
                        Height = source.Height,
                        LineSpacingFactor = source.LineSpacingFactor,
                        LineSpaceDistance = source.LineSpaceDistance
                    };
                    mtext.SetPropertiesFrom(source);
                    append(mtext);
                    return mtext;
                }

                // main
                foreach (SelectedObject selectedObject in psr.Value)
                {
                    var br = (BlockReference)tr.GetObject(selectedObject.ObjectId, OpenMode.ForWrite);
                    try
                    {
                        foreach (ObjectId id in br.AttributeCollection)
                        {
                            var att = (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
                            if (!att.Invisible)
                            {
                                if (att.IsMTextAttribute)
                                    appendMtext(att.MTextAttribute).Rotation += br.Rotation;
                                else
                                    appendDBText(att);
                            }
                        }
                        var btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForWrite);
                        btr.Explodable = true;
                        foreach (ObjectId id in btr)
                        {
                            if (id.ObjectClass.DxfName == "ATTDEF")
                            {
                                var att = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                                if (att.Constant && !att.Invisible)
                                {
                                    if (att.IsMTextAttributeDefinition)
                                        appendMtext(att.MTextAttributeDefinition).TransformBy(br.BlockTransform);
                                    else
                                        appendDBText(att).TransformBy(br.BlockTransform);
                                }
                            }
                        }

                        var ents = new DBObjectCollection();
                        br.Explode(ents);
                        foreach (Entity ent in ents)
                        {
                            if (ent is AttributeDefinition)
                                ent.Dispose();
                            else
                                append(ent);
                        }
                        br.Erase();
                    }
                    catch
                    {
                        ed.WriteMessage($"\nFailed to explode a block named {br.Name}");
                    }
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 9 of 12

SRSDS
Advisor
Advisor

Gile,

I tried to convert your optimized code to vb but the converter didn't like it.

Sounds like multiline text attributes would be  important. Should I mark it as a solution for C# users?

 

0 Likes
Message 10 of 12

_gile
Consultant
Consultant
Accepted solution

Here's a VB conversion (not so difficult, you really should learn C#)

 

    <CommandMethod("XPLODEBLOCK")>
    Public Shared Sub ExplodeBlock()
        Dim doc = Application.DocumentManager.MdiActiveDocument
        Dim db = doc.Database
        Dim ed = doc.Editor
        Dim psr = ed.GetSelection(New SelectionFilter({New TypedValue(0, "INSERT")}))
        If psr.Status <> PromptStatus.OK Then Return

        Using tr = db.TransactionManager.StartTransaction()
            Dim curSpace = CType(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
            For Each selectedObject As SelectedObject In psr.Value
                Dim br = CType(tr.GetObject(selectedObject.ObjectId, OpenMode.ForWrite), BlockReference)

                Try

                    For Each id As ObjectId In br.AttributeCollection
                        Dim att = CType(tr.GetObject(id, OpenMode.ForRead), AttributeReference)

                        If Not att.Invisible Then
                            If att.IsMTextAttribute Then
                                AppendMText(att.MTextAttribute, curSpace, tr).Rotation += br.Rotation
                            Else
                                AppendDBText(att, curSpace, tr)
                            End If
                        End If
                    Next

                    Dim btr = CType(tr.GetObject(br.BlockTableRecord, OpenMode.ForWrite), BlockTableRecord)
                    btr.Explodable = True

                    For Each id As ObjectId In btr

                        If id.ObjectClass.DxfName = "ATTDEF" Then
                            Dim att = CType(tr.GetObject(id, OpenMode.ForRead), AttributeDefinition)

                            If att.Constant AndAlso Not att.Invisible Then
                                If att.IsMTextAttributeDefinition Then
                                    AppendMText(att.MTextAttributeDefinition, curSpace, tr).TransformBy(br.BlockTransform)
                                Else
                                    AppendDBText(att, curSpace, tr).TransformBy(br.BlockTransform)
                                End If
                            End If
                        End If
                    Next

                    Dim ents = New DBObjectCollection()
                    br.Explode(ents)

                    For Each ent As Entity In ents

                        If TypeOf ent Is AttributeDefinition Then
                            ent.Dispose()
                        Else
                            Append(ent, curSpace, tr)
                        End If
                    Next

                    br.[Erase]()
                Catch
                    ed.WriteMessage($"\nFailed to explode a block named {br.Name}")
                End Try
            Next

            tr.Commit()
        End Using
    End Sub

    Private Shared Sub Append(ent As Entity, space As BlockTableRecord, tr As Transaction)
        space.AppendEntity(ent)
        tr.AddNewlyCreatedDBObject(ent, True)
    End Sub

    Private Shared Function AppendDBText(source As DBText, space As BlockTableRecord, tr As Transaction) As DBText
        Dim text As DBText = New DBText()
        text.SetPropertiesFrom(source)
        With text
            .Normal = source.Normal
            .Thickness = source.Thickness
            .Oblique = source.Oblique
            .Rotation = source.Rotation
            .Height = source.Height
            .WidthFactor = source.WidthFactor
            .TextString = source.TextString
            .TextStyleId = source.TextStyleId
            .IsMirroredInX = source.IsMirroredInX
            .IsMirroredInY = source.IsMirroredInY
            .HorizontalMode = source.HorizontalMode
            .VerticalMode = source.VerticalMode
            .Position = source.Position
        End With
        If source.Justify <> AttachmentPoint.BaseLeft Then
            text.Justify = source.Justify
            text.AlignmentPoint = source.AlignmentPoint
        End If
        Append(text, space, tr)
        Return text
    End Function

    Private Shared Function AppendMText(source As MText, space As BlockTableRecord, tr As Transaction) As MText
        Dim mtext As MText = New MText()
        mtext.SetPropertiesFrom(source)
        With mtext
            .Contents = source.Contents
            .FlowDirection = source.FlowDirection
            .Attachment = source.Attachment
            .TextHeight = source.TextHeight
            .TextStyleId = source.TextStyleId
            .Width = source.Width
            .Rotation = source.Rotation
            .Location = source.Location
            .Normal = source.Normal
            .LineSpacingStyle = source.LineSpacingStyle
            .Height = source.Height
            .LineSpacingFactor = source.LineSpacingFactor
            .LineSpaceDistance = source.LineSpaceDistance
        End With
        Append(mtext, space, tr)
        Return mtext
    End Function


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 12

David_Prontnicki
Collaborator
Collaborator

@_gile ,

This is beautiful!!! Thank you very much for taking the time to do this.

 

I do have one question though; I have modified the psr to perform a .SelectAll. This will obviously select everything in every layout and model space. How do I do a select all for just the current space?

 

Dim psr = ed.SelectAll(New SelectionFilter({New TypedValue(0, "INSERT")}))

 

The reason I am asking is if I leave it .SelectAll the entities from the other layouts and model get inserted into the current layout where the routine was originally run. Even though you have this:

 

Dim curSpace = CType(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

 

I would like to iterate through each layout tab and run your routine to ensure that the items stay on their respective layouts. 

 

Thank you,

0 Likes
Message 12 of 12

David_Prontnicki
Collaborator
Collaborator

@_gile ,

Never mind, I found another post of yours that I used to modify: Your Answer to Post

 

So I modified as shown below. 

 

<CommandMethod("XPLODEBLOCK")>
    Public Shared Sub ExplodeBlock()

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

        Dim ctab As String = Application.GetSystemVariable("CTAB")
        Dim filList As TypedValue() = New TypedValue(1) {New TypedValue(0, "INSERT"), New TypedValue(410, ctab)}

        Dim selectionFilter As New SelectionFilter(filList)

        Dim psr As PromptSelectionResult

        psr = ed.SelectAll(selectionFilter)

        If psr.Status <> PromptStatus.OK Then Return

        Using tr = db.TransactionManager.StartTransaction()....
0 Likes