Turns what is typed or clicked at a prompt (x,y, @dx,dy, distance<angle, a distance along the cursor direction, an angle in degrees) into the point, length or angle a command uses.
How the precision is kept
Typed lengths are read by units.js in the drawing's format and typed angles in degrees. The point is then built in 64-bit: absolute coordinates through the user coordinate system, relative ones added to the last point, polar ones by cosine and sine. A clicked distance or angle is one Math.hypot or atan2 from the base point. Values echoed in prompts and messages are rounded to 4 decimals; the values the commands use are not.
Open item. Print the raw CAL result with 17 significant digits instead of 12.
Calculations under this policy
5 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.
A number written for a prompt's default or a message in the command history.
|n| < 10⁻¹⁰ → 0; otherwise n.toFixed(4) without trailing zeros
Used for the defaults shown in prompts and for angles, ratios and settings printed in the history. It rounds to 4 decimals for the text only; the value the command holds is unchanged.
The value a prompt takes when a distance, a number or an angle is typed.
angle = degrees × π ÷ 180 (+ UCS angle for an absolute angle)
Lengths and numbers come from units.js readLength and readNumber and are used as returned; a typed distance must be zero or more. An angle is read in degrees and converted with one multiplication by π and one division by 180; an absolute angle then has the user coordinate system's angle added.
commands.js
lines 155 to 176
CadCraft 0.8.2
case 'distance': {
// feet and inches too, in an architectural or engineering drawing; arithmetic over lengths (0.6 DF.3: 4+7/16)
const r = readLength(typed, this.doc.meta.lunits, this.doc.meta.units);
if (r.ok && r.value >= 0) return this.resolve(r.value);
if (!r.ok && isArithmetic(typed)) return this.refuse(r);
break;
}
case 'number': {
if (w.opts.length) { // a signed length
const r = readLength(typed, this.doc.meta.lunits, this.doc.meta.units);
if (r.ok) return this.resolve(r.value);
if (isArithmetic(typed)) return this.refuse(r);
break;
}
const r = readNumber(typed);
if (r.ok) return this.resolve(r.value);
if (isArithmetic(typed)) return this.refuse(r);
break;
}
case 'angle': {
const r = readAngle(typed); // degrees, with arithmetic (360/7); a bearing N45°23'30"E or 45°23'30" (SU.932)
if (r.ok) return this.resolve(rad(r.value) + (w.opts.ucs ? activeUcs(this.doc)?.ang || 0 : 0)); // an absolute angle: from the UCS X axis (DR.8)
Distance or angle shown by two clicks
64-bit
The distance or the angle a prompt takes when it is shown by picking two points.
d = √(Δx² + Δy²); angle = atan2(Δy, Δx)
The second click resolves the prompt with one Math.hypot or one atan2 from the first point, in 64-bit. The angle is in radians between −π and π and is not normalized here.
commands.js
lines 201 to 205
CadCraft 0.8.2
if (w.opts.base) this.resolve(dist(w.opts.base, point));
else { w.opts.base = point; this.base = point; this.host.prompt(t('cmd.specify_second_point')); }
return true;
case 'angle':
if (w.opts.base) this.resolve(angleOf(w.opts.base, point));
Typed point
64-bit
The point for typed coordinates: absolute, relative to the last point, polar, or a distance along the cursor direction.
x,y → UCS to world; @x,y → last + R(ucs)·(x, y); d<a → from + d·(cos, sin)(a·π ÷ 180 + UCS angle); d → base + d·(cos, sin)(atan2(cursor − base))
Coordinates are read as lengths in the drawing's format; relative input adds the typed offset, turned into world axes, to the last point. Polar input and direct distance go through geom.js polar, so the point carries the rounding of cos and sin: 10<90 gives an x offset of about 6 × 10⁻¹⁶ rather than 0. Direct distance needs the cursor at least 1e-12 drawing units (absolute) from the base point.
commands.js
lines 307 to 337
CadCraft 0.8.2
/** Typed point → {x, y} | null. Lengths in the drawing's format (units.js parseLength: 12'6", 6-1/2, 4+7/16); angles in degrees. */
parsePoint(t) {
let s = t.trim().replace(/\s*([,<@#])\s*/g, '$1');
// in the UCS (DR.8: x,y from its origin along its axes, d<a from its X axis); a * after @ / # or first = world coordinates
let world = false;
s = s.replace(/^([@#]?)\s*\*/, (_m, at) => { world = true; return at; });
const u = world ? null : activeUcs(this.doc);
const L = (x) => parseLength(x, this.doc.meta.lunits, this.doc.meta.units);
const ang = (x) => { const r = readAngle(x); return r.ok ? r.value : null; }; // degrees, arithmetic allowed (0.6 DF.3)
let m;
if ((m = s.match(/^([@#])?([^,<@#]+),([^,<@#]+)$/))) {
const x = L(m[2]), y = L(m[3]);
if (x === null || y === null) return null;
if (m[1] === '@') { const b = this.lastPoint || { x: 0, y: 0 }, d = vecToWorld(u, { x, y }); return { x: b.x + d.x, y: b.y + d.y }; }
return ucsToWorld(u, { x, y });
}
if ((m = s.match(/^(@)?([^,<@#]+)<([^,<@#]+)$/))) {
const d = L(m[2]), a = ang(m[3]);
if (d === null || a === null) return null;
const from = m[1] ? (this.lastPoint || { x: 0, y: 0 }) : ucsToWorld(u, { x: 0, y: 0 });
return polar(from, rad(a) + (u ? u.ang : 0), d);
}
const d = L(s);
if (d !== null) {
const base = this.waiting?.opts.base || this.base;
const cur = this.host.cursor;
if (!base || !cur || dist(base, cur) < 1e-12) return null;
return polar(base, angleOf(base, cur), d);
}
return null;
}
Calculation on the command line
64-bit
The result CAL prints for an expression such as 12'6"+3/4" or 2*450mm.
raw = value.toPrecision(12)
The expression is evaluated by units.js readLength. The history line shows the result in the drawing's length format and, beside it, the raw value rounded to 12 significant digits with toPrecision(12), so the digits a 64-bit number holds beyond the 12th are not shown.
commands.js
lines 3830 to 3835
CadCraft 0.8.2
def('CAL', [], async (c) => {
const s = (await c.string(t('cmd.cal.expression'), { raw: true })).trim();
if (!s) return;
const r = readLength(s, c.doc.meta.lunits, c.doc.meta.units);
if (!r.ok) { c.print(calcMessage(r)); return; }
c.print(t('cmd.cal.result', { value: fmtLen(c, r.value), raw: String(Number(r.value.toPrecision(12))) }));
In detail
Method
x,y → world point; @x,y → last point + offset; d<a → from + d·(cos a, sin a); a lone distance → base + d along the direction to the cursor.
Number types
64-bit numbers.
Tolerances
1e-12 drawing units, absolute: direct distance entry needs the cursor at least this far from the base point. A value under 1e-10 in size is printed as 0.
Limits
Polar and direct-distance points pass through cos and sin, so a point typed as 10<90 lies about 6 × 10⁻¹⁶ off the axis rather than exactly on it. CAL prints its raw result with 12 significant digits.
Approach: 64-bit, direct
Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.