Вы находитесь на странице: 1из 15

Using AutoCAD file formats with open source libraries

Reading DWG and DXF file formats

Christopher Michaelis 30 August 2011


Developer
Consultant

Many experts use AutoCAD and its formats in engineering, design, architecture, geography,
and related fields. It's often useful to combine the data that AutoCAD produces with GIS data
such as shapefiles for placement on maps or for use inside Google Earth or Google Maps.
Learn about two open source libraries—LibreDWG and dxflib—that make the AutoCAD DXF
and DWG file formats more accessible. You also create a translator tool that will write to KML
and shapefile formats and use the GDAL library to facilitate working with GML and shapefile
formats.

Introduction
Many developers and geographic information system (GIS) professionals have been unable to use
a Drawing Interchange Format (DXF) or "drawing" (DWG) file. These AutoCAD formats generally
require that you have Windows® and a copy of AutoCAD to open them. Using a few handy open
source libraries, you can make your applications able to natively read DXF and DWG files on any
operating system at no cost. In this article, you build a converter to translate these file formats into
the more open ESRI shapefile or keyhole markup language (KML) formats. Commercial and open
source software use ESRI Shapefiles, while Google Earth and Google Maps mainly use KML.

AutoCAD DWG and LibreDWG


The most common AutoCAD format is the "drawing" format, with a file extension ending in .dwg.
Few software applications can read this format, which is the default when saving files in AutoCAD.
However, you can use the open source library LibreDWG (see Resources) to read these files. The
file format consists of a control block, which contains additional blocks representing the shapes in
the file, and blocks for model space and paper space, which represent offsets for the coordinates
that lie within the document.

You use the library by opening the document and reading the file, followed by looping through each
block in the main control block, as shown in Listing 1.

© Copyright IBM Corporation 2011 Trademarks


Using AutoCAD file formats with open source libraries Page 1 of 15
developerWorks® ibm.com/developerWorks/

Listing 1. Opening a DWG file and looping through the main control block
Dwg_Data dwg = new Dwg_Data();
int errno = dwg_read_file((char *)inputFilename, dwg);
if (errno) {
fprintf(stderr, "Could not open DWG. Returned error code: $d\n", errno);
delete dwg;
}

Dwg_Object_BLOCK_CONTROL * ctrl = dwg->object[0].tio.object->tio.BLOCK_CONTROL;


dumpBlock(ctrl->model_space);
dumpBlock(ctrl->paper_space);

for (int i = 0; i < ctrl->num_entries; i++) {


dumpBlock(ctrl->block_headers[i]);
}
dwg_free(dwg);

Each block can represent any of several types of geometry: a line, circle, arc, text anchored to a
location, or an insert (an offset to be applied to later blocks). You handle each in turn by accessing
properties on the block objects that get_first_owned_object and get_next_owned_object return,
as illustrated in Listing 2.

Listing 2. Reading objects with get_first_owned_object and


get_next_owned_object
void InputFormatDWG::dumpBlock(Dwg_Object_Ref * block) {
if (!block) return;
if (!block->obj) return;
if (!block->obj->tio.object) return;

Dwg_Object_BLOCK_HEADER * header = block->obj->tio.object->tio.BLOCK_HEADER;


Dwg_Object * obj = get_first_owned_object(block->obj, header);
while (obj) {
if (obj->type == DWG_TYPE_LINE) {
Dwg_Entity_LINE * line = obj->tio.entity->tio.LINE;
printf("Line starting at (%f, %f, %f) ending at (%f, %f, %f)\n", line->start.x,
line->start.y, 0, line->end.x, line->end.y, 0);
// Don't delete "line" - dwg_free will do this
}

obj = get_next_owned_object(block->obj, obj, header);


}
}

In this way, reading a DWG file with LibreDWG is a sequential flow from start to finish. When
implementing LibreDWG in C++, it's important that you include dwg.h inside an extern "C" block to
avoid encountering linker errors later. Here's an example:
extern "C" {
#include <dwg.h>
}

Prerequisites for this library are the autoconf, swig, texinfo, and python-dev packages as well
as compiler packages (build-essential if using Debian or Ubuntu). You can build the library by
downloading it by entering the following on the command line:
git clone git://git.sv.gnu.org/libredwg.git

Using AutoCAD file formats with open source libraries Page 2 of 15


ibm.com/developerWorks/ developerWorks®

