Works out the points a new dimension stores: its two origins, the point on a circle for a radius or diameter, the legs of an angle, and the line position of baseline dimensions.
How the precision is kept
The origins are picked points or the ends of the picked object, computed in 64-bit; an arc's ends are center + r·(cos, sin) of its end angles. The measured value is not computed in this file: dims.js works it out from the stored points. Parallel lines for an angular dimension are detected with a tolerance scaled to the two lines' lengths.
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.
The two points a linear or aligned dimension measures between: picked, or the ends of a picked object.
arc end = center + r·(cos a, sin a); circle: (cx − r, cy) and (cx + r, cy)
Picked points are stored as picked. A line gives its two stored ends; an arc gives center + r·(cos, sin) at each end angle; a circle gives the ends of its level diameter by one subtraction and one addition; a polyline gives the ends of the segment whose middle is nearest the pick.
commands.js
lines 2256 to 2276
CadCraft 0.8.2
/** Two extension line origins: picked points, or (Enter) an object's ends. */
async function twoOrigins(c) {
const a = await c.point(t('cmd.explode.specify_first_extension_line'), { none: true, options: [opt('S', t('cmd.area.object'))] });
if (a && a.option !== 'S') {
const b = await c.point(t('cmd.explode.specify_second_extension_line'), { base: a });
return [P(a), P(b)];
}
for (;;) {
const pick = await c.entity(t('cmd.explode.select_object_dimension'));
const e = c.doc.get(pick.id);
if (e.type === 'line') return [{ x: e.x1, y: e.y1 }, { x: e.x2, y: e.y2 }];
if (e.type === 'arc') return [polar({ x: e.cx, y: e.cy }, e.a0, e.r), polar({ x: e.cx, y: e.cy }, e.a1, e.r)];
if (e.type === 'circle') return [{ x: e.cx - e.r, y: e.cy }, { x: e.cx + e.r, y: e.cy }];
if (e.type === 'poly') {
const ps = prims(e); let best = ps[0], bd = Infinity;
for (const q of ps) { const d = dist(pick.point, primPoint(q, 0.5)); if (d < bd) { bd = d; best = q; } }
return [primPoint(best, 0), primPoint(best, 1)];
}
c.print(t('cmd.explode.pick_line_arc_circle'));
}
}
Horizontal or vertical
64-bit
Whether a linear dimension measures along the X or the Y axis, from where its line is placed.
The location point and the two origins are converted to the user coordinate system, and the dimension is level when the point lies at least as far outside the origins' box in y as in x. The result is the system's angle, or that plus π ÷ 2, normalized to 0…2π.
commands.js
lines 2247 to 2254
CadCraft 0.8.2
/** Horizontal or vertical by where the dimension line goes — in the UCS (DR.8): its X axis is "horizontal". */
function linearRot(p1, p2, cur, u = null) {
const a = toUcs(u, p1), b = toUcs(u, p2), q = toUcs(u, cur), base = u ? u.ang : 0;
const minX = Math.min(a.x, b.x), maxX = Math.max(a.x, b.x), minY = Math.min(a.y, b.y), maxY = Math.max(a.y, b.y);
const outX = q.x < minX ? minX - q.x : q.x > maxX ? q.x - maxX : 0;
const outY = q.y < minY ? minY - q.y : q.y > maxY ? q.y - maxY : 0;
return normAngle(base + (outY >= outX ? 0 : Math.PI / 2));
}
Point on the circle for a radius or diameter
64-bit
The point on an arc or circle that a radius or diameter dimension is attached to.
p₁ = center + r·(cos, sin)(atan2(cursor − center))
The point follows the cursor's direction from the center, at the stored radius. With the cursor within 1e-12 drawing units (absolute) of the center, the direction of the original pick is kept.
Whether two picked lines have an angle between them that can be dimensioned.
parallel when |e × f| < 10⁻¹² × |e| × |f|
The cross product of the two direction vectors is compared with 1e-12 times the product of their lengths, so the test is on the sine of the angle between the lines and does not depend on the size of the drawing.
The origins and line position of each dimension added by DIMCONTINUE or DIMBASELINE.
baseline: loc = previous loc + dli × scale × side × (−sin rot, cos rot), dli defaults to 3.75
A continued dimension starts at the previous one's second origin and reuses its line position. A baseline dimension moves the line by the style's spacing times its scale along the normal; each new line is the previous line plus one step, so the steps add up along the stack. The side is the sign of one dot product, taken as +1 when it is zero.
commands.js
lines 2346 to 2368
CadCraft 0.8.2
async function chain(c, baseline) {
let d = await chainFrom(c);
const first = d;
let n = 0;
for (;;) {
const from = baseline ? first.p1 : d.p2;
const st = d.st || c.doc.current.dim;
const rot = d.kind === 'aligned' ? angleOf(d.p1, d.p2) : (d.rot || 0);
const nrm = { x: -Math.sin(rot), y: Math.cos(rot) };
const side = Math.sign((first.loc.x - first.p1.x) * nrm.x + (first.loc.y - first.p1.y) * nrm.y) || 1;
const step = (st.dli ?? 3.75) * (st.scale || 1) * side;
const loc = baseline ? { x: d.loc.x + nrm.x * step, y: d.loc.y + nrm.y * step } : P(d.loc);
const make = (cur) => dimEnt(c, { kind: 'linear', p1: P(from), p2: P(cur), loc, rot, st: { ...st } });
c.preview((cur) => [make(cur)]);
const p = await c.point(t('cmd.explode.specify_second_extension_line'), { none: true, base: from, options: [opt('U', 'Undo')] });
if (!p) return;
if (p.option === 'U') { if (n) { undoInside(c); n--; d = c.doc.get(c.engine.lastDim) || first; } else c.print(t('cmd.extend.nothing_undo_command')); continue; }
const made = c.doc.change('DIM', () => c.doc.add(make(p)));
c.engine.lastDim = made.id;
c.print('Dimension text = ' + formatMeasure(made));
d = made; n++;
}
}
In detail
Method
Definition points from picks and object ends; baseline spacing from the dimension style.
Number types
64-bit numbers.
Tolerances
1e-12 drawing units, absolute: an aligned dimension between two points closer than this is refused, and a cursor this close to a circle's center keeps the original direction. Two lines are parallel when |e × f| < 1e-12 × |e| × |f|.
Limits
An arc's or circle's dimension points pass through cos and sin, so they lie on the object only to within that rounding. Baseline lines are placed one step from the previous line, so the steps add up along the stack.
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.