// Creates a 3D text block that can be attached to other attachable objects.
// You cannot attach children to text.
// .
// Historically fonts were specified by their "body size", the height of the metal body
// on which the glyphs were cast. This means the size was an upper bound on the size
// of the font glyphs, not a direct measurement of their size. In digital typesetting,
// the metal body is replaced by an invisible box, the em square, whose side length is
// defined to be the font's size. The glyphs can be contained in that square, or they
// can extend beyond it, depending on the choices made by the font designer. As a
// result, the meaning of font size varies between fonts: two fonts at the "same" size
// can differ significantly in the actual size of their characters. Typographers
// customarily specify the size in the units of "points". A point is 1/72 inch. In
// OpenSCAD, you specify the size in OpenSCAD units (often treated as millimeters for 3d
// printing), so if you want points you will need to perform a suitable unit conversion.
// In addition, the OpenSCAD font system has a bug: if you specify size=s you will
// instead get a font whose size is s/0.72. For many fonts this means the size of
// capital letters will be approximately equal to s, because it is common for fonts to
// use about 70% of their height for the ascenders in the font. To get the customary
// font size, you should multiply your desired size by 0.72.
// .
// To find the fonts that you have available in your OpenSCAD installation,
// go to the Help menu and select "Font List".
// Arguments:
// text = Text to create.
// size = The font will be created at this size divided by 0.72. Default: 10
// font = Font to use. Default: "Liberation Sans" (standard OpenSCAD default)
// ---
// halign = If given, specifies the horizontal alignment of the text. `"left"`, `"center"`, or `"right"`. Overrides `anchor=`.
// valign = If given, specifies the vertical alignment of the text. `"top"`, `"center"`, `"baseline"` or `"bottom"`. Overrides `anchor=`.
// spacing = The relative spacing multiplier between characters. Default: `1.0`
// direction = The text direction. `"ltr"` for left to right. `"rtl"` for right to left. `"ttb"` for top to bottom. `"btt"` for bottom to top. Default: `"ltr"`
// language = The language the text is in. Default: `"en"`
// script = The script the text is in. Default: `"latin"`
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"baseline"`
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#subsection-spin). Default: `0`
// Named Anchors:
// "baseline" = Anchors at the baseline of the text, at the start of the string.
// str("baseline",VECTOR) = Anchors at the baseline of the text, modified by the X and Z components of the appended vector.
// Several parameters are the same as for OpenSCAD's builtin `text()`. Some don't seem to have any effect, but are present here for compatibility: `direction`, `language`, and `script`.
// Arguments:
// string = The text to generate. Any leading whitespace, trailing whitespace, and consecutive spaces are stripped before word-wrapping.
// width = the maximum width of a line of text in display units.
// ---
// optimize = When false, tries to fit as many words as possible on each successive line, which may result in a widow (a word all by itself) on the last line. When true, attempts to make the wrapped lines more equal in length. Default: true
// size = font size (decimal number). See the [OpenSCAD documentation](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text) for this the following parameters.
// font = The name of the font that should be used, including an optional style parameter. Default: `"Liberation Sans:style=Bold"` (for OpenSCAD builds before 2021-08-16, default is `"Liberation Mono:style=Bold"`)
// spacing = Factor to increase/decrease the character spacing. Default: 1.0
// direction = Direction of the text flow, "ltr" (left-to-right), "rtl" (right-to-left). This function does not support "ttb" (top-to-bottom), or "btt" (bottom-to-top). Default: "ltr"
// language = Two-letter language code for the text. Default: "en"
// script = The script of the text. Default: "latin"
// charwidth = monospace character width to use for OpenSCAD builds prior to 2021-08-16. If not set, the value is calculated as 83.35% of the font size using font "Liberation Mono:style=Bold". Setting this in later builds results in an error. Default: undef
// Example: Basic textwrap of a single long string to fit within 240 units. Because line length optimization is enabled by default, the resulting lines have roughly equal length, although significantly narrower than 240 units.
// Example: Here is the same thing but with optimization disabled. The lines are as wide as can fit within 240 units for the specified font (and default `size=10`), with a lone word by itself on the last line.
// Example: Here is a longer string with a space between two newlines (`\n \n`) inserted to create paragraphs separated by a blank line. In this case, the optimization tries to maintain equal margins for both paragraphs, and sacrifices the length of the last line of the first paragraph to avoid the second paragraph wrapping to another line.
/// Private function: _get_lines_maxwid(), called by textwrap() and _wrap_optimize()
/// Return the maximum width of the lines represented by line_indexes, which contains array indexes pointing into cumlen, a list of cumulative lengths at end of each word.
// text_array = An array of text strings to display. The array may be a simple list of strings, or a list of paragraphs as returned from `textwrap()`, with each paragraph being a list of strings.
// line_spacing = the proportion of font interline height to use for line spacing. The interline height accounts for the nominal extents of ascenders and descenders in the font glyphs. The actual character size is typically about 72% of the interline height. Default: 1.0
// justify = The horizontal alignment for the text within its bounding box. Possible values are "left", "center", "right", and "full". When `justify="full"` the spaces between words are stretched so that the left and right ends of each line align with the sides of the bounding box. Default: "left"
// justify_last = How to justify the last line of multi-line text in a paragraph. Possible values are the same as for `justify`. This overrides the `justify` parameter if the paragraph consists of a single line. Default: "left"
// size = font size (decimal number). See the [OpenSCAD documentation](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text) for this and following parameters. Default: 10
// font = The name of the font that should be used, including an optional style parameter. Default: `"Liberation Sans:style=Bold"` (for OpenSCAD builds before 2021-08-16, the default is `"Liberation Mono:style=Bold"`)
// spacing = Factor to change the character spacing. Default: 1.0
// direction = Direction of the text flow, "ltr" (left-to-right), "rtl" (right-to-left). This function does not support "ttb" (top-to-bottom), or "btt" (bottom-to-top). Default: "ltr"
// language = Two-letter language code for the text. Default: "en"
// script = The script of the text. Default: "latin"
// $fn = used for subdividing the curved path segments.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `BOTTOM+LEFT`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
// Example(3D,Med): Wrap some text and extrude the resulting array in 3D.
//string="Goplacidlyamidthenoiseandhaste,\
// and remember what peace there may be in silence.";
// text_array = An array of text strings. The array may be a simple list of strings, or a list of paragraphs as returned from `textwrap()`, with each paragraph being a list of strings. If you have a single string of text, then convert it to a list by surrounding it with square brackets; that is, `string` would be passed as `[string]`.
// line_spacing = the proportion of font interline height to use for line spacing. Default: 1.0
// size = font size (decimal number). See the [OpenSCAD documentation](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text) for this and following parameters. Default: 10
// font = The name of the font that should be used, including an optional style parameter. Default: "Liberation Sans:style=Bold" (for OpenSCAD builds before 2021-08-16, default is "Liberation Mono:style=Bold")
// spacing = Factor to increase/decrease the character spacing. Default: 1.0
// Example(2D,Med): This example demonstrates several things at once. The text is wrapped using the default font and size. The original requested width of 280 units is the yellow rectangle, and anchored to it are the wrapped text displayed by `write()` in black, and the bounding box of the wrapped text in green.
// Creates a 3D text block that supports anchoring and single-parameter attachment to attachable objects. You cannot attach children to text.
// Arguments:
// text = Text to create.
// h / height / thickness = Extrusion height for the text. Default: 1
// size = The font will be created at this size divided by 0.72. Default: 10
// font = Font to use. Default: "Liberation Sans" (standard OpenSCAD default)
// ---
// spacing = The relative spacing multiplier between characters. Default: `1.0`
// direction = The text direction. `"ltr"` for left to right. `"rtl"` for right to left. `"ttb"` for top to bottom. `"btt"` for bottom to top. Default: `"ltr"`
// language = The language the text is in. Default: `"en"`
// script = The script the text is in. Default: `"latin"`
// atype = Change vertical center between "baseline" and "ycenter". Default: "baseline"
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"baseline"`
// center = Center the text. Equivalent to `atype="center", anchor=CENTER`. Default: false
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#subsection-spin). Default: `0`
// orient = Vector to rotate top towards. See [orient](attachments.scad#subsection-orient). Default: `UP`
// Anchor Types:
// baseline = Anchor center is relative to text baseline
// ycenter = Anchor center is relative to the actual y direction center of the text
// Place the text letter by letter onto the specified path using textmetrics (if available and requested)
// or user specified letter spacing. The path can be 2D or 3D. In 2D the text appears along the path with letters upright
// as determined by the path direction. In 3D by default letters are positioned on the tangent line to the path with the path normal
// pointing toward the reader. The path normal points away from the center of curvature (the opposite of the normal produced
// by path_normals()). Note that this means that if the center of curvature switches sides the text will flip upside down.
// If you want text on such a path you must supply your own normal or top vector.
// .
// Text appears starting at the beginning of the path, so if the 3D path moves right to left
// then a left-to-right reading language will display in the wrong order. (For a 2D path text will appear upside down.)
// The text for a 3D path appears positioned to be read from "outside" of the curve (from a point on the other side of the
// curve from the center of curvature). If you need the text to read properly from the inside, you can set reverse to
// true to flip the text, or supply your own normal.
// .
// If you do not have the experimental textmetrics feature enabled then you must specify the space for the letters
// using lettersize, which can be a scalar or array. You will have the easiest time getting good results by using
// a monospace font such as "Liberation Mono". Note that even with text metrics, spacing may be different because path_text()
// doesn't do kerning to adjust positions of individual glyphs. Also if your font has ligatures they won't be used.
// .
// By default letters appear centered on the path. The offset can be specified to shift letters toward the reader (in
// the direction of the normal).
// .
// You can specify your own normal by setting `normal` to a direction or a list of directions. Your normal vector should
// point toward the reader. You can also specify
// top, which directs the top of the letters in a desired direction. If you specify your own directions and they
// are not perpendicular to the path then the direction you specify will take priority and the
// letters will not rest on the tangent line of the path. Note that the normal or top directions that you
// specify must not be parallel to the path.
// .
// Historically fonts were specified by their "body size", the height of the metal body
// on which the glyphs were cast. This means the size was an upper bound on the size
// of the font glyphs, not a direct measurement of their size. In digital typesetting,
// the metal body is replaced by an invisible box, the em square, whose side length is
// defined to be the font's size. The glyphs can be contained in that square, or they
// can extend beyond it, depending on the choices made by the font designer. As a
// result, the meaning of font size varies between fonts: two fonts at the "same" size
// can differ significantly in the actual size of their characters. Typographers
// customarily specify the size in the units of "points". A point is 1/72 inch. In
// OpenSCAD, you specify the size in OpenSCAD units (often treated as millimeters for 3d
// printing), so if you want points you will need to perform a suitable unit conversion.
// In addition, the OpenSCAD font system has a bug: if you specify size=s you will
// instead get a font whose size is s/0.72. For many fonts this means the size of
// capital letters will be approximately equal to s, because it is common for fonts to
// use about 70% of their height for the ascenders in the font. To get the customary
// font size, you should multiply your desired size by 0.72.
// .
// To find the fonts that you have available in your OpenSCAD installation,
// go to the Help menu and select "Font List".
// Arguments:
// path = path to place the text on
// text = text to create
// size = The font will be created at this size divided by 0.72.
// thickness / h / height = thickness of letters (not allowed for 2D path)
// font = Font to use. Default: "Liberation Sans" (standard OpenSCAD default)
// ---
// lettersize = scalar or array giving size of letters
// center = center text on the path instead of starting at the first point. Default: false
// offset = distance to shift letters "up" (towards the reader). Not allowed for 2D path. Default: 0
// normal = direction or list of directions pointing towards the reader of the text. Not allowed for 2D path.
// top = direction or list of directions pointing toward the top of the text
// reverse = reverse the letters if true. Not allowed for 2D path. Default: false
// textmetrics = if set to true and lettersize is not given then use the experimental textmetrics feature. You must be running a dev snapshot that includes this feature and have the feature turned on in your preferences. Default: false
// valign = align text to the path using "top", "bottom", "center" or "baseline". You can also adjust position with a numerical offset as in "top-5" or "bottom+2". This only works with textmetrics enabled. You can give a simple numerical offset, which will be relative to the baseline and works even without textmetrics. Default: "baseline"
// kern = scalar or array giving spacing adjusments between each letter. If it's an array it should have one less entry than the text string. Default: 0
// language = text language, passed to OpenSCAD `text()`. Default: "en"
// script = text script, passed to OpenSCAD `text()`. Default: "latin"
// Example(3D,NoScales): The examples use Liberation Mono, a monospaced font. The width is 1/1.2 times the specified size for this font. This text could wrap around a cylinder.
// Example(3D,NoScales): If we want text that reads from the other side we can use reverse. Note we have to reverse the direction of the path and also set the reverse option.
// Example(3D,NoScales): Here the text baseline sits on the path. (Note the default orientation makes text readable from below, so we specify the normal.)
// Example(3D,Med,NoScales): This sine wave wrapped around the cylinder has a twisting normal that produces wild letter layout. We fix it with a custom normal which is different at every path point.
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Liberation Mono");
// Example(3D,NoScales): The kern parameter lets you adjust the letter spacing either with a uniform value for each letter, or with an array to make adjustments throughout the text. Here we show a case where adding some extra space gives a better look in a tight circle. When textmetrics are off, `lettersize` can do this job, but with textmetrics, you'll need to use `kern` to make adjustments relative to the text metric sizes.