by Fenton Webb
Issue
How to interpret the proxy graphic binary data enclosed in AutoCAD DXF files?
Solution
Binary data enclosed in DXF files is stored in blocks of up to 256 bytes under DXF code 310
(i.e., kDxfBinaryChunk). A complete description of standard binary chunks is available in
DXF binary chunk interpretation.
This document describes the proxy graphics binary chunk.
The DXF ENTITY proxy-graphics section is present for non-core AutoCAD entities (custom entities or entities defined in ARX/DBX modules).
It is always preceded by a DXF code 92 (an int32) which indicates the length of the following binary chunk.
The binary chunk contains the proxy graphics generated when the entity’s saveAs() method was called
by AutoCAD during a DXFOUT. It also contains non-graphical metadata (bounding box, color, etc.).
The entity’s saveAs() may call worldDraw(). If worldDraw() returns
false, the system calls viewportDraw() to generate viewport-dependent graphics.
Thus the proxy graphic binary chunk holds the primitive calls recorded during worldDraw() or
viewportDraw(). The chunk is similar in spirit to a Windows Metafile: it contains drawing instructions
rather than a bitmap.
Depending on AutoCAD settings (for example, “Proxy Graphic Never Saved”) and whether the ARX/DBX module
was present at the time of DXFOUT, the proxy graphics chunk can contain:
- A bounding box with class name and logical application name.
- The last known entity graphic description.
The proxy graphics binary chunk is the serialized output of the AcGiWorldDraw/AcGiViewportDraw vector-collector classes
invoked during DXFOUT. Its high-level form is:
{Header}[{Command} [{Command} [{Command} [...]]]]
Each {Command} packet has the form:
{Command Packet Length} {Command OPCODE} [{Command Argument} {Command Argument} ...]
Interpretation Rules
Header Interpretation
To interpret the {Header}:
{int32 / Length of the binary chunk} {int32 / Number of commands}
Command Packet Interpretation
To interpret each {Command} packet:
{int32 / Command Packet Length} {int32 / Command OPCODE} [{Command Argument} {Command Argument} ...]
The {Command Argument}(s) depend on the OPCODE — see the opcode list below.
Command Opcodes
OPCODE = 0 (kAcGiOpBad)
<No AcGiGeometry primitive equivalent>
Should not happen. If it does, skip ahead by the packet length. Present for backward compatibility (R13/R14).
{Nothing}
OPCODE = 1 (kAcGiOpSetExtents)
<No AcGiGeometry primitive equivalent>
Defines an extent by providing two 3D points (min and max).
{AcGePoint3d / Min point} {AcGePoint3d / Max point}
OPCODE = 2 (kAcGiOpCircle1)
<AcGiGeometry::circle (const AcGePoint3d ¢er, double radius, const AcGeVector3d &normal)>
Displays a circle primitive with center and radius.
{AcGePoint3d / Center} {double / Radius} {AcGeVector3d / Normal}
OPCODE = 3 (kAcGiOpCircle2)
<AcGiGeometry::circle (const AcGePoint3d &pt1, const AcGePoint3d &pt2, const AcGePoint3d &pt3)>
Circle defined by three points on its circumference.
{AcGePoint3d / 1st point} {AcGePoint3d / 2nd point} {AcGePoint3d / 3rd point}
OPCODE = 4 (kAcGiOpCircularArc1)
<AcGiGeometry::circularArc (const AcGePoint3d ¢er, double radius, const AcGeVector3d &normal, const AcGeVector3d &startVector, double sweepAngle, AcGiArcType arcType)>
Arc defined by center, radius, normal, start vector, angle and arc type.
{AcGePoint3d / Center} {double / Radius} {AcGeVector3d / Normal} {AcGeVector3d / Start vector} {double / Angle} {int32 / Arc type}
OPCODE = 5 (kAcGiOpCircularArc2)
<AcGiGeometry::circularArc (const AcGePoint3d &start, const AcGePoint3d &point, const AcGePoint3d &end, AcGiArcType arcType)>
Arc defined by three points and an arc type.
{AcGePoint3d / 1st point} {AcGePoint3d / 2nd point} {AcGePoint3d / 3rd point} {int32 / Arc type}
OPCODE = 6 (kAcGiOpPolyline)
<AcGiGeometry::polyline (uint32_t nbPoints, const AcGePoint3d* pVertexList, const AcGeVector3d* pNormal, int32_t lBaseSubEntMarker)>
Draws a polyline.
{int32 / Number of vertices} {AcGePoint3d / Vertex} [{AcGePoint3d / Vertex} [...]]
OPCODE = 7 (kAcGiOpPolygon)
<AcGiGeometry::polygon (uint32_t nbPoints, const AcGePoint3d* pVertexList)>
Draws a polygon.
{int32 / Number of vertices} {AcGePoint3d / Vertex} [{AcGePoint3d / Vertex} [...]]
OPCODE = 8 (kAcGiOpMesh)
<AcGiGeometry::mesh (uint32_t rows, uint32_t columns, const AcGePoint3d* pVertexList, const AcGiEdgeData* pEdgeData, const AcGiFaceData* pFaceData, const AcGiVertexData* pVertexData)>
Draws a mesh.
{int32 / Number of rows} {int32 / Number of columns} {Vertex List} {Edge Data Packet} {Face Data Packet} {Vertex Data Packet}
Calculations
- Number of vertices:
{Number of rows} * {Number of columns} - Number of edges:
2 * {Number of vertices} - {Number of rows} - {Number of columns} - Number of faces:
({Number of rows} - 1) * ({Number of columns} - 1)
{Vertex List} Structure
{AcGePoint3d / Vertex} [{AcGePoint3d / Vertex} [...]]
{Edge Data Packet} Structure
{int32 / Edge info type} {Edge data}
Edge info type is bitwise: ACGI_COLORS (0x01), ACGI_LAYER_IDS (0x100),
ACGI_LINETYPE_IDS (0x200), ACGI_MARKERS (0x20), ACGI_VIS_DATA (0x40).
{Edge data} Sub-structures (order dependent)
// ACGI_COLORS: array of int16
{int16 / Color index} [{int16 / Color index} [...]]
// ACGI_LAYER_IDS: array of ids
{AcDbHardPointerId / Layer ID} [{AcDbHardPointerId / Layer ID} [...]]
// ACGI_LINETYPE_IDS: array of ids
{AcDbHardPointerId / Linetype ID} [{AcDbHardPointerId / Linetype ID} [...]]
// ACGI_MARKERS: array of int32
{int32 / ACGI marker} [{int32 / ACGI marker} [...]]
// ACGI_VIS_DATA: array of booleans
{int8 / Visibility flag} [{int8 / Visibility flag} [...]]
{Face Data Packet} Structure
{int32 / Face info type} {Face data}
Face info type is bitwise: ACGI_COLORS (0x01), ACGI_LAYER_IDS (0x100),
ACGI_MARKERS (0x20), ACGI_NORMALS (0x80), ACGI_VIS_DATA (0x40).
{Face data} Sub-structures (order dependent)
// ACGI_COLORS
{int16 / Color index} [{int16 / Color index} [...]]
// ACGI_LAYER_IDS
{AcDbHardPointerId / Layer ID} [{AcDbHardPointerId / Layer ID} [...]]
// ACGI_MARKERS
{int32 / ACGI marker} [{int32 / ACGI marker} [...]]
// ACGI_NORMALS
{AcGeVector3d / Normal} [{AcGeVector3d / Normal} [...]]
// ACGI_VIS_DATA
{int8 / Visibility flag} [{int8 / Visibility flag} [...]]
{Vertex Data Packet} Structure
{int32 / Vertex info type} {Vertex data}
Vertex info type is bitwise: ACGI_NORMALS (0x80), ACGI_ORIENTATION (0x400).
{Vertex data} Sub-structures (order dependent)
// ACGI_NORMALS
{AcGeVector3d / Normal} [{AcGeVector3d / Normal} [...]]
// ACGI_ORIENTATION
{int32 / AcGiOrientationType} [{int32 / AcGiOrientationType} [...]]
OPCODE = 9 (kAcGiOpShell)
<AcGiGeometry::shell (uint32_t nbVertex, const AcGePoint3d* pVertexList, uint32_t faceListSize, const int32_t* pFaceList, const AcGiEdgeData* pEdgeData, const AcGiFaceData* pFaceData, const AcGiVertexData* pVertexData, const resbuf* pResBuf)>
Draws a shell.
{int32 / Number of vertices} {Vertex List} {int32 / Face list size} {Face list} {Edge Data Packet} {Face Data Packet} {Vertex Data Packet}
{Vertex List}
{AcGePoint3d / Number of vertices} [{AcGePoint3d / Vertex} [...]]
{Face list}
{int32 / Face vertex count} {int32 / Vertex index} [{int32 / Vertex index} [...]]
The Edge Data Packet, Face Data Packet, and Vertex Data Packet follow the same definitions as OPCODE 8 (kAcGiOpMesh).
OPCODE = 10 (kAcGiOpText1)
<AcGiGeometry::text (const AcGePoint3d &position, const AcGeVector3d &normal, const AcGeVector3d &direction, double height, double width, double oblique, const char* pMsg)>
Draws text.
{AcGePoint3d / Position} {AcGeVector3d / Normal} {AcGeVector3d / Direction}
{double / Height} {double / Width} {double / Oblique} {char* / Text string}
OPCODE = 11 (kAcGiOpText2)
<AcGiGeometry::text (const AcGePoint3d &position, const AcGeVector3d &normal, const AcGeVector3d &direction, const char* pMsg, int32_t length, bool raw, const AcGiTextStyle &pTextStyle)>
Draws text with style and options.
{AcGePoint3d / Position} {AcGeVector3d / Normal} {AcGeVector3d / Direction}
{char* / Text string} {int32 / length} {int32 / Raw code} {double / Text size}
{double / Xscale} {double / Obliquing angle} {double / Tracking percentage}
{int32 / IsBackward} {int32 / IsUpsideDown} {int32 / IsVertical}
{int32 / IsUnderlined} {int32 / IsOverlined} {char* / Font name}
{char* / Big font name}
OPCODE = 12 (kAcGiOpXLine)
<AcGiGeometry::xline (const AcGePoint3d &oneXlinePoint, const AcGePoint3d &aDifferentXlinePoint)>
Constructs an xline passing through two points.
{AcGePoint3d / 1st point} {AcGePoint3d / 2nd point}
OPCODE = 13 (kAcGiOpRay)
<AcGiGeometry::ray (const AcGePoint3d &raysStartingPoint, const AcGePoint3d &aDifferentRayPoint)>
Ray starting at one point and passing through a second point.
{AcGePoint3d / 1st point} {AcGePoint3d / 2nd point}
OPCODE = 14 (kAcGiOpColor)
<AcGiSubEntityTraits::setColor (uint16_t color)>
{uint32 / Color index}
OPCODE = 15 (kAcGiOpLayerName)
<AcGiSubEntityTraits::setLayer (const AcDbObjectId layerId)>
{char* / Layer name}
OPCODE = 16 (kAcGiOpLayerIndex)
<AcGiSubEntityTraits::setLayer (const AcDbObjectId layerId)>
{AcDbHardPointerId / Layer ID}
OPCODE = 17 (kAcGiOpLineTypeName)
<AcGiSubEntityTraits::setLineType (const AcDbObjectId linetypeId)>
{char* / Linetype name}
OPCODE = 18 (kAcGiOpLineTypeIndex)
<AcGiSubEntityTraits::setLineType (const AcDbObjectId linetypeId)>
{AcDbHardPointerId / Linetype ID}
OPCODE = 19 (kAcGiOpSelectionMarker)
<AcGiSubEntityTraits::setSelectionMarker (int32_t markerId)>
{uint32 / ACGI marker}
OPCODE = 20 (kAcGiOpFillType)
<AcGiSubEntityTraits::setFillType (AcGiFillType fill)>
{uint32 / AcGiFillType}
OPCODE = 21 (kAcGiBoundingBoxSave)
<No AcGiGeometry primitive equivalent>
{Nothing}
OPCODE = 22 (kAcGiOpTrueColor)
<AcGiSubEntityTraits::setTrueColor (const AcCmEntityColor &color)>
{AcCmEntityColor / True color definition}
Comment: introduced in Tahoe (AutoCAD 2000).
OPCODE = 23 (kAcGiOpLineWeight)
<AcGiSubEntityTraits::setLineWeight (const AcDb::LineWeight lw)>
{double / Lineweight}
OPCODE = 24 (kAcGiOpLineTypeScale)
<AcGiSubEntityTraits::setLineTypeScale (double dScale)>
{double / Line scale}
OPCODE = 25 (kAcGiOpThickness)
<AcGiSubEntityTraits::setThickness (double dThickness)>
{double / Thickness}
OPCODE = 26 (kAcGiOpPlotStyleName)
<AcGiSubEntityTraits::setPlotStyleName (AcDb::PlotStyleNameType type, const AcDbObjectId &id)>
{int32 / PlotStyle name type} {int32 / ID}
OPCODE = 27 (kAcGiOpPushClipBoundary)
<AcGiGeometry::pushClipBoundary (AcGiClipBoundary* pBoundary)>
{AcGiClipBoundary / Clip Boundary}
AcGiClipBoundary Structure
struct AcGiClipBoundary {
// Boundaries
AcGeVector3d m_vNormal;
AcGePoint3d m_ptPoint;
AcGePoint2dArray m_aptPoints;
// Transforms
AcGeMatrix3d m_xToClipSpace;
AcGeMatrix3d m_xInverseBlockRefXForm;
// Z clipping
Adesk::Boolean m_bClippingFront;
Adesk::Boolean m_bClippingBack;
double m_dFrontClipZ;
double m_dBackClipZ;
Adesk::Boolean m_bDrawBoundary;
};
OPCODE = 28 (kAcGiOpPopClipBoundary)
<AcGiGeometry::popClipBoundary ()>
{Nothing}
OPCODE = 29 (kAcGiOpPushTransformM)
<No AcGiGeometry primitive equivalent>
{AcGeMatrix3d / Matrix}
OPCODE = 30 (kAcGiOpPushTransformV)
<No AcGiGeometry primitive equivalent>
{AcGeMatrix3d / Matrix}
OPCODE = 31 (kAcGiOpPopTransform)
<No AcGiGeometry primitive equivalent>
{Nothing}
OPCODE = 32 (kAcGiOpPlineNormal)
<AcGiViewportGeometry::polylineEye (uint32_t nbPoints, const AcGePoint3d* pPoints) or AcGiViewportGeometry::polylineDc (uint32_t nbPoints, const AcGePoint3d* pPoints)>
{int32 / Number of points} {AcGePoint3d / Point definition} [{AcGePoint3d / Point definition} [...]] {AcGeVector3d / Normal}
OPCODE = 33 (kAcGiOpMaxOpCodes)
<No AcGiGeometry primitive equivalent>
Should not happen. If it does, skip to packet length. Present for forward compatibility.
{Nothing}

Leave a Reply