C++ DXF Reader
Reason
One of the scan method modules (Circle) in the old C++ Builder code
is using a DXF-reader written in Delphi Pascal.
The DXF reader is used to show the inspection object in the XY-plane in the 3D OpenGL scene of the system. This code cannot easily be ported to C++ since it is Delphi Pascal.
The Search for a Solution
Asking AI for a DXF Library
I asked AI (Gemini) the following.
Question: I'm using Qt6 C++ and need a DXF-file reader which converts the file into a tree of objects?
Answer:
Library dxflib: (QCAD source)
Pros: This is a well-established open-source C++ library specifically for parsing DXF files. It provides a
DL_CreationInterface that you can implement to receive callbacks for each DXF entity as it's parsed (e.g., addLine,
addCircle, addBlock, etc.). This event-driven approach allows you to build your internal tree structure as the file is read.
It's used by projects like QCAD.
Cons: The forum discussions suggest it might require a good understanding of the DXF format to produce valid output
if you also plan to write DXF, and some users have found the documentation for reading a bit sparse.
How it works for your use case: You would inherit from DL_CreationInterface and in each add* method,
you'd create your custom object (e.g., MyLineObject, MyCircleObject) and add it to your tree data structure.
Library libdxfrw::
Pros: Another C++ library for reading and writing DXF/DWG files. It supports both ASCII and binary DXF formats and can read
DWG files as well. It's actively maintained on GitHub.
Cons: Licensing is GPLv2, which might be a consideration depending on your project's license.
How it works for your use case: You would integrate this library into your project, use its API to load the DXF file,
and then traverse its internal representation of the DXF data to build your own tree of objects.
The dwg2dxf converter included in the package can serve as an example of how to use the library.
Selecting a Library
Library libdxfrw has a CMake file but the there is no interface which allows getting the drawing objects into your own format.
Library dxflib has no CMake support and no separate GitHub repository from the QCAD repository. The only way is to download a
compressed file here.
Looking add both source trees the choice is made to use the dxflib library.
Adding dxflib as Library
Since the library has no CMake or and no Git/GitHub representation I created a cmake library plugin and added that
to my project cmake subdirectory which is part of the search path for CMake packages.
The CMake file downloads the tar.gz compressed file, checks the md5 hash and decompresses is in the cmake-build directory.
The targeted project is of an ARCHIVE type since it will wrapped by a dynamic library to not expose (header files) the used DXF library.
To prevent header file collisions, the file creates a subdirectory where symbolic links of the headers are created where the directory is used for including (PUBLIC).
File: DxfLibConfig.cmake:
# FetchContent added in CMake 3.11, downloads during the configure step.
include(FetchContent)
# Import dxflib library.
FetchContent_Declare(
dxflib-3.26.4
URL https://qcad.org/archives/dxflib/dxflib-3.26.4-src.tar.gz
URL_HASH MD5=70f23a9d2ed64d4f039aef1fb2109d11
DOWNLOAD_EXTRACT_TIMESTAMP true
)
FetchContent_MakeAvailable("dxflib-3.26.4")
# Define a variable for the target name and source directory.
set(DXFLIB_TARGET "dxflib")
set(DXFLIB_SOURCE_DIR "${dxflib-3.26.4_SOURCE_DIR}")
add_library("${DXFLIB_TARGET}" STATIC
${DXFLIB_SOURCE_DIR}/src/dl_attributes.h
${DXFLIB_SOURCE_DIR}/src/dl_codes.h
${DXFLIB_SOURCE_DIR}/src/dl_creationadapter.h
${DXFLIB_SOURCE_DIR}/src/dl_creationinterface.h
${DXFLIB_SOURCE_DIR}/src/dl_dxf.h
${DXFLIB_SOURCE_DIR}/src/dl_entities.h
${DXFLIB_SOURCE_DIR}/src/dl_exception.h
${DXFLIB_SOURCE_DIR}/src/dl_extrusion.h
${DXFLIB_SOURCE_DIR}/src/dl_writer.h
${DXFLIB_SOURCE_DIR}/src/dl_writer_ascii.h
${DXFLIB_SOURCE_DIR}/src/dl_dxf.cpp
${DXFLIB_SOURCE_DIR}/src/dl_writer_ascii.cpp
)
if (WIN32)
target_compile_definitions("${DXFLIB_TARGET}" PRIVATE _CRT_SECURE_NO_DEPRECATE)
endif ()
# Create the destination directory if it doesn't exist.
file(MAKE_DIRECTORY "${DXFLIB_SOURCE_DIR}/include/dxflib")
# Find all header files in the source directory.
file(GLOB DXFLIB_HEADERS "${DXFLIB_SOURCE_DIR}/src/*.h")
if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
# Copy each header file to the created include subdirectory.
file(COPY ${DXFLIB_HEADERS} DESTINATION "${DXFLIB_SOURCE_DIR}/include/dxflib")
else ()
# Create a symlink for each header.
foreach (DXFLIB_HEADER IN LISTS DXFLIB_HEADERS)
file(RELATIVE_PATH DXFLIB_HEADER "${DXFLIB_SOURCE_DIR}/src" "${DXFLIB_HEADER}")
file(CREATE_LINK "../../src/${DXFLIB_HEADER}" "${DXFLIB_SOURCE_DIR}/include/dxflib/${DXFLIB_HEADER}" SYMBOLIC COPY_ON_ERROR)
endforeach ()
endif ()
# For when building a dynamic library.
#target_compile_definitions(sf-dxflib PRIVATE DXFLIB_LIBRARY)
# Set the =include directories for building and using.
target_include_directories("${DXFLIB_TARGET}"
PRIVATE "${DXFLIB_SOURCE_DIR}/src"
PUBLIC "${DXFLIB_SOURCE_DIR}/include"
)
# Enable the required '-fPIC' compiler option for GNU compilers.
set_target_properties("${DXFLIB_TARGET}" PROPERTIES POSITION_INDEPENDENT_CODE ON)
# Remove variables after usage.
unset(DXFLIB_TARGET)
unset(DXFLIB_SOURCE_DIR)
unset(DXFLIB_HEADERS)
unset(DXFLIB_HEADER)
Dynamic DXF Wrapper Library
The dynamic DXF wrapper library sf-dxf uses the dxflib archive to create a class sf::dxf::Reader (derived from QObject)
the embedded class sf::dxf::Reader::Adapter holds all dxflib dependencies to isolate the rest of the code and generate
our own entities for drawing.
The class sf::dxf::GraphicsScene is derived from QGraphicsScene which is the way in Qt to view a
2D-scene in a QSceneView derived class using the read/generated entities.
DXF 2D & 3D Test Application
For testing the library, a test application is created.
Visualizing in 2D to check if all required entities are created.
For visualizing the DXF entities into 3D space using separate line segments using OpenGL GL_LINES are needed.
Circles and arcs are presented by line segments using a density value for the length of an arc segment.

