scanruler-mcp 0.1.0 → 0.3.0

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.
package/src/commands.json CHANGED
@@ -2,10 +2,19 @@
2
2
  {
3
3
  "name": "align.auto",
4
4
  "title": "Auto-align the part",
5
- "description": "Read a coordinate system off the scan and apply it, as Auto-align then Confirm alignment do: the directions most faces are square to and the axis round walls run along, the part standing on its base, its long side along X. Returns what the pose was read from, the transform and the elements afterwards. One undo step.",
5
+ "description": "Read a coordinate system off the scan and apply it, as Auto-align then Confirm alignment do: the directions most faces are square to and the axis round walls run along, the part standing on its base, its long side along X. Returns what the pose was read from, the transform and how many elements moved with it. One undo step.",
6
6
  "input": {
7
7
  "type": "object",
8
- "properties": {},
8
+ "properties": {
9
+ "detail": {
10
+ "type": "string",
11
+ "enum": [
12
+ "brief",
13
+ "full"
14
+ ],
15
+ "description": "brief (the default): the transform and how many elements moved with the part. full: every element where it now is, as the list gives it."
16
+ }
17
+ },
9
18
  "additionalProperties": false
10
19
  },
11
20
  "readOnly": false,
@@ -15,10 +24,19 @@
15
24
  {
16
25
  "name": "align.clear",
17
26
  "title": "Reset the alignment",
18
- "description": "Put the part back in the coordinates the scanner delivered it in, with everything measured on it. One undo step.",
27
+ "description": "Put the part back in the coordinates the scanner delivered it in, with everything measured on it. Returns how many elements moved with it. One undo step.",
19
28
  "input": {
20
29
  "type": "object",
21
- "properties": {},
30
+ "properties": {
31
+ "detail": {
32
+ "type": "string",
33
+ "enum": [
34
+ "brief",
35
+ "full"
36
+ ],
37
+ "description": "brief (the default): the transform and how many elements moved with the part. full: every element where it now is, as the list gives it."
38
+ }
39
+ },
22
40
  "additionalProperties": false
23
41
  },
24
42
  "readOnly": false,
@@ -28,7 +46,7 @@
28
46
  {
29
47
  "name": "align.datum",
30
48
  "title": "Align the part to datums",
31
- "description": "A 3-2-1 alignment, as the panel’s alignment box sets it up: primary levels the part — a plane (or 3 points on a face) whose outward normal becomes primaryAxis (default z-, the face the part stands on facing down); secondary turns it — a line, axis or plane (or 2 points along an edge) laid along secondaryAxis (default x+); origin is the zero point — a point, sphere or circle (or 1 point). Each is an element by id or name, or points on the scan in mm. An origin alone moves the part without turning it. Everything measured moves with the part. Returns the transform applied and the elements afterwards. One undo step.",
49
+ "description": "A 3-2-1 alignment, as the panel’s alignment box sets it up: primary levels the part — a plane (or 3 points on a face) whose outward normal becomes primaryAxis (default z-, the face the part stands on facing down); secondary turns it — a line, axis or plane (or 2 points along an edge) laid along secondaryAxis (default x+); origin is the zero point — a point, sphere or circle (or 1 point). Each is an element by id or name, or points on the scan in mm. An origin alone moves the part without turning it. Everything measured moves with the part. Returns the transform applied — the whole alignment the part carries, when it was aligned before — and how many elements moved with it. One undo step.",
32
50
  "input": {
33
51
  "type": "object",
34
52
  "properties": {
@@ -208,6 +226,14 @@
208
226
  }
209
227
  ],
210
228
  "description": "The zero point: an element, or a point on the scan."
229
+ },
230
+ "detail": {
231
+ "type": "string",
232
+ "enum": [
233
+ "brief",
234
+ "full"
235
+ ],
236
+ "description": "brief (the default): the transform and how many elements moved with the part. full: every element where it now is, as the list gives it."
211
237
  }
212
238
  },
213
239
  "additionalProperties": false
@@ -219,10 +245,19 @@
219
245
  {
220
246
  "name": "align.symmetry",
221
247
  "title": "Align the part on its symmetry plane",
222
- "description": "Settle the part’s pose on its mirror plane and apply it, as Use symmetry then Confirm alignment do: the pose is Auto-align’s, the mirror plane a measured symmetry plane or one searched for on the scan; the axis nearest its normal is turned onto it and the zero point put on it. Refuses when the scan has no symmetry plane. Returns the note on what it settled on, the transform and the elements afterwards. One undo step.",
248
+ "description": "Settle the part’s pose on its mirror plane and apply it, as Use symmetry then Confirm alignment do: the pose is Auto-align’s, the mirror plane a measured symmetry plane or one searched for on the scan; the axis nearest its normal is turned onto it and the zero point put on it. Refuses when the scan has no symmetry plane. Returns the note on what it settled on, the transform and how many elements moved with it. One undo step.",
223
249
  "input": {
224
250
  "type": "object",
225
- "properties": {},
251
+ "properties": {
252
+ "detail": {
253
+ "type": "string",
254
+ "enum": [
255
+ "brief",
256
+ "full"
257
+ ],
258
+ "description": "brief (the default): the transform and how many elements moved with the part. full: every element where it now is, as the list gives it."
259
+ }
260
+ },
226
261
  "additionalProperties": false
227
262
  },
228
263
  "readOnly": false,
@@ -299,6 +334,36 @@
299
334
  "returnsFile": false,
300
335
  "returnsImage": false
301
336
  },
337
+ {
338
+ "name": "deviation.hotspots",
339
+ "title": "Where the deviation lies over tolerance",
340
+ "description": "The deviation map read as patches: the scan vertices whose deviation lies past the tolerance (the map’s own, under deviation.settings, unless tolerance says otherwise) gathered into connected regions, the largest and farthest first — where the part is off, how large each place is and by how much, instead of one number over the whole part. Each patch: its centre and box in mm (in the frame the scan is measured in — what scan.query { box } and element.fit take), its area, how many vertices, the mean and the extreme deviation and which side (outside the reference or inside), the point of the extreme and the scan vertex there, and a few of its vertices (what element.fit_marked takes). With a map against the reference part the patch’s centre and extreme are given on the reference too (onReference — what the Deviation workspace shows and view.render { frame } takes there). grain is how close two vertices over tolerance have to be to be one patch, three point spacings by default. found and over say how many patches and vertices over tolerance there were in all — within the search distance, the vertices the map draws as a measurement. Then far, the vertices past the search distance, which the map draws bare: read it every time — far.inside is the scan deeper inside the reference than the search distance, where the reference has material the part has not (a hole, a pocket or a slot the model lacks), far.outside the scan further off it, where the part has what the model has not, or scan spray; each with its count and its patches, the largest first, and far.count both together; unmeasured says how many vertices the facing limit left without a reading. Needs a deviation map (deviation.align, or deviation.set_target). Changes nothing.",
341
+ "input": {
342
+ "type": "object",
343
+ "properties": {
344
+ "tolerance": {
345
+ "type": "number",
346
+ "description": "± mm; the map’s tolerance by default.",
347
+ "exclusiveMinimum": 0
348
+ },
349
+ "patches": {
350
+ "type": "integer",
351
+ "description": "How many patches to name; 8 by default, 50 at most.",
352
+ "minimum": 1,
353
+ "maximum": 50
354
+ },
355
+ "grain": {
356
+ "type": "number",
357
+ "description": "mm — how close two vertices over tolerance have to be to be one patch; three point spacings by default.",
358
+ "exclusiveMinimum": 0
359
+ }
360
+ },
361
+ "additionalProperties": false
362
+ },
363
+ "readOnly": true,
364
+ "returnsFile": false,
365
+ "returnsImage": false
366
+ },
302
367
  {
303
368
  "name": "deviation.measure",
304
369
  "title": "Measure the deviation map",
@@ -416,7 +481,7 @@
416
481
  {
417
482
  "name": "deviation.settings",
418
483
  "title": "Set how the deviation is read",
419
- "description": "The deviation map’s reading: range, the colour scale ± mm; maxDistance, how far from the reference a point may be to count, mm; bands, a stepped scale of that many colours or null for smooth; tolerance, ± mm, the share within which the statistics give; facingDeg, how far the reference surface a point is measured against may turn from facing it, degrees, or null for the nearest surface whatever it faces — a change of it measures the map again. Returns the deviation state. One undo step.",
484
+ "description": "The deviation map’s reading: range, the colour scale ± mm; maxDistance, how far from the reference a point may be to count, mm; bands, a stepped scale of that many colours or null for smooth; tolerance, ± mm, the share within which the statistics give; facingDeg, how far the reference surface a point is measured against may turn from facing it, degrees, or null for the nearest surface whatever it faces — a change of it measures the map again; colormap, the colour map every deviation map and the live map of the bodies are drawn in — the person’s own choice, kept in the browser and outside the undo, so set it only to read a render by its colours and read settings.colormap for what the ramp shows at −range, 0 and +range and the caps past either end before judging a picture. Returns the deviation state. One undo step.",
420
485
  "input": {
421
486
  "type": "object",
422
487
  "properties": {
@@ -461,6 +526,21 @@
461
526
  }
462
527
  ],
463
528
  "description": "Facing limit, degrees, or null."
529
+ },
530
+ "colormap": {
531
+ "type": "string",
532
+ "enum": [
533
+ "jet",
534
+ "viridis",
535
+ "magma",
536
+ "plasma",
537
+ "inferno",
538
+ "cividis",
539
+ "mako",
540
+ "rocket",
541
+ "turbo"
542
+ ],
543
+ "description": "The colour map: jet (blue inside, green on the surface, red outside) or one of the perceptual ramps."
464
544
  }
465
545
  },
466
546
  "additionalProperties": false
@@ -472,7 +552,7 @@
472
552
  {
473
553
  "name": "dimension.add",
474
554
  "title": "Add a dimension",
475
- "description": "Measure between elements, or a size or tolerance of one, as the panel’s dimension box does. refs are the elements by id or name. Without type, the type follows the elements as clicking them in the viewport does — two spheres or points give their centre distance, two planes their distance, a plane and an axis their distance, and so on. With type, it is one of: dist-point-point (From, To); dist-point-axis (Point, Axis); dist-point-plane (Point, Plane); dist-axis-axis (Axis A, Axis B); dist-axis-plane (Axis, Plane); dist-plane-plane (From, To); angle-axis-axis (Axis A, Axis B); angle-axis-plane (Axis, Plane); angle-plane-plane (Plane A, Plane B); size-diameter (Feature); form-flatness (Plane); form-cylindricity (Cylinder); form-circularity (Circle); form-sphericity (Sphere); orient-parallelism (Feature, Datum); orient-perpendicularity (Feature, Datum); orient-angularity (Feature, Datum); loc-coaxiality (Feature, Datum axis). anchor, for two spheres: center (default), gap or span. limit holds the value to a ceiling or a nominal ± band. Returns the dimension with its value (mm or degrees, full precision), the formatted value the panel shows, and the verdict. One undo step.",
555
+ "description": "Measure between elements, or a size or tolerance of one, as the panel’s dimension box does. refs are the elements by id or name. Without type, the type follows the elements as clicking them in the viewport does — two spheres or points give their centre distance, two planes their distance, a plane and an axis their distance, and so on. With type, it is one of: dist-point-point (From, To); dist-point-axis (Point, Axis); dist-point-plane (Point, Plane); dist-axis-axis (Axis A, Axis B); dist-axis-plane (Axis, Plane); dist-plane-plane (From, To); angle-axis-axis (Axis A, Axis B); angle-axis-plane (Axis, Plane); angle-plane-plane (Plane A, Plane B); size-diameter (Feature); form-flatness (Plane); form-cylindricity (Cylinder); form-circularity (Circle); form-sphericity (Sphere); orient-parallelism (Feature, Datum); orient-perpendicularity (Feature, Datum); orient-angularity (Feature, Datum); loc-coaxiality (Feature, Datum axis). anchor, for two spheres: center (default), gap or span. limit holds the value to a ceiling or a nominal ± band. Returns the dimension with its value (mm or degrees, finer than the panel shows it), the formatted value the panel shows, and the verdict. One undo step.",
476
556
  "input": {
477
557
  "type": "object",
478
558
  "properties": {
@@ -771,7 +851,7 @@
771
851
  {
772
852
  "name": "element.construct",
773
853
  "title": "Construct an element",
774
- "description": "Construct an element from others and typed-in numbers, as the panel’s creation methods do — by kind: point (point-coords, point-centroid, point-midpoint, point-line-plane), line (line-two-points, line-axis, line-plane-plane), plane (plane-three-points, plane-offset, plane-midplane, plane-coords, plane-symmetry), circle (circle-plane-cylinder, circle-plane-sphere, circle-coords). refs fill the method’s slots in order, by element id or name; params are its numbers in order (or by key: x, y, z; offset; nx, ny, nz, px, py, pz; d, cx, cy, cz). point-centroid and plane-symmetry measure the scan themselves: vertices confines them to a marked surface, seed starts the symmetry search from a plane. Returns the element. One undo step.",
854
+ "description": "Construct an element from others and typed-in numbers, as the panel’s creation methods do — by kind: point (point-coords, point-centroid, point-midpoint, point-line-plane), line (line-two-points, line-axis, line-plane-plane), plane (plane-three-points, plane-offset, plane-midplane, plane-coords, plane-symmetry), circle (circle-plane-cylinder, circle-plane-sphere, circle-coords). refs fill the method’s slots in order, by element id or name; params are its numbers in order (or by key: x, y, z; offset; nx, ny, nz, px, py, pz; d, cx, cy, cz). point-centroid and plane-symmetry measure the scan themselves: vertices confines them to a marked surface, seed starts the symmetry search from a plane. plane-symmetry finds the scan’s own mirror plane as an element, the alignment left as it is (align.symmetry re-poses the part on it instead), and answers with the search’s residual: symmetry { rms, matched, sampled } and a note. Returns the element. One undo step.",
775
855
  "input": {
776
856
  "type": "object",
777
857
  "properties": {
@@ -911,7 +991,7 @@
911
991
  {
912
992
  "name": "element.fit",
913
993
  "title": "Fit an element",
914
- "description": "Fit an element on the scan where the panel would take a click: a plane, sphere, cylinder, cone or torus grows its surface from the place given and is best-fitted to it; a point is the place itself; a circle goes through three or more places. `at` is one place, or a list — a feature seen in patches can be seeded on each. A place is { vertex } (a scan vertex), { point: [x, y, z] } (the nearest scan vertex to a point, mm, in the current frame), or { screen } / { candidate } (not available yet). Returns the element with its fit at full precision and the seed actually used (vertex and point), so a recipe can be replayed on another scan. One undo step.",
994
+ "description": "Fit an element on the scan where the panel would take a click: a plane, sphere, cylinder, cone or torus grows its surface from the place given and is best-fitted to it; a point is the place itself; a circle goes through three or more places. `at` is one place, or a list — a feature seen in patches can be seeded on each. A place is { vertex } (a scan vertex), { point: [x, y, z] } (the nearest scan vertex to a point, mm, in the current frame), or { screen } / { candidate } (not available yet). Returns the element with its fit and the seed actually used (vertex and point), so a recipe can be replayed on another scan. One undo step.",
915
995
  "input": {
916
996
  "type": "object",
917
997
  "properties": {
@@ -1502,7 +1582,7 @@
1502
1582
  {
1503
1583
  "name": "flat.calibrate",
1504
1584
  "title": "Calibrate the image",
1505
- "description": "Set the image’s scale against a known length, as the Calibrate tool does: distance takes two places a known distance apart, diameter three or more on a circle of known diameter; mm is that length. Every measurement on the image follows the new scale. Returns the calibration. One undo step.",
1585
+ "description": "Set the image’s scale against a known length, as the Calibrate tool does: distance takes two places a known distance apart, diameter three or more on a circle of known diameter; mm is that length. Every measurement on the image follows the new scale, and the edges are found again (their chain numbers change). Returns the calibration. One undo step.",
1506
1586
  "input": {
1507
1587
  "type": "object",
1508
1588
  "properties": {
@@ -1548,7 +1628,7 @@
1548
1628
  {
1549
1629
  "name": "flat.detect_edges",
1550
1630
  "title": "Detect the image’s edges",
1551
- "description": "Find the edges in the image again at a sensitivity from 0 (only the strongest) to 1 (every faint one) — what the seed and edge methods of flat.fit and the snapping of every place follow. Needs the browser. Returns how many edge chains were found.",
1631
+ "description": "Find the edges in the image again at a sensitivity from 0 (only the strongest) to 1 (every faint one) — what the edge methods of flat.fit and the snapping of every place follow. The chains are numbered afresh. Needs the browser. Returns how many edge chains were found.",
1552
1632
  "input": {
1553
1633
  "type": "object",
1554
1634
  "properties": {
@@ -1618,10 +1698,170 @@
1618
1698
  "returnsFile": false,
1619
1699
  "returnsImage": false
1620
1700
  },
1701
+ {
1702
+ "name": "flat.edges",
1703
+ "title": "List the detected edges",
1704
+ "description": "The edge chains detected on the sheet, by number — what flat.fit takes as chains and flat.render writes beside each. Each with its length, whether it closes on itself, how many points and the box round it, in the sheet’s units; the longest first, or with near the nearest first, each with its point nearest that place and how far (within reach only, when given). box keeps the chains that enter it, minLength the long ones. tolerance adds each chain’s polyline, thinned to stray no further than that (5000 points at most over all). limit chains at most, 50 by default. The numbers hold until the edges are found again. Changes nothing.",
1705
+ "input": {
1706
+ "type": "object",
1707
+ "properties": {
1708
+ "box": {
1709
+ "type": "object",
1710
+ "properties": {
1711
+ "min": {
1712
+ "type": "array",
1713
+ "items": {
1714
+ "type": "number"
1715
+ },
1716
+ "description": "The lowest corner.",
1717
+ "minItems": 2,
1718
+ "maxItems": 2
1719
+ },
1720
+ "max": {
1721
+ "type": "array",
1722
+ "items": {
1723
+ "type": "number"
1724
+ },
1725
+ "description": "The highest corner.",
1726
+ "minItems": 2,
1727
+ "maxItems": 2
1728
+ }
1729
+ },
1730
+ "required": [
1731
+ "min",
1732
+ "max"
1733
+ ],
1734
+ "additionalProperties": false,
1735
+ "description": "Only chains with a point in this box."
1736
+ },
1737
+ "near": {
1738
+ "type": "array",
1739
+ "items": {
1740
+ "type": "number"
1741
+ },
1742
+ "description": "Nearest this place first.",
1743
+ "minItems": 2,
1744
+ "maxItems": 2
1745
+ },
1746
+ "reach": {
1747
+ "type": "number",
1748
+ "description": "With near: only chains this close.",
1749
+ "exclusiveMinimum": 0
1750
+ },
1751
+ "minLength": {
1752
+ "type": "number",
1753
+ "description": "Only chains at least this long.",
1754
+ "minimum": 0
1755
+ },
1756
+ "tolerance": {
1757
+ "type": "number",
1758
+ "description": "Add each chain’s polyline, thinned to this.",
1759
+ "exclusiveMinimum": 0
1760
+ },
1761
+ "limit": {
1762
+ "type": "integer",
1763
+ "description": "Chains at most — 50 by default.",
1764
+ "minimum": 1,
1765
+ "maximum": 2000
1766
+ }
1767
+ },
1768
+ "additionalProperties": false
1769
+ },
1770
+ "readOnly": true,
1771
+ "returnsFile": false,
1772
+ "returnsImage": false
1773
+ },
1774
+ {
1775
+ "name": "flat.edit",
1776
+ "title": "Change a 2D element, dimension, note or count",
1777
+ "description": "Change one thing on the 2D sheet, named by its id (or name): an element, a dimension or a count takes a new name; a note new text or a new place (at, its lower-left corner); any of them visible: false to leave it out of the stage, the picture and the exports, true to bring it back. Returns the 2D state. One undo step.",
1778
+ "input": {
1779
+ "type": "object",
1780
+ "properties": {
1781
+ "element": {
1782
+ "oneOf": [
1783
+ {
1784
+ "type": "integer",
1785
+ "description": "The 2D element’s id.",
1786
+ "minimum": 1
1787
+ },
1788
+ {
1789
+ "type": "string",
1790
+ "description": "Its name — \"Line 1\".",
1791
+ "minLength": 1
1792
+ }
1793
+ ],
1794
+ "description": "A 2D element."
1795
+ },
1796
+ "dimension": {
1797
+ "oneOf": [
1798
+ {
1799
+ "type": "integer",
1800
+ "description": "Its id.",
1801
+ "minimum": 1
1802
+ },
1803
+ {
1804
+ "type": "string",
1805
+ "description": "Its name — \"Distance 1\".",
1806
+ "minLength": 1
1807
+ }
1808
+ ],
1809
+ "description": "A 2D dimension."
1810
+ },
1811
+ "note": {
1812
+ "type": "integer",
1813
+ "description": "A note, by its id.",
1814
+ "minimum": 1
1815
+ },
1816
+ "count": {
1817
+ "oneOf": [
1818
+ {
1819
+ "type": "integer",
1820
+ "description": "Its id.",
1821
+ "minimum": 1
1822
+ },
1823
+ {
1824
+ "type": "string",
1825
+ "description": "Its name — \"Count 1\".",
1826
+ "minLength": 1
1827
+ }
1828
+ ],
1829
+ "description": "A count (tally)."
1830
+ },
1831
+ "name": {
1832
+ "type": "string",
1833
+ "description": "The new name.",
1834
+ "minLength": 1
1835
+ },
1836
+ "text": {
1837
+ "type": "string",
1838
+ "description": "A note’s new text.",
1839
+ "minLength": 1
1840
+ },
1841
+ "at": {
1842
+ "type": "array",
1843
+ "items": {
1844
+ "type": "number"
1845
+ },
1846
+ "description": "A note’s new lower-left corner.",
1847
+ "minItems": 2,
1848
+ "maxItems": 2
1849
+ },
1850
+ "visible": {
1851
+ "type": "boolean",
1852
+ "description": "Shown, or left out."
1853
+ }
1854
+ },
1855
+ "additionalProperties": false
1856
+ },
1857
+ "readOnly": false,
1858
+ "returnsFile": false,
1859
+ "returnsImage": false
1860
+ },
1621
1861
  {
1622
1862
  "name": "flat.fit",
1623
1863
  "title": "Fit a 2D element",
1624
- "description": "Make a 2D element on the sheet as its tool does — kind point, line, circle, arc or spline, by a method of that kind: point: flat-point-pick (pick), flat-point-midpoint (construct), flat-point-intersect (construct), flat-point-center (construct); line: flat-line-pick (pick), flat-line-seed (seed), flat-line-edge (edge); circle: flat-circle-pick (pick), flat-circle-seed (seed), flat-circle-edge (edge); arc: flat-arc-pick (pick), flat-arc-edge (edge); spline: flat-spline-pick (pick). A pick method takes points, the places clicked; a seed method one place on a detected edge, grown along it; an edge method a place on an edge, taken whole; a construct method refs, other 2D elements by id or name. Returns the element with its fit. One undo step.",
1864
+ "description": "Make a 2D element on the sheet as its tool does — kind point, line, circle, arc or spline, by a method of that kind: point: flat-point-pick (pick), flat-point-midpoint (construct), flat-point-intersect (construct), flat-point-center (construct); line: flat-line-pick (pick), flat-line-seed (seed), flat-line-edge (edge); circle: flat-circle-pick (pick), flat-circle-seed (seed), flat-circle-edge (edge); arc: flat-arc-pick (pick), flat-arc-edge (edge); spline: flat-spline-pick (pick). A pick method takes points, the places clicked — each snapped to the nearest detected edge within reach unless snap: false, and the answer’s picks say where each landed and on which chain. A seed method takes one place on a detected edge and grows along it; an edge method a place on an edge, taken whole. The edge methods also take chains — whole edge chains by number (flat.edges, flat.render) — and box, every edge point inside it (of those chains only, with both); the kind’s edge method is the default then. A construct method takes refs, other 2D elements by id or name. Returns the element with its fit. One undo step.",
1625
1865
  "input": {
1626
1866
  "type": "object",
1627
1867
  "properties": {
@@ -1655,6 +1895,44 @@
1655
1895
  "description": "The places, in the sheet’s units.",
1656
1896
  "minItems": 1
1657
1897
  },
1898
+ "chains": {
1899
+ "type": "array",
1900
+ "items": {
1901
+ "type": "integer",
1902
+ "minimum": 0
1903
+ },
1904
+ "description": "Edge chains by number, taken whole — for an edge or seed method.",
1905
+ "minItems": 1
1906
+ },
1907
+ "box": {
1908
+ "type": "object",
1909
+ "properties": {
1910
+ "min": {
1911
+ "type": "array",
1912
+ "items": {
1913
+ "type": "number"
1914
+ },
1915
+ "description": "The lowest corner.",
1916
+ "minItems": 2,
1917
+ "maxItems": 2
1918
+ },
1919
+ "max": {
1920
+ "type": "array",
1921
+ "items": {
1922
+ "type": "number"
1923
+ },
1924
+ "description": "The highest corner.",
1925
+ "minItems": 2,
1926
+ "maxItems": 2
1927
+ }
1928
+ },
1929
+ "required": [
1930
+ "min",
1931
+ "max"
1932
+ ],
1933
+ "additionalProperties": false,
1934
+ "description": "Edge points inside this box, in the sheet’s units — for an edge or seed method."
1935
+ },
1658
1936
  "refs": {
1659
1937
  "type": "array",
1660
1938
  "items": {
@@ -1678,6 +1956,15 @@
1678
1956
  "type": "string",
1679
1957
  "description": "A name for it.",
1680
1958
  "minLength": 1
1959
+ },
1960
+ "snap": {
1961
+ "type": "boolean",
1962
+ "description": "Picks snap to the nearest edge within reach — true by default, as the panel’s Snap box is."
1963
+ },
1964
+ "reach": {
1965
+ "type": "number",
1966
+ "description": "How far a place reaches for an edge, in the sheet’s units — ten image pixels by default.",
1967
+ "exclusiveMinimum": 0
1681
1968
  }
1682
1969
  },
1683
1970
  "required": [
@@ -1689,6 +1976,78 @@
1689
1976
  "returnsFile": false,
1690
1977
  "returnsImage": false
1691
1978
  },
1979
+ {
1980
+ "name": "flat.note_add",
1981
+ "title": "Write a note on the sheet",
1982
+ "description": "Write a text note on the 2D sheet, as the Text tool does — a label beside a part, a size read elsewhere, a remark. One line, as the tool writes it: a line break is written as \" / \". at is its lower-left corner, in the sheet’s units. It is drawn on the stage and in flat.render, written into the SVG and DXF exports and listed in the report. Returns the note with its id. One undo step.",
1983
+ "input": {
1984
+ "type": "object",
1985
+ "properties": {
1986
+ "text": {
1987
+ "type": "string",
1988
+ "description": "What it says.",
1989
+ "minLength": 1
1990
+ },
1991
+ "at": {
1992
+ "type": "array",
1993
+ "items": {
1994
+ "type": "number"
1995
+ },
1996
+ "description": "Its lower-left corner.",
1997
+ "minItems": 2,
1998
+ "maxItems": 2
1999
+ }
2000
+ },
2001
+ "required": [
2002
+ "text",
2003
+ "at"
2004
+ ],
2005
+ "additionalProperties": false
2006
+ },
2007
+ "readOnly": false,
2008
+ "returnsFile": false,
2009
+ "returnsImage": false
2010
+ },
2011
+ {
2012
+ "name": "flat.objects",
2013
+ "title": "Find the parts on the image",
2014
+ "description": "The separate parts lying on the flatbed image, parted from the background by a grey level (Otsu’s, unless threshold is given; dark says the parts are darker than the background, read off the image’s border by default) and numbered in reading order — rows from the top, left to right. Each with its area (holes left out) and holes, box, centroid, equivalentDiameter (of a circle of its area), feret — the largest and smallest caliper widths and the directions they are measured along, degrees from +X — axisAngle (its long axis, degrees), and chains, the edge chains along its outline, longest first. minArea drops smaller ones: 1 mm² by default, or its pixels at 600 dpi on an image with no scale. outline adds each outline as a polygon thinned to that tolerance. flat.profile takes an object by its number. limit, 100 by default. Changes nothing.",
2015
+ "input": {
2016
+ "type": "object",
2017
+ "properties": {
2018
+ "threshold": {
2019
+ "type": "integer",
2020
+ "description": "Grey level, 0 to 255.",
2021
+ "minimum": 0,
2022
+ "maximum": 255
2023
+ },
2024
+ "dark": {
2025
+ "type": "boolean",
2026
+ "description": "The parts are darker than the background."
2027
+ },
2028
+ "minArea": {
2029
+ "type": "number",
2030
+ "description": "The smallest part, in the sheet’s units squared.",
2031
+ "minimum": 0
2032
+ },
2033
+ "outline": {
2034
+ "type": "number",
2035
+ "description": "Add each outline, thinned to this, in the sheet’s units.",
2036
+ "exclusiveMinimum": 0
2037
+ },
2038
+ "limit": {
2039
+ "type": "integer",
2040
+ "description": "Parts at most — 100 by default.",
2041
+ "minimum": 1,
2042
+ "maximum": 1000
2043
+ }
2044
+ },
2045
+ "additionalProperties": false
2046
+ },
2047
+ "readOnly": true,
2048
+ "returnsFile": false,
2049
+ "returnsImage": false
2050
+ },
1692
2051
  {
1693
2052
  "name": "flat.open_image",
1694
2053
  "title": "Open a flatbed image",
@@ -1718,23 +2077,294 @@
1718
2077
  "returnsImage": false
1719
2078
  },
1720
2079
  {
1721
- "name": "flat.report",
1722
- "title": "Get the 2D report",
1723
- "description": "The 2D Measure report as its Copy button gives it: the image or section, the scale it rests on, the alignment, every element and dimension.",
2080
+ "name": "flat.profile",
2081
+ "title": "Profile an outline and count its peaks",
2082
+ "description": "An outline read against a centre or along an axis, and its peaks counted — the teeth of a knurl or a gear. The outline: an object of the last flat.objects by number, or edge chains by number (several make one). radial (the default): its radius against the angle about about — a circle, arc or point — or about the outline’s own centre: a part standing upright, seen from above. axial: its distance from about — a line — or from the outline’s own long axis, against the position along it, each side apart (left and right of the axis’ direction): a part lying on its side. A peak counts when it stands prominence above the higher of the valleys either side — by default 0.3 of the profile’s spread, never under the outline’s noise. Returns per side the count, the pitch (degrees round, or along the axis), the envelope (largest, smallest, mean peak, mean valley; radial also as diameters) and every peak’s angle or position and place; points adds the sampled profile. mark: true puts a count on the sheet with a numbered pick on every peak, to check by eye — one undo step; otherwise nothing changes.",
1724
2083
  "input": {
1725
2084
  "type": "object",
1726
- "properties": {},
1727
- "additionalProperties": false
1728
- },
1729
- "readOnly": true,
1730
- "returnsFile": false,
1731
- "returnsImage": false
1732
- },
1733
- {
1734
- "name": "flat.set_alignment",
1735
- "title": "Align the sheet",
1736
- "description": "Put the sheet’s zero point at origin and its X axis through xAxis, as the Align tool’s two clicks do — every coordinate on the sheet is then read in that frame. clear: true takes the alignment off. Returns the 2D state. One undo step.",
1737
- "input": {
2085
+ "properties": {
2086
+ "object": {
2087
+ "type": "integer",
2088
+ "description": "An object of the last flat.objects, by number.",
2089
+ "minimum": 1
2090
+ },
2091
+ "chains": {
2092
+ "type": "array",
2093
+ "items": {
2094
+ "type": "integer",
2095
+ "minimum": 0
2096
+ },
2097
+ "description": "Edge chains by number, as one outline.",
2098
+ "minItems": 1
2099
+ },
2100
+ "about": {
2101
+ "oneOf": [
2102
+ {
2103
+ "type": "integer",
2104
+ "description": "The 2D element’s id.",
2105
+ "minimum": 1
2106
+ },
2107
+ {
2108
+ "type": "string",
2109
+ "description": "Its name — \"Line 1\".",
2110
+ "minLength": 1
2111
+ }
2112
+ ],
2113
+ "description": "A circle, arc or point to read the radius about, or a line to read the distance from."
2114
+ },
2115
+ "axis": {
2116
+ "type": "string",
2117
+ "enum": [
2118
+ "radial",
2119
+ "axial"
2120
+ ],
2121
+ "description": "Without about: radial about the outline’s centre (the default), or axial along its long axis."
2122
+ },
2123
+ "samples": {
2124
+ "type": "integer",
2125
+ "description": "Bins round the turn, or along the axis — from the point count by default.",
2126
+ "minimum": 16,
2127
+ "maximum": 20000
2128
+ },
2129
+ "prominence": {
2130
+ "type": "number",
2131
+ "description": "How far a peak must stand out, in the sheet’s units.",
2132
+ "exclusiveMinimum": 0
2133
+ },
2134
+ "mark": {
2135
+ "type": "boolean",
2136
+ "description": "Put a count on every peak."
2137
+ },
2138
+ "points": {
2139
+ "type": "boolean",
2140
+ "description": "Add the sampled profile."
2141
+ }
2142
+ },
2143
+ "additionalProperties": false
2144
+ },
2145
+ "readOnly": false,
2146
+ "returnsFile": false,
2147
+ "returnsImage": false
2148
+ },
2149
+ {
2150
+ "name": "flat.remove",
2151
+ "title": "Remove from the 2D sheet",
2152
+ "description": "Remove elements, dimensions, notes and counts from the 2D sheet, each by id or name (a note by id) — all of them or none. An element built on a removed one stays and says it has lost its source, and a dimension on one turns invalid, as in the panel; the answer names them. Returns what is left. One undo step.",
2153
+ "input": {
2154
+ "type": "object",
2155
+ "properties": {
2156
+ "elements": {
2157
+ "type": "array",
2158
+ "items": {
2159
+ "oneOf": [
2160
+ {
2161
+ "type": "integer",
2162
+ "description": "The 2D element’s id.",
2163
+ "minimum": 1
2164
+ },
2165
+ {
2166
+ "type": "string",
2167
+ "description": "Its name — \"Line 1\".",
2168
+ "minLength": 1
2169
+ }
2170
+ ],
2171
+ "description": "A 2D element."
2172
+ }
2173
+ },
2174
+ "dimensions": {
2175
+ "type": "array",
2176
+ "items": {
2177
+ "oneOf": [
2178
+ {
2179
+ "type": "integer",
2180
+ "minimum": 1
2181
+ },
2182
+ {
2183
+ "type": "string",
2184
+ "minLength": 1
2185
+ }
2186
+ ]
2187
+ },
2188
+ "description": "Dimensions, by id or name."
2189
+ },
2190
+ "notes": {
2191
+ "type": "array",
2192
+ "items": {
2193
+ "type": "integer",
2194
+ "minimum": 1
2195
+ },
2196
+ "description": "Notes, by id."
2197
+ },
2198
+ "counts": {
2199
+ "type": "array",
2200
+ "items": {
2201
+ "oneOf": [
2202
+ {
2203
+ "type": "integer",
2204
+ "minimum": 1
2205
+ },
2206
+ {
2207
+ "type": "string",
2208
+ "minLength": 1
2209
+ }
2210
+ ]
2211
+ },
2212
+ "description": "Counts, by id or name."
2213
+ }
2214
+ },
2215
+ "additionalProperties": false
2216
+ },
2217
+ "readOnly": false,
2218
+ "returnsFile": false,
2219
+ "returnsImage": false
2220
+ },
2221
+ {
2222
+ "name": "flat.render",
2223
+ "title": "Picture the sheet",
2224
+ "description": "A picture of the 2D sheet as a PNG, drawn as the sheet lies in the sheet’s own units — +X right, +Y up, whatever the stage’s alignment or turns — with a grid ruled in those units and its values written along the top and left edges. map says where it lies: picture pixel (column c, row r from the top) is the sheet place [left + c·unitsPerPx, top − r·unitsPerPx], to hand straight back as a place. frame zooms in on a box. show puts layers in or out: image, edges (the detected chains — as the panel shows them by default), chains (their numbers, as flat.fit and flat.edges name them), elements (with counts and the alignment), dimensions, notes, labels (names and readings), grid. width and height in pixels: the frame’s shape at most 800 on its long side by default, up to 2048. Needs the browser.",
2225
+ "input": {
2226
+ "type": "object",
2227
+ "properties": {
2228
+ "frame": {
2229
+ "oneOf": [
2230
+ {
2231
+ "type": "object",
2232
+ "properties": {
2233
+ "min": {
2234
+ "type": "array",
2235
+ "items": {
2236
+ "type": "number"
2237
+ },
2238
+ "description": "The lowest corner.",
2239
+ "minItems": 2,
2240
+ "maxItems": 2
2241
+ },
2242
+ "max": {
2243
+ "type": "array",
2244
+ "items": {
2245
+ "type": "number"
2246
+ },
2247
+ "description": "The highest corner.",
2248
+ "minItems": 2,
2249
+ "maxItems": 2
2250
+ }
2251
+ },
2252
+ "required": [
2253
+ "min",
2254
+ "max"
2255
+ ],
2256
+ "additionalProperties": false,
2257
+ "description": "A box on the sheet."
2258
+ },
2259
+ {
2260
+ "type": "object",
2261
+ "properties": {
2262
+ "at": {
2263
+ "type": "array",
2264
+ "items": {
2265
+ "type": "number"
2266
+ },
2267
+ "description": "Its centre.",
2268
+ "minItems": 2,
2269
+ "maxItems": 2
2270
+ },
2271
+ "size": {
2272
+ "oneOf": [
2273
+ {
2274
+ "type": "number",
2275
+ "exclusiveMinimum": 0
2276
+ },
2277
+ {
2278
+ "type": "array",
2279
+ "items": {
2280
+ "type": "number",
2281
+ "exclusiveMinimum": 0
2282
+ },
2283
+ "minItems": 2,
2284
+ "maxItems": 2
2285
+ }
2286
+ ],
2287
+ "description": "Its side, or [width, height]."
2288
+ }
2289
+ },
2290
+ "required": [
2291
+ "at",
2292
+ "size"
2293
+ ],
2294
+ "additionalProperties": false,
2295
+ "description": "A box round a place."
2296
+ }
2297
+ ],
2298
+ "description": "What to picture, in the sheet’s units — the whole sheet by default."
2299
+ },
2300
+ "width": {
2301
+ "type": "integer",
2302
+ "description": "Pixels across, 64 to 2048.",
2303
+ "minimum": 64,
2304
+ "maximum": 2048
2305
+ },
2306
+ "height": {
2307
+ "type": "integer",
2308
+ "description": "Pixels down, 64 to 2048.",
2309
+ "minimum": 64,
2310
+ "maximum": 2048
2311
+ },
2312
+ "show": {
2313
+ "type": "object",
2314
+ "properties": {
2315
+ "image": {
2316
+ "type": "boolean"
2317
+ },
2318
+ "edges": {
2319
+ "type": "boolean"
2320
+ },
2321
+ "chains": {
2322
+ "type": "boolean"
2323
+ },
2324
+ "elements": {
2325
+ "type": "boolean"
2326
+ },
2327
+ "dimensions": {
2328
+ "type": "boolean"
2329
+ },
2330
+ "notes": {
2331
+ "type": "boolean"
2332
+ },
2333
+ "labels": {
2334
+ "type": "boolean"
2335
+ },
2336
+ "grid": {
2337
+ "type": "boolean"
2338
+ }
2339
+ },
2340
+ "additionalProperties": false,
2341
+ "description": "Layers in (true) or out (false)."
2342
+ }
2343
+ },
2344
+ "additionalProperties": false
2345
+ },
2346
+ "readOnly": true,
2347
+ "returnsFile": true,
2348
+ "returnsImage": true
2349
+ },
2350
+ {
2351
+ "name": "flat.report",
2352
+ "title": "Get the 2D report",
2353
+ "description": "The 2D Measure report as its Copy button gives it: the image or section, the scale it rests on, the alignment, every element, dimension, count and note.",
2354
+ "input": {
2355
+ "type": "object",
2356
+ "properties": {},
2357
+ "additionalProperties": false
2358
+ },
2359
+ "readOnly": true,
2360
+ "returnsFile": false,
2361
+ "returnsImage": false
2362
+ },
2363
+ {
2364
+ "name": "flat.set_alignment",
2365
+ "title": "Align the sheet",
2366
+ "description": "Put the part’s zero point at origin and its X axis through xAxis, as the Align tool’s two clicks do: the report, the panel and the exports then read in that frame. Places given to the commands stay the sheet’s own. clear: true takes the alignment off. Returns the 2D state. One undo step.",
2367
+ "input": {
1738
2368
  "type": "object",
1739
2369
  "properties": {
1740
2370
  "origin": {
@@ -1766,6 +2396,19 @@
1766
2396
  "returnsFile": false,
1767
2397
  "returnsImage": false
1768
2398
  },
2399
+ {
2400
+ "name": "history.checkpoint",
2401
+ "title": "Mark the history",
2402
+ "description": "Mark where the undo history stands, before a run of changes that should stand or fall together: history.restore { checkpoint } later undoes every step made since, back to this mark. Changes nothing. Returns the checkpoint, the step on top and how many there are.",
2403
+ "input": {
2404
+ "type": "object",
2405
+ "properties": {},
2406
+ "additionalProperties": false
2407
+ },
2408
+ "readOnly": true,
2409
+ "returnsFile": false,
2410
+ "returnsImage": false
2411
+ },
1769
2412
  {
1770
2413
  "name": "history.redo",
1771
2414
  "title": "Redo",
@@ -1779,6 +2422,28 @@
1779
2422
  "returnsFile": false,
1780
2423
  "returnsImage": false
1781
2424
  },
2425
+ {
2426
+ "name": "history.restore",
2427
+ "title": "Back to a mark in the history",
2428
+ "description": "Undo every step made since history.checkpoint gave this checkpoint, newest first, as the undo key would one by one — so a run of changes that went wrong in the middle is taken back whole. Refused, undoing nothing, when the mark is no longer under the steps on top — undone past it, or the history started afresh (a scan or a project opened). Returns the steps undone, newest first, and the session afterwards.",
2429
+ "input": {
2430
+ "type": "object",
2431
+ "properties": {
2432
+ "checkpoint": {
2433
+ "type": "string",
2434
+ "description": "What history.checkpoint returned.",
2435
+ "minLength": 1
2436
+ }
2437
+ },
2438
+ "required": [
2439
+ "checkpoint"
2440
+ ],
2441
+ "additionalProperties": false
2442
+ },
2443
+ "readOnly": false,
2444
+ "returnsFile": false,
2445
+ "returnsImage": false
2446
+ },
1782
2447
  {
1783
2448
  "name": "history.undo",
1784
2449
  "title": "Undo",
@@ -1823,6 +2488,27 @@
1823
2488
  "returnsFile": false,
1824
2489
  "returnsImage": false
1825
2490
  },
2491
+ {
2492
+ "name": "project.rename",
2493
+ "title": "Name the project",
2494
+ "description": "Give the project a name — what Save Project saves it under, the stem of every export and the browser tab’s title, kept in the project file. An empty name takes it off, and the scan’s or the image’s name stands in again. session.state reads it as project.name.",
2495
+ "input": {
2496
+ "type": "object",
2497
+ "properties": {
2498
+ "name": {
2499
+ "type": "string",
2500
+ "description": "The name; empty takes it off."
2501
+ }
2502
+ },
2503
+ "required": [
2504
+ "name"
2505
+ ],
2506
+ "additionalProperties": false
2507
+ },
2508
+ "readOnly": false,
2509
+ "returnsFile": false,
2510
+ "returnsImage": false
2511
+ },
1826
2512
  {
1827
2513
  "name": "project.save",
1828
2514
  "title": "Save the project",
@@ -1868,6 +2554,99 @@
1868
2554
  "returnsFile": false,
1869
2555
  "returnsImage": false
1870
2556
  },
2557
+ {
2558
+ "name": "scan.fit_surface",
2559
+ "title": "Fit a sloped or curved patch",
2560
+ "description": "A patch of the scan measured as a surface — a sloped side, a twisted ruled face, a dome, a saddle, a fairing — the points given as vertices (from scan.query or a patch) or as a box (normal keeps those facing a way, within withinDeg, 30 by default). The best plane through them sets the patch’s own frame: origin at their centroid, normal (w) out of it, basisU and basisV in it, all in the frame the part is measured in now. Each model is a height over (u, v) along the normal: plane h = a + b·u + c·v; bilinear + d·u·v (a hyperbolic paraboloid: a straight-lined twisted face); quadric + d·u² + e·u·v + f·v² (a dome, bowl, saddle or a cylinder’s strip). Each answers its coefficients, rms and worst (mm off along the normal); the quadric also curvature: k1 and k2 (1/mm, the larger first), r1 and r2 (their radii, null where flat), axis1 and axis2 (their directions in the world) and shape (flat, cylinder, dome or saddle) at the patch’s middle. model: one of them, or best (the default) — every one, and best names the simplest whose rms is within a tenth of the lowest: the model that holds, plain. At most limit points are fitted (20000), spread evenly. Changes nothing.",
2561
+ "input": {
2562
+ "type": "object",
2563
+ "properties": {
2564
+ "vertices": {
2565
+ "type": "array",
2566
+ "items": {
2567
+ "type": "integer",
2568
+ "minimum": 0
2569
+ },
2570
+ "description": "The scan vertices of the patch.",
2571
+ "minItems": 7
2572
+ },
2573
+ "box": {
2574
+ "type": "object",
2575
+ "properties": {
2576
+ "min": {
2577
+ "type": "array",
2578
+ "items": {
2579
+ "type": "number"
2580
+ },
2581
+ "description": "The lowest corner, mm.",
2582
+ "minItems": 3,
2583
+ "maxItems": 3
2584
+ },
2585
+ "max": {
2586
+ "type": "array",
2587
+ "items": {
2588
+ "type": "number"
2589
+ },
2590
+ "description": "The highest corner, mm.",
2591
+ "minItems": 3,
2592
+ "maxItems": 3
2593
+ }
2594
+ },
2595
+ "required": [
2596
+ "min",
2597
+ "max"
2598
+ ],
2599
+ "additionalProperties": false,
2600
+ "description": "The patch as the scan inside a box, in place of vertices."
2601
+ },
2602
+ "normal": {
2603
+ "type": "object",
2604
+ "properties": {
2605
+ "dir": {
2606
+ "type": "array",
2607
+ "items": {
2608
+ "type": "number"
2609
+ },
2610
+ "description": "The direction, any length.",
2611
+ "minItems": 3,
2612
+ "maxItems": 3
2613
+ },
2614
+ "withinDeg": {
2615
+ "type": "number",
2616
+ "description": "Degrees; 30 by default.",
2617
+ "exclusiveMinimum": 0,
2618
+ "maximum": 180
2619
+ }
2620
+ },
2621
+ "required": [
2622
+ "dir"
2623
+ ],
2624
+ "additionalProperties": false,
2625
+ "description": "With box: only the vertices facing this way."
2626
+ },
2627
+ "model": {
2628
+ "type": "string",
2629
+ "enum": [
2630
+ "plane",
2631
+ "bilinear",
2632
+ "quadric",
2633
+ "best"
2634
+ ],
2635
+ "description": "Which surface; best (the default) fits each and names the simplest that holds."
2636
+ },
2637
+ "limit": {
2638
+ "type": "integer",
2639
+ "description": "How many points at most; 20000 by default.",
2640
+ "minimum": 7,
2641
+ "maximum": 20000
2642
+ }
2643
+ },
2644
+ "additionalProperties": false
2645
+ },
2646
+ "readOnly": true,
2647
+ "returnsFile": false,
2648
+ "returnsImage": false
2649
+ },
1871
2650
  {
1872
2651
  "name": "scan.nearest",
1873
2652
  "title": "Find a place on the scan",
@@ -1966,81 +2745,345 @@
1966
2745
  "format": "binary",
1967
2746
  "description": "The file’s contents."
1968
2747
  },
1969
- "name": {
1970
- "type": "string",
1971
- "description": "The file's name with its extension — \"ballbar.stl\". It is what the session calls the model.",
1972
- "minLength": 1
2748
+ "name": {
2749
+ "type": "string",
2750
+ "description": "The file's name with its extension — \"ballbar.stl\". It is what the session calls the model.",
2751
+ "minLength": 1
2752
+ },
2753
+ "units": {
2754
+ "type": "string",
2755
+ "enum": [
2756
+ "mm",
2757
+ "cm",
2758
+ "m",
2759
+ "in"
2760
+ ],
2761
+ "description": "What the file’s coordinates are in: mm (the default), cm, m or in. An STL carries no units of its own; PLY and OBJ are taken in millimetres unless told otherwise. Everything is measured in millimetres once read."
2762
+ },
2763
+ "discard": {
2764
+ "type": "boolean",
2765
+ "description": "Replace the session even though it holds measurements — they are lost (a project file saved before keeps them). Without it the command refuses when there is work to lose."
2766
+ }
2767
+ },
2768
+ "required": [
2769
+ "bytes",
2770
+ "name"
2771
+ ],
2772
+ "additionalProperties": false
2773
+ },
2774
+ "readOnly": false,
2775
+ "returnsFile": false,
2776
+ "returnsImage": false
2777
+ },
2778
+ {
2779
+ "name": "scan.query",
2780
+ "title": "Read the scan’s points",
2781
+ "description": "The scan’s vertices inside a box, or within a radius of a point, with their outward normals — the points on a face, to measure a dimension or a draft angle off, or to see what the scan has where a model is being built. normal keeps only the vertices facing a direction (within withinDeg, 30 by default): the top face alone, say. At most limit come back (1000 by default, 20000 at most): past it every k-th matching vertex is kept, spread evenly, and step says which k. Returns how many matched, the vertices kept (their numbers, as scan.nearest and element.fit_marked name them), their points and normals in millimetres, in the frame the part is measured in now, the box round the points kept, their centroid and mean normal. Changes nothing.",
2782
+ "input": {
2783
+ "type": "object",
2784
+ "properties": {
2785
+ "box": {
2786
+ "type": "object",
2787
+ "properties": {
2788
+ "min": {
2789
+ "type": "array",
2790
+ "items": {
2791
+ "type": "number"
2792
+ },
2793
+ "description": "The lowest corner, mm.",
2794
+ "minItems": 3,
2795
+ "maxItems": 3
2796
+ },
2797
+ "max": {
2798
+ "type": "array",
2799
+ "items": {
2800
+ "type": "number"
2801
+ },
2802
+ "description": "The highest corner, mm.",
2803
+ "minItems": 3,
2804
+ "maxItems": 3
2805
+ }
2806
+ },
2807
+ "required": [
2808
+ "min",
2809
+ "max"
2810
+ ],
2811
+ "additionalProperties": false,
2812
+ "description": "A box in the frame the part is measured in now."
2813
+ },
2814
+ "near": {
2815
+ "type": "object",
2816
+ "properties": {
2817
+ "at": {
2818
+ "type": "array",
2819
+ "items": {
2820
+ "type": "number"
2821
+ },
2822
+ "description": "The centre, mm.",
2823
+ "minItems": 3,
2824
+ "maxItems": 3
2825
+ },
2826
+ "radius": {
2827
+ "type": "number",
2828
+ "description": "How far from it, mm.",
2829
+ "exclusiveMinimum": 0
2830
+ }
2831
+ },
2832
+ "required": [
2833
+ "at",
2834
+ "radius"
2835
+ ],
2836
+ "additionalProperties": false,
2837
+ "description": "A ball about a point — in place of box."
2838
+ },
2839
+ "normal": {
2840
+ "type": "object",
2841
+ "properties": {
2842
+ "dir": {
2843
+ "type": "array",
2844
+ "items": {
2845
+ "type": "number"
2846
+ },
2847
+ "description": "The direction, any length.",
2848
+ "minItems": 3,
2849
+ "maxItems": 3
2850
+ },
2851
+ "withinDeg": {
2852
+ "type": "number",
2853
+ "description": "How far from it a normal may lean, degrees; 30 by default.",
2854
+ "exclusiveMinimum": 0,
2855
+ "maximum": 180
2856
+ }
2857
+ },
2858
+ "required": [
2859
+ "dir"
2860
+ ],
2861
+ "additionalProperties": false,
2862
+ "description": "Keep only the vertices whose outward normal faces this way."
2863
+ },
2864
+ "limit": {
2865
+ "type": "integer",
2866
+ "description": "How many vertices at most; 1000 by default, 20000 at most.",
2867
+ "minimum": 1,
2868
+ "maximum": 20000
2869
+ }
2870
+ },
2871
+ "additionalProperties": false
2872
+ },
2873
+ "readOnly": true,
2874
+ "returnsFile": false,
2875
+ "returnsImage": false
2876
+ },
2877
+ {
2878
+ "name": "section.cut",
2879
+ "title": "Cut a section",
2880
+ "description": "Cut the scan with a plane and keep the cut as a section, measured in the 2D workspace (flat) — where it is put on the sheet. across is what the plane is taken across: an element with a direction (a plane, cylinder, cone, line or circle) by id or name, or a coordinate plane \"XY\", \"YZ\" or \"ZX\", which is laid through the part’s centre. offset slides the plane along its normal, mm — from the element, or for a coordinate plane the coordinate itself. Returns the section: its plane and how many chains the cut has. One undo step.",
2881
+ "input": {
2882
+ "type": "object",
2883
+ "properties": {
2884
+ "across": {
2885
+ "oneOf": [
2886
+ {
2887
+ "type": "integer",
2888
+ "description": "The element’s id.",
2889
+ "minimum": 1
2890
+ },
2891
+ {
2892
+ "type": "string",
2893
+ "description": "The element’s name, as the list shows it — \"Sphere 1\".",
2894
+ "minLength": 1
2895
+ }
2896
+ ],
2897
+ "description": "An element with a direction, or a coordinate plane \"XY\", \"YZ\", \"ZX\"."
2898
+ },
2899
+ "offset": {
2900
+ "type": "number",
2901
+ "description": "Where along the normal the plane lies, mm."
2902
+ },
2903
+ "name": {
2904
+ "type": "string",
2905
+ "description": "A name for it; otherwise it is numbered — \"Section 2\".",
2906
+ "minLength": 1
2907
+ }
2908
+ },
2909
+ "required": [
2910
+ "across"
2911
+ ],
2912
+ "additionalProperties": false
2913
+ },
2914
+ "readOnly": false,
2915
+ "returnsFile": false,
2916
+ "returnsImage": false
2917
+ },
2918
+ {
2919
+ "name": "section.get",
2920
+ "title": "Read a section’s polylines",
2921
+ "description": "A section’s cut as the polylines it is: each chain’s points in order, as the 2D sheet lays them flat — [u, v] millimetres in the section’s plane, what flat.fit and a sketch on the section take — and, with space \"world\" or \"both\", as [x, y, z] in the frame the part is measured in now. With them the plane (origin, normal, basisU, basisV: a sheet point is origin + u·basisU + v·basisV), and for each chain whether it is closed (a loop; its first point is repeated at the end), its length along the path, how many points it has and the box round it on the sheet. At most limit points come back over all the chains (4000 by default, 50000 at most): past it every k-th point of a chain is kept, its ends always, and step says which k. chains picks chains by their index. Changes nothing.",
2922
+ "input": {
2923
+ "type": "object",
2924
+ "properties": {
2925
+ "section": {
2926
+ "oneOf": [
2927
+ {
2928
+ "type": "integer",
2929
+ "description": "The section’s id.",
2930
+ "minimum": 1
2931
+ },
2932
+ {
2933
+ "type": "string",
2934
+ "description": "The section’s name, as the list shows it — \"Section 1\".",
2935
+ "minLength": 1
2936
+ }
2937
+ ],
2938
+ "description": "The section, by id or name."
2939
+ },
2940
+ "chains": {
2941
+ "type": "array",
2942
+ "items": {
2943
+ "type": "integer",
2944
+ "description": "A chain’s index.",
2945
+ "minimum": 0
2946
+ },
2947
+ "description": "Which chains; every one when left out.",
2948
+ "minItems": 1
1973
2949
  },
1974
- "units": {
2950
+ "space": {
1975
2951
  "type": "string",
1976
2952
  "enum": [
1977
- "mm",
1978
- "cm",
1979
- "m",
1980
- "in"
2953
+ "sheet",
2954
+ "world",
2955
+ "both"
1981
2956
  ],
1982
- "description": "What the file’s coordinates are in: mm (the default), cm, m or in. An STL carries no units of its own; PLY and OBJ are taken in millimetres unless told otherwise. Everything is measured in millimetres once read."
2957
+ "description": "sheet (the default): [u, v] on the section’s plane; world: [x, y, z]; both."
1983
2958
  },
1984
- "discard": {
1985
- "type": "boolean",
1986
- "description": "Replace the session even though it holds measurements — they are lost (a project file saved before keeps them). Without it the command refuses when there is work to lose."
2959
+ "limit": {
2960
+ "type": "integer",
2961
+ "description": "How many points at most, over every chain asked for; 4000 by default, 50000 at most.",
2962
+ "minimum": 2,
2963
+ "maximum": 50000
1987
2964
  }
1988
2965
  },
1989
2966
  "required": [
1990
- "bytes",
1991
- "name"
2967
+ "section"
1992
2968
  ],
1993
2969
  "additionalProperties": false
1994
2970
  },
1995
- "readOnly": false,
2971
+ "readOnly": true,
1996
2972
  "returnsFile": false,
1997
2973
  "returnsImage": false
1998
2974
  },
1999
2975
  {
2000
- "name": "section.cut",
2001
- "title": "Cut a section",
2002
- "description": "Cut the scan with a plane and keep the cut as a section, measured in the 2D workspace (flat) — where it is put on the sheet. across is what the plane is taken across: an element with a direction (a plane, cylinder, cone, line or circle) by id or name, or a coordinate plane \"XY\", \"YZ\" or \"ZX\", which is laid through the part’s centre. offset slides the plane along its normal, mm — from the element, or for a coordinate plane the coordinate itself. Returns the section: its plane and how many chains the cut has. One undo step.",
2976
+ "name": "section.render",
2977
+ "title": "Picture a section",
2978
+ "description": "A picture of a section as a PNG, for checking a slice against what was built on it: the scan’s cut as points on the section’s sheet ([u, v] mm as section.get gives them, +u right, +v up), a grid ruled in millimetres with its values at the top and left margins, a scale bar, and over it what the workspaces’ layers draw — a model’s cut by the section’s plane as outlines, a sketch’s pieces on the section with their ids. Every scan point within ten tolerances of an outline is read against it: on it within ± tolerance (grey), or off it (red), outside the outline or inside it; points with no outline near are pale. The answer gives gap: points (the cut’s), read, over (red), outside and inside (of a closed outline — inside is scan within the model’s material, so the model stands proud there; outside, the model is short), max and rms (mm) and overBox (the sheet box round the red, to frame the next look); layers: each layer drawn by key, its outlines and pieces counted; map: picture pixel (column c, row r from the top) is the sheet place [left + c·unitsPerPx, top − r·unitsPerPx]. section names a section; or plane { origin, normal } cuts the scan there for the picture alone — no section is made, the sheet’s u and v any pair square to the normal (the answer’s sheet gives them). frame { at: [u, v], size } looks at a square of the sheet; everything by default. tolerance: the Deviation workspace’s by default. layers: the keys to draw; every one by default, [] for the scan alone. 800 px on the long side by default, up to 2048. Needs the browser. Changes nothing.",
2003
2979
  "input": {
2004
2980
  "type": "object",
2005
2981
  "properties": {
2006
- "across": {
2982
+ "section": {
2007
2983
  "oneOf": [
2008
2984
  {
2009
2985
  "type": "integer",
2010
- "description": "The element’s id.",
2986
+ "description": "The section’s id.",
2011
2987
  "minimum": 1
2012
2988
  },
2013
2989
  {
2014
2990
  "type": "string",
2015
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
2991
+ "description": "The section’s name — \"Section 1\".",
2016
2992
  "minLength": 1
2017
2993
  }
2018
2994
  ],
2019
- "description": "An element with a direction, or a coordinate plane \"XY\", \"YZ\", \"ZX\"."
2995
+ "description": "The section, by id or name."
2020
2996
  },
2021
- "offset": {
2997
+ "plane": {
2998
+ "type": "object",
2999
+ "properties": {
3000
+ "origin": {
3001
+ "type": "array",
3002
+ "items": {
3003
+ "type": "number"
3004
+ },
3005
+ "description": "A point on the plane, mm.",
3006
+ "minItems": 3,
3007
+ "maxItems": 3
3008
+ },
3009
+ "normal": {
3010
+ "type": "array",
3011
+ "items": {
3012
+ "type": "number"
3013
+ },
3014
+ "description": "Its normal.",
3015
+ "minItems": 3,
3016
+ "maxItems": 3
3017
+ }
3018
+ },
3019
+ "required": [
3020
+ "origin",
3021
+ "normal"
3022
+ ],
3023
+ "additionalProperties": false,
3024
+ "description": "A plane to cut the scan by for the picture alone, in place of a section."
3025
+ },
3026
+ "frame": {
3027
+ "type": "object",
3028
+ "properties": {
3029
+ "at": {
3030
+ "type": "array",
3031
+ "items": {
3032
+ "type": "number"
3033
+ },
3034
+ "description": "The sheet place in the middle, [u, v] mm.",
3035
+ "minItems": 2,
3036
+ "maxItems": 2
3037
+ },
3038
+ "size": {
3039
+ "type": "number",
3040
+ "description": "The side of the square looked at, mm.",
3041
+ "exclusiveMinimum": 0
3042
+ }
3043
+ },
3044
+ "required": [
3045
+ "at",
3046
+ "size"
3047
+ ],
3048
+ "additionalProperties": false,
3049
+ "description": "Look at a square of the sheet."
3050
+ },
3051
+ "tolerance": {
2022
3052
  "type": "number",
2023
- "description": "Where along the normal the plane lies, mm."
3053
+ "description": "± mm a scan point may lie off the outlines and still be on them.",
3054
+ "exclusiveMinimum": 0
2024
3055
  },
2025
- "name": {
2026
- "type": "string",
2027
- "description": "A name for it; otherwise it is numbered — \"Section 2\".",
2028
- "minLength": 1
3056
+ "layers": {
3057
+ "type": "array",
3058
+ "items": {
3059
+ "type": "string",
3060
+ "minLength": 1
3061
+ },
3062
+ "description": "The layers to draw, by key; every one by default."
3063
+ },
3064
+ "width": {
3065
+ "type": "integer",
3066
+ "description": "Pixels across, 64 to 2048.",
3067
+ "minimum": 64,
3068
+ "maximum": 2048
3069
+ },
3070
+ "height": {
3071
+ "type": "integer",
3072
+ "description": "Pixels down, 64 to 2048.",
3073
+ "minimum": 64,
3074
+ "maximum": 2048
2029
3075
  }
2030
3076
  },
2031
- "required": [
2032
- "across"
2033
- ],
2034
3077
  "additionalProperties": false
2035
3078
  },
2036
- "readOnly": false,
2037
- "returnsFile": false,
2038
- "returnsImage": false
3079
+ "readOnly": true,
3080
+ "returnsFile": true,
3081
+ "returnsImage": true
2039
3082
  },
2040
3083
  {
2041
3084
  "name": "session.reset",
2042
3085
  "title": "Start over",
2043
- "description": "Close the scan, the reference part and the 2D image, and with them every measurement, as opening an empty project does. Refuses while the session holds measurements unless discard is true. Not undoable: the history starts over too.",
3086
+ "description": "Close the scan, the reference part and the 2D image, and with them every measurement and the project’s name, as opening an empty project does. Refuses while the session holds measurements unless discard is true. Not undoable: the history starts over too.",
2044
3087
  "input": {
2045
3088
  "type": "object",
2046
3089
  "properties": {
@@ -2058,7 +3101,7 @@
2058
3101
  {
2059
3102
  "name": "session.state",
2060
3103
  "title": "Read the session",
2061
- "description": "The whole session as JSON: the app and its plugins, the workspace on screen, whether it is busy, the scan (file, units, vertex and triangle counts, bounding box, centre, size, applied alignment), every element with its fit at full precision, every dimension with its value, limit and verdict, the sections, what is open in the panels, the deviation, wall thickness and 2D Measure state with their statistics, the guided hint for the next step, and the undo history. Lengths in millimetres, angles in degrees. Read it before acting and after.",
3104
+ "description": "The whole session as JSON: the app and its plugins, the workspace on screen, whether it is busy, the scan (file, units, vertex and triangle counts, bounding box, centre, size, applied alignment), every element with its fit, every dimension with its value, limit and verdict, the sections, what is open in the panels, the deviation, wall thickness and 2D Measure state with their statistics, the guided hint for the next step, and the undo history. Lengths in millimetres, angles in degrees. Read it before acting and after.",
2062
3105
  "input": {
2063
3106
  "type": "object",
2064
3107
  "properties": {},
@@ -2203,7 +3246,7 @@
2203
3246
  {
2204
3247
  "name": "view.render",
2205
3248
  "title": "Picture the view",
2206
- "description": "A picture of the 3D view as a PNG — what the person sees in the viewport, without the HTML labels over it (dimension values, names). Give view and/or fit to turn the view first, as view.set does. width and height in pixels: the viewport’s own shape at most 1280 pixels on its long side by default; one of them alone keeps the viewport’s shape. Waits for the session to settle first. Needs the viewport.",
3249
+ "description": "A picture of the 3D view as a PNG — what the person sees in the viewport, without the HTML labels over it (dimension values, names). Give view and/or fit to turn the view first, as view.set does, or frame to frame a box or a place. show puts the scan, the reference, the sections, the elements or the labels on screen or away for the picture alone, by key — { scan: false } pictures what was built on the scan on its own; view.set lists the keys. section cuts everything open for the picture alone, as view.set does. width and height in pixels: the viewport’s own shape at most 800 pixels on its long side by default, enough to check a step by — ask for more (up to 2048) for a picture to keep; one of them alone keeps the viewport’s shape. Waits for the session to settle first. Needs the viewport.",
2207
3250
  "input": {
2208
3251
  "type": "object",
2209
3252
  "properties": {
@@ -2235,6 +3278,127 @@
2235
3278
  "fit": {
2236
3279
  "type": "boolean",
2237
3280
  "description": "Bring everything shown into the frame, keeping the direction looked from."
3281
+ },
3282
+ "show": {
3283
+ "type": "object",
3284
+ "description": "What to show or put away, by key, true or false: scan, reference (the Deviation workspace’s reference part), sections, elements (the measured elements and dimensions), labels — and the keys a workspace adds (view.set answers with every key standing now and whether it is shown). { scan: false } pictures what was built on the scan on its own.",
3285
+ "properties": {
3286
+ "scan": {
3287
+ "type": "boolean"
3288
+ },
3289
+ "reference": {
3290
+ "type": "boolean"
3291
+ },
3292
+ "sections": {
3293
+ "type": "boolean"
3294
+ },
3295
+ "elements": {
3296
+ "type": "boolean"
3297
+ },
3298
+ "labels": {
3299
+ "type": "boolean"
3300
+ }
3301
+ }
3302
+ },
3303
+ "frame": {
3304
+ "oneOf": [
3305
+ {
3306
+ "type": "object",
3307
+ "properties": {
3308
+ "min": {
3309
+ "type": "array",
3310
+ "items": {
3311
+ "type": "number"
3312
+ },
3313
+ "description": "The lowest corner, mm.",
3314
+ "minItems": 3,
3315
+ "maxItems": 3
3316
+ },
3317
+ "max": {
3318
+ "type": "array",
3319
+ "items": {
3320
+ "type": "number"
3321
+ },
3322
+ "description": "The highest corner, mm.",
3323
+ "minItems": 3,
3324
+ "maxItems": 3
3325
+ }
3326
+ },
3327
+ "required": [
3328
+ "min",
3329
+ "max"
3330
+ ],
3331
+ "additionalProperties": false,
3332
+ "description": "A box, in the frame the part is measured in now."
3333
+ },
3334
+ {
3335
+ "type": "object",
3336
+ "properties": {
3337
+ "at": {
3338
+ "type": "array",
3339
+ "items": {
3340
+ "type": "number"
3341
+ },
3342
+ "description": "The centre, mm.",
3343
+ "minItems": 3,
3344
+ "maxItems": 3
3345
+ },
3346
+ "size": {
3347
+ "type": "number",
3348
+ "description": "The width of the view there, mm.",
3349
+ "exclusiveMinimum": 0
3350
+ }
3351
+ },
3352
+ "required": [
3353
+ "at",
3354
+ "size"
3355
+ ],
3356
+ "additionalProperties": false,
3357
+ "description": "A place, looked at from `size` mm across."
3358
+ }
3359
+ ],
3360
+ "description": "Frame a box or a place instead of everything shown — a corner or a fillet looked at closely; fit is then left alone."
3361
+ },
3362
+ "section": {
3363
+ "oneOf": [
3364
+ {
3365
+ "type": "boolean",
3366
+ "description": "true opens it as the Section key does — square to the view, through the part’s middle; false puts it away."
3367
+ },
3368
+ {
3369
+ "type": "object",
3370
+ "properties": {
3371
+ "across": {
3372
+ "oneOf": [
3373
+ {
3374
+ "type": "integer",
3375
+ "description": "The element’s id.",
3376
+ "minimum": 1
3377
+ },
3378
+ {
3379
+ "type": "string",
3380
+ "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3381
+ "minLength": 1
3382
+ }
3383
+ ],
3384
+ "description": "A coordinate plane \"XY\", \"YZ\", \"ZX\", or an element with a direction."
3385
+ },
3386
+ "offset": {
3387
+ "type": "number",
3388
+ "description": "Where along its normal, mm: for a coordinate plane the coordinate, for an element from its centre."
3389
+ },
3390
+ "flip": {
3391
+ "type": "boolean",
3392
+ "description": "Take away the half away from the camera instead."
3393
+ }
3394
+ },
3395
+ "required": [
3396
+ "across"
3397
+ ],
3398
+ "additionalProperties": false
3399
+ }
3400
+ ],
3401
+ "description": "The section view: everything cut open at a plane, the half toward the camera taken away, closed parts capped — to see inside. Set after any turn."
2238
3402
  }
2239
3403
  },
2240
3404
  "additionalProperties": false
@@ -2246,7 +3410,7 @@
2246
3410
  {
2247
3411
  "name": "view.set",
2248
3412
  "title": "Turn the view",
2249
- "description": "Turn the 3D view to a standard view and/or fit everything shown into the frame — with neither given, it fits. It waits for the session to settle first (a fit, a map, a rebuild), so what was just made is in the frame. Not a step of the history. Needs the viewport. Returns the view.",
3413
+ "description": "Turn the 3D view to a standard view and/or fit everything shown into the frame — with neither given, it fits — or frame a box or a place (frame). show puts the scan, the reference, the sections, the elements or the labels on screen or away, by key, and leaves them so — { scan: false } to look at what was built on the scan without it. section cuts everything open at a plane to look inside, and leaves it so. It waits for the session to settle first (a fit, a map, a rebuild), so what was just made is in the frame. Not a step of the history. Needs the viewport. Returns the view, the section view (null when off) and, under shown, every key that can be shown now and whether it is.",
2250
3414
  "input": {
2251
3415
  "type": "object",
2252
3416
  "properties": {
@@ -2266,6 +3430,127 @@
2266
3430
  "fit": {
2267
3431
  "type": "boolean",
2268
3432
  "description": "Bring everything shown into the frame, keeping the direction looked from."
3433
+ },
3434
+ "show": {
3435
+ "type": "object",
3436
+ "description": "What to show or put away, by key, true or false: scan, reference (the Deviation workspace’s reference part), sections, elements (the measured elements and dimensions), labels — and the keys a workspace adds (view.set answers with every key standing now and whether it is shown). { scan: false } pictures what was built on the scan on its own.",
3437
+ "properties": {
3438
+ "scan": {
3439
+ "type": "boolean"
3440
+ },
3441
+ "reference": {
3442
+ "type": "boolean"
3443
+ },
3444
+ "sections": {
3445
+ "type": "boolean"
3446
+ },
3447
+ "elements": {
3448
+ "type": "boolean"
3449
+ },
3450
+ "labels": {
3451
+ "type": "boolean"
3452
+ }
3453
+ }
3454
+ },
3455
+ "frame": {
3456
+ "oneOf": [
3457
+ {
3458
+ "type": "object",
3459
+ "properties": {
3460
+ "min": {
3461
+ "type": "array",
3462
+ "items": {
3463
+ "type": "number"
3464
+ },
3465
+ "description": "The lowest corner, mm.",
3466
+ "minItems": 3,
3467
+ "maxItems": 3
3468
+ },
3469
+ "max": {
3470
+ "type": "array",
3471
+ "items": {
3472
+ "type": "number"
3473
+ },
3474
+ "description": "The highest corner, mm.",
3475
+ "minItems": 3,
3476
+ "maxItems": 3
3477
+ }
3478
+ },
3479
+ "required": [
3480
+ "min",
3481
+ "max"
3482
+ ],
3483
+ "additionalProperties": false,
3484
+ "description": "A box, in the frame the part is measured in now."
3485
+ },
3486
+ {
3487
+ "type": "object",
3488
+ "properties": {
3489
+ "at": {
3490
+ "type": "array",
3491
+ "items": {
3492
+ "type": "number"
3493
+ },
3494
+ "description": "The centre, mm.",
3495
+ "minItems": 3,
3496
+ "maxItems": 3
3497
+ },
3498
+ "size": {
3499
+ "type": "number",
3500
+ "description": "The width of the view there, mm.",
3501
+ "exclusiveMinimum": 0
3502
+ }
3503
+ },
3504
+ "required": [
3505
+ "at",
3506
+ "size"
3507
+ ],
3508
+ "additionalProperties": false,
3509
+ "description": "A place, looked at from `size` mm across."
3510
+ }
3511
+ ],
3512
+ "description": "Frame a box or a place instead of everything shown — a corner or a fillet looked at closely; fit is then left alone."
3513
+ },
3514
+ "section": {
3515
+ "oneOf": [
3516
+ {
3517
+ "type": "boolean",
3518
+ "description": "true opens it as the Section key does — square to the view, through the part’s middle; false puts it away."
3519
+ },
3520
+ {
3521
+ "type": "object",
3522
+ "properties": {
3523
+ "across": {
3524
+ "oneOf": [
3525
+ {
3526
+ "type": "integer",
3527
+ "description": "The element’s id.",
3528
+ "minimum": 1
3529
+ },
3530
+ {
3531
+ "type": "string",
3532
+ "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3533
+ "minLength": 1
3534
+ }
3535
+ ],
3536
+ "description": "A coordinate plane \"XY\", \"YZ\", \"ZX\", or an element with a direction."
3537
+ },
3538
+ "offset": {
3539
+ "type": "number",
3540
+ "description": "Where along its normal, mm: for a coordinate plane the coordinate, for an element from its centre."
3541
+ },
3542
+ "flip": {
3543
+ "type": "boolean",
3544
+ "description": "Take away the half away from the camera instead."
3545
+ }
3546
+ },
3547
+ "required": [
3548
+ "across"
3549
+ ],
3550
+ "additionalProperties": false
3551
+ }
3552
+ ],
3553
+ "description": "The section view: everything cut open at a plane, the half toward the camera taken away, closed parts capped — to see inside. Set after any turn."
2269
3554
  }
2270
3555
  },
2271
3556
  "additionalProperties": false