Resources Numerical accuracy Calculation policy

Text from drawings as stroked edges

The line segments that draw the text of an imported drawing in the 3D model, and the width of a string.

How the precision is kept

Glyphs are polylines on a grid where a capital is 9 units high; a string is scaled by height ÷ 9 and the width factor in 64-bit. Round parts of letters are elliptical arcs sampled every 15 degrees, so letter shapes are polygons by design.

Calculations under this policy

3 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

m3d/strokefont.js CadCraft 0.8.2 64-bit 3 calculations Reviewed

Tests None found by the review

Arc of a glyph

64-bit

The points of the round parts of letters.

n = max(2, ⌈|a₁ − a₀| ÷ 15⌉); p = (c_x + r_x cos a, c_y + r_y sin a)

Angles are in degrees, each computed from its index and converted to radians once.

  • m3d/strokefont.js
  • lines 18 to 27
  • CadCraft 0.8.2
/** Points of an elliptical arc, degrees, a0 → a1 (counter-clockwise when a1 > a0, clockwise when a1 < a0). */
function E(cx, cy, rx, ry, a0, a1) {
  const n = Math.max(2, Math.ceil(Math.abs(a1 - a0) / 15));
  const out = [];
  for (let i = 0; i <= n; i++) {
    const a = ((a0 + ((a1 - a0) * i) / n) * Math.PI) / 180;
    out.push([cx + rx * Math.cos(a), cy + ry * Math.sin(a)]);
  }
  return out;
}

Width of a string

64-bit

The advance of a string in drawing units, used to align and wrap text.

width = (Σ (glyph width + 2) − 2) × h ÷ 9 × width factor

Glyph widths are numbers on the 9-unit grid, added in order and scaled once. A width factor of 0 is taken as 1.

  • m3d/strokefont.js
  • lines 151 to 156
  • CadCraft 0.8.2
/** The advance of a string, in drawing units. */
export function textWidth(text, h = 1, wf = 1) {
  let w = 0;
  for (const ch of String(text)) w += ((G[ch] || BOX)[0] + GAP);
  return Math.max(0, w - GAP) * (h / 9) * (wf || 1);
}

Strokes of a string

64-bit

The polylines of a string at a given height, width factor and slant.

x = x₀ + p_x × s_x + p_y × s × tan(oblique); y = p_y × s; s = h ÷ 9

Each glyph point is scaled and sheared in one expression; the pen position advances by (glyph width + 2) × s_x per character, added character by character. tan(oblique) is not limited, so a slant near 90° gives very large x.

  • m3d/strokefont.js
  • lines 158 to 170
  • CadCraft 0.8.2
/** Polylines of a string (see the header). */
export function textStrokes(text, { h = 1, wf = 1, oblique = 0 } = {}) {
  const s = h / 9, sx = s * (wf || 1), sh = Math.tan(oblique || 0);
  const lines = [];
  let x = 0, missing = 0;
  for (const ch of String(text)) {
    let g = G[ch];
    if (!g) { if (/\s/.test(ch)) g = G[' ']; else { g = BOX; missing++; } }
    for (const l of g[1]) lines.push(l.map(([px, py]) => [x + px * sx + py * s * sh, py * s]));
    x += (g[0] + GAP) * sx;
  }
  return { lines, width: Math.max(0, x - GAP * sx), missing };
}

In detail

Method
Glyph polylines scaled and sheared: x = x₀ + p_x·s_x + p_y·s·tan(oblique), y = p_y·s.
Number types
64-bit numbers.
Limits
Arcs in glyphs are sampled every 15 degrees. A character with no glyph is drawn as a box and counted.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach