OSGeo / gdal

GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.
https://gdal.org
Other
4.77k stars 2.5k forks source link

DXF: cannot read SPLINE without control points #10397

Open tlguoc opened 1 month ago

tlguoc commented 1 month ago

What is the bug?

Hello, when I open the dxf file using gdal, the following error occurs: ERROR 1: E:\buildsystem\src\gdal-3-9-vc16x64\ogr\ogrsf_frmts\dxf\ogrdxflayer.cpp, 2158: error at line 14182 of D:...myfile.dxf

Steps to reproduce the issue

The data blocks that throw exceptions are as follows: AcDbSpline 71 3 74 5 42 0.0000001 43 0.0000001 44 0.0000000001 12 0.0 22 0.0 32 0.0 13 0.0 23 0.0 33 0.0 11 -0.000000000000000389 21 2.4000000000000004 31 0.0 11 0.12152369922108264 21 2.524917634128653 31 0.0 11 0.29408421623707781 21 2.5908671836230353 31 0.0 11 0.50232461270399753 21 2.6376008372037889 31 0.0 11 0.79996846968402602 21 2.9000504449667028 31 0.0 0

Versions and provenance

I am using GDAL-3.9.0 version,windows 11

Additional context

No response

tlguoc commented 1 month ago

![Uploading errorData.png…]()

rouault commented 1 month ago

@tlguoc Please share a whole file. Does it open fine in other DXF readers?

rouault commented 1 month ago

I've tried to investigate, by adapting the content above into one of the sample DXF file of GDAL test suite: test.dxf.zip The error I get on reading is: ERROR 1: /home/even/gdal/gdal/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp, 2165: error at line 68 of test.dxf Investigating further, I see that OGRDXFLayer::InsertSplineWithChecks() returns a nullptr because the check at line https://github.com/OSGeo/gdal/blob/064ce89ca2c2328cd0cf1e120c4f7f9a2d7e61b6/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp#L2204 fails. At that point, adfControlPoints is just the single {0} init value, nControlPoints = 0 and nOrder = 4. So this object is missing at least 4 control points with codes 10 and 20, which are absent in the snippet given above. Either the DXF objet is incorrect, or the InsertSplineWithChecks() routine totally misses a potential valid case CC @atlight

atlight commented 1 month ago

According to the DXF docs (pages 130-121), the group codes 11, 21, 31 are used for specifying a spline's fit points (not control points). However GDAL does not handle these group codes at all: https://github.com/OSGeo/gdal/blob/064ce89ca2c2328cd0cf1e120c4f7f9a2d7e61b6/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp#L2074-L2083

The reason this has never come up before is because the major CAD packages always write out the control points for splines using group codes 10, 20, 30. If the user defined the spline by its fits points, the CAD package does write out 11, 21, 31 group codes (fit points), but it also writes out the 10, 20, 30 group codes (control points). So GDAL only needs to be able to read control points in order to be able to render any spline.

At least that's the theory. @tlguoc's file says otherwise. Where did this file come from? Was it hand-crafted by you?

tlguoc commented 1 month ago

According to the DXF docs (pages 130-121), the group codes 11, 21, 31 are used for specifying a spline's fit points (not control points). However GDAL does not handle these group codes at all:

https://github.com/OSGeo/gdal/blob/064ce89ca2c2328cd0cf1e120c4f7f9a2d7e61b6/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp#L2074-L2083

The reason this has never come up before is because the major CAD packages always write out the control points for splines using group codes 10, 20, 30. If the user defined the spline by its fits points, the CAD package does write out 11, 21, 31 group codes (fit points), but it also writes out the 10, 20, 30 group codes (control points). So GDAL only needs to be able to read control points in order to be able to render any spline.

At least that's the theory. @tlguoc's file says otherwise. Where did this file come from? Was it hand-crafted by you?

First of all, thank you very much for your question. My dxf file was generated by converting DWG through aspose.cad. I have two files, using Datasource ds=ogr Open(dxfPath, 0); When using the method, the same error as the one asked above will also be printed, but in the end, ds will return it, but the other copy will not, and ds will return null. I compared two dxf files that reported errors and found that they were both errors when reading data from the dxf file AcDbSpline. Among the files where ds returned null, there was only one AcDbSpline, while the other dxf file had 17 AcDbSplines. However, only 15 exceptions were thrown, and the final returned ds was not null.

atlight commented 1 month ago

Okay, if Aspose.CAD is generating these, we should support them. It's worth noting that AutoCAD can read this style of spline just fine, even though GDAL currently can't.

We already have logic to calculate a spline from its control points, currently only used for spline leaders: https://github.com/OSGeo/gdal/blob/064ce89ca2c2328cd0cf1e120c4f7f9a2d7e61b6/ogr/ogrsf_frmts/dxf/ogrdxf_leader.cpp#L1261

So it's just a matter of extending that logic to SPLINE entities whose control points are not specified.