mozman / ezdxf

Python interface to DXF
https://ezdxf.mozman.at
MIT License
930 stars 191 forks source link

bbox bug on text location calculation #402

Closed chibai closed 3 years ago

chibai commented 3 years ago

test.zip

from ezdxf import recover, bbox
dxf_doc, dxf_auditor= recover.readfile('test.dxf')
cache = bbox.Cache(uuid=False)
ext = bbox.extents(dxf_doc.modelspace(), cache = cache)
print(ext)

I get error below: Traceback (most recent call last): File ".\test.py", line 7, in ext = bbox.extents(dxf_doc.modelspace(), cache = cache) File "D:\Development\Python\Python38\lib\site-packages\ezdxf\bbox.py", line 133, in extents for box in multi_flat(entities, flatten=flatten, cache=cache): File "D:\Development\Python\Python38\lib\site-packages\ezdxf\bbox.py", line 160, in multiflat box = extends([entity]) File "D:\Development\Python\Python38\lib\site-packages\ezdxf\bbox.py", line 150, in extends_ for _box in multirecursive(entities, flatten=flatten, cache=cache): File "D:\Development\Python\Python38\lib\site-packages\ezdxf\bbox.py", line 105, in multi_recursive
for primitive in primitives: File "D:\Development\Python\Python38\lib\site-packages\ezdxf\disassemble.py", line 540, in to_primitives yield make_primitive(e, max_flattening_distance) File "D:\Development\Python\Python38\lib\site-packages\ezdxf\disassemble.py", line 471, in make_primitive primitive = cls(entity) File "D:\Development\Python\Python38\lib\site-packages\ezdxf\disassemble.py", line 109, in init self._convert_entity() File "D:\Development\Python\Python38\lib\site-packages\ezdxf\disassemble.py", line 384, in _convert_entity content: List[str] = get_content() File "D:\Development\Python\Python38\lib\site-packages\ezdxf\disassemble.py", line 303, in get_content return text_wrap(text, box_width, font.text_width) File "D:\Development\Python\Python38\lib\site-packages\ezdxf\tools\text.py", line 495, in text_wrap if box_width is not None and get_text_width( File "D:\Development\Python\Python38\lib\site-packages\ezdxf\tools\fonts.py", line 431, in text_width return max(path.vertices[:, 0].tolist()) * self._width_factor File "D:\Development\Python\Python38\lib\site-packages\matplotlib\textpath.py", line 417, in vertices self._revalidate_path() File "D:\Development\Python\Python38\lib\site-packages\matplotlib\textpath.py", line 438, in _revalidate_path self._cached_vertices = tr.transform(self._vertices) File "D:\Development\Python\Python38\lib\site-packages\matplotlib\transforms.py", line 1717, in transform return self.transform_affine(values) File "D:\Development\Python\Python38\lib\site-packages\matplotlib\transforms.py", line 1799, in transform_affine return affine_transform(points, mtx) RuntimeError: In affine_transform: Invalid vertices array.

I was wondering is there any way to avoid this kind of error

mozman commented 3 years ago

image

Your STYLE settings causes a runtime error in Matplotlib.

You are using the bigfont attribute in the STYLE entity to define the font. This is not supported by ezdxf, because I have no clue how this works. The font attribute references the Simplex.shx font which is not suitable to represent chinese characters.

The only advice I can give you is to choose a working TTF font, don't use SHX fonts.

chibai commented 3 years ago

Thanks for your helping, but the fonts problem of chinese text really makes me frustrated

chibai commented 3 years ago

image

Your STYLE settings causes a runtime error in Matplotlib.

You are using the bigfont attribute in the STYLE entity to define the font. This is not supported by ezdxf, because I have no clue how this works. The font attribute references the Simplex.shx font which is not suitable to represent chinese characters.

The only advice I can give you is to choose a working TTF font, don't use SHX fonts.

Thanks for your answer~~I think I can update the font of TEXT and MLTEXT to make my program work smoothly. For MLTEXT, I found function <set_font(name: str, bold: bool = False, italic: bool = False, codepage: int = 1252, pitch: int = 0) → None > may make it work But for TEXT, I can't find a font update function.

Whould you please tell me how can I change the text font for TEXT and MLTEXT in ezdxf?? Thanks a lot!

mozman commented 3 years ago

This does not solve your problem in conjunction with ezdxf. The root of the problem for ezdxf is the font attribute of the text STYLE entity not the MTEXT entity itself. Create a new text style with a working TTF font and assign this text style as new style attribute to the problematic TEXT and MTEXT entities:

import ezdxf

doc = ezdxf.readfile("test.dxf")
doc.styles.new('SIMSUN', dxfattribs={'font': 'simsun.ttf'})
msp = doc.modelspace()
for e in msp.query('MTEXT TEXT'):
    e.dxf.style = 'SIMSUN'
doc.saveas('simsun.dxf')

The simsun.ttf font seems to be a reliable font for the chinese language. The font seems to be installed automatically by Windows or an Autodesk product as it is also available in my western W10 setup and I did not install the font manually.

Special solution, exact for your example, fix only the text styles with a bigfont attribute:

for style in doc.styles:
    if style.dxf.bigfont:
        style.dxf.font = "simsun.ttf"
        style.dxf.bigfont = ""
mozman commented 3 years ago

The real issue is that the MTEXT entity uses inline codes to switch the font {\fSimSun|b0|i0|c134|p2;主入口}, these inline codes are ignored by ezdxf and falls back to the fonts defined by the associated STYLE entity (see posts above). In this case Matplotlib and PyQt fall back to their default font, but the PyQt default font handles more unicode characters than the Matplotlib default font. Therefore the drawing add-on crashes by using the Matplotlib backend too, but the PyQt backend handles the MTEXT entity correct, if you ignore the fact that the default font is ugly.

chibai commented 3 years ago

This does not solve your problem in conjunction with ezdxf. The root of the problem for ezdxf is the font attribute of the text STYLE entity not the MTEXT entity itself. Create a new text style with a working TTF font and assign this text style as new style attribute to the problematic TEXT and MTEXT entities:

import ezdxf

doc = ezdxf.readfile("test.dxf")
doc.styles.new('SIMSUN', dxfattribs={'font': 'simsun.ttf'})
msp = doc.modelspace()
for e in msp.query('MTEXT TEXT'):
    e.dxf.style = 'SIMSUN'
doc.saveas('simsun.dxf')

The simsun.ttf font seems to be a reliable font for the chinese language. The font seems to be installed automatically by Windows or an Autodesk product as it is also available in my western W10 setup and I did not install the font manually.

Special solution, exact for your example, fix only the text styles with a bigfont attribute:

for style in doc.styles:
    if style.dxf.bigfont:
        style.dxf.font = "simsun.ttf"
        style.dxf.bigfont = ""

Thanks a lot! I need a general solution, so I choose your first solution~ It really works!!

mozman commented 3 years ago

I have to disappoint you, this is not a generic solution, this works only if only chinese characters are used. If you have DXF documents with e.g. chinese and arabic characters, this will not work and I assume there is no simple generic solution for this problem. The commit f22dc9281cfa8e42600fcd9a8e1665403e804049 solves the crash but nothing else. The DXF format was designed only with AutoCAD in mind and therefore relies on the infrastructure installed by AutoCAD and AutoCAD as the CAD application. DXF was designed to ensure AutoCAD cross-platform compatibility in the early days when different hardware platforms with different binary data formats were common. The name DXF (Drawing eXchange Format) may suggest a universal exchange format, but it is not.

chibai commented 3 years ago

Got it! Sir!!