Closed mozman closed 3 years ago
And cad_viewer.py
renders SHX fonts nicer than BricsCAD:
The marked text for the font TXT.SHX looks good here (see #332), but the magic is that this is not the TXT.SHX font, it is the ROMANS.SHX font which maps to "romans__.ttf"
I recognized yet that we have the possibility to vectorize text:
The red polylines shows the TextPath.vertices
, the white polylines are the polylines created by TextPath.to_polygons()
.
As you see the (0, 0) is an artifact and not a real boundary point of the char.
The Arial font used here uses only quadratic bezier curves, which I haven't implemented in my Path
class, but this would be easy to add, because quadratic bezier curves are much simpler and faster than cubic bezier curves. This would add text vectorization support with the help of matplotlib.
First string to ezdxf Path conversion using matplotlib, exported as LWPOLYLINE entities:
Example: https://github.com/mozman/ezdxf/blob/master/examples/text_string_to_path.py
... and as HATCH entities:
This is finally a function that I can use in my job :-). It is not possible in Allplan to create transparent text for watermarks, and even exploding text in BricsCAD creates only outlines (LWPOLYLINES), which have to be filled afterwards.
There seems to be an text rendering issue in the drawing add-on.
The red text is rendered by BricsCAD, the yellow outline is created by the text2path add-on using the matplotlib TextPath() rendering and the result is very close:
The same text rendered by cad_viewer.py:
example script: https://github.com/mozman/ezdxf/blob/master/examples/addons/text_entity_to_path.py
DXF file: entity2path.zip
This example shows the limits of my current approach for ALIGNED and FIT alignments:
The text created by text2path (yellow) is exact 12 drawing units wide as defined by insert=(0, 0) and align_point=(12, 0), but TrueView and BricsCAD render the text (red) a little bit narrower and with an offset to (0, 0).
The text2path add-on scales the paths by their bounding box extents. I have no idea if it's possible to render a text to an exact length by the matplotlib TextPath() render tool, it only supports a size parameter, but no width factor or anything similar to scale the length of the text.
This is an example where ezdxf is correct, but does not match the result of CAD applications.
PS: cad_viewer.py: FIT is perfect and ALIGNED has an incorrect text height. Which means the solution for the stretching problem is already solved in the drawing add-on!
ALIGNED is solved, was my fault by introducing an arbitrary scaling factor, but this factor was necessary for at least one example:
draw_cad.py is OK (perfect!) - the error has to be in the PyQt5 backend used by cad_viewer.py:
PS: Results in cad_viewer.py depend on the font:
Stretch factor of QFont was not set in the pyqt backend, but doing so makes the result worse :-(
if you want to go down this route, in my own code I'm using matplotlib to render the text paths and using Qt to display them. This way I can achieve the same results when rendering to images or displaying, but the matplotlib text rendering is unfortunately slower.
from PyQt5 import QtGui as qg
from matplotlib.path import Path as MatplotlibPath
def matplotlib_path_to_qt_path(path: MatplotlibPath) -> qg.QPainterPath:
out = qg.QPainterPath()
assert len(path.vertices) == len(path.codes)
points = list(reversed(path.vertices.tolist()))
codes = list(reversed(path.codes))
while codes:
code = codes.pop()
if code == MatplotlibPath.STOP:
points.pop()
elif code == MatplotlibPath.MOVETO:
out.moveTo(*points.pop())
elif code == MatplotlibPath.LINETO:
out.lineTo(*points.pop())
elif code == MatplotlibPath.CURVE3:
(x1, y1), (x2, y2) = points.pop(), points.pop()
assert codes.pop() == MatplotlibPath.CURVE3
out.quadTo(x1, y1, x2, y2)
elif code == MatplotlibPath.CURVE4:
(x1, y1), (x2, y2), (x3, y3) = points.pop(), points.pop(), points.pop()
assert codes.pop() == MatplotlibPath.CURVE4
assert codes.pop() == MatplotlibPath.CURVE4
out.cubicTo(x1, y1, x2, y2, x3, y3)
elif code == MatplotlibPath.CLOSEPOLY:
points.pop() # will be (0, 0)
out.closeSubpath()
else:
raise ValueError(code)
return out
The drawing add-on is more your baby :-).
For me the current status is good enough as this is only a problem for certain fonts, hopefully a minority of the fonts used in real drawings.
Luckily the default fonts which I have chosen, do not look that bad. I think we are as close to the (AutoCAD) standard as we can with reasonable effort (yellow outlines by matplotlib):
The magenta text frames are calculated by ezdxf with matplotlib support.
Arial Regular BricsCAD vs cad_viewer.py - this is very good:
Arial Narrow -
cad_viewe.py
stretches the text too wide:Arial Black perfect:
The example above shows also a problem of BOTTOM text alignment. BricsCAD (same in TrueView) renders the text with more space between baseline and descender:
Arial Regular:
Arial Black:
The font metrics do not show a difference which could explain this behavior. I guess this is not solvable with the tools we have.
Font measurements for Arial Regular:
Font measurements for Arial Black:
And now really strange things
Wrong TOP text alignment for font "Baby Kruffy":
Font measurements:
Letters: "Xxp" :-)
Font Bouton, where the current font measurement can not succeed:
Letters: "Xxp" :-)
Something positive at the end - regular fonts work very well:
Without the text frames it is hard to notice the difference to CAD applications: