haplokuon / netDxf

.net dxf Reader-Writer
MIT License
994 stars 405 forks source link

How to handle Blocks #133

Open OakLD opened 5 years ago

OakLD commented 5 years ago

Forgive me please, if I missed any documentation or posts related to the issue (I found only indirectly related ones).

How do one handles blocks? All I want to do is to read all lines, arcs and circles in a file and process them, but those in blocks are not part of collections in DxfDocument (.Circles, .Lines, etc.).

I tried to read entities of all blocks, but they appear to be Nothing right from start. This is a test routine in my drawing layer:

        For ib = 0 To dxfdoc.Blocks.Count - 1   ' browse blocks
            Dim Blck As netDxf.Blocks.Block = dxfdoc.Blocks(ib)   ' get block (one by one)
            If IsNothing(Blck) = False Then         ' <<<<<< they're always "Nothing"
                For ir = 0 To Blck.Entities.Count - 1   
                    Dim e As netDxf.Entities.EntityObject = Blck.Entities(ir)
                    Select Case e.Type
                        Case netDxf.Entities.EntityType.Line
                            Dim L As netDxf.Entities.Line = e
                            g.DrawLine(Pens.Black, New Point((L.StartPoint.X - DXFshiftX) * DxfScale + ShiftX,
                                                                ((L.StartPoint.Y - DXFshiftY) * DxfScale + ShiftY)),
                                                       New Point((L.EndPoint.X - DXFshiftX) * DxfScale + ShiftX,
                                                                 (L.EndPoint.Y - DXFshiftY) * DxfScale + ShiftY))
                    End Select
                Next ir
            End If
        Next ib

Here, it shows me (during breakpoint debugging), that there are 3 blocks in the particular document, but each of them is Nothing, even if referenced directly as dxfDoc.Blocks(0).

But this is just a blind shot, since I didn't find anything specific about blocks in netDxf, my approach might be completely wrong. I.e., is there a way to explode Blocks into Lines, Circles, etc.?

I'd appreaciate an advice on this subject.

haplokuon commented 5 years ago

You are confusing Blocks with Inserts. There are two main types of objects, TableObjects that are named objects that describe characteristics and properties of the entities, and EntityObjects that are the actual objects that has a graphical representation.

An Insert is a reference to a Block, multiples references of the same block might exist in the same drawing. This is the same kind of relationship that a Text or a MText entity has with its TextStyle, like a MLine entity has with its MLineStyle, etc...

You need to iterate through the list of Inserts not the Blocks. Additionally, to know the final position of the entities contained inside a Block that is referenced by an Insert, you need to apply the transformation defined in the insert, its position, scale, and rotation. You can do it yourself or use the Explode method of the Insert class.

One more thing, you do not access a TableObject by its index but by its name, that is why in your code dxfdoc.Blocks(ib) is returning Nothing. You are passing an integer but a string its required instead.

OakLD commented 5 years ago

Thank you very much, @haplokuon.

All clear to me (in theory). It's been some 15 years since I've been clicking ordinary CAD :-). No wonder I forgot, that blocks are definitions and that they actually have their inserted instances.

I'll try couple of things, starting with Explode method.

Thank you very much, once again.

OakLD commented 5 years ago

OK, so I found out, that the Explode() function to explode "Inserts" of Blocks has been added in one of the latest releases. I found out too, that there is a similar problem with block-like entities called LWPOLYLINE, which I didn't know they existed (they appearance is similar to blocks).

I set to create a convesion from LWPOLYLINE to lines and arcs, studied documentation and wrote functions and I was nearly done, when I remembered I didn't check LWPOLYLINE classs of the netDxf - and there it is: Explode() function :-)

With those, it was pretty easy to explode them and add the resulting entities to the document collection:

        ' #######################  BLOCKS  ######################
        For ir = 1 To 5
            For ii = 0 To DXFdoc.Inserts.Count - 1
                Dim ins As netDxf.Entities.Insert = DXFdoc.Inserts(ii)
                BlockEntitiess = ins.Explode()
                For Each Ent In BlockEntitiess
                    DXFdoc.AddEntity(Ent)
                Next
            Next
        Next

        ' #######################  LIGHT WEIGHT POLYLINES  ######################
        For ii = 0 To DXFdoc.LwPolylines.Count - 1
            Dim lwpl As netDxf.Entities.LwPolyline = DXFdoc.LwPolylines(ii)
            Dim EntList As List(Of Entities.EntityObject)
            EntList = lwpl.Explode()
            For ir = 0 To EntList.Count - 1
                DXFdoc.AddEntity(EntList(ir))
            Next
        Next

In case of blocks (or precisely thier instances - "Inserts"), I ran it in loop 5 times to break blocks inside blocks. I would expect this would happen when Explode() is called (it doesn't), but it is not difficult to add resulting List(Of EntityObject) into the DXF document.

So I hope that this might help a bit to new users.