Demystifying DXF: LEADER and MULTILEADER implementation notes

Introduction

As part of my work on the DXF driver in the open-source Geospatial Data Abstraction Library (GDAL), I was tasked with the job of implementing support for leader elements.

For those unfamiliar with CAD, leaders are essentially arrows emanating from a text label or symbol, serving to point out some important aspect of the drawing.

LEADER demo

AutoCAD offers two different kinds of leader objects:

I hope these notes, which are intended to supplement the DXF specification, will help those who need to interact with the DXF format programmatically but have limited AutoCAD knowledge, or possibly even no access to the software. I assume a basic level of familiarity with the DXF format.

My implementation

Here is the C++ code of the DXF LEADER and MULTILEADER translator that I developed for GDAL/OGR. It should not be too difficult to read most of that code even if you're completely unfamiliar with OGR or GDAL. And here is a demo DXF file with all kinds of different LEADER and MULTILEADER objects which you can use to test your implementation.

LEADER

The LEADER entity represents an arrow, made up of one or more vertices (or spline fit points) and an arrowhead. The label or other content to which the LEADER is attached is stored as a separate entity, and is not part of the LEADER itself.

As noted above, LEADER shares its styling infrastructure with DIMENSION. To style these entities correctly, you begin with the styling properties of the selected dimension style, then apply any overrides indicated in the entity itself. The DXF spec provides an example.

Compared to the sprawling complexity of DIMENSION, rendering a simple LEADER entity is easy. It is simply a matter of connecting the vertices by straight line segments and attaching an arrowhead at the end (in most cases). The only difficulty is the "hook line" feature, described in the following section.

The hook line