. . . followed by:
./autogen.sh && ./configure && make && sudo make install

AutoCAD DXF and dxflib


The DXF format is an export option from within AutoCAD. As such, more applications support it
than support DWG, and the file format specification is published (see Resources for a link to the
full DXF specification). You can, however, read these files using the open source dxflib library.
Unlike LibreDWG, reading a DXF file is driven less by sequential coding of your own. In fact, using
dxflib feels something like writing event-driven code.

You open the file by calling the in function of the DL_Dxf object and passing a pointer to a
class that inherits from the DL_CreationAdapter abstract class. As the in function runs, it calls
several functions in the class passed to it. There are dozens of such functions (see the DXFLib
Programmer's Guide link in Resources), but you'll care only about a handful in most cases
—typically, addPoint, addLine, addCircle, and addVertex. You only need to implement those
functions you care about; the rest you can omit. Listing 3 shows a simple example of loading a
DXF file and reading only lines from it.

Listing 3. Loading a DXF file and reading only lines


LineReader.h:
#ifndef LINEREADER_H
#define LINEREADER_H

#include "dxflib/src/dl_dxf.h"
#include "dxflib/src/dl_creationadapter.h"
#include <stdio.h>

class LineReader: public DL_CreationAdapter {


public:
// Our functions:
void readLines(const char * filename);

// Overloading from parent DL_CreationAdapter:


void addLine(const DL_LineData& data);

};
#endif

LineReader.cpp:
void LineReader::readLines(const char * filename) {
DL_Dxf * getData = new DL_Dxf();
if (!getData->in(filename, this)) {
fprintf(stderr, "Could not retrieve data from input file.\n");
delete getData;
exit(1);
}
delete getData;
}

void LineReader::addLine(const DL_LineData& data) {


printf("Line starting at (%f, %f, %f) ending at (%f, %f, %f)\n",
data.x1, data.y1, data.z1, data.x2, data.y2, data.z2);
}

Using AutoCAD file formats with open source libraries Page 3 of 15


developerWorks® ibm.com/developerWorks/

Like DWG, the DXF format can contain inserts, which represent offsets to be applied to geometric
features encountered after the insert. These inserts must be stored internally and applied to
coordinates as they are encountered. Similarly, adding polylines (lines with multiple vertices)
requires storing some data. The library first calls addPolyline, indicating that a line is coming; it
then calls addVertex once for each vertex of the line. Finally, the line is ended when endEntity or
endBlock is called, at which point you have the complete line and can render it, export it to a new
format, or take other action.

You can build and install the DXF library by simply entering the following on the command line:
./configure && make && sudo make install

You may receive error messages about strcasecmp as well as about strlen being undeclared.
The dxflib library was built to use GCC/G++ 4.2, and in version 4.3, some reorganization of
header files took place. Fixing this error requires adding a few includes in src/dl_writer.h and
src/dl_writer_ascii.h as well as in #include <cstring> and #include <cstdlib> near the other
includes.

Note: These changes were already made to the copy of dxflib included with the converter source
code available in Download, so this change applies only if you download dxflib directly from the
dxflib website.

KML and plain text/Xerces-C++


The KML format that Google Earth and Google Maps use is a specialized form of XML; as such,
you can use libraries such as Xerces-C++ XML Parser (see Resources for a link) to work with KML
files. When reading these formats, formal libraries like Xerces-C++ are advisable for handling more
complex structures that you may encounter. When writing, it is usually sufficient to use simple built-
in language functionality to write text files, and then generate the appropriate text yourself.

A basic KML file consists of a Document section that contains a name and description. The file may
also contain one or more folders (used to organize shapes logically), and inside each folder are
placemarks. The placemarks are the actual shape, which you can define as LineString, Point,
Polygon, or other types. Writing a KML file requires writing properly formatted text representing the
shapes, as shown in Listing 4.

Using AutoCAD file formats with open source libraries Page 4 of 15


ibm.com/developerWorks/ developerWorks®

Listing 4. A simple KML file


<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>test</name>
<open>1</open>
<description>Converted from AutoCAD DXF or DWG</description>
<Folder>
<name>test</name>
<Placemark>
<LineString>
<tessellate>0</tessellate>
<coordinates>27.54998,82.27393,0.00000 39.72346,9.25601,0.00000</coordinates>
</LineString>
</Placemark>
</Folder>
</Document>
</kml>

You may also encounter KMZ files, which are just KML files compressed with ZIP compression.
See Resources for a link to a beginner tutorial on KML and complete KML documentation.

ESRI Shapefile and GDAL/OGR


The shapefile format is a commercial (but open) binary data format published by ESRI (see
Resources for a link to the full technical description). You can use the open source OGR Simple
Feature Library—part of the Geospatial Data Abstraction Layer (GDAL)—to access these files
easily. In your example converter, you only need output, but this library also simplifies reading
shape data. Writing data requires opening an output data source and creating a data layer within
it. You can create fields to store nonspatial data for each shape. After the output data source has
been created, you can add multiple shapes (called features) to the data source. Creating a feature
requires that you also create a geometry, such as a point or line, and associate it with the feature.
The feature acts as a container for all field/nonspatial and geometric data.

Listing 5 shows the code for creating a new shapefile data source and a single point inside the
dataset. See the OGR C++ read/write tutorial and the OGR class hierarchy and documentation
links in Resources for more information on using OGR and for a download link to the library itself.
Most Linux® distribution repositories include the GDAL library and header files as libgdal1-1.7.0
and libgdal1-dev (the version may vary).

Listing 5. Creating a shapefile with a single point inside it


OGRRegisterAll();
OGRSFDriver drv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("ESRI Shapefile");
if (drv == NULL) {
fprintf(stderr, "Could not open Shapefile OGR driver.\n");
return;
}

OGRDataSource ds = drv->CreateDataSource(filename, NULL);


if (ds == NULL) {
fprintf(stderr, "Could not create output file.\n");
return;
}

OGRLayer lyr = ds->CreateLayer("Layer", NULL, wkbPoint, NULL);


if (lyr == NULL) {

Using AutoCAD file formats with open source libraries Page 5 of 15


developerWorks® ibm.com/developerWorks/

fprintf(stderr, "Could not create layer.\n");


return;
}

// Add an ID field
OGRFieldDefn newField("id", OFTInteger);
newField.SetWidth(32);
lyr->CreateField(&newField);

if (!lyr) {
fprintf(stderr, "No output layer is available.");
return;
}

OGRFeature * newFeat = OGRFeature::CreateFeature(lyr->GetLayerDefn());


newFeat->SetField("id", lyr->GetFeatureCount(1));
OGRPoint point;
point.setX(15.653);
point.setY(43.783);
point.setZ(0);
newFeat->SetGeometry(&point);
lyr->CreateFeature(newFeat);

// Clean up your memory


OGRFeature::DestroyFeature(newFeat);

if (ds) {
// Will trigger saving the file and also
// clean up any layer references from Create/Get Layer calls
OGRDataSource::DestroyDataSource(ds);
}

Implementing file format libraries


There are three main ways to implement a file format library in software. The first way— native
implementation in applications— requires that you be able to use the libraries from your code
directly, which means that you may have to write your code in a particular set of languages,
depending on binding availability. It also requires some strong linkage, which may cause minor
errors when library versions are updated. However, direct implementation in your application does
make using the format feel much smoother to users.

Another method is to write a plug-in or extension for your application that provides support for
the desired file formats. This method gives you some degree of separation between a file format
library and your application code. If your application already has a plug-in framework, this may be
a good option. For example, Quantum GIS, a common desktop GIS application, uses a plug-in
architecture; one such plug-in allows you to use delimited text files directly in the application.

The last and simplest method of all— a stand-alone converter— can be created to translate
between two or more file formats. This technique has the advantage of being reusable regardless
of your end goals for the data at the cost of adding another step for users.

A command-line translator for DXF/DWG to KML/Shapefile


In this example, you take the simpler and more reusable route of creating a file format translator.
Your goal is to create a converter that is easy to extend to handle additional formats and that
keeps logic for any particular input or output format as separate as possible. These goals lead to
the definition of two abstract classes: InputFormat and OutputFormat (see Listing 6).

Using AutoCAD file formats with open source libraries Page 6 of 15


ibm.com/developerWorks/ developerWorks®

Listing 6. InputFormat and OutputFormat abstract class definitions


OutputFormat.h:
#ifndef OUTPUTFORMAT_H
#define OUTPUTFORMAT_H

#include "OutputFormatTypes.h"
#include <vector>

class OutputFormat {
public:
OutputFormat() {};
~OutputFormat() {};

// Standard feature types:


virtual void addPoint(OutputFeaturePoint newPoint) = 0;
virtual void addLine(OutputFeatureLine newLine) = 0;
virtual void addPolyLine(std::vector<OutputFeaturePoint *> newPoints) = 0;
virtual void addPolygon(std::vector<OutputFeaturePoint *> newPoints) = 0;

// For approximating text on DXF/DWG with a separate point layer with


// a label attribute:
virtual void addText(OutputFeaturePoint location, const char * text) = 0;

// The cleanup function


virtual void finalizeOutput() = 0;
};
#endif

InputFormat.h:
#ifndef INPUTFORMAT_H
#define INPUTFORMAT_H

#include "OutputFormat.h"

class InputFormat {
public:
InputFormat() {};
~InputFormat() {};
virtual void readFeaturesInto(OutputFormat * outputHandler) = 0;
};
#endif

Any format you implement must inherit from one of these classes. In this way, the main function
and entry point of the program can deal exclusively with determining which class to instantiate.
After an input file and output file have been defined, conversion can take place with a single line of
code:
input->readFeaturesInto(output);

The role of the main function (see Listing 7) then becomes solely instantiating the proper input and
output formats, culminating in the readFeaturesInto function call.

Listing 7. The main() function of the AutoCAD converter


void usage(char * me) {
printf("Usage: %s inputfile outputfile [point|line|polygon]\n", me);
printf("Input formats supported:\n");
printf("\tAutoCAD DXF (*.dxf)\n");
printf("\tAutoCAD DWG (*.dwg)\n");
printf("Output formats supported:\n");
printf("\tText (*.txt)\n");
printf("\tESRI Shapefile (*.shp)\n");

Using AutoCAD file formats with open source libraries Page 7 of 15


developerWorks® ibm.com/developerWorks/

printf("\tKeyhold Markup Language (*.kml)\n");


printf("\nInput format and output format are determined automatically by file extension.
\n");
printf("If you use a shapefile as the output format, please additionally specify\n");
printf("point, line, or polygon output shapefile type.\n");
}

int main(int argc, char * argv[]) {


if (argc < 3) {
usage(argv[0]);
return 1;
}

OutputFormat * output = NULL;


InputFormat * input = NULL;
struct stat fileExists;

// Set up output format first...


std::string outFile = argv[2];
if (outFile.rfind('.') == std::string::npos) {
printf("I couldn't make sense of your output filename's extension: %s. Please use
filename.shp, filename.kml, or filename.txt.\n", argv[2]);
return 1;
}
if (outFile.substr(outFile.rfind('.')+1) == "txt") {
printf("Setting up output file %s...\n", argv[2]);
output = new OutputFormatText(argv[2]);
}
else if (outFile.substr(outFile.rfind('.')+1) == "shp") {
if (argc < 4) {
printf("When specifying shapefile output, please also specify 'point', 'line', or
'polygon'. See usage.\n");
return 1;
}
std::string textAttributeFile = outFile.substr(0, outFile.rfind('.')) + "_text.shp";
OGRwkbGeometryType type;
if (strcmp(argv[3], "line") == 0) {
type = wkbLineString;
}
else if (strcmp(argv[3], "point") == 0) {
type = wkbPoint;
}
else if (strcmp(argv[3], "polygon") == 0) {
type = wkbPolygon;
}
else {
printf("I didn't understand %s. Please use point, line, or polygon.\n", argv[3]);
return 1;
}
printf("Setting up output file %s...\n", argv[2]);
output = new OutputFormatSHP(argv[2], textAttributeFile.c_str(), outFile.substr(0,
outFile.rfind('.')).c_str(), type);
}
else if (outFile.substr(outFile.rfind('.')+1) == "kml") {
printf("Setting up output file %s...\n", argv[2]);
output = new OutputFormatKML(argv[2], outFile.substr(0, outFile.rfind('.')).c_str());
}

// Next grab the input file


std::string inFile = argv[1];
if (inFile.rfind('.') == std::string::npos) {
printf("I couldn't make sense of your input filename's extension: %s. Please use
filename.dxf or filename.dwg.\n", argv[1]);
delete output;
return 1;
}
if (stat(argv[1], &fileExists) != 0) {

Using AutoCAD file formats with open source libraries Page 8 of 15


ibm.com/developerWorks/ developerWorks®

printf("The specified input file does not exist or is not accessible: %s\n", argv[1]);
return 1;
}
if (inFile.substr(inFile.rfind('.')+1) == "dxf") {
input = new InputFormatDXF(argv[1]);
printf("Setting up input file %s...\n", argv[1]);
}
else if (inFile.substr(inFile.rfind('.')+1) == "dwg") {
input = new InputFormatDWG(argv[1]);
printf("Setting up input file %s...\n", argv[1]);
}

if (!input) {
printf("The input file was not recognized or could not be opened.\n");
return 1;
}
if (!output) {
printf("The output file was not recognized or could not be opened.\n");
return 1;
}

printf("Converting file...\n");
input->readFeaturesInto(output);
output->finalizeOutput();
printf("Done!\n");

delete input;
delete output;
return 0;
}

The only required function in the InputFormat class is readFeaturesInto, which leaves it open to
the individual input format how it actually wants to provide features (shapes) to the provided output
class. The OutputFormat class has a few more required functions, however— functions to add
various types of geometric shapes. You define your own classes for point and line so that you can
provide all arguments as double values instead of integers and so that you can provide a z-axis.

The ESRI Shapefile format has one important limitation; it can only store shapes of a single type
(for example, only lines, only points, or only polygons). No other formats discussed in this article
— DXF, DWG, and KML— have this restriction. In the OutputFormatSHP class, you check to see
what kind of shapefile you're creating; if it's not the right type, you handle it the best you can. While
creating a point shapefile, when you are prompted to add a polyline shape, add each vertex as
an individual point. While creating a line shapefile, if you are prompted to add a point, a warning
is written to standard error indicating that the shape was ignored. The DXF and DWG file formats
also support arcs and circles, which you can approximate in your output formats by creating
multiple small line segments approximating the circle or arc.

When compiling the example application, you may receive error messages relating to dwg.h. Both
the dxflib and LibreDWG libraries define the global definition THICKNESS, so edit the dwg.h file in
its installed location (for example, /usr/local/include/dwg.h) and change the name of the THICKNESS
constant or add an underscore (_) at the end. (This is not actually used in this example code.)

Note: See the Download section for the full source code of this example file format translator.

Using AutoCAD file formats with open source libraries Page 9 of 15


developerWorks® ibm.com/developerWorks/

Wrapping the translator in a website


At this point, you have a fully functional command-line translator for file formats. However, most of
the users who typically ask how to read these files are neither command-line savvy nor capable
of building the converter from source themselves. It makes sense, then, to provide a simple web-
based gateway to this tool, so that people needing quick conversion of one or two files can easily
do so. At the same time, you can create a system in which files are automatically converted when
added to a particular directory on disk—useful for FTP interaction or for access through a CIFS file
share.

First, create a handful of directories for the various shapefile output format types:

• uploads_KML and uploads_Text for KML and text output formats


• uploads_Point, uploads_Polyline, and uploads_Polygon for the various types of shapefile
output formats
The convention will be that any DXF or DWG file uploaded into any of these locations will be
converted into the format the directory name implies. Outputs should be placed in another
directory, called outputs.

Given such a setup, you can construct a simple BASH shell script (see Listing 8) to check for
DWG and DXF files in this location and trigger the converter with the appropriate command-line
arguments. To aid in future debugging, this script can also save all uploaded inputs together with
generated outputs into a time-stamped .zip file for administrative use. You can set this script up
to run periodically as a cron job or for FTP and CIFS (Windows file share) use as an automatic
converter.

Listing 8. BASH script to check for files pending conversion and pass them to
the converter
#!/bin/bash -u

# Polyline Shapefile queue


cd /var/www/acadconverter.chrismichaelis.com/uploads_Polyline
for file in /var/www/acadconverter.chrismichaelis.com/uploads_Polyline/*.d*; do
[[ "$file" =~ .dxf$ || "$file" =~ dwg$ ]] && {
base=$(basename "$file")
base=${base%.dwg}
base=${base%.dxf}
/var/www/acadconverter.chrismichaelis.com/bin/AutoCADConverter \
"$file" "$base.shp" line
[ -e "../outputs/$base.zip" ] && rm -f "../outputs/$base.zip"
zip "../outputs/$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf"
zip "../uploads_done/$(date +%s)_$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf" "$file"
rm -f "$file" "$base.shx" "$base.shp" "$base.dbf" "${base}_text.shp" \
"${base}_text.shx" "${base}_text.dbf"
}
done

# Polygon Shapefile queue


cd /var/www/acadconverter.chrismichaelis.com/uploads_Polygon
for file in /var/www/acadconverter.chrismichaelis.com/uploads_Polygon/*.d*; do
[[ "$file" =~ .dxf$ || "$file" =~ dwg$ ]] && {
base=$(basename "$file")

Using AutoCAD file formats with open source libraries Page 10 of 15


ibm.com/developerWorks/ developerWorks®

base=${base%.dwg}
base=${base%.dxf}
/var/www/acadconverter.chrismichaelis.com/bin/AutoCADConverter "$file" \
"$base.shp" polygon
[ -e "../outputs/$base.zip" ] && rm -f "../outputs/$base.zip"
zip "../outputs/$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf"
zip "../uploads_done/$(date +%s)_$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf" "$file"
rm -f "$file" "$base.shx" "$base.shp" "$base.dbf" "${base}_text.shp" \
"${base}_text.shx" "${base}_text.dbf"
}
done

# Point Shapefile queue


cd /var/www/acadconverter.chrismichaelis.com/uploads_Point
for file in /var/www/acadconverter.chrismichaelis.com/uploads_Point/*.d*; do
[[ "$file" =~ .dxf$ || "$file" =~ dwg$ ]] && {
base=$(basename "$file")
base=${base%.dwg}
base=${base%.dxf}
/var/www/acadconverter.chrismichaelis.com/bin/AutoCADConverter "$file" \
"$base.shp" point
[ -e "../outputs/$base.zip" ] && rm -f "../outputs/$base.zip"
zip "../outputs/$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf"
zip "../uploads_done/$(date +%s)_$base.zip" "$base.shx" "$base.shp" "$base.dbf" \
"${base}_text.shp" "${base}_text.shx" "${base}_text.dbf" "$file"
rm -f "$file" "$base.shx" "$base.shp" "$base.dbf" "${base}_text.shp" \
"${base}_text.shx" "${base}_text.dbf"
}
done

# KML queue
cd /var/www/acadconverter.chrismichaelis.com/uploads_KML
for file in /var/www/acadconverter.chrismichaelis.com/uploads_KML/*.d*; do
[[ "$file" =~ .dxf$ || "$file" =~ dwg$ ]] && {
base=$(basename "$file")
base=${base%.dwg}
base=${base%.dxf}
/var/www/acadconverter.chrismichaelis.com/bin/AutoCADConverter "$file" "$base.kml"
[ -e "../outputs/$base.zip" ] && rm -f "../outputs/$base.zip"
zip "../outputs/$base.zip" "$base.kml"
zip "../uploads_done/$(date +%s)_$base.zip" "$base.kml" "$file"
rm -f "$file" "$base.kml"
}
done

# Text queue
cd /var/www/acadconverter.chrismichaelis.com/uploads_Text
for file in /var/www/acadconverter.chrismichaelis.com/uploads_Text/*.d*; do
[[ "$file" =~ .dxf$ || "$file" =~ dwg$ ]] && {
base=$(basename "$file")
base=${base%.dwg}
base=${base%.dxf}
/var/www/acadconverter.chrismichaelis.com/bin/AutoCADConverter "$file" "$base.txt"
[ -e "../outputs/$base.zip" ] && rm -f "../outputs/$base.zip"
zip "../outputs/$base.zip" "$base.txt"
zip "../uploads_done/$(date +%s)_$base.zip" "$base.txt" "$file"
rm -f "$file" "$base.txt"
}
done

The website itself can be a simple file upload page. In this case, including an upload progress bar
would be a good enhancement. An open source tool called Ajax Upload (see Resources for a link)

Using AutoCAD file formats with open source libraries Page 11 of 15


developerWorks® ibm.com/developerWorks/

uses XMLHttpRequest to help produce a more fluid upload interface. In your HTML page, use the
jQuery ready function to create the file uploader once the page has loaded and pass the selected
output format along with the uploaded file (see Listing 9). The stock PHP upload script provided
with the Ajax Upload tool is used, and at the end of that script, the handleUpload command is
altered to save the uploaded file into the correct directory for the desired output type. Rather than
wait for the scheduled cron job to take place, you then use the exec PHP function to start the
script and convert the file. The HTML page waits a few moments for conversion to finish, and then
directs the visitor to the generated .zip file containing the produced output files.

Listing 9. jQuery ready() function to set up the file uploader


$(document).ready(function() {
var uploader = new qq.FileUploader({
'element': $('#inputFile')[0],
'action': 'fileuploader.php',
'params': { 'outputFormat': $('#outputFormat option:selected').attr('value') },
'onComplete': function(id, file, response) {
if (!response.success) return;
// Please Wait
$('#postLoader').hide()
$('#postLoader').html('<img src="clock.png" height="210" width="210"><br />
Please Wait...');
$('#postLoader').slideDown();

// for IE compatibility, don't use anonymous function in setTimeout


setTimeout("showDownload('" + file.replace(".dwg", "").replace(".dxf", "") + "');",
5000);
return true;
}
});

$('#outputFormat').change(function() {
uploader.setParams({
'outputFormat': $('#outputFormat option:selected').attr('value')
});
});
});

function showDownload(file) {
$('#postLoader').slideUp('slow', function() { $('#postLoader').html('<img
src="download.png" height="48" width="48" align="absmiddle">
<a href="outputs/' + file + '.zip">Download Ouptut</a>').slideDown(); });
}

This code simplifies the converter considerably, accomplishing the goal of making it easily
accessible to anyone who needs a file converted. See Resources for a link to the completed web
interface to the converter, or see the Download section for complete source code to the converter
web page.

Conclusion
You can extend the simple file format converter in this example to handle more file formats for
geometric and geographic data. You can use the libraries demonstrated here to extend any
software tool to natively handle these file formats. Bindings for these libraries are available in
multiple languages beyond the C++ usage and syntax demonstrated here.

Using AutoCAD file formats with open source libraries Page 12 of 15


ibm.com/developerWorks/ developerWorks®

Downloads
Description Name Size
AutoCAD file format converter source code AutoCADConverter-SourceCode.zip 1.6MB
Converter website source code ConverterWebsite-SourceCode.zip 0.36MB

Using AutoCAD file formats with open source libraries Page 13 of 15


developerWorks® ibm.com/developerWorks/

Resources
Learn

• Using geospatial data in applications on Linux using GDAL (Christopher Michaelis,


developerWorks, February 2011): Find additional background on concepts and terms used in
this article.
• DXF Reference: Get help troubleshooting problems or taking decoding into your own hands.
• The dxflib Programmer's Guide: Start learning more about using dxflib in practical
applications.
• The Google KML tutorial: Get started with KML.
• KML documentation: Learn more advanced features.
• The ESRI Shapefile technical description: Learn more about writing your own shapefile
parsing code without using third-party libraries.
• The OGR API tutorial: Get more detail on how to use OGR/GDAL to interact with shapefiles.
• OGR Class Hierarchy and Documentation: Explore full functionality of the OGR Simple
Feature Library.
• AutoCAD converter web page: Learn more about the website and converter tool described in
this article.
• developerWorks Open source: Find extensive how-to information, tools, and project updates
to help you develop with open source technologies and use them with IBM's products.
• developerWorks technical events and webcasts: Stay current with the latest technology.
• Technology bookstore: Browse for books on these and other technical topics.
• developerWorks podcasts: Listen to interesting interviews and discussions for software
developers.

Get products and technologies

• The dxflib library website includes source code downloads and documentation.
• GNU LibreDWG website: Find source code as well as documentation.
• Xerces-C++ XML Parser: Use this excellent and reliable way to parse complex XML
documents (including derivatives like GML and KML).
• GDAL download page: Get the source code for OGR—a part of GDAL—.
• Ajax Upload: Get this tool that uses XmlHTTPRequest to display friendly upload progress
bars on HTTP file uploads.
• C/C++ development: You might also be interested in the optimization you can achieve with
IBM's XL C/C++ for AIX and Linux.

Discuss

• developerWorks blogs: Check out these blogs and get involved in the developerWorks
community.

Using AutoCAD file formats with open source libraries Page 14 of 15


ibm.com/developerWorks/ developerWorks®

About the author


Christopher Michaelis

Christopher Michaelis is a developer specializing in web hosting and web


applications. He attended Utah State University and Idaho State University, studying
computer science and geographic information science. His experience covers a
wide range of development, including applications for environmental modeling,
education, diabetes data analysis, systems administration tools, web hosting, platform
integration, and location-based services.

© Copyright IBM Corporation 2011


(www.ibm.com/legal/copytrade.shtml)
Trademarks
(www.ibm.com/developerworks/ibm/trademarks/)

Using AutoCAD file formats with open source libraries Page 15 of 15

Вам также может понравиться