UNPKG

@tracespace/plotter

Version:

Plot @tracespace/parser ASTs into image trees.

665 lines (664 loc) 18.4 kB
import { COMMENT as Ct, GRAPHIC as F, LEADING as B, TRAILING as j, COORDINATE_FORMAT as Pt, UNITS as Rt, IN as Tt, TOOL_MACRO as St, TOOL_DEFINITION as J, MACRO_SHAPE as Lt, TOOL_CHANGE as It, POLYGON as Nt, OBROUND as K, RECTANGLE as Gt, CIRCLE as vt, MACRO_VARIABLE as bt, MACRO_PRIMITIVE as Dt, MACRO_THERMAL as wt, MACRO_MOIRE_DEPRECATED as Ft, MACRO_POLYGON as Ht, MACRO_OUTLINE as zt, MACRO_LOWER_LEFT_LINE_DEPRECATED as Bt, MACRO_CENTER_LINE as jt, MACRO_VECTOR_LINE_DEPRECATED as Wt, MACRO_VECTOR_LINE as Vt, MACRO_CIRCLE as qt, DRILL as $t, SHAPE as I, SEGMENT as G, SLOT as kt, INTERPOLATE_MODE as st, QUADRANT_MODE as Yt, SINGLE as Ut, REGION_MODE as Z, DONE as Xt, MOVE as W, CW_ARC as ct, CCW_ARC as ot, LINE as Qt } from "@tracespace/parser"; const Jt = "image", v = "imageShape", it = "imagePath", Kt = "imageRegion", O = "line", g = "arc", S = "circle", H = "rectangle", M = "polygon", z = "outline", Y = "layeredShape", { PI: T } = Math, P = T / 2, at = 3 * P, A = 2 * T; function V(t) { return t >= 0 && t <= A ? t : t < 0 ? t + A : t > A ? t - A : V(t); } function tt(t) { return t >= P ? t - P : t + at; } function ut(t) { return t * Math.PI / 180; } function C(t, e, n = 0) { const r = ut(n), [c, s] = [Math.sin(r), Math.cos(r)], [o, i] = t, a = o * s - i * c + e[0], p = o * c + i * s + e[1]; return [a, p]; } function pt(t, e) { return t[0] === e[0] && t[1] === e[1]; } function q(t) { return t.length === 0; } function ft() { return []; } function yt(t, e) { return q(t) ? e : q(e) ? t : [ Math.min(t[0], e[0]), Math.min(t[1], e[1]), Math.max(t[2], e[2]), Math.max(t[3], e[3]) ]; } function N(t) { return t.reduce(yt, ft()); } function ht(t) { return N(t.map(lt)); } function lt(t) { return t.type === v ? U(t.shape) : X( t.segments, t.type === it ? t.width : void 0 ); } function U(t) { switch (t.type) { case S: { const { cx: e, cy: n, r } = t; return $([e, n], r); } case H: { const { x: e, y: n, xSize: r, ySize: c } = t; return [e, n, e + r, n + c]; } case M: return N(t.points.map((e) => $(e))); case z: return X(t.segments); case Y: return N(t.shapes.filter(({ erase: e }) => !e).map(U)); } } function X(t, e = 0) { const n = e / 2, r = []; for (const c of t) if (r.push(c.start, c.end), c.type === g) { const { start: s, end: o, center: i, radius: a } = c, p = Math.abs(o[2] - s[2]); let [f, u] = o[2] > s[2] ? [s[2], o[2]] : [o[2], s[2]]; f = V(f), u = V(u); const l = [ [i[0] + a, i[1]], [i[0], i[1] + a], [i[0] - a, i[1]], [i[0], i[1] - a] ]; for (const y of l) (f > u || p === A) && r.push(y), f = tt(f), u = tt(u); } return N(r.map((c) => $(c, n))); } function $(t, e = 0) { return [ t[0] - e, t[1] - e, t[0] + e, t[1] + e ]; } const Ce = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, add: yt, empty: ft, fromGraphic: lt, fromGraphics: ht, fromPath: X, fromShape: U, isEmpty: q, sum: N }, Symbol.toStringTag, { value: "Module" })), Zt = /FORMAT={?(\d):(\d)/; function te(t) { const { children: e } = t; let n = null, r = null, c = null, s = 0; for (; s < e.length && (n === null || r === null || c === null); ) { const o = e[s]; switch (o.type) { case Rt: { n = o.units; break; } case Pt: { r = o.format, c = o.zeroSuppression; break; } case F: { const { coordinates: i } = o; for (const a of Object.values(i)) { if (c !== null) break; a.endsWith("0") || a.includes(".") ? c = B : a.startsWith("0") && (c = j); } break; } case Ct: { const { comment: i } = o, a = Zt.exec(i); /suppress trailing/i.test(i) ? c = j : /(suppress leading|keep zeros)/i.test(i) && (c = B), a && (r = [Number(a[1]), Number(a[2])]); break; } } s += 1; } return { units: n ?? Tt, coordinateFormat: r ?? [2, 4], zeroSuppression: c ?? B }; } const b = "simpleTool", dt = "macroTool"; function ee() { return Object.create(ne); } const ne = { _currentToolCode: void 0, _toolsByCode: {}, _macrosByName: {}, use(t) { if (t.type === St && (this._macrosByName[t.name] = t.children), t.type === J) { const { shape: e, hole: n } = t, r = e.type === Lt ? { type: dt, macro: this._macrosByName[e.name] ?? [], variableValues: e.variableValues } : { type: b, shape: e, ...n && { hole: n } }; this._toolsByCode[t.code] = r; } return (t.type === J || t.type === It) && (this._currentToolCode = t.code), typeof this._currentToolCode == "string" ? this._toolsByCode[this._currentToolCode] : void 0; } }; function re() { return Object.create(se); } const se = { _DEFAULT_ARC_OFFSETS: { i: 0, j: 0, a: 0 }, _previousPoint: { x: 0, y: 0 }, use(t, e) { let n = this._DEFAULT_ARC_OFFSETS, r = this._previousPoint, c = r; if (t.type === F) { const { coordinates: s } = t, o = R(s.x0, r.x, e), i = R(s.y0, r.y, e), a = R(s.x, o, e), p = R(s.y, i, e), f = R(s.i, 0, e), u = R(s.j, 0, e), l = R(s.a, 0, e); (r.x !== o || r.y !== i) && (r = { x: o, y: i }), (c.x !== a || c.y !== p) && (c = { x: a, y: p }), (f !== 0 || u !== 0 || l !== 0) && (n = { i: f, j: u, a: l }); } return this._previousPoint = c, { startPoint: r, endPoint: c, arcOffsets: n }; } }; function R(t, e, n) { if (typeof t != "string") return e; if (t.includes(".") || t === "0") return Number(t); const { coordinateFormat: r, zeroSuppression: c } = n, [s, o] = r, [i, a] = t.startsWith("+") || t.startsWith("-") ? [t[0], t.slice(1)] : ["+", t], p = s + o, f = c === j ? a.padEnd(p, "0") : a.padStart(p, "0"), u = f.slice(0, s), l = f.slice(s); return Number(`${i}${u}.${l}`); } function et(t, e) { const { x: n, y: r } = e; switch (t.type) { case vt: { const { diameter: c } = t; return { type: S, cx: n, cy: r, r: c / 2 }; } case Gt: case K: { const { xSize: c, ySize: s } = t, o = c / 2, i = s / 2, a = { type: H, x: n - o, y: r - i, xSize: c, ySize: s }; return t.type === K && (a.r = Math.min(o, i)), a; } case Nt: { const { diameter: c, rotation: s, vertices: o } = t, i = c / 2, a = ut(s ?? 0), p = A / o, f = Array.from({ length: o }).map( (u, l) => { const y = p * l + a, h = n + i * Math.cos(y), _ = r + i * Math.sin(y); return [h, _]; } ); return { type: M, points: f }; } } } function k(t) { if (t.type === S) { const { cx: e, cy: n, r } = t; return [ { type: g, start: [e + r, n, 0], end: [e + r, n, A], center: [e, n], radius: r } ]; } if (t.type === H) { const { x: e, y: n, xSize: r, ySize: c, r: s } = t; return s === r / 2 ? [ { type: O, start: [e + r, n + s], end: [e + r, n + c - s] }, { type: g, start: [e + r, n + c - s, 0], end: [e, n + c - s, T], center: [e + s, n + c - s], radius: s }, { type: O, start: [e, n + c - s], end: [e, n + s] }, { type: g, start: [e, n + s, T], end: [e + r, n + s, A], center: [e + s, n + s], radius: s } ] : s === c / 2 ? [ { type: O, start: [e + s, n], end: [e + r - s, n] }, { type: g, start: [e + r - s, n, -P], end: [e + r - s, n + c, P], center: [e + r - s, n + s], radius: s }, { type: O, start: [e + r - s, n + c], end: [e + s, n + c] }, { type: g, start: [e + s, n + c, P], end: [e + s, n, at], center: [e + s, n + s], radius: s } ] : [ { type: O, start: [e, n], end: [e + r, n] }, { type: O, start: [e + r, n], end: [e + r, n + c] }, { type: O, start: [e + r, n + c], end: [e, n + c] }, { type: O, start: [e, n + c], end: [e, n] } ]; } return t.type === M ? t.points.map((e, n) => { const r = n < t.points.length - 1 ? n + 1 : 0; return { type: O, start: e, end: t.points[r] }; }) : t.segments; } function ce(t, e) { const { shape: n, hole: r } = t, c = et(n, e.endPoint), s = r ? et(r, e.endPoint) : void 0; return s === void 0 ? c : { type: z, segments: [...k(c), ...k(s)] }; } function oe(t, e) { const n = t.filter((r) => r.type === O).map((r) => ie(r, e)); return { type: v, shape: { type: Y, shapes: n } }; } function ie(t, e) { const { start: n, end: r } = t, [c, s] = n, [o, i] = r, [a, p] = [e.xSize / 2, e.ySize / 2], f = Math.atan2(i - s, o - i), [u, l] = [c - a, c + a], [y, h] = [s - p, s + p], [_, E] = [o - a, o + a], [m, x] = [i - p, i + p]; let d = []; return pt(n, r) ? d = [ [u, y], [l, y], [E, m], [E, x], [_, x], [u, h] ] : f >= 0 && f < P ? d = [ [u, y], [l, y], [E, m], [E, x], [_, x], [u, h] ] : f >= P && f <= T ? d = [ [l, y], [l, h], [E, x], [_, x], [_, m], [u, y] ] : f >= -T && f < -P ? d = [ [l, h], [u, h], [_, x], [_, m], [E, m], [l, y] ] : d = [ [u, h], [u, y], [_, m], [E, m], [E, x], [l, h] ], { type: M, points: d }; } const _t = "cw", Q = "ccw"; function nt(t, e, n) { return e === void 0 ? xt(t) : ae(t, e, n); } function rt(t, e, n = !1) { if (t.length > 0) { if (n) return { type: Kt, segments: t }; if ((e == null ? void 0 : e.type) === b && e.shape.type === S) return { type: it, width: e.shape.diameter, segments: t }; if ((e == null ? void 0 : e.type) === b && e.shape.type === H) return oe(t, e.shape); } } function xt(t) { return { type: O, start: [t.startPoint.x, t.startPoint.y], end: [t.endPoint.x, t.endPoint.y] }; } function ae(t, e, n = !1) { const { startPoint: r, endPoint: c, arcOffsets: s } = t, o = s.a > 0 ? s.a : (s.i ** 2 + s.j ** 2) ** 0.5; if (n || s.a > 0) { if (r.x === c.x && r.y === c.y) return xt(t); const [u, l, y] = ue(t, o).map((h) => D(r, c, h, e)).sort(([h, _], [E, m]) => { const x = Math.abs(_[2] - h[2]), d = Math.abs(m[2] - E[2]); return x - d; })[0]; return { type: g, start: u, end: l, center: y, radius: o }; } const i = { x: r.x + s.i, y: r.y + s.j }, [a, p, f] = D( r, c, i, e ); return { type: g, start: a, end: p, center: f, radius: o }; } function D(t, e, n, r) { let c = Math.atan2( t.y - n.y, t.x - n.x ), s = Math.atan2( e.y - n.y, e.x - n.x ); return r === Q ? s = s > c ? s : s + A : c = c > s ? c : c + A, [ [t.x, t.y, c], [e.x, e.y, s], [n.x, n.y] ]; } function ue(t, e) { const { x: n, y: r } = t.startPoint, { x: c, y: s } = t.endPoint, [o, i] = [c - n, s - r], [a, p] = [c + n, s + r], f = Math.sqrt(o ** 2 + i ** 2); if (e <= f / 2) return [{ x: n + o / 2, y: r + i / 2 }]; const u = Math.sqrt(4 * e ** 2 / f ** 2 - 1), [l, y] = [a / 2, p / 2], [h, _] = [i * u / 2, o * u / 2]; return [ { x: l + h, y: y - _ }, { x: l - h, y: y + _ } ]; } function pe(t, e) { const n = [], r = Object.fromEntries( t.variableValues.map((c, s) => [`$${s + 1}`, c]) ); for (const c of t.macro) if (c.type === bt && (r[c.name] = w(c.value, r)), c.type === Dt) { const s = [e.endPoint.x, e.endPoint.y], o = c.parameters.map((i) => w(i, r)); n.push(...fe(c.code, s, o)); } return { type: Y, shapes: n }; } function w(t, e) { if (typeof t == "number") return t; if (typeof t == "string") return e[t]; const n = w(t.left, e), r = w(t.right, e); switch (t.operator) { case "+": return n + r; case "-": return n - r; case "x": return n * r; case "/": return n / r; } } function fe(t, e, n) { switch (t) { case qt: return [ye(e, n)]; case Vt: case Wt: return [he(e, n)]; case jt: return [le(e, n)]; case Bt: return [de(e, n)]; case zt: return [_e(e, n)]; case Ht: return [xe(e, n)]; case Ft: return me(e, n); case wt: return [Ee(e, n)]; } return []; } function ye(t, e) { const [n, r, c, s, o] = e, i = r / 2, [a, p] = C([c, s], t, o); return { type: S, erase: n === 0, cx: a, cy: p, r: i }; } function he(t, e) { const [n, r, c, s, o, i, a] = e, [p, f] = [i - s, o - c], u = r / 2, l = Math.sqrt(p ** 2 + f ** 2), [y, h] = [u * f / l, u * p / l]; return { type: M, erase: n === 0, points: [ [c + y, s - h], [o + y, i - h], [o - y, i + h], [c - y, s + h] ].map((_) => C(_, t, a)) }; } function le(t, e) { const [n, r, c, s, o, i] = e, [a, p] = [r / 2, c / 2]; return { type: M, erase: n === 0, points: [ [s - a, o - p], [s + a, o - p], [s + a, o + p], [s - a, o + p] ].map((f) => C(f, t, i)) }; } function de(t, e) { const [n, r, c, s, o, i] = e; return { type: M, erase: n === 0, points: [ [s, o], [s + r, o], [s + r, o + c], [s, o + c] ].map((a) => C(a, t, i)) }; } function _e(t, e) { const [n, , ...r] = e.slice(0, -1), c = e[e.length - 1]; return { type: M, erase: n === 0, points: r.flatMap( (s, o) => o % 2 === 1 ? [[r[o - 1], s]] : [] ).map((s) => C(s, t, c)) }; } function xe(t, e) { const [n, r, c, s, o, i] = e, a = o / 2, p = 2 * T / r, f = []; let u; for (u = 0; u < r; u++) { const l = p * u, y = c + a * Math.cos(l), h = s + a * Math.sin(l); f.push(C([y, h], t, i)); } return { type: M, erase: n === 0, points: f }; } function me(t, e) { const n = (x) => C(x, t, e[8]), [r, c, s, o, i, a, p, f] = e, [u, l] = n([r, c]), y = p / 2, h = f / 2, _ = []; let E = 0, m = s; for (; m >= 0 && E < a; ) { const x = m / 2, d = x - o; _.push(x), d > 0 && _.push(d), E += 1, m = 2 * (d - i); } return [ { type: z, segments: _.flatMap((x) => k({ type: S, cx: u, cy: l, r: x })) }, // Vertical stroke { type: M, points: [ [r - y, c - h], [r + y, c - h], [r + y, c + h], [r - y, c + h] ].map(n) }, // Horizontal stroke { type: M, points: [ [r - h, c - y], [r + h, c - y], [r + h, c + y], [r - h, c + y] ].map(n) } ]; } function Ee(t, e) { const [n, r, c, s, o, i] = e, a = C([n, r], t, i), [p, f] = [c / 2, s / 2], u = o / 2, l = p ** 2 - u ** 2, y = f ** 2 - u ** 2, h = Math.sqrt(l), _ = y >= 0 ? Math.sqrt(y) : u, E = [0, 90, 180, 270], m = []; for (const x of E) { const d = [ [_, u], [h, u], [u, h], [u, _] ].map((L) => C(L, [n, r], x)).map((L) => C(L, t, i)), [Et, Ot, Mt] = D( { x: d[1][0], y: d[1][1] }, { x: d[2][0], y: d[2][1] }, { x: a[0], y: a[1] }, Q ); if (m.push( { type: O, start: d[0], end: d[1] }, { type: g, start: Et, end: Ot, center: Mt, radius: p }, { type: O, start: d[2], end: d[3] } ), !pt(d[0], d[3])) { const [L, gt, At] = D( { x: d[3][0], y: d[3][1] }, { x: d[0][0], y: d[0][1] }, { x: a[0], y: a[1] }, _t ); m.push({ type: g, start: L, end: gt, center: At, radius: f }); } } return { type: z, segments: m }; } function Oe(t) { const e = Object.create(Me); return t === $t ? Object.assign(e, ge) : e; } const Me = { _currentPath: void 0, _arcDirection: void 0, _ambiguousArcCenter: !1, _regionMode: !1, _defaultGraphic: void 0, plot(t, e, n) { const r = [], c = this._setGraphicState(t), s = this._plotCurrentPath(t, e, c); if (s && r.push(s), c === I && (e == null ? void 0 : e.type) === b && r.push({ type: v, shape: ce(e, n) }), c === I && (e == null ? void 0 : e.type) === dt && r.push({ type: v, shape: pe(e, n) }), c === G && (this._currentPath = this._currentPath ?? { segments: [], region: this._regionMode, tool: e }, this._currentPath.segments.push( nt(n, this._arcDirection, this._ambiguousArcCenter) )), c === kt) { const o = rt([nt(n)], e); o && r.push(o); } return r; }, _setGraphicState(t) { if (t.type === st && (this._arcDirection = mt(t.mode)), t.type === Yt && (this._ambiguousArcCenter = t.quadrant === Ut), t.type === Z && (this._regionMode = t.region), t.type === F) return t.graphic === G ? this._defaultGraphic = G : t.graphic !== null && (this._defaultGraphic = void 0), t.graphic ?? this._defaultGraphic; }, _plotCurrentPath(t, e, n) { if (this._currentPath !== void 0 && (e !== this._currentPath.tool || t.type === Z || t.type === Xt || n === W && this._currentPath.region || n === I && this._currentPath !== void 0)) { const r = rt( this._currentPath.segments, this._currentPath.tool, this._currentPath.region ); return this._currentPath = void 0, r; } } }, ge = { _defaultGraphic: I, _ambiguousArcCenter: !0, _setGraphicState(t) { if (t.type === st) { const { mode: e } = t; this._arcDirection = mt(e), e === ct || e === ot || e === Qt ? this._defaultGraphic = G : e === W ? this._defaultGraphic = W : this._defaultGraphic = I; } if (t.type === F) return t.graphic ?? this._defaultGraphic; } }; function mt(t) { if (t === ot) return Q; if (t === ct) return _t; } function Pe(t) { const e = te(t), n = ee(), r = re(), c = Oe(t.filetype), s = []; for (const o of t.children) { const i = n.use(o), a = r.use(o, e), p = c.plot(o, i, a); s.push(...p); } return { type: Jt, units: e.units, size: ht(s), children: s }; } export { g as ARC, Ce as BoundingBox, S as CIRCLE, Jt as IMAGE, it as IMAGE_PATH, Kt as IMAGE_REGION, v as IMAGE_SHAPE, Y as LAYERED_SHAPE, O as LINE, z as OUTLINE, M as POLYGON, H as RECTANGLE, A as TWO_PI, Pe as plot, pt as positionsEqual }; //# sourceMappingURL=tracespace-plotter.js.map