If the DIMTAD dimension style property ("Text pos vert" in AutoCAD's Properties pane) is set to anything other than "Centered" (0), the leader line extends beneath the text. This extension is known as a "hook line".

LEADER DIMTAD

Unfortunately, the endpoint of this hook line is not stored in the DXF file. We have to calculate it using the (211,221,231) direction vector, the text width stored in group code 41, and a "flip" boolean in group code 74. The calculation, written in pseudocode, is as follows (gc stands for "group code"):

if ( DIMTAD != 0 && gc73 == 0 && gc41 > 0 && count(vertices) >= 2 )
{
    directionVector = (gc211, gc221, gc231) or (1.0, 0.0, 0.0) if the group codes are not present
    if ( gc74 == 1 )
        directionVector = -directionVector
    
    lastVertex = the last (gc10, gc20, gc30) present  
    vertices.append( lastVertex + ( DIMGAP * DIMSCALE + gc41 ) * directionVector )
}

This code flips the direction vector when group code 74 is 1, contrary to what the DXF spec appears to say. I assume the spec is wrong on this, since it doesn't match AutoCAD's behaviour.

Splines

You might also wonder how to render spline LEADERs. The DXF documentation mentions that LEADERs are rendered as splines when group code 72 is set to 1, but it doesn't give any detail.

As far as I can tell, the recipe is like this:

Bear in mind that the vertices are treated as fit points. Elsewhere in the DXF format, splines are generated from control points, so you may need to adjust your logic.

LEADERs are legacy

Autodesk seems to be very firmly treating LEADER and QLEADER as a legacy feature. The LEADER user documentation recommends that users switch to the MLEADER workflow, and the default AutoCAD toolbars do not contain a button to insert a LEADER. The reality is, unless you can get all your users to downsave their drawings to pre-2008 DXF versions, you are going to need MULTILEADER support in your DXF reader.

MULTILEADER

This is where the fun begins. MULTILEADERs differ from LEADERs in a number of important ways:

MLEADER anatomy

Sources of information

The DXF spec is only one place to look for information on MULTILEADER.

You should also look at the ObjectARX documentation for AcDbMLeader, the C++ class used internally by AutoCAD to represent MULTILEADERs. The DXF representation of MULTILEADER is essentially a spewing-out of the data in this class, much more so than for other entities, so this documentation is especially valuable. For example, the page on AcDbMLeader::leaderLineType() states that this function returns the leader line type as a AcDbMLeaderStyle::LeaderType value. From the values of that enum, we now know how to interpret common group code 170!

The Open Design Alliance reverse-engineer of the DWG format, sections 19.4.46 and 19.4.83, acts as a handy cross-reference. The DWG and DXF formats are so similar in structure that the ODA DWG spec references the DXF group codes where it can. Although the copyright statement is rather stern, you are unlikely to use the document to the extent that copyright becomes a concern.

Structure

Totally missing from the DXF spec is a description of the way the MULTILEADER entity is structured. It is divided into sections by 30x group codes, which always have the text values given below:

...              // common group codes
300
CONTEXT_DATA{
  ...            // context data group codes
  302
  LEADER{
    ...          // leader group codes (referred to as "Leader Node" in the DXF spec)
    304
    LEADER_LINE{
      ...        // leader line group codes
    305
    }
    304
    LEADER_LINE{
      ...        // leader line group codes
    305
    }
    ...          // further leader group codes
  303
  }
  302
  LEADER{
    ...          // leader group codes with leader line section(s)
  303
  }
  ...            // further context data group codes
301
}
...              // further common group codes

There could be zero or more leader or leader line sections. Group codes have different meanings depending on the section they appear in (the DXF spec got this bit right).

Entity handles

The MULTILEADER entity refers to other DXF objects by their handle, not by their name. Even text styles and ATTDEF entities, which are always referred to by name in other entities, are referenced by their handle. Common group codes 342, 344 and 330, and context data group codes 340 and 341, are all handle references.

Geometry

There are three types of vertices in a MULTILEADER:

MLEADER vertices

Depending on the value of common group code 170, a MULTILEADER may be straight (1), spline (2) or "none" (0). Straight rendering simply involves joining relevant vertices of each leader line and providing a dogleg, interrupting the lines at breaks. Spline rendering is done in the same way as LEADER (see above). "None" means that the leaders are not rendered at all - only the content (text or block) is to be shown.

Calculating the dogleg/landing

As with LEADER, some calculations must be performed to find the entire geometry. This involves establishing whether a dogleg needs to be drawn, and if so, calculating the endpoint of the dogleg.

The dogleg endpoint is simply calculated as landing point + (dogleg length * dogleg direction vector).

For a particular leader within the MULTILEADER, a dogleg is drawn if:

If the dogleg is not drawn, the dogleg endpoint still must be calculated, because in this case, the landing point is ignored and the leader lines terminate at the dogleg endpoint instead.

MLEADER dogleg on/off

Breaks

Straight MULTILEADER leader lines can be "broken" to avoid intersections with other linework in the drawing. Each break (also known as DIMBREAK, from the AutoCAD command) is stored as a pair of points. The break (gap in the line) begins at the first point and ends at the second point.

MLEADER breaks

The breaks that lie between vertex n and vertex n + 1 are stored after vertex n in the leader line section. Leader line group codes (11,21,31) give the start point and codes (12,22,32) give the end point. The 11,21,31,12,22,32 sequence is repeated for each break in that particular segment of the leader line.

Breaks in the dogleg are stored as part of the leader section. The start of a break is given by leader group codes (12,22,32) and the end by (13,23,33), which may be repeated in the same way.

Breaks are not used in spline MULTILEADERs.

Content

Common group code 172 determines whether the MULTILEADER has text content (2), block content (1), or no content (0).

Text content

In AutoCAD, the text content of a MULTILEADER is internally represented as an AcDbMText (MTEXT) data member belonging to the AcDbMLeader class. Although the group codes are different, there is a good chance you will be able to share code between your implementations of MTEXT and MLEADER.

The text is anchored at the point given by context data group codes (12,22,32), corresponding to MTEXT group codes (10,20,30).

Where the same value appears in both the common and context data sections (for example, text color), AutoCAD uses the value given in the context data section.

Block content

Instead of text, a MULTILEADER may have a block reference as its content. The common group code 344 stores the handle of a BLOCK_RECORD. Your renderer should insert this block at the position given by context data group codes (15,25,35). The DXF spec lists some other parameters in the context data section (block normal direction, block scale, and block rotation) which are interpreted as for INSERT. There doesn't appear to be a way to set a specific block color for a multileader in AutoCAD, so I don't know what 93 is for.

The group code 47 appears 16 times to give some kind of matrix. Since the last four values seem to always be zero, I assume this is a 3D affine transformation, but it is unclear why this matrix is provided when the rotation, scale and translation are also independently present. In my implementation I have chosen to ignore this matrix, because I assume it's only useful when extrusions are in the picture, and I don't wish to support extrusions of MULTILEADERs for the time being.

Block attributes are stored very differently in MULTILEADER entities compared to an ordinary INSERT. The handle (not the name) of the relevant ATTDEF is given in common group code 330, followed by an index (177), a "width" of some kind (44), and the value of the attribute (302). This sequence of four codes is repeated as required. If you are writing a DXF converter, chances are you have chosen to strip out ATTDEF entities; you will clearly need to reconsider this so you can render MULTILEADER block attributes.

A significant amount of my MULTILEADER code in GDAL is taken up processing block attributes. It might seem like a minor and inconsequential feature, but it is actually very important to implement it properly - it is common to see MULTILEADERs which consist of the leader label (say, a key number) enclosed in a circle. This is invariably structured as a block containing a circle and an ATTDEF for the label into which the text needs to be substituted.

Colors

The overall color of the MULTILEADER is stored in the usual way (62/440 group codes in the common section). But it seems that the developers got lazy for other color values, like common group code 91. The raw value of the RGBM union that is part of the AcDbEntityColor class is written straight to the DXF as a signed 32-bit integer. As an example, this means that ByBlock is no longer the familiar 0, but instead -1056964608 (0xC1000000).

Extrusions (OCS)

Extrusions, also known as object coordinate systems (OCS), are an aspect of the MULTILEADER entity that I have not explored. If anyone has figured out how these work for MULTILEADER, please feel free to submit an issue or pull request against this site.


Alan Thomas
ThinkSpatial
athomas@thinkspatial.com.au
July 2018

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.


Back to Alan Thomas' home page