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

boundingbox calculation bug in ezdxf #574

Closed
chibai opened this issue Nov 5, 2021 · 10 comments
Closed

boundingbox calculation bug in ezdxf #574

chibai opened this issue Nov 5, 2021 · 10 comments

Comments

@chibai
Copy link

chibai commented Nov 5, 2021

Describe the bug
In this dxf file, I want to calculate the boundingbox of whole image.
But I think this result is wrong.

test.zip

To Reproduce

from pathlib import Path
import ezdxf
from ezdxf import bbox
doc = ezdxf.readfile('test.dxf')
cache = bbox.Cache()
ext = bbox.extents(doc.modelspace(), cache= cache)
print(ext)

result is below:

python test.py
findfont: Font family [''] not found. Falling back to DejaVu Sans.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
[(-2531981575.7466483, 1204.7609229232767, -0.0008778303645091671), (2532846575.411637, 68940.94752145144, 151.9999999995343)]

Expected behavior
I wish the boudingbox calculation could correct

Screenshots
1636081265(1)

mozman added a commit that referenced this issue Nov 7, 2021
mozman added a commit that referenced this issue Nov 7, 2021
@mozman
Copy link
Owner

mozman commented Nov 7, 2021

Fixed calculation returns: [(43602.91986147462, 1204.7609229232767, -0.0008778303645091671), (472897.0736118274, 68940.94752145144, 151.9999999995343)]

There are hidden entities on a disabled layer!

image

@chibai
Copy link
Author

chibai commented Nov 8, 2021

@mozman Dear, found another one
test.zip

