Resources Numerical accuracy Calculation policy

Properties in DWG and DXF: transparency, lineweights, dimension variables

Converts transparency, lineweights and dimension style settings between the drawing's values and the whole-number or text forms DWG and DXF keep.

How the precision is kept

The formats set the resolution here: transparency is kept as one byte of opacity and lineweights as whole hundredths of a millimeter, so both are rounded with Math.round on the way out. Real-valued dimension variables pass as 64-bit numbers; whole-number variables are rounded to integers. A hatch's pattern origin is written as number text that reads back to the same 64-bit value.

Calculations under this policy

9 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.

dwg-props.js CadCraft 0.8.2 64-bit 9 calculations Reviewed

Tests bin/test-cadcraft.mjs

Transparency to the file's word

64-bit

Converts a transparency percentage to the opacity byte the file stores.

alpha = Math.round(255 × (1 − clamp(tr, 0, 90) ÷ 100)); word = 0x02000000 + alpha

The percentage is clamped to 0 to 90 and rounded to one of 256 opacity steps, about 0.39 percent each. The unsigned shift is applied to the assembled word, not to a measured value.

  • dwg-props.js
  • lines 36 to 42
  • CadCraft 0.8.2
/** CadCraft's tr (absent / null by layer, 'ByBlock', 0–90 %) → DXF 440 word, or undefined (by layer). */
export function trWord(tr) {
  if (tr === 'ByBlock') return 0x01000000;
  if (!Number.isFinite(tr)) return undefined;
  const alpha = Math.round(255 * (1 - Math.max(0, Math.min(90, tr)) / 100));
  return (0x02000000 | alpha) >>> 0;
}

Opacity byte to transparency

64-bit

Converts the file's opacity byte back to a transparency percentage.

p = Math.round((1 − alpha ÷ 255) × 100); p ≤ 0 → none; capped at 90

The result is a whole percent. A whole percent written by trWord reads back the same: the alpha rounding moves it by at most 0.5 ÷ 2.55 = 0.2 percent, which rounds back. A fractional percent comes back as a whole number.

  • dwg-props.js
  • line 57
  • CadCraft 0.8.2
const pct = (alpha) => { const p = Math.round((1 - alpha / 255) * 100); return p > 0 ? Math.min(90, p) : undefined; };

Transparency from a file value

64-bit

Reads a transparency word or record: by block, by layer or an opacity byte.

The word is split with unsigned shifts into its kind (top byte) and its opacity (low byte); these are bit fields, not measurements. The byte goes through pct.

  • dwg-props.js
  • lines 43 to 56
  • CadCraft 0.8.2
/** A DXF 440 word or a cc-dwg transparency ({ byLayer } | { byBlock } | { alpha 0–255 } | the raw word) → tr or undefined. */
export function trFrom(v) {
  if (v === undefined || v === null || v === '') return undefined;
  if (typeof v === 'object') {
    if (v.byBlock) return 'ByBlock';
    if (Number.isFinite(v.alpha)) return pct(v.alpha);
    return undefined;
  }
  const w = Number(v) >>> 0;
  const kind = w >>> 24;
  if (kind === 1) return 'ByBlock';
  if (kind === 2 || kind === 3) return pct(w & 0xff);
  return undefined;
}

Dimension lineweight to hundredths

64-bit

Converts a dimension line or extension line weight in millimeters to the file's whole number.

Math.round(v × 100) for v ≥ 0; −1, −2, −3 kept as codes

Rounded to 0.01 mm because the variable is a whole number of hundredths. Anything that is not a finite number of at least 0 becomes −2 (by block).

  • dwg-props.js
  • line 161
  • CadCraft 0.8.2
const lw100 = (v) => (v === -1 || v === -2 || v === -3 ? v : Number.isFinite(v) && v >= 0 ? Math.round(v * 100) : -2);

Style value to a dimension variable

64-bit

Converts one dimension style setting to the value its variable holds in the file.

real: the number (0 when not finite); int: Math.round; bool: 1 or 0; lineweight: lw100; separator: 44 or 46

Real variables (sizes, scales, round-off, tolerances) are passed as the 64-bit number unchanged. Whole-number variables such as the decimal places are rounded with Math.round.

  • dwg-props.js
  • lines 163 to 174
  • CadCraft 0.8.2
/** One st value → its variable's value (number or string). */
function out1(kind, v, key) {
  switch (kind) {
    case 'real': return Number.isFinite(+v) ? +v : 0;
    case 'int': return Math.round(+v || 0);
    case 'bool': return v ? 1 : 0;
    case 'color': return typeof v === 'string' ? nearestAci(v) : aci(v);
    case 'lw': return lw100(v);
    case 'sep': return String(v) === ',' ? 44 : 46;
    default: return v;
  }
}

Dimension variable to a style value

64-bit

Converts one variable read from a file to the dimension style setting.

real: parseFloat; int: Math.round(parseFloat); lineweight: x ÷ 100 for 0 ≤ x ≤ 211

parseFloat reads decimal text to the nearest 64-bit number and passes a number through unchanged. A value that is not finite is left out, so the style keeps its previous setting. Lineweights outside 0 to 211 hundredths are left out.

  • dwg-props.js
  • lines 175 to 191
  • CadCraft 0.8.2
