HiGreg figured out holes already, his last post talks about combining 2 separate polygons into one using very thin string.
Thank you both, @eelik and @qu1ck! I appreciate the gerber spec excerpt. I felt I learned enough about the problem and was seeking algorithmic solutions and upon review of options decided that the Clipper library was going to be useful. Then I looked at the KiCAD source code and, of course, the KiCAD developers needed the same functionality.
SHAPE_POLY_SET has several methods that might be useful. There are also boolean operations using the Clipper library (the library I would have chosen as well)
.Fracture (and Unfracture)
.Simplify
Within the Fracture() method, Simplify() is commented:
Simplify( aFastMode ); // remove overlapping holes/degeneracy
And simplify “just” does a union on all outlines of the SHAPE_POLY_SET.
The basic SHAPE_POLY_SET structure seems to support multiple outlines (filled contours) and multiple holes within each outline. However, this basic structure does not appear to be saved in full when saving the board (confirmed through experiment, but not yet through source code review). There doesn’t seem to be a method that returns several SHAPE_POLY_SETs that would allow adding those to the board as separate DRAWSEGMENT S_POLYGONs. I can do so in python if necessary. I’ll do more source code review and experimentation to find the right combination of functions, but it does seem at the moment that KiCAD provides the necessary methods and geometric functions.
And just for fun, here’s my field of fonts that I experiment with. It includes the full set of glyphs several times from several fonts.
Edit (followup): Fracture seems to work, basically. Here is a short experiment of saving. After loading, it looks perfect:
All I did was add a call to polyset.Fracture(1) the (1 indicates whether it is fastmode, 0 doesn’t work but 1 does). This seems to work with multiple holes (“B”). I think I’m currently creating polygons as separate SHAPE_POLY_SETs, so I’m not testing the capability of Fracture to work with multiple polygons.
When I try to process all the glyphs in the set, KiCAD crashes. I’m wondering whether this has to do with the inconsistent windings I saw earlier.
Ok. I tried to process all the glyphs in NotoSans-Regular again and it worked without crashing. Not sure why it crashed before. But after save and load, I only see a few artifacts from the fracture, which are totally acceptable. I’ve indicated a sample of the letters with (barely visible) artifacts with a pink dot below the letter.
Edit: drawing all the glyphs now takes significantly more time (4x-5x maybe). I am doing two things different: estimated winding with ALL points instead of “simplified points”. And Fracture()ing after each hole added to the SHAPE_POLY_SET. “Simplified points” are when I take Bezier curves and just add the end points and control points. I can estimate winding and (mostly accurate) which polygons are within others with the simplified.
I can speed some of this (back) up, but not all of it.
I myself did attempt to make a plug-in that uses HarfBuzz and FreeType to put glyphs onto PCB as a footprint (contains polygons), but never finished that. Perhaps someone else could revise this idea.
That’s a good idea. Maybe someone will continue with it! Thanks for posting these leads to open source libraries for working with fonts.
Just for fun, I downloaded a 3x5 (super small!) font ttf file and imported. I continue to fix bugs so there’s a reasonable interface for displaying characters within KiCAD using KiCommand. You can rotate, scale, and place text anywhere.
Still working through bugs. To do so, I’m printing large numbers of characters from a large number of fonts. Here’s my font list, I’ve printed out the name in the respective font. The list is too long to show detail along with the entire list, but here’s a zoomed out look at the list:
And a detail screenshot that shows some of the anomalies in CamBam fonts:
A KiCAD refresh takes a minute or so with 11000 characters, and crashes entirely when I try to print all characters from all these fonts. My thought is some CamBam characters might have unexpected contour definitions (i.e. crossing or touching). I also have to make sure there are no bizarre arrangements of existing characters as a result of my testing (improperly formed polygons or polygons located outside of -1000mm to 1000mm) which KiCAD might have trouble with.
Is there any possible optimizations that could be done to reduce the refresh time, I get its a very large number of polygons, but curious if its the drawing stage or some pre-processing that has to run each refresh?
I haven’t confirmed the environment (re: bizarre polygons or out-of-range locations). But if I can get to it, I can investigate more and file a bug report. Does anyone have similar experience with 11000 or more objects? (refresh is a call in Python to pcbnew.Refresh().
Edit: I’m now up to 25K polygon DRAWSEGMENT objects and refresh is less than a second. Here’s a partial screenshot of all characters in 40 different fonts. Not sure why the top 10 are not showing all of their characters.
I’ve been able to combine all the polygons in a single glyph into one DRAWSEGMENT. Previously, each individual polygon or character component that was an “outline” was its own DRAWSEGMENT, individually movable. Now, all of them are lumped into the same DRAWSEGMENT and the select/move together. This is done with .AddOutline() and .AddHole() on one DRAWSEGMENT S_POLYGON per glyph.
Note in the above screenshot the character “a” with diacritical marks above it are all selected as a single moveable DRAWSEGMENT. This is indicated by the selected DRAWSEGMENT having edit points defining the outline. If there were multiple DRAWSEGMENTs selected, KiCAD wouldn’t highlight the individual polygon points in the outlines.
It’s looking better each time I am able to work on it. I’ve been able to interpret OpenType fonts of type CFF and OpenType collections (*.otc files). That in addition to the TTF fonts above opens up a large number of available fonts. Here is a sample from
Noto-sans-cjk-jp-regular.
There’s still some work on tracking down the bugs in the glyphs for a, s, M, Q, S, 3, 4, and 8. I’m glad all the work I did on TTF character spacing carries over. What’s new here was building the KiFont files by the cycling through font collection, and interpreting the glyph information (“Character Strings”) in CFF and translating them to SVG. Then I relied on the SVG to KiCAD Polygon code I already had developed for TTF fonts.
Not easy, but fairly straightforward. Also interpreting the glyphs and building the KiFont files takes a long time, perhaps 2-3 minutes per font. There were 36 fonts in the CJK Sans OpenType collection. Plus the files are big, about 50MB per font. I’ll probably not try to reduce that until I get something published. For now, you only need to keep the font files from which you want to place characters. And once placed, you don’t need the files anymore.
The code probably supports TrueType collections, but that hasn’t been specifically tested yet.
Amazing work you are doing HiGreg.
Here are the 47000+ characters in the Noto-sans-cjk-jp-regular font. This comes from an OpenType Collection (*.otc) file along with 35 other fonts and variations.
A zoom in to the upper left reveals that some glyphs are still not quite right. Still investigating some of these. I’ve already found some glyph calculation errors, there must be a few more.
I finally got Noto-sans-cjk-jp-regular font printing with no errors. This was a whirlwind of (my own) bugs to find. A few things I had to get through include outlines are not all CW or CWW (as the font specification suggests), instead they were mixed. wn_PnPoly() algorithm to determine winding REQUIRES a clockwise winding to return the correct answer. SHAPE_POLY_SET.Fracture(1) needed to be done once instead of multiple times (after adding each hole doesn’t work). I finally put together a brute force determination of which outlines were supposed to be polygons and which were supposed to be holes. It probably will randomly fail if there are overlapping outlines (it depends on exactly which point is chosen for the in/out determination). I was using wn_PnPoly() for comparing which outlines were inside others, but I had to extend it to comparing all outlines with each other, then I can count the number of embedded polygons and alternately choose polygon, hole, polygon, etc. This can be optimized, but I’ll save that for another day. Most fonts are specified as non-zero winding, but there are some, apparently, that are even/odd winding. I’m probably conflating the two types of windings, as I have read in one place that for non-overlapping contours/outlines that it should result in the same answer. Either way, my current algorithm seems to be working for this font. I’ll try the other fonts in my list as time permits. And it takes about 6-7 minutes to print all 47000+ characters of this font using my Python code. Maybe I can reduce that, but I’m not sure.
I’m not sure if people like the super-frequent updates on progress, or the large image files. Hopefully this isn’t too much posting…
Here’s a snippet of 80 fonts printed in full. I’m seeing a consistent error with the overlapping circles glyph but other than that, it looks pretty clean. I’m also seeing that some fonts don’t have unicode tables, particularly the “symbols” fonts (or I’m not interpreting the unicode tables correctly). I’ll have to come up with an algorithm (at some point) for overlapping contours, but the current algorithm looks to be working well for most glyphs in the Noto fonts and a few others (osifont, times new roman).
Its good to see the updates, some of us have wanted other fonts for a long time now,
Is this being merged to the nightlies? or will that happen when your happy with the few edge cases
This is all python code. It will be published with KiCommand python plugin. But I know using KiCommand is a hurdle for some people (KiCommand is a stack-based command line for KiCAD in development since 2017). I’m trying to separate out the font code so it could theoretically be separated out into its own plugin. Ideally someone (maybe me) will create a dedicated GUI for font placement. Whether I do all of that part or someone else does is still to be seen. The Python font code will be first available on the KiCommand github. I’d be happy to summarize the code structure if anyone is interested (or you can just wait for the code).
Work continues on fonts. Because it is difficult to add Python packages to KiCAD python (at least on Windows), I’ve created a separate Python3 program that converts font files (ttf, otf) and font collection files (ttc, otc) into a format suitable for the KiCAD font system I’ve created. The font format is simply a pickle file (created with the pickle Python package) of the font class I’ve written. The font class carries glyphs, glyph names, unicode conversion table, and spacing parameters. Glpyhs are stored as SVG contours and converted to polygons right before placing on the board. Right now I’m focused on left to right fonts only, but others could be supported in the future. Creating this program bypasses the need for me to provide fonts and all of the licensing issues that that entails. With this program, you supply your own TrueType or OpenType font files (or font collection files). This means you could use any fonts you wish.
The fontimport.py is a Python 3.7 file and requires the fontTools Python package to be installed on your system. If you think this will be a barrier for you, please let me know.
On my system, I execute the following on the command line to get help from fontimport.py:
python fontimport.py -h
Here is the current help text for the fontimport.py file:
usage: fontimport.py [-h] [--version] [--output OUTPUT] [--input INPUT]
[--recursive] [--exec]
optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
--output OUTPUT output directory
--input INPUT input directory or file
--recursive search find files recursively when --input is a directory
--exec without this option, just list environment and files, but do not write to the output. Actually writing to the output requires this option.
The font system is integrated into KiCommand. If you are interested in adding a variety of fonts to your project (or just a font different that KiCAD default font), you may want to have a peek at KiCommand in preparation. It’s currently working on KiCAD 5.1.6-release. There’s a README file on github and a tutorial and a discussion thread on this forum. It’s been designed on Windows and is tested well there. I’ve seen it used on MacOS, but I don’t know if Linux is working. KiCAD on Windows uses Python 2.7, but I think the other OSes are using Python 3. If you have a chance to test KiCommand on MacOS or Linux, please let me know in the Discussion thread or github issues about any problems you discover. If it works without problems, please let me know in the Discussion thread.
There will be new KiCommand commands to place font characters on the board. Here is a sampling of commands in their current state:
- Noto-sans-regular setfont - set the current font to Noto-sans-regular
- "Hello World" stringtogeom newdrawing refresh - print Hello World in the current font at 0,0
- Tmm,235,47 split “Board Version 1.0” stringtogeom append newdrawing refresh - print the indicated string at location 235,37 specified in mm
The default font size is 10 points, where a point is 1/72 of an inch (this is the industry definition of a point, in fontspeak). The “font size” is an indication of the size of the “em height” which is roughly the height of the “m” character. So by default, characters print out at 0.14" or 3.5mm. You can scale with the S parameter like this:
- S,2,Tmm,235,37 split “Board Version 1.0” stringtogeom append newdrawing refresh - print the indicated string at coordinates (mm) 235,37 at 2 times the default size. Perhaps I’ll modify the size indicator at some point to take advantage of a text height parameter (similar to the way KiCAD text size is handled)
You can embed control characters like newline (\n) or unicode characters with \uXXXX notation where the XXXX is the hexadecimal unicode code point. The wxWidget input to KiCommand should also be able to handle direct unicode input, but I haven’t tried that yet.
There are also ways to specify the accuracy of the bezier approximation by specifying a number of “steps”.
- beziersteps 5 int params - change the bezier steps parameter to 5 (which happens to be the default)
Here is the lowercase “b” with 2, 3, 4, and 5 bezier steps:
I’ve had no real problems specifying up to 30 steps, but the increase accuracy doesn’t seem worth the significantly larger number of polygon points. Steps of 5 seem sufficient, and maybe up to 10 might be good for super smooth curves. Because I’m not sure of the best number of steps, it can be changed by users.
It would be great to have a GUI to add board text in any chosen font, I just haven’t had the time to build one, and KiCommand seemed like a good way to verify basic functionality and get the fonts tested by a variety of users and systems.
Let me know if you have a specific font you want me to test, and I will, if it is freely available.
Please post comments or questions here.
Edit: clarified that polygons are used on the board, and fixed command-line argument “–exec”
KiCommand preliminary font support has been published to github.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.