@things-factory/figure-ui 10.1.88 → 10.1.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/client/modeller/editor.ts +29 -3
  2. package/client/modeller/figure-parts.ts +2 -0
  3. package/client/modeller/figure-section-editor.ts +93 -8
  4. package/client/modeller/figure-section-panel.ts +3 -1
  5. package/client/modeller/maturity.ts +8 -1
  6. package/client/modeller/palette.ts +13 -0
  7. package/client/modeller/section-drawing.ts +25 -5
  8. package/client/modeller/starting-shape.ts +5 -3
  9. package/dist-client/modeller/clips.d.ts +1 -1
  10. package/dist-client/modeller/editor.d.ts +6 -0
  11. package/dist-client/modeller/editor.js +27 -3
  12. package/dist-client/modeller/editor.js.map +1 -1
  13. package/dist-client/modeller/figure-parts.js +2 -0
  14. package/dist-client/modeller/figure-parts.js.map +1 -1
  15. package/dist-client/modeller/figure-section-editor.d.ts +8 -0
  16. package/dist-client/modeller/figure-section-editor.js +89 -8
  17. package/dist-client/modeller/figure-section-editor.js.map +1 -1
  18. package/dist-client/modeller/figure-section-panel.js +3 -1
  19. package/dist-client/modeller/figure-section-panel.js.map +1 -1
  20. package/dist-client/modeller/maturity.js +8 -1
  21. package/dist-client/modeller/maturity.js.map +1 -1
  22. package/dist-client/modeller/palette.js +13 -0
  23. package/dist-client/modeller/palette.js.map +1 -1
  24. package/dist-client/modeller/section-drawing.d.ts +12 -0
  25. package/dist-client/modeller/section-drawing.js +22 -5
  26. package/dist-client/modeller/section-drawing.js.map +1 -1
  27. package/dist-client/modeller/starting-shape.d.ts +3 -2
  28. package/dist-client/modeller/starting-shape.js +4 -0
  29. package/dist-client/modeller/starting-shape.js.map +1 -1
  30. package/dist-client/route.d.ts +1 -1
  31. package/dist-client/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +5 -5
  33. package/test/browser/acceptance-page.js +9 -0
  34. package/test/palette-icons.test.ts +5 -2
  35. package/test/parts-wiring.test.ts +1 -1
  36. package/test/section-editor.test.ts +57 -3
  37. package/translations/en.json +7 -1
  38. package/translations/ja.json +7 -1
  39. package/translations/ko.json +7 -1
  40. package/translations/ms.json +7 -1
  41. package/translations/zh.json +7 -1
@@ -26,6 +26,19 @@ export function paletteRecipe(kind, id) {
26
26
  { x: 0, z: 43 }
27
27
  ]
28
28
  };
29
+ case 'pyramid':
30
+ /* A tetrahedron: the drawn triangle's, drawn up to one point over its middle. */
31
+ return {
32
+ ...standing(100),
33
+ kind,
34
+ dimensions: { height: 100 },
35
+ points: [
36
+ { x: -50, z: -43 },
37
+ { x: 50, z: -43 },
38
+ { x: 0, z: 43 }
39
+ ],
40
+ apex: { x: 0, z: 0 }
41
+ };
29
42
  case 'plate':
30
43
  return { ...standing(10), kind: 'box', dimensions: { width: 600, height: 10, depth: 400 } };
31
44
  case 'wall':
@@ -1 +1 @@
1
- {"version":3,"file":"palette.js","sourceRoot":"","sources":["../../client/modeller/palette.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FigurePrimitiveCreation } from '@hatiolab/figure-model'\n\nimport type { FigurePaletteKind } from './figure-parts.js'\n\n/**\n * What a palette button makes: the part at a starting size a person then changes. Standing on the floor (its lowest\n * point at y 0) where the provider's frame is centred; a portal's frame already rises from its bottom.\n */\nexport function paletteRecipe(kind: FigurePaletteKind, id: string): FigurePrimitiveCreation {\n const standing = (height: number) => ({ id, position: { x: 0, y: height / 2, z: 0 } })\n switch (kind) {\n case 'box':\n return { ...standing(100), kind, dimensions: { width: 100, height: 100, depth: 100 } }\n case 'cylinder':\n return { ...standing(100), kind, dimensions: { radius: 50, length: 100 } }\n case 'rounded-box':\n return { ...standing(100), kind, dimensions: { width: 100, height: 100, depth: 100, round: 10 } }\n case 'sphere':\n return { ...standing(100), kind, dimensions: { radiusX: 50, radiusY: 50, radiusZ: 50 } }\n case 'frustum':\n return { ...standing(100), kind, dimensions: { radiusTop: 0, radiusBottom: 50, height: 100 } }\n case 'polygon':\n return {\n ...standing(100),\n kind,\n dimensions: { height: 100 },\n points: [\n { x: -50, z: -43 },\n { x: 50, z: -43 },\n { x: 0, z: 43 }\n ]\n }\n case 'plate':\n return { ...standing(10), kind: 'box', dimensions: { width: 600, height: 10, depth: 400 } }\n case 'wall':\n return { ...standing(2400), kind: 'box', dimensions: { width: 1000, height: 2400, depth: 100 } }\n case 'hollow-box':\n /* A tote at a tote's size: walls and floor that keep their thickness when it grows. */\n return { ...standing(300), kind: 'hollow-box', dimensions: { width: 600, height: 300, depth: 400, roundX: 20, roundZ: 20, wallX: 10, wallZ: 10, floor: 15 } }\n case 'portal':\n return {\n id,\n position: { x: 0, y: 0, z: 0 },\n kind: 'portal',\n /* A door frame at a door's size, as a wall is a wall's: its width, height, depth and the jambs' and head's thickness. */\n dimensions: { width: 1000, height: 2200, depth: 150, jamb: 100, head: 100 }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"palette.js","sourceRoot":"","sources":["../../client/modeller/palette.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FigurePrimitiveCreation } from '@hatiolab/figure-model'\n\nimport type { FigurePaletteKind } from './figure-parts.js'\n\n/**\n * What a palette button makes: the part at a starting size a person then changes. Standing on the floor (its lowest\n * point at y 0) where the provider's frame is centred; a portal's frame already rises from its bottom.\n */\nexport function paletteRecipe(kind: FigurePaletteKind, id: string): FigurePrimitiveCreation {\n const standing = (height: number) => ({ id, position: { x: 0, y: height / 2, z: 0 } })\n switch (kind) {\n case 'box':\n return { ...standing(100), kind, dimensions: { width: 100, height: 100, depth: 100 } }\n case 'cylinder':\n return { ...standing(100), kind, dimensions: { radius: 50, length: 100 } }\n case 'rounded-box':\n return { ...standing(100), kind, dimensions: { width: 100, height: 100, depth: 100, round: 10 } }\n case 'sphere':\n return { ...standing(100), kind, dimensions: { radiusX: 50, radiusY: 50, radiusZ: 50 } }\n case 'frustum':\n return { ...standing(100), kind, dimensions: { radiusTop: 0, radiusBottom: 50, height: 100 } }\n case 'polygon':\n return {\n ...standing(100),\n kind,\n dimensions: { height: 100 },\n points: [\n { x: -50, z: -43 },\n { x: 50, z: -43 },\n { x: 0, z: 43 }\n ]\n }\n case 'pyramid':\n /* A tetrahedron: the drawn triangle's, drawn up to one point over its middle. */\n return {\n ...standing(100),\n kind,\n dimensions: { height: 100 },\n points: [\n { x: -50, z: -43 },\n { x: 50, z: -43 },\n { x: 0, z: 43 }\n ],\n apex: { x: 0, z: 0 }\n }\n case 'plate':\n return { ...standing(10), kind: 'box', dimensions: { width: 600, height: 10, depth: 400 } }\n case 'wall':\n return { ...standing(2400), kind: 'box', dimensions: { width: 1000, height: 2400, depth: 100 } }\n case 'hollow-box':\n /* A tote at a tote's size: walls and floor that keep their thickness when it grows. */\n return { ...standing(300), kind: 'hollow-box', dimensions: { width: 600, height: 300, depth: 400, roundX: 20, roundZ: 20, wallX: 10, wallZ: 10, floor: 15 } }\n case 'portal':\n return {\n id,\n position: { x: 0, y: 0, z: 0 },\n kind: 'portal',\n /* A door frame at a door's size, as a wall is a wall's: its width, height, depth and the jambs' and head's thickness. */\n dimensions: { width: 1000, height: 2200, depth: 150, jamb: 100, head: 100 }\n }\n }\n}\n"]}
@@ -36,7 +36,19 @@ export interface SectionWorking {
36
36
  /** Along each plane axis: a rectangle's size, an ellipse's diameter. Empty for a drawn section. */
37
37
  across: Partial<Record<Axis, number>>;
38
38
  length: number;
39
+ /** A drawn section's end drawn to one point (a pyramid), across the plane axes; null for a push. */
40
+ apex: Partial<Record<Axis, number>> | null;
39
41
  }
42
+ /** A pushed part's section, axis and ends -- or a pyramid's, whose end is its apex (figure-model `loft@1`). */
43
+ export declare function drawnOf(shape: FigureEvaluatedShape): {
44
+ axis: Axis;
45
+ section: FigureSection;
46
+ start: number;
47
+ end: number;
48
+ apex: Partial<Record<Axis, number>> | null;
49
+ } | undefined;
50
+ /** Where a new apex goes: over the middle of the points' span, whole millimetres. */
51
+ export declare function apexOver(points: Points, axis: Axis): Partial<Record<Axis, number>>;
40
52
  /** The working state of a pushed part as it stands. */
41
53
  export declare function workingOf(shape: FigureEvaluatedShape): SectionWorking;
42
54
  /** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */
@@ -81,9 +81,23 @@ export function extentOf(points, axis) {
81
81
  return Math.ceil((far * 1.4 + 40) / 50) * 50;
82
82
  }
83
83
  export const POINT_LIMIT = FIGURE_SECTION_POINT_LIMIT;
84
+ /** A pushed part's section, axis and ends -- or a pyramid's, whose end is its apex (figure-model `loft@1`). */
85
+ export function drawnOf(shape) {
86
+ if (shape.extrusion)
87
+ return { ...shape.extrusion, apex: null };
88
+ if (shape.loft)
89
+ return { ...shape.loft, apex: shape.loft.apex };
90
+ return undefined;
91
+ }
92
+ /** Where a new apex goes: over the middle of the points' span, whole millimetres. */
93
+ export function apexOver(points, axis) {
94
+ const [u, v] = FIGURE_SECTION_PLANE[axis];
95
+ const mid = (x) => Math.round((Math.min(...points.map(p => p[x])) + Math.max(...points.map(p => p[x]))) / 2);
96
+ return { [u]: mid(u), [v]: mid(v) };
97
+ }
84
98
  /** The working state of a pushed part as it stands. */
85
99
  export function workingOf(shape) {
86
- const e = shape.extrusion;
100
+ const e = drawnOf(shape);
87
101
  const s = e.section;
88
102
  const [u, v] = FIGURE_SECTION_PLANE[e.axis];
89
103
  const across = s.kind === 'rectangle'
@@ -91,12 +105,13 @@ export function workingOf(shape) {
91
105
  : s.kind === 'ellipse'
92
106
  ? { [u]: 2 * s.radius[u], [v]: 2 * s.radius[v] }
93
107
  : {};
94
- return { points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [], across, length: e.end - e.start };
108
+ return { points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [], across, length: e.end - e.start, apex: e.apex ? { ...e.apex } : null };
95
109
  }
96
110
  /** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */
97
111
  export function sectionOf(shape, w) {
98
- const s = shape.extrusion.section;
99
- const [u, v] = FIGURE_SECTION_PLANE[shape.extrusion.axis];
112
+ const e = drawnOf(shape);
113
+ const s = e.section;
114
+ const [u, v] = FIGURE_SECTION_PLANE[e.axis];
100
115
  if (s.kind === 'polygon')
101
116
  return { kind: 'polygon', points: w.points };
102
117
  if (s.kind === 'ellipse')
@@ -105,12 +120,14 @@ export function sectionOf(shape, w) {
105
120
  }
106
121
  /** What would be refused, as words, with the section's own issues for marking points and sides. By the kernel's checks. */
107
122
  export function workingIssuesOf(shape, w) {
108
- const e = shape.extrusion;
123
+ const e = drawnOf(shape);
109
124
  const section = sectionOf(shape, w);
110
125
  const issues = checkFigureSection(section, e.axis);
111
126
  const words = issues.map(i => issueWords(i, w.points, e.axis));
112
127
  if (!(Number.isFinite(w.length) && w.length > 0))
113
128
  words.push({ key: 'figure.text.section-issue-length', params: {} });
129
+ if (w.apex && !Object.values(w.apex).every(n => Number.isFinite(n)))
130
+ words.push({ key: 'figure.text.section-issue-number', params: {} });
114
131
  if (!issues.length && words.length === 0 && shape.cavity) {
115
132
  const made = figureExtrusionFeaturesOf({ axis: e.axis, section, start: e.start, end: e.start + w.length }, [shape.cavity]);
116
133
  if ('refused' in made) {
@@ -1 +1 @@
1
- {"version":3,"file":"section-drawing.js","sourceRoot":"","sources":["../../client/modeller/section-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_SECTION_PLANE, FIGURE_SECTION_POINT_LIMIT, checkFigureSection, figureExtrusionFeaturesOf, figureSectionSidesOf } from '@hatiolab/figure-model'\nimport type { FigureEvaluatedShape, FigureSection, FigureSectionIssue, FigureSectionPoint } from '@hatiolab/figure-model'\n\n/*\n * What the section editor does to a drawn section's points, and how it says what is wrong with them (ADR-0100 §3.2).\n * The points are the kernel's own (`{ id, x, z }` for a push along Y), their validity is the kernel's own check, and a\n * point's number on screen is its own name's number (Q9): p3 is 「3」 before and after any edit, and deleting it leaves\n * 1, 2 and 4.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type Points = readonly FigureSectionPoint[]\n\n/** The number a point is shown by: its name's number. */\nexport const pointLabel = (id: string) => /^p(\\d+)$/.exec(id)?.[1] ?? id\n\n/** The next point's name: one past the highest number the loop has, so a new point never takes a gap's number. */\nexport function nextPointId(points: Points): string {\n return `p${Math.max(0, ...points.map(p => Number(/^p(\\d+)$/.exec(p.id)?.[1] ?? 0))) + 1}`\n}\n\n/** A point in the middle of the side from `from` to the point after it, whole millimetres; the new point's id with it. */\nexport function insertAfter(points: Points, from: string, axis: Axis): { points: FigureSectionPoint[]; id: string } {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const i = points.findIndex(p => p.id === from)\n const a = points[i]!,\n b = points[(i + 1) % points.length]!\n const id = nextPointId(points)\n const mid = { id, [u]: Math.round((a[u]! + b[u]!) / 2), [v]: Math.round((a[v]! + b[v]!) / 2) } as FigureSectionPoint\n return { points: [...points.slice(0, i + 1), mid, ...points.slice(i + 1)], id }\n}\n\n/** The points less one, or why not: a section is three points or more. */\nexport function removePoint(points: Points, id: string): FigureSectionPoint[] | { refused: 'too-few' } {\n if (points.length <= 3) return { refused: 'too-few' }\n return points.filter(p => p.id !== id)\n}\n\nexport function movePoint(points: Points, id: string, at: Partial<Record<Axis, number>>): FigureSectionPoint[] {\n return points.map(p => (p.id === id ? { ...p, ...at } : p))\n}\n\n/** What is wrong with the points, by the kernel's own check. */\nexport const issuesOf = (points: Points, axis: Axis) => checkFigureSection({ kind: 'polygon', points: [...points] }, axis)\n\n/** A side said in the loop's order, 3–4 not 4–3: its id is the pair in name order, which a person never sees. */\nfunction sideLabel(points: Points, axis: Axis, side: string): string {\n const s = figureSectionSidesOf({ kind: 'polygon', points: [...points] }, axis).find(x => x.id === side)\n const [a, b] = s?.from ? [s.from, s.to!] : side.split('~')\n return `${pointLabel(a!)}–${pointLabel(b!)}`\n}\n\n/** An issue as the words that say it: an i18n key and its values. */\nexport function issueWords(issue: FigureSectionIssue, points: Points, axis: Axis): { key: string; params: Record<string, string> } {\n const line = (s: string) => sideLabel(points, axis, s)\n switch (issue.code) {\n case 'SIDES_CROSS':\n return { key: 'figure.text.section-issue-cross', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_TOUCH':\n return { key: 'figure.text.section-issue-touch', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_FOLD':\n return { key: 'figure.text.section-issue-fold', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'ZERO_LENGTH_SIDE':\n return { key: 'figure.text.section-issue-zero-length', params: { a: line(issue.side) } }\n case 'ZERO_AREA':\n return { key: 'figure.text.section-issue-zero-area', params: {} }\n case 'TOO_FEW_POINTS':\n return { key: 'figure.text.section-issue-too-few', params: {} }\n case 'TOO_MANY_POINTS':\n return { key: 'figure.text.section-issue-too-many', params: { limit: String(issue.limit) } }\n case 'CORNER_TOO_LARGE':\n return { key: 'figure.text.section-issue-corner', params: { max: String(Math.round(issue.max * 1000) / 1000) } }\n default:\n return { key: 'figure.text.section-issue-number', params: {} }\n }\n}\n\n/** Every side and point an issue names, to mark on the drawing -- by more than colour: the list says them too. */\nexport function markedBy(issues: readonly FigureSectionIssue[]): { sides: Set<string>; points: Set<string> } {\n const sides = new Set<string>(),\n points = new Set<string>()\n for (const i of issues) {\n if ('sides' in i) for (const s of i.sides) sides.add(s)\n if ('side' in i) sides.add(i.side)\n if ('point' in i) points.add(i.point)\n if ('at' in i) points.add(String(i.at).split('.')[0]!)\n }\n for (const s of sides) for (const p of s.split('~')) points.add(p)\n return { sides, points }\n}\n\n/** How far the drawing reaches from the origin: the points' farthest coordinate with room around, in 50 mm steps. */\nexport function extentOf(points: Points, axis: Axis): number {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const far = Math.max(1, ...points.flatMap(p => [Math.abs(p[u] ?? 0), Math.abs(p[v] ?? 0)]))\n return Math.ceil((far * 1.4 + 40) / 50) * 50\n}\n\nexport const POINT_LIMIT = FIGURE_SECTION_POINT_LIMIT\n\n/** What the section editor holds while it is open: the points of a drawn section, the widths across, the length. */\nexport interface SectionWorking {\n points: FigureSectionPoint[]\n /** Along each plane axis: a rectangle's size, an ellipse's diameter. Empty for a drawn section. */\n across: Partial<Record<Axis, number>>\n length: number\n}\n\n/** The working state of a pushed part as it stands. */\nexport function workingOf(shape: FigureEvaluatedShape): SectionWorking {\n const e = shape.extrusion!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n const across =\n s.kind === 'rectangle'\n ? { [u]: s.size[u]!, [v]: s.size[v]! }\n : s.kind === 'ellipse'\n ? { [u]: 2 * s.radius[u]!, [v]: 2 * s.radius[v]! }\n : {}\n return { points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [], across, length: e.end - e.start }\n}\n\n/** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */\nexport function sectionOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureSection {\n const s = shape.extrusion!.section\n const [u, v] = FIGURE_SECTION_PLANE[shape.extrusion!.axis]\n if (s.kind === 'polygon') return { kind: 'polygon', points: w.points }\n if (s.kind === 'ellipse') return { kind: 'ellipse', radius: { [u]: w.across[u]! / 2, [v]: w.across[v]! / 2 } }\n return { kind: 'rectangle', size: { [u]: w.across[u]!, [v]: w.across[v]! }, ...(s.corner ? { corner: s.corner } : {}) }\n}\n\n/** What would be refused, as words, with the section's own issues for marking points and sides. By the kernel's checks. */\nexport function workingIssuesOf(\n shape: FigureEvaluatedShape,\n w: SectionWorking\n): { issues: FigureSectionIssue[]; words: Array<{ key: string; params: Record<string, string> }> } {\n const e = shape.extrusion!\n const section = sectionOf(shape, w)\n const issues = checkFigureSection(section, e.axis)\n const words = issues.map(i => issueWords(i, w.points, e.axis))\n if (!(Number.isFinite(w.length) && w.length > 0)) words.push({ key: 'figure.text.section-issue-length', params: {} })\n if (!issues.length && words.length === 0 && shape.cavity) {\n const made = figureExtrusionFeaturesOf({ axis: e.axis, section, start: e.start, end: e.start + w.length }, [shape.cavity])\n if ('refused' in made) {\n const r = made.refused\n words.push({ key: r.code === 'CAVITY_NO_LENGTH' ? 'figure.text.section-issue-cavity-length' : 'figure.text.section-issue-cavity-walls', params: {} })\n }\n }\n return { issues, words }\n}\n"]}
1
+ {"version":3,"file":"section-drawing.js","sourceRoot":"","sources":["../../client/modeller/section-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_SECTION_PLANE, FIGURE_SECTION_POINT_LIMIT, checkFigureSection, figureExtrusionFeaturesOf, figureSectionSidesOf } from '@hatiolab/figure-model'\nimport type { FigureEvaluatedShape, FigureSection, FigureSectionIssue, FigureSectionPoint } from '@hatiolab/figure-model'\n\n/*\n * What the section editor does to a drawn section's points, and how it says what is wrong with them (ADR-0100 §3.2).\n * The points are the kernel's own (`{ id, x, z }` for a push along Y), their validity is the kernel's own check, and a\n * point's number on screen is its own name's number (Q9): p3 is 「3」 before and after any edit, and deleting it leaves\n * 1, 2 and 4.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type Points = readonly FigureSectionPoint[]\n\n/** The number a point is shown by: its name's number. */\nexport const pointLabel = (id: string) => /^p(\\d+)$/.exec(id)?.[1] ?? id\n\n/** The next point's name: one past the highest number the loop has, so a new point never takes a gap's number. */\nexport function nextPointId(points: Points): string {\n return `p${Math.max(0, ...points.map(p => Number(/^p(\\d+)$/.exec(p.id)?.[1] ?? 0))) + 1}`\n}\n\n/** A point in the middle of the side from `from` to the point after it, whole millimetres; the new point's id with it. */\nexport function insertAfter(points: Points, from: string, axis: Axis): { points: FigureSectionPoint[]; id: string } {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const i = points.findIndex(p => p.id === from)\n const a = points[i]!,\n b = points[(i + 1) % points.length]!\n const id = nextPointId(points)\n const mid = { id, [u]: Math.round((a[u]! + b[u]!) / 2), [v]: Math.round((a[v]! + b[v]!) / 2) } as FigureSectionPoint\n return { points: [...points.slice(0, i + 1), mid, ...points.slice(i + 1)], id }\n}\n\n/** The points less one, or why not: a section is three points or more. */\nexport function removePoint(points: Points, id: string): FigureSectionPoint[] | { refused: 'too-few' } {\n if (points.length <= 3) return { refused: 'too-few' }\n return points.filter(p => p.id !== id)\n}\n\nexport function movePoint(points: Points, id: string, at: Partial<Record<Axis, number>>): FigureSectionPoint[] {\n return points.map(p => (p.id === id ? { ...p, ...at } : p))\n}\n\n/** What is wrong with the points, by the kernel's own check. */\nexport const issuesOf = (points: Points, axis: Axis) => checkFigureSection({ kind: 'polygon', points: [...points] }, axis)\n\n/** A side said in the loop's order, 3–4 not 4–3: its id is the pair in name order, which a person never sees. */\nfunction sideLabel(points: Points, axis: Axis, side: string): string {\n const s = figureSectionSidesOf({ kind: 'polygon', points: [...points] }, axis).find(x => x.id === side)\n const [a, b] = s?.from ? [s.from, s.to!] : side.split('~')\n return `${pointLabel(a!)}–${pointLabel(b!)}`\n}\n\n/** An issue as the words that say it: an i18n key and its values. */\nexport function issueWords(issue: FigureSectionIssue, points: Points, axis: Axis): { key: string; params: Record<string, string> } {\n const line = (s: string) => sideLabel(points, axis, s)\n switch (issue.code) {\n case 'SIDES_CROSS':\n return { key: 'figure.text.section-issue-cross', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_TOUCH':\n return { key: 'figure.text.section-issue-touch', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_FOLD':\n return { key: 'figure.text.section-issue-fold', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'ZERO_LENGTH_SIDE':\n return { key: 'figure.text.section-issue-zero-length', params: { a: line(issue.side) } }\n case 'ZERO_AREA':\n return { key: 'figure.text.section-issue-zero-area', params: {} }\n case 'TOO_FEW_POINTS':\n return { key: 'figure.text.section-issue-too-few', params: {} }\n case 'TOO_MANY_POINTS':\n return { key: 'figure.text.section-issue-too-many', params: { limit: String(issue.limit) } }\n case 'CORNER_TOO_LARGE':\n return { key: 'figure.text.section-issue-corner', params: { max: String(Math.round(issue.max * 1000) / 1000) } }\n default:\n return { key: 'figure.text.section-issue-number', params: {} }\n }\n}\n\n/** Every side and point an issue names, to mark on the drawing -- by more than colour: the list says them too. */\nexport function markedBy(issues: readonly FigureSectionIssue[]): { sides: Set<string>; points: Set<string> } {\n const sides = new Set<string>(),\n points = new Set<string>()\n for (const i of issues) {\n if ('sides' in i) for (const s of i.sides) sides.add(s)\n if ('side' in i) sides.add(i.side)\n if ('point' in i) points.add(i.point)\n if ('at' in i) points.add(String(i.at).split('.')[0]!)\n }\n for (const s of sides) for (const p of s.split('~')) points.add(p)\n return { sides, points }\n}\n\n/** How far the drawing reaches from the origin: the points' farthest coordinate with room around, in 50 mm steps. */\nexport function extentOf(points: Points, axis: Axis): number {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const far = Math.max(1, ...points.flatMap(p => [Math.abs(p[u] ?? 0), Math.abs(p[v] ?? 0)]))\n return Math.ceil((far * 1.4 + 40) / 50) * 50\n}\n\nexport const POINT_LIMIT = FIGURE_SECTION_POINT_LIMIT\n\n/** What the section editor holds while it is open: the points of a drawn section, the widths across, the length. */\nexport interface SectionWorking {\n points: FigureSectionPoint[]\n /** Along each plane axis: a rectangle's size, an ellipse's diameter. Empty for a drawn section. */\n across: Partial<Record<Axis, number>>\n length: number\n /** A drawn section's end drawn to one point (a pyramid), across the plane axes; null for a push. */\n apex: Partial<Record<Axis, number>> | null\n}\n\n/** A pushed part's section, axis and ends -- or a pyramid's, whose end is its apex (figure-model `loft@1`). */\nexport function drawnOf(shape: FigureEvaluatedShape):\n | { axis: Axis; section: FigureSection; start: number; end: number; apex: Partial<Record<Axis, number>> | null }\n | undefined {\n if (shape.extrusion) return { ...shape.extrusion, apex: null }\n if (shape.loft) return { ...shape.loft, apex: shape.loft.apex }\n return undefined\n}\n\n/** Where a new apex goes: over the middle of the points' span, whole millimetres. */\nexport function apexOver(points: Points, axis: Axis): Partial<Record<Axis, number>> {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const mid = (x: Axis) => Math.round((Math.min(...points.map(p => p[x]!)) + Math.max(...points.map(p => p[x]!))) / 2)\n return { [u]: mid(u), [v]: mid(v) }\n}\n\n/** The working state of a pushed part as it stands. */\nexport function workingOf(shape: FigureEvaluatedShape): SectionWorking {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n const across =\n s.kind === 'rectangle'\n ? { [u]: s.size[u]!, [v]: s.size[v]! }\n : s.kind === 'ellipse'\n ? { [u]: 2 * s.radius[u]!, [v]: 2 * s.radius[v]! }\n : {}\n return { points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [], across, length: e.end - e.start, apex: e.apex ? { ...e.apex } : null }\n}\n\n/** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */\nexport function sectionOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureSection {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n if (s.kind === 'polygon') return { kind: 'polygon', points: w.points }\n if (s.kind === 'ellipse') return { kind: 'ellipse', radius: { [u]: w.across[u]! / 2, [v]: w.across[v]! / 2 } }\n return { kind: 'rectangle', size: { [u]: w.across[u]!, [v]: w.across[v]! }, ...(s.corner ? { corner: s.corner } : {}) }\n}\n\n/** What would be refused, as words, with the section's own issues for marking points and sides. By the kernel's checks. */\nexport function workingIssuesOf(\n shape: FigureEvaluatedShape,\n w: SectionWorking\n): { issues: FigureSectionIssue[]; words: Array<{ key: string; params: Record<string, string> }> } {\n const e = drawnOf(shape)!\n const section = sectionOf(shape, w)\n const issues = checkFigureSection(section, e.axis)\n const words = issues.map(i => issueWords(i, w.points, e.axis))\n if (!(Number.isFinite(w.length) && w.length > 0)) words.push({ key: 'figure.text.section-issue-length', params: {} })\n if (w.apex && !Object.values(w.apex).every(n => Number.isFinite(n))) words.push({ key: 'figure.text.section-issue-number', params: {} })\n if (!issues.length && words.length === 0 && shape.cavity) {\n const made = figureExtrusionFeaturesOf({ axis: e.axis, section, start: e.start, end: e.start + w.length }, [shape.cavity])\n if ('refused' in made) {\n const r = made.refused\n words.push({ key: r.code === 'CAVITY_NO_LENGTH' ? 'figure.text.section-issue-cavity-length' : 'figure.text.section-issue-cavity-walls', params: {} })\n }\n }\n return { issues, words }\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * What a person calls a part's shape (ADR-0100 §2.1): the starting shape it reads as -- 상자, 둥근 상자, 위가 열린 상자,
3
- * 원기둥, 문틀, 구, 원뿔, 그린 단면. A word for the screen, read from the shape node's own params; it is not a kind of
3
+ * 원기둥, 문틀, 구, 원뿔, 그린 단면, 뿔. A word for the screen, read from the shape node's own params; it is not a kind of
4
4
  * stored shape, and nothing is decided by it.
5
5
  */
6
- export type StartingShapeKind = 'cube' | 'rounded-box' | 'hollow-box' | 'cylinder' | 'portal' | 'sphere' | 'frustum' | 'polygon';
6
+ export type StartingShapeKind = 'cube' | 'rounded-box' | 'hollow-box' | 'cylinder' | 'portal' | 'sphere' | 'frustum' | 'polygon' | 'pyramid';
7
7
  export declare function startingShapeKindOf(shape: {
8
8
  op: string;
9
9
  params?: Record<string, unknown>;
@@ -27,6 +27,7 @@ export declare function startingShapeKindOfBody(shape: {
27
27
  kind: string;
28
28
  };
29
29
  };
30
+ loft?: unknown;
30
31
  } | undefined): StartingShapeKind | undefined;
31
32
  /** Whether a body is round across -- a circle or an ellipse pushed, anything turned: it takes a segment count. */
32
33
  export declare const isRoundBody: (shape: Parameters<typeof startingShapeKindOfBody>[0]) => boolean;
@@ -2,6 +2,8 @@ export function startingShapeKindOf(shape) {
2
2
  const p = shape?.params ?? {};
3
3
  if (shape?.op === 'revolve@1')
4
4
  return p.profile === 'taper' ? 'frustum' : 'sphere';
5
+ if (shape?.op === 'loft@1')
6
+ return 'pyramid';
5
7
  if (shape?.op !== 'extrude@1')
6
8
  return undefined;
7
9
  if (p.section === 'ellipse')
@@ -19,6 +21,8 @@ export function startingShapeKindOf(shape) {
19
21
  * a door frame is the section with jambs, a drawn section the rest of the drawn ones.
20
22
  */
21
23
  export function startingShapeKindOfBody(shape) {
24
+ if (shape?.loft)
25
+ return 'pyramid';
22
26
  if (shape?.revolution)
23
27
  return shape.revolution.profile.kind === 'taper' ? 'frustum' : 'sphere';
24
28
  const s = shape?.extrusion?.section;
@@ -1 +1 @@
1
- {"version":3,"file":"starting-shape.js","sourceRoot":"","sources":["../../client/modeller/starting-shape.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,mBAAmB,CAAC,KAAmE;IACrG,MAAM,CAAC,GAAG,KAAK,EAAE,MAAM,IAAI,EAAE,CAAA;IAC7B,IAAI,KAAK,EAAE,EAAE,KAAK,WAAW;QAAE,OAAO,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;IAClF,IAAI,KAAK,EAAE,EAAE,KAAK,WAAW;QAAE,OAAO,SAAS,CAAA;IAC/C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,UAAU,CAAA;IAC9C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC7C,IAAI,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC3C,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,YAAY,CAAA;IACjC,OAAO,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAA;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAwM;IAC9O,IAAI,KAAK,EAAE,UAAU;QAAE,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;IAC9F,MAAM,CAAC,GAAG,KAAK,EAAE,SAAS,EAAE,OAAO,CAAA;IACnC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IACxB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,UAAU,CAAA;IAC3C,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAM,CAAC,UAAU,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7F,IAAI,KAAM,CAAC,MAAM;QAAE,OAAO,YAAY,CAAA;IACtC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAA;AAC1C,CAAC;AAED,kHAAkH;AAClH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAoD,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA","sourcesContent":["/**\n * What a person calls a part's shape (ADR-0100 §2.1): the starting shape it reads as -- 상자, 둥근 상자, 위가 열린 상자,\n * 원기둥, 문틀, 구, 원뿔, 그린 단면. A word for the screen, read from the shape node's own params; it is not a kind of\n * stored shape, and nothing is decided by it.\n */\nexport type StartingShapeKind = 'cube' | 'rounded-box' | 'hollow-box' | 'cylinder' | 'portal' | 'sphere' | 'frustum' | 'polygon'\n\nexport function startingShapeKindOf(shape: { op: string; params?: Record<string, unknown> } | undefined): StartingShapeKind | undefined {\n const p = shape?.params ?? {}\n if (shape?.op === 'revolve@1') return p.profile === 'taper' ? 'frustum' : 'sphere'\n if (shape?.op !== 'extrude@1') return undefined\n if (p.section === 'ellipse') return 'cylinder'\n if (p.section === 'polygon') return 'polygon'\n if (p.section === 'portal') return 'portal'\n if (p.cavity) return 'hollow-box'\n return p.corner === 'round' ? 'rounded-box' : 'cube'\n}\n\n/**\n * The same word for an evaluated body, when only the shape the kernel evaluated is in hand (a row of the parts list):\n * a door frame is the section with jambs, a drawn section the rest of the drawn ones.\n */\nexport function startingShapeKindOfBody(shape: { provider?: string; dimensions?: Record<string, number>; extrusion?: { section: { kind: string; corner?: unknown } }; cavity?: unknown; revolution?: { profile: { kind: string } } } | undefined): StartingShapeKind | undefined {\n if (shape?.revolution) return shape.revolution.profile.kind === 'taper' ? 'frustum' : 'sphere'\n const s = shape?.extrusion?.section\n if (!s) return undefined\n if (s.kind === 'ellipse') return 'cylinder'\n if (s.kind === 'polygon') return shape!.dimensions?.jamb !== undefined ? 'portal' : 'polygon'\n if (shape!.cavity) return 'hollow-box'\n return s.corner ? 'rounded-box' : 'cube'\n}\n\n/** Whether a body is round across -- a circle or an ellipse pushed, anything turned: it takes a segment count. */\nexport const isRoundBody = (shape: Parameters<typeof startingShapeKindOfBody>[0]) => ['cylinder', 'sphere', 'frustum'].includes(startingShapeKindOfBody(shape) ?? '')\n"]}
1
+ {"version":3,"file":"starting-shape.js","sourceRoot":"","sources":["../../client/modeller/starting-shape.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,mBAAmB,CAAC,KAAmE;IACrG,MAAM,CAAC,GAAG,KAAK,EAAE,MAAM,IAAI,EAAE,CAAA;IAC7B,IAAI,KAAK,EAAE,EAAE,KAAK,WAAW;QAAE,OAAO,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;IAClF,IAAI,KAAK,EAAE,EAAE,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC5C,IAAI,KAAK,EAAE,EAAE,KAAK,WAAW;QAAE,OAAO,SAAS,CAAA;IAC/C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,UAAU,CAAA;IAC9C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC7C,IAAI,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC3C,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,YAAY,CAAA;IACjC,OAAO,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAA;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAwN;IAC9P,IAAI,KAAK,EAAE,IAAI;QAAE,OAAO,SAAS,CAAA;IACjC,IAAI,KAAK,EAAE,UAAU;QAAE,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;IAC9F,MAAM,CAAC,GAAG,KAAK,EAAE,SAAS,EAAE,OAAO,CAAA;IACnC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IACxB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,UAAU,CAAA;IAC3C,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAM,CAAC,UAAU,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7F,IAAI,KAAM,CAAC,MAAM;QAAE,OAAO,YAAY,CAAA;IACtC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAA;AAC1C,CAAC;AAED,kHAAkH;AAClH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAoD,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA","sourcesContent":["/**\n * What a person calls a part's shape (ADR-0100 §2.1): the starting shape it reads as -- 상자, 둥근 상자, 위가 열린 상자,\n * 원기둥, 문틀, 구, 원뿔, 그린 단면, 뿔. A word for the screen, read from the shape node's own params; it is not a kind of\n * stored shape, and nothing is decided by it.\n */\nexport type StartingShapeKind = 'cube' | 'rounded-box' | 'hollow-box' | 'cylinder' | 'portal' | 'sphere' | 'frustum' | 'polygon' | 'pyramid'\n\nexport function startingShapeKindOf(shape: { op: string; params?: Record<string, unknown> } | undefined): StartingShapeKind | undefined {\n const p = shape?.params ?? {}\n if (shape?.op === 'revolve@1') return p.profile === 'taper' ? 'frustum' : 'sphere'\n if (shape?.op === 'loft@1') return 'pyramid'\n if (shape?.op !== 'extrude@1') return undefined\n if (p.section === 'ellipse') return 'cylinder'\n if (p.section === 'polygon') return 'polygon'\n if (p.section === 'portal') return 'portal'\n if (p.cavity) return 'hollow-box'\n return p.corner === 'round' ? 'rounded-box' : 'cube'\n}\n\n/**\n * The same word for an evaluated body, when only the shape the kernel evaluated is in hand (a row of the parts list):\n * a door frame is the section with jambs, a drawn section the rest of the drawn ones.\n */\nexport function startingShapeKindOfBody(shape: { provider?: string; dimensions?: Record<string, number>; extrusion?: { section: { kind: string; corner?: unknown } }; cavity?: unknown; revolution?: { profile: { kind: string } }; loft?: unknown } | undefined): StartingShapeKind | undefined {\n if (shape?.loft) return 'pyramid'\n if (shape?.revolution) return shape.revolution.profile.kind === 'taper' ? 'frustum' : 'sphere'\n const s = shape?.extrusion?.section\n if (!s) return undefined\n if (s.kind === 'ellipse') return 'cylinder'\n if (s.kind === 'polygon') return shape!.dimensions?.jamb !== undefined ? 'portal' : 'polygon'\n if (shape!.cavity) return 'hollow-box'\n return s.corner ? 'rounded-box' : 'cube'\n}\n\n/** Whether a body is round across -- a circle or an ellipse pushed, anything turned: it takes a segment count. */\nexport const isRoundBody = (shape: Parameters<typeof startingShapeKindOfBody>[0]) => ['cylinder', 'sphere', 'frustum'].includes(startingShapeKindOfBody(shape) ?? '')\n"]}
@@ -1 +1 @@
1
- export default function route(page: string): "figure-list" | "figure-modeller" | undefined;
1
+ export default function route(page: string): "figure-modeller" | "figure-list" | undefined;