Skip to content

Commit

Permalink
DXF: add creation option to set and DXF system variables
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Dec 3, 2024
1 parent 5e173b5 commit 9dd8963
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 15 deletions.
102 changes: 101 additions & 1 deletion autotest/ogr/ogr_dxf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import ogrtest
import pytest

from osgeo import gdal, ogr
from osgeo import gdal, ogr, osr


###############################################################################
Expand Down Expand Up @@ -4020,3 +4020,103 @@ def test_ogr_dxf_read_closed_polyline_with_bulge():
f = lyr.GetNextFeature()
g = f.GetGeometryRef()
assert g.GetGeometryType() == ogr.wkbPolygon


###############################################################################


def test_ogr_dxf_write_INSUNITS(tmp_vsimem):

filename = str(tmp_vsimem / "out.dxf")

with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=METERS"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == "6"

with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=21"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == "21"

with gdal.quiet_errors():
with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=INVALID"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == " 1"

with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=FROM_CRS"]
) as ds:
srs = osr.SpatialReference()
srs.ImportFromEPSG(32631)
ds.CreateLayer("test", srs=srs)
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == "6"

# No CRS
with gdal.quiet_errors():
with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=FROM_CRS"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == " 1"

# Not a projected CRS
with gdal.quiet_errors():
with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=FROM_CRS"]
) as ds:
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
ds.CreateLayer("test", srs=srs)
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == " 1"

# Unknown linear units
with gdal.quiet_errors():
with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["INSUNITS=FROM_CRS"]
) as ds:
srs = osr.SpatialReference()
srs.ImportFromProj4("+proj=merc +to_meter=2")
ds.CreateLayer("test", srs=srs)
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$INSUNITS", "DXF_HEADER_VARIABLES") == " 1"


###############################################################################


def test_ogr_dxf_write_MEASUREMENT(tmp_vsimem):

filename = str(tmp_vsimem / "out.dxf")

with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["MEASUREMENT=METRIC"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$MEASUREMENT", "DXF_HEADER_VARIABLES") == "1"

with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["MEASUREMENT=1"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$MEASUREMENT", "DXF_HEADER_VARIABLES") == "1"

with gdal.quiet_errors():
with ogr.GetDriverByName("DXF").CreateDataSource(
filename, options=["MEASUREMENT=INVALID"]
) as ds:
pass
with ogr.Open(filename) as ds:
assert ds.GetMetadataItem("$MEASUREMENT", "DXF_HEADER_VARIABLES") == " 0"
36 changes: 26 additions & 10 deletions doc/source/drivers/vector/dxf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,32 @@ The driver supports the following dataset creation options:
Override the trailer file used - in place
of trailer.dxf located in the GDAL_DATA directory.

- .. dsco:: FIRST_ENTITY
:choices: <integer>

Identifier of first entity

- .. dsco:: INSUNITS
:choices: HEADER_VALUE, FROM_CRS, UNITLESS, INCHES, FEET, MILLIMETERS, CENTIMETERS, METERS, US_SURVEY_FEET
:default: HEADER_VALUE
:since: 3.11

Drawing units for the model space
(`$INSUNITS <https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2018/ENU/AutoCAD-Core/files/GUID-A58A87BB-482B-4042-A00A-EEF55A2B4FD8-htm.html>`__ system variable).
Defaults to the value of the header template, which is ``INCHES``.
The special value ``FROM_CRS`` means that the linear units of the CRS of
the layer, when it is a projected CRS, are used to set ``$INSUNITS``.

- .. dsco:: MEASUREMENT
:choices: HEADER_VALUE, IMPERIAL, METRIC
:default: HEADER_VALUE
:since: 3.11

Whether the current drawing uses imperial or metric hatch pattern and linetype
(`$MEASUREMENT <https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2018/ENU/AutoCAD-Core/files/GUID-1D074C55-0B63-482E-8A37-A52AC0C7C8FE-htm.html>`__ system variable).
Defaults to the value of the header template, which is ``IMPERIAL``.


The header and trailer templates can be
complete DXF files. The driver will scan them and only extract the
needed portions (portion before or after the ENTITIES section).
Expand Down Expand Up @@ -474,16 +500,6 @@ It is assumed that patterns are using "g" (georeferenced) units for
defining the line pattern. If not, the scaling of the DXF patterns is
likely to be wrong - potentially very wrong.

Units
~~~~~

GDAL writes DXF files with measurement units set to "Imperial - Inches".
If you need to change the units, edit the
`$MEASUREMENT <https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2018/ENU/AutoCAD-Core/files/GUID-1D074C55-0B63-482E-8A37-A52AC0C7C8FE-htm.html>`__
and
`$INSUNITS <https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2018/ENU/AutoCAD-Core/files/GUID-A58A87BB-482B-4042-A00A-EEF55A2B4FD8-htm.html>`__
variables in the header template.

--------------


Expand Down
3 changes: 3 additions & 0 deletions ogr/ogrsf_frmts/dxf/ogr_dxf.h
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,9 @@ class OGRDXFWriterDS final : public GDALDataset

bool m_bHeaderFileIsTemp = false;
bool m_bTrailerFileIsTemp = false;
OGRSpatialReference m_oSRS{};
std::string m_osINSUNITS = "HEADER_VALUE";
std::string m_osMEASUREMENT = "HEADER_VALUE";

public:
OGRDXFWriterDS();
Expand Down
4 changes: 4 additions & 0 deletions ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,8 @@ bool OGRDXFDataSource::ReadHeaderSection()
}

oHeaderVariables[l_osName] = szLineBuf;
GDALDataset::SetMetadataItem(l_osName.c_str(), szLineBuf,
"DXF_HEADER_VARIABLES");
}
if (nCode < 0)
{
Expand Down Expand Up @@ -857,6 +859,8 @@ bool OGRDXFDataSource::ReadHeaderSection()
}

oHeaderVariables[l_osName] = szLineBuf;
GDALDataset::SetMetadataItem(l_osName.c_str(), szLineBuf,
"DXF_HEADER_VARIABLES");
}
if (nCode < 0)
{
Expand Down
22 changes: 22 additions & 0 deletions ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,28 @@ void RegisterOGRDXF()
"file' default='trailer.dxf'/>"
" <Option name='FIRST_ENTITY' type='int' description='Identifier of "
"first entity'/>"
" <Option name='INSUNITS' type='string-select' "
"description='Drawing units for the model space ($INSUNITS system "
"variable)' default='HEADER_VALUE'>"
" <Value>HEADER_VALUE</Value>"
" <Value>FROM_CRS</Value>"
" <Value alias='0'>UNITLESS</Value>"
" <Value alias='1'>INCHES</Value>"
" <Value alias='2'>FEET</Value>"
" <Value alias='4'>MILLIMETERS</Value>"
" <Value alias='5'>CENTIMETERS</Value>"
" <Value alias='6'>METERS</Value>"
" <Value alias='21'>US_SURVEY_FEET</Value>"
" </Option>"
" <Option name='MEASUREMENT' type='string-select' "
"description='Whether the current drawing uses imperial or metric "
"hatch "
"pattern and linetype ($MEASUREMENT system variable)' "
"default='HEADER_VALUE'>"
" <Value>HEADER_VALUE</Value>"
" <Value alias='0'>IMPERIAL</Value>"
" <Value alias='1'>METRIC</Value>"
" </Option>"
"</CreationOptionList>");

poDriver->SetMetadataItem(
Expand Down
Loading

0 comments on commit 9dd8963

Please sign in to comment.