JDXF User Guide

Basic Workflow

The class DXFGraphics implements the graphics operations defined by the standard Java Graphics2D class. To create a DXF drawing, you use the standard Java Graphics drawing calls (including drawing, transformations, etc.) on an instance of DXFGraphics. The DXFGraphics will encode these Java drawing commands as DXF objects in an associated DXFDocument, which can then be retrieved as a text string and saved in a DXF file.

A DXFGraphics is associated with a DXFDocument. The basic workflow is:

/* Create a DXF document and get its associated DXFGraphics instance */

DXFDocument dxfDocument = new 
    DXFDocument("Example");
DXFGraphics dxfGraphics = 
    dxfDocument.getGraphics();
 

/* Do drawing commands as on any other Graphics. If you have a paint(Graphics) method, you can just use it with the DXFGraphics instance since it's a subclass of Graphics. */
paint(dxfGraphics);
 
/* Get the DXF output as a string - it's just text - and  save  in a file for use with a CAD package */
String dxfText = dxfDocument.toDXFString();
String filePath = “path/to/file.dxf”;
FileWriter fileWriter = new FileWriter(filePath);
fileWriter.write(dxfText);
fileWriter.flush();
fileWriter.close();


/* For drawing, just use standard Java
   drawing operations */
public void paint(Graphics graphics)
{
  // set pen characteristics
  graphics.setColor(Color.RED);
  graphics.setStroke(new BasicStroke(3));
  
  // draw stuff - line, rectangles, ovals, ...
  graphics.drawLine(0, 0, 1000, 500);
  graphics.drawRect(1000, 500, 150, 150);
  graphics.drawRoundRect(20, 200, 130, 100, 20, 
                                             10);
  graphics.drawOval(200, 800, 200, 400);
  graphics.drawArc(100, 1900, 400, 200, 60, 150);

  // can draw filled shapes, which get 
  // implemented as DXF hatches
  graphics.setColor(Color.BLUE);
  graphics.fillRect(100, 100, 100, 50);
  int[] xPoints = {200, 300, 250};
  int[] yPoints = {200, 250, 300};
  graphics.fillPolygon(xPoints, yPoints, 
                                xPoints.length);

  // text too
  graphics.setFont(new Font(Font.MONOSPACED, 
                            Font.PLAIN, 38));
  graphics.drawString("Some 38-point monospaced   
      blue text at position 480, 400", 480, 400);

  // and even transformations
  graphics.shear(0.1f, 0.2f);
  graphics.drawRect(100, 100, 200, 200);
}

 

Layers

In AutoCAD, it’s generally considered good practice to place entities into explicit layers, rather than leaving them in the default layer, called layer “0”. In fact, layer “0” is generally reserved for special uses like block definitions (see below). JDXF supports the use of layers with the DXFDocument setLayer(layerName) command, which causes subsequent drawing commands to be placed on the specified layer, as illustrated in the following code snippet.

DXFDocument dxfDocument = new 
    DXFDocument("Example");
DXFGraphics dxfGraphics =
    dxfDocument.getGraphics();

// set layer - drawing goes 
// onto Layer 1
dxfDocument.setLayer("Layer 1");
graphics.drawRect(1000, 500, 150, 150);

// set new layer - all subsequent drawing 
// goes onto Layer 2
dxfDocument.setLayer("Layer 2");
graphics.drawOval(1000, 500, 150, 150);

Note that setLayer will create and add a layer with the specified name if one is not already present in the document. Note also that layer names are case insensitive.

When a layer is first created, it is assigned the current color, linewidth and linetype (solid, dashed, etc.) of the associated DXFGraphics object at the time setLayer is called. This is relevant when ByLayer is assigned to entities (discussed below).

ByLayer attribute for entities

One frequent approach in CAD drawings is for all of the entities on a given layer to use the color and pen style associated with that layer – for example, lines in a “Water” layer might be blue and thick, lines in an “Electrical” layer might be red and thin, etc. Rather than specifying the colors and line characteristics of the individual entities in each layer, they can instead have the value “ByLayer” assigned to these parameters, which instructs the CAD program to use the layer’s color and line instead when these are drawn. This then makes it easy to change this if you decide to use a different color or line for these elements – you just need to change the layer’s parameters.

The JDXF library supports this through the DXFDocument method setPenByLayer(boolean), available in version 2.0+. When setPenByLayer(true) is called, all subsequent draw calls will create entities whose color and line characteristics have the ByLayer value, and which will then be drawn in the CAD program with the color/line of the associated layer.

DXFDocument dxfDocument = new 
    DXFDocument("Example");
DXFGraphics dxfGraphics =
    dxfDocument.getGraphics();

// set pen characteristics to be used for layer
graphics.setStroke(new BasicStroke(2));
graphics.setColor(Color.RED);

// set layer; will be assigned the current 
// color/linewidth of graphics (red, 2)
dxfDocument.setLayer("Layer 1");

// now set all subsequently drawn objects 
// to take on the pen of their layer, not the
// graphics at the time they are drawn
dxfDocument.setPenByLayer(true);

// oval will have color/pen of Layer 1 (red, 2)
// in the DXF output
graphics.drawOval(500, 500, 150, 150);
// change pen color and draw;
// since the rectangle is going on Layer 1
// and setPenByLayer is true, it will appear
// red in the DXF image since it takes the
// color of its layer
graphics.setColor(Color.BLUE);
graphics.drawRect(1000, 500, 150, 150);

// turn off the ByLayer flag; subsequent objects
// will be given the current color/style, not 
// that of their layer; the oval will be blue
dxfDocument.setPenByLayer(false);
graphics.drawOval(1000, 500, 150, 150);

One thing to note is that when setPenByLayer is set, the color/width of the graphics pen is ignored by draw commands when the DXF entities are created. As such, the colors in the DXF output when viewed in a CAD program may differ from the colors in the onscreen Java AWT output unless the Java pen is kept synced with the layer color.

Blocks

Version 2.0+ of the JDXF library supports the creation and insertion of DXF blocks through the method insertShapesAsBlocks(boolean) of the DXFDocument class. A Block is a collection of DXF entities that can be inserted at multiple locations in the DXF document. This is similar to a Java Shape object, which can consist of multiple graphical objects. When insertShapesAsBlocks is set to true, a call to the graphics draw(Shape) method for a specific Shape will result in the definition of a block in the Blocks section of the DXF output and the placement of a corresponding Insert entity in the Entities section. Subsequent calls to draw(Shape) (likely using translations and rotations to relocate) will result in additional Insert entities for the corresponding block. This can significantly reduce the size of the DXF output, since the Block definition for the shape is included only once.

The generated blocks are placed into the default layer “0”, as is common practice in AutoCAD. Additionally, the entities within the block have their color and pen attributes set to the special value ByBlock. In this way the entities will take on the pen characteristics of the corresponding Insert entities (which may themselves use the ByLayer setting to take on the color/line of their respective layers).

An example of block generation is given below.

DXFDocument dxfDocument = new 
    DXFDocument("Example");
DXFGraphics dxfGraphics =
    dxfDocument.getGraphics();

// set to create blocks when draw(Shape) is used
dxfDocument.insertShapesAsBlocks(true);

// create/set layer for drawing
dxfDocument.setLayer("Layer 1");


// create a Path - "ice cream cone"
Path2D.Double path1 = new 
    Path2D.Double(Path2D.WIND_EVEN_ODD);
path.moveTo(0, 0);
path.lineTo(50, 200);
path.lineTo(100, 0);
path.quadTo(50, -100, 0, 0);

// translate graphics to prepare to draw the 
// shape at position (300, 300)
graphics.translate(300, 300);

// call the draw(Shape) method; this will 
// generate a block in the dxf output, and insert 
// the block at position (300, 300) in Layer 1
graphics.draw(path);

// reset the graphics transform, then translate 
// and rotate and re-draw the shape; since the 
// block has already been defined, this will 
// result in just an Insert entity at the new 
// location, rotated
graphics.translate(-300, -300);
graphics.translate(200, 100);
graphics.rotate(Math.PI/4);
draw(path);

Note that only the draw(Shape) method results in Block creation. All of the other drawing methods (drawRect, drawOval, etc.) just create corresponding DXF entities directly in the Entities section of the output. Thus in the example below, though the two approaches to draw a rectangle would result in the same image when viewed with a DXF viewer, the generated DXF for the second would include a Block definition for the rectangle and an Insert of that block into the drawing.

DXFDocument dxfDocument = new 
    DXFDocument("Example");
DXFGraphics dxfGraphics =
    dxfDocument.getGraphics();

// set to create blocks when draw(Shape) is used
dxfDocument.insertShapesAsBlocks(true);

// create/set layer for drawing
dxfDocument.setLayer("Layer 1");


// draw a rectangle using drawRect - will create 
// a DXF rectangle in the Entities section of the // DXF output as usual
graphics.drawRect(0, 0, 100, 100);

// draw a rectangle as a shape; will create a 
// block definition in the Blocks section of the 
// DXF output, and an Insert in the Entities 
// section
graphics.draw(new Rectangle2D.Double(0, 0, 100, 100));

One thing to keep in mind is that when the insertShapesAsBlocks flag is true, the first call to draw(Shape) for a specific shape will create both the Block definition in the DXF and an Insert of the block at the current graphics location. You will probably want to translate and/or rotate to position the Insert at the desired location before calling draw(Shape). Note however that the current graphics transform is ignored when the Block is created, so the block definition itself won’t be translated or rotated, just the Insert.

Note also that the JDXF library tries to avoid creating new Blocks if an existing block would be equivalent to the new one to be created. Thus if two paths path1 and path2 are created using identical operations, a call to draw(path1) followed by a call to draw(path2) will result in only one Block definition with two corresponding inserts in the DXF.

One final caveat: the DXF Insert entity allows only scaling, position and rotation; there is no provision for representing shear (where the x and y axes are skewed and no longer at right angles to one another). As such, if the graphics transform contains shear (which is unusual in CAD in any case), the JDXF library will simply place the DXF entities associated with the Java Shape directly in the DXF entity section without creating a block definition.

Configuration Switches

The JDXF library contains a number of methods in DXFDocument used to configure the output. These are listed below (and detailed in the Javadoc documentation). Except for setUnits, which is applicable globally, these switches affect DXF generation only for the drawing commands that occur after they are called (and before any additional calls). So for example, a call to setLayer(“Layer 1”) will cause all following entities to be placed on Layer 1, and a subsequent call to setLayer(“Layer 2”) will cause the next entities drawn to be placed on Layer 2. This is illustrated in the code snippet under the discussion of Layers above.

setUnits(int unitsCode)

Set the units for interpreting the dimension values in the DXF file. See the Javadoc documentation for the applicable units codes.

setPrecisionDigits(int decimalDigits)

Set the number of digits of precision to output into the DXF file for measurement quantities (locations, angles, etc.) All calculations are done internally as double-precision quantities; however this allows the specification of how many decimal digits should be output in the DXF file. This avoids the annoyance of rounding error that may otherwise result in an angle expected to be 45 degrees represented as 45.0000000347 degrees. By setting the precision to something like 5 digits, this would be output as 45.0 degrees. The number of digits must be between 0 and 16, since 16 is the maximum precision of an IEEE double quantity. Default is 10 digits.

generateCircularArcs(boolean useCircles)

When true, the DXF output will include circles and circular arcs when appropriate rather than always using the more general elliptical arcs. Note that Java AWT graphics class doesn’t include specific circle and circular arc drawing commands, providing just drawOval and drawArc for all such shapes. However, DXF can represent true circles and circular arcs, and setting optimizeArcs to true will cause these to be used in addition to elliptical arcs. Default is true; circular arcs will be generated.

generatePoints(boolean usePoints)

When true, the DXF output will include points in place of zero-length lines and zero-radius circles. Note that Java  AWT graphics class doesn’t include specific point drawing commands; the standard approach to representing a point onscreen is to create a line with the same start and end point, which will be represented as a single pixel. Default is true; points will be generated.

setLayer(String layerName)

Set the current layer, creating a new layer if one with the supplied name doesn’t already exist. All  subsequent entities will be assigned to this layer until the next call to setLayer. When created, the  layer is assigned the drawing charateristics – color, line width and linetype – that the corresponding  DXFGraphics object has at the time of the call.

The default is for all entities to be placed on the default layer “0”. Calling setLayer(“0”) or setLayer(null) will reset the layer to the default layer.

setPenByLayer(boolean useLayerPen)

When setPenByLayer(true) is called, all subsequent entities will have their color, line width and linetype set to ByLayer, so that they will use the values of their assigned layer rather than the current values set for the DXFGraphics object. Default is false; entities will be assigned the color/linewidth/linetype of the graphics object.

insertShapesAsBlocks(boolean useBlocks)

When true, Java Shapes will be incorporated as Blocks in the DXF output when draw(Shape) is called and included as Insert entities (when feasible – see below). The Insert entities will use the current Java transform to translate  and rotate the corresponding Block to position it in the drawing. Note that this is feasible only when the Java transform consists only of scaling, rotation and translation, i.e., has no shear component, since the DXF Insert declaration provides only these operations. Thus if the Java transform includes shear, the Shape will be incorporated directly in the Entities section even if this flag is true. Default is false; Shapes will be drawn as entities inline rather than referenced as blocks.

Note that the entities within Blocks are assigned to layer “0”, the default layer, and the pen characteristics  (color, linewidth, linetype) are assigned values of ByBlock. In this way, they will inherit the layers and pen characteristics of the corresponding Insert entities.

Xrecords

Xrecords are used to store non-graphical information in the Objects section of a DXF file. An Xrecord consists of user-selected group codes in the range of 1 – 369 (excluding 5 and 105) that are assigned user-defined data. The JDXF library supports the addition of Xrecords that store text information through the addXrecord( ) method of the top-level DXFDocument class. The data is assigned to group codes using the setAttribute( ) method of the DXFXrecord class, as in the following code snippet.

DXFDocument dxfDocument = new
    DXFDocument("Example");

// add an Xrecord giving title/author info
DXFXrecord xRecord = dxfDocument.addXrecord();

// add text for group codes 330, 331 and 332
xRecord.setAttribute(330, "Title: DXF Test");
xRecord.setAttribute(331, "Author: J. Sevy");
xRecord.setAttribute(332, "Date: 2023");

// draw using the DXFGraphics object as usual
DXFGraphics dxfGraphics =
    dxfDocument.getGraphics();

An Xrecord can be added before, during or after drawing.

Computing, lutherie, mathematics, finance, and other resources