DXF and the classes

What each class becomes in a DXF file, what each entity of a file becomes when it is read, and how a frame, a layer and a version are kept.

Two sides: geometry and drawings

DXF is read and written by compiled code, src/__dxf__.cc, which needs nothing but Octave. It takes the objects themselves and builds them by their constructors, so there is no list of entities to handle in between. The package meets DXF from two sides:

GeometryDrawings
Classesgeom.Polyline, geom.Spline, geom.Path, geom.Regiondraw.Drawing
Writewrite (G, FILE) for one object, geom.write (C, FILE) for a cell of them write (D, FILE)
Readgeom.read (FILE) draw.read (FILE)
ForProfiles to build solids from, parts for a laser or a router, outlines exchanged with a CAD program. Objects keep their frame in 3-D.Technical drawings: dimensions, text, hatches, blocks, layers, line types and colours. Everything lies in the plane z = 0.

Both sides write the same format, R2000 by default, and both read files from R12 to R2018, so a file written from one side can be read by the other.

Writing geom objects

Each geom class has a write method, and geom.write writes a cell array of any mix of them in one pass. The file name must end in .dxf.

ClassWritten as
geom.PolylineOne LWPOLYLINE with its bulges, its plane held as the entity's normal and elevation.
geom.SplineOne SPLINE, with its fit points where it was drawn through points.
geom.PathIts pieces, LINE, ARC in its own plane and SPLINE, bound by a GROUP.
geom.RegionIts loops, the outline first, bound by a GROUP: a loop of lines and arcs as one closed LWPOLYLINE, a loop with a spline in it as its pieces. With 'Fill', true, a solid HATCH as well, written with the group.

Geom objects carry no layer, line type or colour of their own; the options give them, one value for every object or, in geom.write, a cell array of one per object:

OptionValue
'Layer'The layer, '0' by default.
'Linetype''CONTINUOUS' by default, or a line type of draw.linetype: HIDDEN, CENTER, PHANTOM, DASHED, DASHDOT, DOT.
'Colour'An AutoCAD colour index from 1 to 256, 256 meaning the layer's colour, the default. True colour came only with R2004.
'Fill'true adds a solid hatch over a region; false by default.
'Version''R2000', the default, or 'R12', which holds only lines and arcs, so only polylines may be written as R12.
'LTScale'The line-type scale written in the header, 1 by default, so dashes look the same wherever the file is opened.
R = geom.Region ([0, 0; 60, 0; 60, 40; 0, 40], {[20, 20, 1; 40, 20, 1]});
P = geom.Path ([0, 0, 0; 0, 0, 50; 30, 0, 80]);

write (R, 'plate.dxf', 'Layer', 'PLATE', 'Fill', true);
geom.write ({R, P}, 'parts.dxf', 'Layer', {'PLATE', 'ROUTE'});

A DXF file is not appended to. Adding to one rewrites its tables, its handles and its objects section, so a file is written whole, from every object it is to hold.

Reading geom objects

What is in the file

Without options, geom.read returns what is in the file: a row cell array with one geom object per entity, in the order of the file, nothing joined and nothing reclassified.

EntityRead as
LINE, ARC, CIRCLE, LWPOLYLINE, a flat POLYLINE geom.Polyline
SPLINE, ELLIPSE geom.Spline, an ellipse as its exact rational spline
HATCHThe geom.Region objects it fills
A LINE slanting in 3-D, a 3-D POLYLINEgeom.Path, since no single plane holds them
A group the package wroteOne object, of the class its extended data names
Text, dimensions, inserts, points, meshes, solids Skipped

A group the package wrote comes back whole, so what was written is what is read: a region keeps its holes, a closed path stays a path, and the hatch written with 'Fill' is part of its region, never a second one. 'Layer' keeps only what lies on one layer, its name compared without regard to case, as CAD programs compare them.

C = geom.read ('plate.dxf')                     # one region, with its bore
C = geom.read ('parts.dxf')                     # a region and a path
C = geom.read ('parts.dxf', 'Layer', 'route')   # the path alone

Building one object from loose entities

A file from another program holds loose lines and arcs, not regions. 'Type' builds one object of a class from them:

'Type'Builds
'polyline'A geom.Polyline, from one entity.
'spline'A geom.Spline, from one entity.
'path'A geom.Path, the entities chained end to end by geom.Path.chain.
'region'A geom.Region, the entities chained into closed loops and the loops that share a plane nested by geom.Region.nest into an outline and its holes.

Ends closer than 1e-4 mm are joined and snapped to one point, which is above the rounding of coordinates in a file and below anything that can be made. The package's own groups count as already built. Exactly one object must result: more than one is an error naming the layer, as is finding candidates on several layers with no 'Layer' given, and finding none. Separate parts belong on separate layers, and 'Layer' picks one.

Four separate lines, as a CAD program would leave them, become one region ready to extrude:

L = {geom.Polyline([0, 0; 50, 0]), geom.Polyline([50, 0; 50, 30]), ...
     geom.Polyline([50, 30; 0, 30]), geom.Polyline([0, 30; 0, 0])};
geom.write (L, 'lines.dxf', 'Layer', 'PROFILE');

C = geom.read ('lines.dxf');                    # four open polylines
R = geom.read ('lines.dxf', 'Type', 'region');  # one closed region
S = solid.extrude (R, 10);

Whatever is skipped, and with 'Type' whatever is left over, is reported in one warning per read, counted by entity type.

Frames

Every geom object lies in a geom.UCS, and DXF has no place for one, so the package keeps it as extended data under the registered application DRAFTING: the origin in group 1011 and the x axis in group 1013, and for a path, a spline or a region the normal in a second 1013, since a flat entity keeps its normal in group 210. On a group, the same data names the class, geom.Path or geom.Region, in group 1000.

geom.read restores the frame, for a flat object only when the stored normal still matches the entity's and the origin still lies in its plane. The coordinates of the entities stay authoritative, so a frame left stale by an edit elsewhere can never move the geometry.

## A region in the plane x = 5, written and read back in the same frame
T = geom.Region ([0, 0; 30, 0; 30, 20; 0, 20]);
T.UCS = geom.UCS ([1, 0, 0], [5, 0, 0]);
write (T, 'tilted.dxf');
B = geom.read ('tilted.dxf', 'Type', 'region');
B.UCS == T.UCS

A file without that data is read in any plane. An entity whose normal is the world z axis is moved to its height. One whose normal points down the z axis is mirrored into the plane facing up first, as 2-D CAD programs treat it. Any other is read in DXF's own frame for its plane. Paths and splines are read in world coordinates.

Drawings

write (D, FILE) writes a draw.Drawing with its layer table and every entity on its layer. Each entity is written as itself:

Entity in the drawingWritten as
line, point, arc, circle, ellipse, text, splineThe DXF entity of the same name
polylineLWPOLYLINE, its bulges kept
path, regionIts pieces or loops, bound by a group that names the class
hatchHATCH over its region, the holes left clear, with its pattern, angle and spacing
dimensionDIMENSION, its picture in an anonymous block, so a CAD program measures it again; the picture on layer 0 and by block, so the dimension's own layer governs it
centre mark, leaderThe lines and text they are drawn with
block and insertThe block once, placed by INSERT however often it is used

A drawing writes no frames, since everything in it lies in z = 0: its path and region groups carry only their class name.

Layers

A drawing keeps a layer table, as a DXF file does, and the two map one to one:

In D.LayersIn the file
colourThe layer's colour, group 62
linetypeThe layer's line type, group 6, declared in the LTYPE table
lineweightGroup 370, the nearest of the weights DXF allows; none in R12
visible falseThe colour negated, the layer switched off; a frozen layer reads as not visible too
plot falseGroup 290 set to 0, the layer not printed

An entity drawn 'byLayer', as entities are unless told otherwise, is written by layer: no line type, colour or weight of its own, so a CAD program that changes a layer changes everything on it. An entity with a colour, line type or weight of its own is written with it. Read back, the table returns whole and by-layer entities stay by layer.

OptionValue
'Version''R2000', the default, or 'R12'; a drawing holding an ellipse, a spline, a path, a region or a hatch is an error under R12, naming what it cannot hold.
'Dimensions''associative', the default, or 'explode' to write each dimension as its lines and text, for a program that cannot read a DIMENSION.
'Blocks''reference', the default, or 'expand' to copy each block's contents in place of every insert, for a program that ignores INSERT.
'DimScale'Multiplies the dimension ornament: a drawing meant for 1:50 wants 50. 1 by default.
'LTScale'The line-type scale, 1 by default.

draw.read gives the drawing back as a draw.Drawing named 'imported', with the file's layer table and each entity on its layer. Dimensions return as dimensions, rebuilt from their definition points as the method that would have made them, so they measure the geometry again rather than repeating a number. Blocks return with their inserts, nested blocks included, hatches over their regions, and a path or region the package wrote as that path or region. A hatch pattern the package does not define is drawn as 'ANSI31', and an MTEXT returns as one line of text, its formatting removed.

R = geom.Region ([0, 0; 60, 0; 60, 40; 0, 40], {[20, 20, 1; 40, 20, 1]});

D = draw.Drawing ('plate');
D.Layer = 'OUTLINE';
D = D.region (R);
D.Layer = 'DIMENSIONS';
D = D.dim ([0, 0], [60, 0], -10, 'horizontal');
D = D.diam ([30, 20], 10);
write (D, 'drawing.dxf');

E = draw.read ('drawing.dxf');                  # the region and two dimensions
layers (E)                                      # DIMENSIONS and OUTLINE

write (D, 'exploded.dxf', 'Dimensions', 'explode');

A drawing lies in the plane z = 0, so draw.read mirrors an entity facing down into the plane facing up and drops heights. An entity on any other plane, a mesh, a solid, an entity in paper space and an insert of a block the file does not define are skipped and reported. A geom object can go into a drawing only if it lies in the xy plane; one in another plane is written with geom.write instead.

Versions, units and text

  • Written: R2000 (AC1015) by default, which holds what the package draws as itself: LWPOLYLINE with its bulges, SPLINE, ELLIPSE, HATCH, groups and extended data. R12 (AC1009) on request, for lines and arcs only.
  • Read: ASCII DXF from R12 (AC1009) to R2018 (AC1032). A binary DXF is an error.
  • Units: the writer declares millimetres. The reader converts coordinates to millimetres from the units the file declares in $INSUNITS, and reads a file declaring none as millimetres.
  • Text: written with every character outside ASCII escaped as \U+XXXX, so it reads the same whatever the reader's code page. Read from the code page the header names before R2007, and as UTF-8 from R2007 on.