Friday, April 10 2015

Importing Bézier curves into OpenSCAD

OpenSCAD has some fairly basic 2D drawing primitives. If you can’t draw it with circles and polygons, you have to either approximate with line segments or construct your shape with unions, intersections, differences, and scalings. Or you can import DXF files, with some limitations.

Sadly, the primary limitation is “does not support things like curves/splines”, which means that any nice curves have to be rendered to lines by the converter. Adobe Illustrator won’t even make the attempt, so most people use Inkscape for this.

However, with the most recent release, there’s a way to get high-quality curves into OpenSCAD with only a modicum of pain: custom fonts. Draw up a nice shape in Illustrator or Inkscape, save it as SVG, run it through FontForge, and then call the new text() module from your SCAD file. And you don’t even need to learn to use FontForge; you just need to download a version that has Python scripting enabled, and run a script like this:

#!/usr/bin/python
import sys
import fontforge
font = fontforge.font()
letter=65
for arg in sys.argv[1:]:
	char = font.createChar(letter)
	char.importOutlines(arg)
	letter+=1
font.familyname = "testfont"
font.generate('testfont.ttf')

Now you just need to copy the font into the same directory as your OpenSCAD file and tell it to render a letter (first SVG file is ‘A’, etc):

use <testfont.ttf>;
rotate_extrude() 
	text(text="A", size=100, font="testfont");

[Updated] In order to get the placement and sizing perfect, you should set the origin of your SVG file at (0,200) with a height of 720, in a 1000x1000 document with the unit set to pixels. It will render any SVG you throw at it, but because it’s being treated as a font, it will be aligned by the baseline and capheight parameters; no doubt a more robust script could adjust those for you. If you add a print char.boundingBox() line to the script, you’ll see how FontForge has translated your dimensions. Inkscape comes with a “FontForge Glyph” template that works well; just add a second guideline at y=920, and resize the page to match the width of your drawing before saving.

[Updated: I wrote a more robust svg2ttf script that resizes and repositions each SVG file to make them work. Character tracking is off a bit, so you want to use separate text() commands for each character, and not try to render multiple characters in one string.]

As usual, set $fs and $fa to adjust the rendering quality.

And here it is in action. The item on the left is a sake cup modeled in OpenSCAD (SCAD file). The one on the right is the same shape imported into Inkscape and tweaked inside and out. (SVG files: OpenSCAD, Inkscape)

Sakecup

Why a sake cup? Somewhere in the 120+ pages of “when do we get our Shapeoko 3’s” on the forums was a suggestion about what sort of thing to make first. Someone mentioned a common practice among 3D printer builders of making a shot glass and toasting their success (quickly, because alcohol doesn’t work well in those plastics). A typical shot glass is hard to make with a CNC mill, between the tapered sides and the depth, so I grabbed a sake cup off the shelf and knocked together a model of it. Both the top and bottom depths are possible with my 2.5-inch YG-1 ballnose end mill (getting it perfectly centered so the two sides match will require a bit of jigging…), and as long as you ignore exotic tropical hardwoods, you can drink out of it safely.

After the toast, I’ll put some sort of finish on it, most likely CA glue.

I actually did a 3D print of the original version at the office. It came out pretty nice, but the bottom was a bit rough due to the unsupported areas, which is another reason to do this sort of thing as a two-sided CNC job.