/** A variable's value → the st value (checked), or undefined. */
function in1(kind, raw) {
  const n = typeof raw === 'object' && raw !== null ? (raw.rgb !== undefined ? '#' + (raw.rgb & 0xffffff).toString(16).padStart(6, '0') : raw.index) : raw;
  switch (kind) {
    case 'real': { const x = parseFloat(n); return Number.isFinite(x) ? x : undefined; }
    case 'int': { const x = Math.round(parseFloat(n)); return Number.isFinite(x) ? x : undefined; }
    case 'bool': return parseFloat(n) ? true : n === true ? true : false;
    case 'color': {
      if (typeof n === 'string' && /^#[0-9a-f]{6}$/i.test(n)) return n.toLowerCase();
      const x = Math.round(parseFloat(n));
      return x === 256 ? null : x === 0 ? 0 : x >= 1 && x <= 255 ? x : undefined;
    }
    case 'lw': { const x = Math.round(parseFloat(n)); return x === -1 || x === -2 || x === -3 ? x : x >= 0 && x <= 211 ? x / 100 : undefined; }
    case 'sep': return Math.round(parseFloat(n)) === 44 ? ',' : '.';
    default: return undefined;
  }
}

Tolerance mode and text gap

64-bit

Works out the tolerance mode (symmetric, deviation, limits, basic) and the text gap from the file's variables.

symmetric when |tp − tm| < 1e-12; gap < 0 → basic and gap = −gap

The symmetric test is absolute at 1e-12. A negative gap marks a basic dimension in the file; its sign is removed and the magnitude kept unchanged.

  • dwg-props.js
  • lines 269 to 286
  • CadCraft 0.8.2
function specials(get, st) {
  const tih = get('DIMTIH'), toh = get('DIMTOH');
  if (tih !== undefined || toh !== undefined) st.tih = !!+(tih ?? 0) && !!+(toh ?? tih ?? 0);
  const p = get('DIMPOST');
  if (p !== undefined) { const [pre, suf] = post(p); if (pre) st.pre = pre; else delete st.pre; if (suf) st.suf = suf; else delete st.suf; }
  const ap = get('DIMAPOST');
  if (ap !== undefined) { const [pre, suf] = post(ap); if (pre) st.apre = pre; else delete st.apre; if (suf) st.asuf = suf; else delete st.asuf; }
  const tol = get('DIMTOL'), lim = get('DIMLIM');
  if (tol !== undefined || lim !== undefined || st.gap < 0) {
    if (+lim) st.tol = 'lim';
    else if (+tol) st.tol = Math.abs((st.tp || 0) - (st.tm || 0)) < 1e-12 ? 'sym' : 'dev';
    else if (st.gap < 0) st.tol = 'basic';
    else if (tol !== undefined || lim !== undefined) delete st.tol;
  }
  if (st.gap < 0) st.gap = -st.gap;
  const unit = get('DIMUNIT');
  if (unit !== undefined && st.lunit === undefined) { const u = Math.round(+unit); st.lunit = u === 6 ? 4 : u === 7 ? 5 : u; }
}

Dimension style as file variables

64-bit

Every variable of a dimension style, by name, for a DIMSTYLE record.

basic tolerance: DIMGAP = −|gap|

Each setting goes through out1. For a basic dimension the gap is written negative, the way the format marks it; a gap of 0 is written as −0.625.

  • dwg-props.js
  • lines 197 to 209
  • CadCraft 0.8.2
/** The style's variables, by name (a DIMSTYLE record's vars; DXF codes through dstyleItems). Every key, so nothing falls back to another program's defaults. */
export function varsOf(st) {
  const s = { ...DEF, ...(st || {}) };
  const v = {};
  for (const [key, name, , kind] of DIMVARS) v[name] = out1(kind, s[key], key);
  v.DIMTIH = s.tih ? 1 : 0; v.DIMTOH = s.tih ? 1 : 0;
  v.DIMPOST = postOf(s.pre, s.suf); v.DIMAPOST = postOf(s.apre, s.asuf);
  v.DIMTOL = s.tol === 'sym' || s.tol === 'dev' ? 1 : 0; v.DIMLIM = s.tol === 'lim' ? 1 : 0;
  if (s.tol === 'basic') v.DIMGAP = -Math.abs(v.DIMGAP || 0.625);
  v.DIMSAH = (s.blk1 || '') !== (s.blk2 || '') ? 1 : 0;
  if (!(st && st.lunit)) delete v.DIMLUNIT;   // absent = decimal; the style's own stays
  return v;
}

Hatch pattern origin as text

64-bit

Writes a hatch's pattern origin into the file as two numbers in a text field.

text = CCHORG: followed by x, a comma and y

The numbers are turned into text by string concatenation, which gives the shortest decimal that reads back to the same 64-bit value; propsFromXdata reads them with Number. The origin survives a save and open unchanged.

  • dwg-props.js
  • line 86
  • CadCraft 0.8.2
if (e.type === 'hatch' && !e.solid && (Number.isFinite(e.ox) || Number.isFinite(e.oy)) && (e.ox || e.oy)) cc.push('CCHORG:' + (+e.ox || 0) + ',' + (+e.oy || 0));

In detail

Method
alpha = round(255 × (1 − percent ÷ 100)); percent = round((1 − alpha ÷ 255) × 100); lineweight = round(mm × 100).
Number types
64-bit numbers; alpha 0 to 255; lineweights 0 to 211 hundredths of a millimeter.
Tolerances
A tolerance is symmetric when |upper − lower| < 1e-12 (absolute).
Limits
Transparency is held to a whole percent between 0 and 90. Lineweights are held to 0.01 mm.

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