import ezdxf
from ezdxf import bbox
doc = ezdxf.readfile('test.dxf')
cache = bbox.Cache()
ext = bbox.extents(doc.modelspace(), cache= cache)
print(ext)
Traceback (most recent call last):
  File "E:\projectsDevelopment\ezdxf_test\test.py", line 6, in <module>
    ext = bbox.extents(doc.modelspace(), cache= cache)
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\bbox.py", line 141, in extents
    for box in multi_flat(entities, flatten=flatten, cache=cache):
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\bbox.py", line 171, in multi_flat
    box = extends_([entity])
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\bbox.py", line 161, in extends_
    for _box in multi_recursive(entities_, flatten=flatten, cache=cache):
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\bbox.py", line 110, in multi_recursive
    for primitive in primitives:
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\disassemble.py", line 560, in to_primitives
    yield make_primitive(e, max_flattening_distance)
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\disassemble.py", line 505, in make_primitive
    primitive = cls(entity)
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\disassemble.py", line 119, in __init__
    self._convert_entity()
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\disassemble.py", line 298, in _convert_entity
    corner_vertices = text_line.corner_vertices(
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\tools\text.py", line 158, in corner_vertices
    return TextLine.transform_2d(
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\tools\text.py", line 223, in transform_2d
    insert = Vec3(insert)
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\math\_vector.py", line 61, in __init__
    self._x, self._y, self._z = self.decompose(*args)
  File "E:\Python\Python39\lib\site-packages\ezdxf-0.17.1b3-py3.9.egg\ezdxf\math\_vector.py", line 168, in decompose
    length = len(data)
TypeError: object of type 'NoneType' has no len()

This dxf file is transfered from AutoCad after command AUDIT

@chibai
Copy link
Author

chibai commented Nov 18, 2021

Dear mozman
@mozman
test.zip
There's a complex dxf file, make the python program broken~~Is that because out of memory?

import ezdxf
from ezdxf import bbox
doc = ezdxf.readfile('test.dxf')
cache = bbox.Cache()
visible_non_text_entities = [e for e in doc.modelspace() if e.dxf.invisible == 0 and e.dxftype() not in ['MTEXT', 'TEXT', 'ATTRIB', 'HATCH']]
ext = bbox.extents(visible_non_text_entities, cache= cache)
print(len(list(visible_non_text_entities)))
print(ext)

results is below

python test.py
findfont: Font family [''] not found. Falling back to DejaVu Sans.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.
Matplotlib RuntimeError: In affine_transform: Invalid vertices array.

@mozman
Copy link
Owner

mozman commented Nov 18, 2021

I have no idea why this crashes and the debugger doesn't help. I can only fix this if you find a simpler example for this issue.

@chibai
Copy link
Author

chibai commented Nov 18, 2021

I have no idea why this crashes and the debugger doesn't help. I can only fix this if you find a simpler example for this issue.

import ezdxf
from ezdxf import bbox
doc = ezdxf.readfile('test.dxf')
cache = bbox.Cache()
visible_non_text_entities = [e for e in doc.modelspace() if e.dxf.invisible == 0 and e.dxftype() not in ['MTEXT', 'TEXT', 'ATTRIB', 'HATCH']]
for entity in visible_non_text_entities:
    print(entity)
    print(bbox.extents([entity], cache=cache))
#ext = bbox.extents(visible_non_text_entities, cache= cache)
print(len(list(visible_non_text_entities)))
#print(ext)

I can identify the broken time: when calculate the boundingbox of INSERT(#7C32)
I'm trying to separate the single INSERT as one DXF file

@mozman
Copy link
Owner

mozman commented Nov 18, 2021

The real culprit are the INSERT 17ED and the LWPOLYLINES 17E7 and 17E8 which have an elevation of 2.99...e+99 which moves them very far into the territory of floating point imprecision errors.

EDIT: this is the first useful application for the new property DXFEntity.source_of_copy

@chibai
Copy link
Author

chibai commented Nov 18, 2021

The real culprit are the INSERT 17ED and the LWPOLYLINES 17E7 and 17E8 which have an elevation of 2.99...e+99 which moves them very far into the territory of floating point imprecision errors.

EDIT: this is the first useful application for the new property DXFEntity.source_of_copy

Any plan or idea to fix this?

@mozman
Copy link
Owner

mozman commented Nov 18, 2021

Setting the elevation of all INSERT entities to 0 is maybe a hot-fix:

for e in doc.entitydb.values():
    if e.dxftype() == "INSERT":
        e.dxf.insert = e.dxf.insert.replace(z=0)

For the real fix I need some time.

@chibai
Copy link
Author

chibai commented Nov 18, 2021

Setting the elevation of all INSERT entities to 0 is maybe a hot-fix:

for e in doc.entitydb.values():
    if e.dxftype() == "INSERT":
        e.dxf.insert = e.dxf.insert.replace(z=0)

For the real fix I need some time.

Got it, I will update it in my code~

mozman added a commit that referenced this issue Nov 18, 2021
Added a check for suddenly big distances (>1e12) which
can occur for very big coordinates.

2.9999999999e99 - 2.9999999998e99 = 9.999985256176552e+88

A small floating point imprecision in the mantissa can lead
to large differences, which broke the current implementation
of the path flattening algorithm.

The fix is to stop the recursion for sagitta distances > 1e12,
which is just an educated guess and is most likely not
the final solution for this issue.
mozman added a commit that referenced this issue Nov 18, 2021
Added a check for suddenly big distances (>1e12) which
can occur for very big coordinates.

2.9999999999e99 - 2.9999999998e99 = 9.999985256176552e+88

A small floating point imprecision in the mantissa can lead
to large differences, which broke the current implementation
of the path flattening algorithm.

The fix is to stop the recursion for sagitta distances > 1e12,
which is just an educated guess and is most likely not
the final solution for this issue.
mozman added a commit that referenced this issue Nov 18, 2021
@mozman
Copy link
Owner

mozman commented Nov 18, 2021

The bounding box calculation for the last example should work. Please close this issue if the fix work for you and do not add further example files, just open a new issue. The bounding box calculation just shows the issues, the errors causing the issues are different.

@chibai chibai closed this as completed Nov 22, 2021
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).
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