Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling "path.flattening()" on some DXF files crashes the Python interpreter #663

Closed
angelo-aldrovandi-hydro-com opened this issue Apr 4, 2022 · 4 comments

Comments

@angelo-aldrovandi-hydro-com
Copy link

angelo-aldrovandi-hydro-com commented Apr 4, 2022

Making a path out of a POLYLINE and calling path.flattening() crashes the Python interpreter with 0xC00000FD with some DXF files (which look completely normal files).

This is a code snippet you might use:


doc, _ = ezdxf.recover.readfile(filename)
entities = list(doc.modelspace().query('POLYLINE LWPOLYLINE'))
for entity in entities:
path = ezdxf.render.path.make_path(entity)
# This crashes Python interpreter with 0xC00000FD
vertices = list(path.flattening(tolerance))
# render/path.py:671 -> return Bezier4P((s, c1, c2, e)).flattening(distance, segments)


I'm Python 3.8.7 64bit on Windows 10 and ezdxf==0.15.2 (but I also tried 0.17.2, current stable version at the time of writing)

Thanks in advance for your support 👍

Crash.zip

@angelo-aldrovandi-hydro-com angelo-aldrovandi-hydro-com changed the title Loading some DXF files could crash Python interpreter Calling "path.flattening()" on some DXF files crashes the Python interpreter Apr 4, 2022
@mozman
Copy link
Owner

mozman commented Apr 4, 2022

This is a know issue if handling with big coordinates. The POLYLINE entity has an elevation of 1.391912e+19.
The bezier interpolation algorithm returns points with floating point imprecision like z=1.3919120000000002e+19, which looks not much but 1.391912e+19 - 1.3919120000000002e+19 = -2048.0. I have added an emergency exit for suddenly very large distances, but this max value is currently 1e12 which does not cover this example.

I have no idea how to solve this issue. The best solution is to keep coordinates of entities in the range of planet earth ;-).

I will try to avoid the stack overflow in the c-extension.

@mozman
Copy link
Owner

mozman commented Apr 4, 2022

A fix could be to translate this entities to the xy-plane:

from ezdxf import path
...

for e in doc.modelspace().query('POLYLINE LWPOLYLINE'):
    z = e.dxf.elevation.z
    if z > 1e12:
        e.translate(0, 0, -z)
    p = path.make_path(e)
    vertices = list(p.flattening(tolerance))

mozman added a commit that referenced this issue Apr 5, 2022
This solution is also not perfect, the result differs from
the result with small coordinates, but at least no recursion
error will be raised.

The perfect solution would be:

1. detect curve control point extents
2. move curve near origin and store original offset
3. flatten curve and add offset to result vertices
4. move curve back, if curve processing handled inplace
   as the current implementation does

This is too much additional processing for a slightly
better result and large coordinates are the exception
like elevation > 1e12 in some 2D DXF files!
mozman added a commit that referenced this issue Apr 5, 2022
This uses the first control point as offset and stores
the curve with start point = origin = (0, 0, 0).

This avoids floating point errors with large coordinates
(like #574, #663) if the control points are "close" together
but are located in "outer space" (elevation issue).
@angelo-aldrovandi-hydro-com
Copy link
Author

Thanks for your reply, the workaround is working indeed 👍 I will also implement some scale-check on loading, I guess it's on the z-plane only, because drawings must be otherwise properly scaled. Thanks again!

@mozman
Copy link
Owner

mozman commented Apr 5, 2022

The latest implementation should fix the large coordinate issue for Bezier4P and Bezier3P curves (representation of arcs in paths) by internally translating the curve to the origin of the coordinate system, start point of the curve is (0, 0, 0).

The only unresolved problem are curves where the distances between control points are very large, but this is an inherent floating point problem.

@mozman mozman closed this as completed Apr 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants