scanruler-mcp 0.4.5 → 0.6.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
@@ -1,11 +1,11 @@
1
1
  {
2
- "app": "0.8.0",
3
- "saved": "2026-10-26T07:21:55.736Z",
2
+ "app": "0.9.2",
3
+ "saved": "2026-10-31T15:11:20.100Z",
4
4
  "commands": [
5
5
  {
6
6
  "name": "align.auto",
7
7
  "title": "Auto-align the part",
8
- "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. level: settled (the default) lays all the faces on the axes at once, by area — a flange a degree off square shares its error with the base; largest squares the axis nearest the largest flat face exactly onto its normal and turns the other two about it onto the faces square to them. Returns what the pose was read from, the transform, how many elements moved with it, and square — how square it came out: largest (the largest flat face: the axis it is square to, its area in mm², tiltDeg — the angle between its fitted plane’s normal and that axis) and per axis the faces square to it (tiltDeg weighted by area, their area, the largest three each with area, tiltDeg and centre in the new frame). A drafted wall reads as its draft. One undo step.",
8
+ "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. level: settled (the default) lays all the faces on the axes at once, by area; largest squares the largest flat face exactly and settles the rest about its normal. Returns what the pose was read from, the transform, how many elements moved, and square — how square it came out: largest (the largest flat face’s axis, area, tiltDeg) and per axis the faces square to it with their tilts. Trap: a drafted wall reads as its draft, not as an alignment error. One undo step.",
9
9
  "input": {
10
10
  "type": "object",
11
11
  "properties": {
@@ -15,7 +15,7 @@
15
15
  "settled",
16
16
  "largest"
17
17
  ],
18
- "description": "settled (the default): the best fit of all the faces square to the axes. largest: square to the largest flat face exactly, the others settled about its normal."
18
+ "description": "settled (the default): all faces at once, by area. largest: the largest flat face exactly, the rest settled about its normal."
19
19
  },
20
20
  "detail": {
21
21
  "type": "string",
@@ -23,7 +23,7 @@
23
23
  "brief",
24
24
  "full"
25
25
  ],
26
- "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."
26
+ "description": "brief (the default): the transform and how many elements moved. full: every element where it now is."
27
27
  }
28
28
  },
29
29
  "additionalProperties": false
@@ -45,7 +45,7 @@
45
45
  "brief",
46
46
  "full"
47
47
  ],
48
- "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."
48
+ "description": "brief (the default): the transform and how many elements moved. full: every element where it now is."
49
49
  }
50
50
  },
51
51
  "additionalProperties": false
@@ -57,7 +57,7 @@
57
57
  {
58
58
  "name": "align.datum",
59
59
  "title": "Align the part to datums",
60
- "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 or an axis (or 2 points along an edge) laid along secondaryAxis (default x+), or a plane, whose outward NORMAL goes on secondaryAxis, not along it (a side wall as secondary with x+ ends up facing x+), turned square to the primary; origin is the zero point — a point, sphere or circle (or 1 point). Each is an element by id or name, or points in mm: points are used as given, not snapped to the scan (an origin point is the zero exactly where it is; scan.nearest puts a point on the surface first). Each datum zeroes the coordinates it owns (a plane the one along its normal, an axis or line the two across it); the origin sets only the coordinates they leave open — with a plane and a line, the one along the line. An origin alone moves the part without turning it, all three coordinates. Everything measured moves with the part. On the part’s first alignment the coordinates nothing sets are centred on the scan’s box centre; keepFree: true leaves them where they are. Returns the transform applied — the whole alignment the part carries, when it was aligned before — how many elements moved with it, centred (the coordinates centred, as [\"y\"]), with an origin which coordinates it set and where its point now stands (a note when that is off zero), and parallelFace when a face parallel to a levelling plane and within 5 mm of it holds more of the scan (its offset along the plane’s outward normal, how many times the area, a note) — the part may stand on that one. One undo step.",
60
+ "description": "A 3-2-1 alignment, as the panel’s alignment box sets it up: primary levels the part — a plane (or 3 points) whose outward normal becomes primaryAxis (default z-); secondary turns it — a line or axis (or 2 points) laid along secondaryAxis (default x+), or a plane; origin is the zero point — a point, sphere or circle (or 1 point). Elements by id or name, or points in mm used as given, not snapped. Trap: a plane as secondary puts its outward NORMAL on secondaryAxis, not its face along it. Each datum zeroes the coordinates it owns, the origin only those left open; an origin alone moves without turning. On a first alignment the coordinates nothing sets are centred on the scan’s box (keepFree: true leaves them). Returns the transform applied, how many elements moved, centred, origin { set, at, note } and parallelFace when a face parallel to the levelling plane within 5 mm holds more of the scan. One undo step.",
61
61
  "input": {
62
62
  "type": "object",
63
63
  "properties": {
@@ -70,16 +70,16 @@
70
70
  "oneOf": [
71
71
  {
72
72
  "type": "integer",
73
- "description": "The element’s id.",
73
+ "description": "Its id.",
74
74
  "minimum": 1
75
75
  },
76
76
  {
77
77
  "type": "string",
78
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
78
+ "description": "Its name — \"Sphere 1\".",
79
79
  "minLength": 1
80
80
  }
81
81
  ],
82
- "description": "A measured element for levelling."
82
+ "description": "An element for levelling."
83
83
  }
84
84
  },
85
85
  "required": [
@@ -101,7 +101,7 @@
101
101
  "minItems": 3,
102
102
  "maxItems": 3
103
103
  },
104
- "description": "3 points on the scan for levelling — they span the face.",
104
+ "description": "3 points, mm — they span the face.",
105
105
  "minItems": 3,
106
106
  "maxItems": 3
107
107
  }
@@ -124,7 +124,7 @@
124
124
  "z+",
125
125
  "z-"
126
126
  ],
127
- "description": "The axis the primary’s outward normal becomes — default z-."
127
+ "description": "The axis the primary’s outward normal becomes; default z-."
128
128
  },
129
129
  "secondary": {
130
130
  "oneOf": [
@@ -135,16 +135,16 @@
135
135
  "oneOf": [
136
136
  {
137
137
  "type": "integer",
138
- "description": "The element’s id.",
138
+ "description": "Its id.",
139
139
  "minimum": 1
140
140
  },
141
141
  {
142
142
  "type": "string",
143
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
143
+ "description": "Its name — \"Sphere 1\".",
144
144
  "minLength": 1
145
145
  }
146
146
  ],
147
- "description": "A measured element for rotation."
147
+ "description": "An element for rotation."
148
148
  }
149
149
  },
150
150
  "required": [
@@ -166,7 +166,7 @@
166
166
  "minItems": 3,
167
167
  "maxItems": 3
168
168
  },
169
- "description": "2 points on the scan for rotation — they run along the edge.",
169
+ "description": "2 points, mm — they run along the edge.",
170
170
  "minItems": 2,
171
171
  "maxItems": 2
172
172
  }
@@ -189,7 +189,7 @@
189
189
  "z+",
190
190
  "z-"
191
191
  ],
192
- "description": "The axis the secondary runs along — a plane’s normal, for a plane — default x+."
192
+ "description": "The axis the secondary runs along (a plane: its normal); default x+."
193
193
  },
194
194
  "origin": {
195
195
  "oneOf": [
@@ -200,16 +200,16 @@
200
200
  "oneOf": [
201
201
  {
202
202
  "type": "integer",
203
- "description": "The element’s id.",
203
+ "description": "Its id.",
204
204
  "minimum": 1
205
205
  },
206
206
  {
207
207
  "type": "string",
208
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
208
+ "description": "Its name — \"Sphere 1\".",
209
209
  "minLength": 1
210
210
  }
211
211
  ],
212
- "description": "A measured element for the zero point."
212
+ "description": "An element for the zero point."
213
213
  }
214
214
  },
215
215
  "required": [
@@ -240,7 +240,7 @@
240
240
  },
241
241
  "keepFree": {
242
242
  "type": "boolean",
243
- "description": "On a first alignment, leave the coordinates nothing sets where they are instead of centring the part on them."
243
+ "description": "First alignment: leave the coordinates nothing sets where they are instead of centring."
244
244
  },
245
245
  "detail": {
246
246
  "type": "string",
@@ -248,7 +248,7 @@
248
248
  "brief",
249
249
  "full"
250
250
  ],
251
- "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."
251
+ "description": "brief (the default): the transform and how many elements moved. full: every element where it now is."
252
252
  }
253
253
  },
254
254
  "additionalProperties": false
@@ -260,7 +260,7 @@
260
260
  {
261
261
  "name": "align.symmetry",
262
262
  "title": "Align the part on its symmetry plane",
263
- "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.",
263
+ "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. One undo step.",
264
264
  "input": {
265
265
  "type": "object",
266
266
  "properties": {
@@ -270,7 +270,7 @@
270
270
  "brief",
271
271
  "full"
272
272
  ],
273
- "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."
273
+ "description": "brief (the default): the transform and how many elements moved. full: every element where it now is."
274
274
  }
275
275
  },
276
276
  "additionalProperties": false
@@ -282,7 +282,7 @@
282
282
  {
283
283
  "name": "deviation.align",
284
284
  "title": "Best-fit the scan onto the reference",
285
- "description": "Rigid best fit (no scale) of the scan onto the reference part, then the deviation map under it. mode auto (the default) finds the pose on its own; points starts from three or more pairs of corresponding points — a point on the scan and the same point on the reference, mm — then refines; local refines the fit in hand on a marked surface only (vertices, scan vertex numbers), within searchDistance mm. Returns the alignment (RMS, points matched, transform) and the map’s statistics. One undo step.",
285
+ "description": "Rigid best fit (no scale) of the scan onto the reference part, then the deviation map under it. mode auto (the default) finds the pose on its own; points starts from three or more pairs of corresponding points (scan and reference, mm) then refines; local refines the fit in hand on a marked surface only (vertices), within searchDistance mm. Returns the alignment (RMS, points matched, transform) and the map’s statistics. One undo step.",
286
286
  "input": {
287
287
  "type": "object",
288
288
  "properties": {
@@ -293,7 +293,7 @@
293
293
  "points",
294
294
  "local"
295
295
  ],
296
- "description": "auto (default), points or local."
296
+ "description": "auto (the default), points or local."
297
297
  },
298
298
  "pairs": {
299
299
  "type": "array",
@@ -334,12 +334,12 @@
334
334
  "type": "integer",
335
335
  "minimum": 0
336
336
  },
337
- "description": "local: the marked surface, scan vertex numbers.",
337
+ "description": "local: the surface to refine on, scan vertex numbers.",
338
338
  "minItems": 3
339
339
  },
340
340
  "searchDistance": {
341
341
  "type": "number",
342
- "description": "local: how far a point may be from the reference to count, mm.",
342
+ "description": "local: how far a point may lie from the reference to count, mm.",
343
343
  "exclusiveMinimum": 0
344
344
  }
345
345
  },
@@ -352,7 +352,7 @@
352
352
  {
353
353
  "name": "deviation.export",
354
354
  "title": "Export the deviation as data",
355
- "description": "The deviation map as a file of readings, for working on it elsewhere: side \"scan\" (the default) a reading per scan vertex — its place in the frame the scan is measured in (what scan.query gives) and its signed distance from the reference part, or from the element deviation.set_target measures against; side \"reference\" a reading per sample of the map on the reference (deviation.settings { on: \"reference\" } — measured if it is not yet), in the reference’s frame, positive where the reference stands outside the scan. format: ply (the default; binary, float x, y, z, deviation and uchar measured), npy (an N × 4 float32 array x, y, z, d, for numpy.load) or csv (x,y,z,d, for a spreadsheet). The distance is NaN (\"nan\" in the CSV) where there is no reading; a reading past the search distance is kept as it is — the map draws it bare and the statistics leave it out, so measured is 0 on it (PLY), and in the others |d| ≤ searchDistance says it counts. Returns the file and the figures to check it by: readings, measured, withinTolerance and withinTolerancePct (of the measured, ± tolerance — on the scan’s side what the deviation state’s stats give; on the reference’s, by reading, where the state gives it by area), tolerance and searchDistance. Changes nothing.",
355
+ "description": "The deviation map as a file of readings, for working on it elsewhere: side \"scan\" (the default) a reading per scan vertex with its signed distance from the reference (or the element measured against), side \"reference\" a reading per sample on the reference; format ply (the default, binary), npy (N × 4 float32 x, y, z, d) or csv. Returns the file with readings, measured, withinTolerance, withinTolerancePct, tolerance and searchDistance. Trap: the distance is NaN where there is no reading, and a reading past the search distance is kept as it is — |d| ≤ searchDistance says it counts. Changes nothing.",
356
356
  "input": {
357
357
  "type": "object",
358
358
  "properties": {
@@ -383,7 +383,7 @@
383
383
  {
384
384
  "name": "deviation.hotspots",
385
385
  "title": "Where the deviation lies over tolerance",
386
- "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, depth, the median |deviation| over the patch; volume, mm³ past the tolerance (the ranking key); kind, \"feature\" when the patch is at least 4 mm² and 25 point spacings² across and its depth at least 2× the tolerance — material missing or misplaced, to model or to name — else \"texture\", the surface's own roughness poking past the tolerance, small or shallow, 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. features says how many of all the patches found are features and their share of everything past the tolerance (shareOfExcess, 0–1), with what a feature patch asks: a patch over a tolerance well above the scan’s noise is never noise, so read each by its kind — a feature is modelled or named, never put down to scatter. 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). on: \"reference\" reads the map on the reference instead (deviation.settings { on }, measured if it is not yet): the patches are of the reference, in its frame, outside where the reference stands proud of the scan (material the part has not) and inside where it is short of it; far is the reference past the search distance from the scan, by side; and noScan, the reference with no scan behind it, in patches the largest first — surface the model has on no evidence: inferred, unscanned, or not on the part. Changes nothing.",
386
+ "description": "The deviation map read as patches: the vertices past the tolerance gathered into connected regions, the largest and farthest first — where the part is off, how large each place is and by how much. Needs a map (deviation.align or deviation.set_target). Returns each patch’s centroid, box, area, count, mean, extreme, depth, volume, kind (\"feature\": material missing or misplaced, to model or name; \"texture\": roughness), side, the extreme’s point and vertex, a few vertices, and onReference; features, found, over and unmeasured; on: \"reference\" reads the map on the reference, adding noScan. Trap: read far every time — the vertices past the search distance, which the map draws bare: far.inside is scan deep inside the reference (a hole, pocket or slot the model lacks), far.outside scan standing off it. Changes nothing.",
387
387
  "input": {
388
388
  "type": "object",
389
389
  "properties": {
@@ -400,7 +400,7 @@
400
400
  },
401
401
  "grain": {
402
402
  "type": "number",
403
- "description": "mm — how close two vertices over tolerance have to be to be one patch; three point spacings by default.",
403
+ "description": "mm two vertices over tolerance may lie apart and be one patch; three point spacings by default.",
404
404
  "exclusiveMinimum": 0
405
405
  },
406
406
  "on": {
@@ -434,7 +434,7 @@
434
434
  {
435
435
  "name": "deviation.open_reference",
436
436
  "title": "Open the reference part",
437
- "description": "Open the nominal part the scan is compared with — STEP straight from CAD, or STL, PLY or OBJ — in place of the one there is; any alignment and map against the old one go. The elements measured on the scan stay. Returns the deviation state. Not undoable: a new reference starts a new history.",
437
+ "description": "Open the nominal part the scan is compared with — STEP from CAD, or STL, PLY, OBJ or 3MF — in place of the one there is; any alignment and map against the old one go, the elements measured on the scan stay. Returns the deviation state. Not undoable: a new reference starts a new history.",
438
438
  "input": {
439
439
  "type": "object",
440
440
  "properties": {
@@ -445,7 +445,7 @@
445
445
  },
446
446
  "name": {
447
447
  "type": "string",
448
- "description": "The file's name with its extension — \"bracket.step\". It is what the session calls the model.",
448
+ "description": "The file's name with its extension — \"bracket.step\".",
449
449
  "minLength": 1
450
450
  },
451
451
  "units": {
@@ -456,7 +456,7 @@
456
456
  "m",
457
457
  "in"
458
458
  ],
459
- "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."
459
+ "description": "The file’s units: mm (the default), cm, m or in. Everything is measured in mm once read."
460
460
  }
461
461
  },
462
462
  "required": [
@@ -472,7 +472,7 @@
472
472
  {
473
473
  "name": "deviation.set_target",
474
474
  "title": "Measure against an element",
475
- "description": "Map how far the scan strays from one of its own fitted elements — a plane, cylinder, cone, sphere or torus — instead of from a reference part, as choosing the element in the panel does; null goes back to the reference. side is the material side, read off the scan when the element is chosen (outward: the element’s outer side; inward: a bore or shell) — give it to override. facingDeg limits which surface counts to what faces the element within that many degrees, null for any. Needs the viewport. Returns the map’s statistics. One undo step.",
475
+ "description": "Map how far the scan strays from one of its own fitted elements — a plane, cylinder, cone, sphere or torus — instead of from a reference part; null goes back to the reference. side is the material side, read off the scan when the element is chosen (outward: the element’s outer side; inward: a bore or shell) — give it to override. facingDeg limits which surface counts to what faces the element within that many degrees, null for any. Needs the viewport. Returns the map’s statistics. One undo step.",
476
476
  "input": {
477
477
  "type": "object",
478
478
  "properties": {
@@ -482,12 +482,12 @@
482
482
  "oneOf": [
483
483
  {
484
484
  "type": "integer",
485
- "description": "The element’s id.",
485
+ "description": "Its id.",
486
486
  "minimum": 1
487
487
  },
488
488
  {
489
489
  "type": "string",
490
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
490
+ "description": "Its name — \"Sphere 1\".",
491
491
  "minLength": 1
492
492
  }
493
493
  ],
@@ -506,7 +506,7 @@
506
506
  "outward",
507
507
  "inward"
508
508
  ],
509
- "description": "The material side."
509
+ "description": "The material side; read off the scan by default."
510
510
  },
511
511
  "facingDeg": {
512
512
  "oneOf": [
@@ -520,7 +520,7 @@
520
520
  "description": "Off."
521
521
  }
522
522
  ],
523
- "description": "The facing limit, degrees."
523
+ "description": "The facing limit, degrees, or null for any."
524
524
  }
525
525
  },
526
526
  "required": [
@@ -535,7 +535,7 @@
535
535
  {
536
536
  "name": "deviation.settings",
537
537
  "title": "Set how the deviation is read",
538
- "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; on, which surface a map against the reference part is painted on — \"scan\" (the scan by its distance to the reference, the default) or \"reference\" (the reference by its distance to the scan, measured the first time it is asked for: positive where the reference stands outside the scan — material the part has not, a boss or a wall the model has and the scan does not — negative where it is short of it, grey where no scan stands behind it, a reading past the search distance in the cap of its end). Read both: the scan’s side finds what the model lacks, the reference’s what the model has that the part has not, and how much of the model no scan supports (onReference.noScanPct in the state). show, the map switch (the view bar’s Map key): false leaves the surface bare to look at its shape, the map still measured and read — the figures, hotspots and pins go on; true paints it again; a project keeps it, so read settings.show in the state when a render comes out uncoloured. The map paints in the Deviation workspace only — a command of another workspace puts that one on screen, and workspace.set deviation brings the map back; view.render pictures the side on screen there and says which map it painted (map) or why none (mapWhy), elsewhere that the Deviation workspace is not on screen. Returns the deviation state. One undo step.",
538
+ "description": "The deviation map’s reading: range (colour scale, ± mm), maxDistance (search distance, mm), bands, tolerance (± mm the statistics count within), facingDeg (a change measures the map again), colormap (the person’s own choice, kept outside the undo — read settings.colormap for the ramp before judging a picture), on (which surface a map against the reference is painted on; read both sides) and show (the map switch; false leaves the surface bare, the map still measured). Returns the deviation state. Trap: the map paints in the Deviation workspace only — workspace.set deviation brings it back, and view.render says which map it painted (map) or why none (mapWhy). One undo step.",
539
539
  "input": {
540
540
  "type": "object",
541
541
  "properties": {
@@ -594,7 +594,7 @@
594
594
  "rocket",
595
595
  "turbo"
596
596
  ],
597
- "description": "The colour map: jet (blue inside, green on the surface, red outside) or one of the perceptual ramps."
597
+ "description": "jet (blue inside, green on the surface, red outside) or a perceptual ramp."
598
598
  },
599
599
  "on": {
600
600
  "type": "string",
@@ -602,11 +602,11 @@
602
602
  "scan",
603
603
  "reference"
604
604
  ],
605
- "description": "The surface the map is painted on: the scan, or the reference."
605
+ "description": "The surface the map is painted on; scan by default."
606
606
  },
607
607
  "show": {
608
608
  "type": "boolean",
609
- "description": "The map painted on the part (true) or the surface left bare (false)."
609
+ "description": "The map painted (true) or the surface left bare (false)."
610
610
  }
611
611
  },
612
612
  "additionalProperties": false
@@ -618,18 +618,18 @@
618
618
  {
619
619
  "name": "deviation.volume",
620
620
  "title": "Volume error",
621
- "description": "The scan and the reference part compared as solids, on a grid of small cells: each cell inside one and not the other is an error, touching cells a region. Read it before the surface patches — it tells how much material is wrong and where, which the nearest-point map cannot. excess is material the reference has and the part has not (a boss modelled where there is air, a hole not cut), missing material the part has and the reference has not (a boss not modelled, a pocket cut where the part is solid), wherever it is: behind a wall, inside a cavity, past the search distance. Where the scan has a hole the reference stands in for it; what the scan still does not say is unsure, never an error. Within the tolerance of the scan’s surface a difference is noise; nothing thinner than smallestSeen (two cells) is seen — the surface map stays the tool for fine offsets. Answers totals (mm³ and share of the reference’s volume, %) and the regions largest first, each with its kind, volume (mm³), maxDepth (mm from the scan’s surface), thickness (volume over the area it shares with a surface), shape — layer (a face standing off, about thickness thick) or lump (material there or not) —, centroid, deepest point and box in the reference’s frame (what view.render { frame } takes in the Deviation workspace), evidence (the share of its scan side that is real scan rather than reference standing in) and confidence. Needs the scan aligned to the reference (deviation.align). Shows the regions in the Deviation workspace, the colour plot put away. About 15 s on a 1.5M-triangle scan; within a box, less. Changes nothing kept.",
621
+ "description": "The scan and the reference part compared as solids, on a grid of small cells: each cell inside one and not the other is an error, touching cells a region. Read it before the surface patches — it tells how much material is wrong and where, which the nearest-point map cannot: excess is material the reference has and the part has not, missing the other way round, unsure where the scan does not say (never an error). Needs deviation.align. Returns totals (mm³ and % of the reference) and the regions largest first, each with kind, volume, maxDepth, thickness, shape (layer or lump), centroid, deepest, box, evidence and confidence. Trap: nothing thinner than smallestSeen (two cells) is seen — the surface map stays the tool for fine offsets. About 15 s on a 1.5M-triangle scan. Changes nothing kept.",
622
622
  "input": {
623
623
  "type": "object",
624
624
  "properties": {
625
625
  "tolerance": {
626
626
  "type": "number",
627
- "description": "± mm; the map’s tolerance (deviation.settings) by default.",
627
+ "description": "± mm; the map’s tolerance by default.",
628
628
  "exclusiveMinimum": 0
629
629
  },
630
630
  "cell": {
631
631
  "type": "number",
632
- "description": "The cell, mm; by default half the tolerance or a 250th of the reference’s longest side, the larger — and coarser if the grid would pass 16M cells.",
632
+ "description": "The cell, mm; by default half the tolerance or a 250th of the reference’s longest side, the larger.",
633
633
  "exclusiveMinimum": 0
634
634
  },
635
635
  "regions": {
@@ -646,7 +646,7 @@
646
646
  "items": {
647
647
  "type": "number"
648
648
  },
649
- "description": "The lowest corner, mm.",
649
+ "description": "Lowest corner, mm.",
650
650
  "minItems": 3,
651
651
  "maxItems": 3
652
652
  },
@@ -655,7 +655,7 @@
655
655
  "items": {
656
656
  "type": "number"
657
657
  },
658
- "description": "The highest corner, mm.",
658
+ "description": "Highest corner, mm.",
659
659
  "minItems": 3,
660
660
  "maxItems": 3
661
661
  }
@@ -665,7 +665,7 @@
665
665
  "max"
666
666
  ],
667
667
  "additionalProperties": false,
668
- "description": "Only this box is looked at, in the frame the reference is measured in."
668
+ "description": "Only this box is looked at, in the reference’s frame."
669
669
  },
670
670
  "kinds": {
671
671
  "type": "array",
@@ -691,7 +691,7 @@
691
691
  {
692
692
  "name": "dimension.add",
693
693
  "title": "Add a dimension",
694
- "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 — a section by its id or name counts as the plane it was cut on. 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.",
694
+ "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, in slot order (a section counts as the plane it was cut on). Without type, the type follows the elements as clicking them does — two planes their distance, a plane and an axis theirs, and so on; with type, one of dist-point-point, dist-point-axis, dist-point-plane, dist-axis-axis, dist-axis-plane, dist-plane-plane, angle-axis-axis, angle-axis-plane, angle-plane-plane, size-diameter, form-flatness, form-cylindricity, form-circularity, form-sphericity, orient-parallelism, orient-perpendicularity, orient-angularity, loc-coaxiality (the measure-reference guide lists each one’s slots). 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), the formatted value and the verdict. One undo step.",
695
695
  "input": {
696
696
  "type": "object",
697
697
  "properties": {
@@ -701,12 +701,12 @@
701
701
  "oneOf": [
702
702
  {
703
703
  "type": "integer",
704
- "description": "The element’s id.",
704
+ "description": "Its id.",
705
705
  "minimum": 1
706
706
  },
707
707
  {
708
708
  "type": "string",
709
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
709
+ "description": "Its name — \"Sphere 1\".",
710
710
  "minLength": 1
711
711
  }
712
712
  ],
@@ -718,7 +718,7 @@
718
718
  },
719
719
  "type": {
720
720
  "type": "string",
721
- "description": "The dimension type — see the description. Optional.",
721
+ "description": "The dimension type — see the description.",
722
722
  "minLength": 1
723
723
  },
724
724
  "anchor": {
@@ -728,7 +728,7 @@
728
728
  "gap",
729
729
  "span"
730
730
  ],
731
- "description": "Between two spheres: centre to centre (default), the gap between their surfaces, or the span across them."
731
+ "description": "Two spheres: centre to centre (the default), the gap between them, or the span across them."
732
732
  },
733
733
  "limit": {
734
734
  "oneOf": [
@@ -744,7 +744,7 @@
744
744
  },
745
745
  "max": {
746
746
  "type": "number",
747
- "description": "The value may be this and no more — a tolerance zone’s width, mm or degrees."
747
+ "description": "The most the value may be, mm or degrees."
748
748
  }
749
749
  },
750
750
  "required": [
@@ -769,12 +769,12 @@
769
769
  },
770
770
  "plus": {
771
771
  "type": "number",
772
- "description": "How far above it is allowed.",
772
+ "description": "Allowed above it.",
773
773
  "minimum": 0
774
774
  },
775
775
  "minus": {
776
776
  "type": "number",
777
- "description": "How far below it is allowed (a positive number).",
777
+ "description": "Allowed below it (positive).",
778
778
  "minimum": 0
779
779
  }
780
780
  },
@@ -787,7 +787,7 @@
787
787
  "additionalProperties": false
788
788
  }
789
789
  ],
790
- "description": "What the value is checked against; the readout and the report then carry a pass or fail verdict."
790
+ "description": "What the value is checked against, for a pass or fail verdict."
791
791
  },
792
792
  "basic": {
793
793
  "type": "number",
@@ -795,7 +795,7 @@
795
795
  },
796
796
  "name": {
797
797
  "type": "string",
798
- "description": "A name for it; otherwise it is numbered — \"Distance 2\".",
798
+ "description": "A name; otherwise numbered — \"Distance 2\".",
799
799
  "minLength": 1
800
800
  }
801
801
  },
@@ -819,7 +819,7 @@
819
819
  "oneOf": [
820
820
  {
821
821
  "type": "integer",
822
- "description": "The dimension’s id.",
822
+ "description": "Its id.",
823
823
  "minimum": 1
824
824
  },
825
825
  {
@@ -851,7 +851,7 @@
851
851
  "oneOf": [
852
852
  {
853
853
  "type": "integer",
854
- "description": "The dimension’s id.",
854
+ "description": "Its id.",
855
855
  "minimum": 1
856
856
  },
857
857
  {
@@ -897,7 +897,7 @@
897
897
  "oneOf": [
898
898
  {
899
899
  "type": "integer",
900
- "description": "The dimension’s id.",
900
+ "description": "Its id.",
901
901
  "minimum": 1
902
902
  },
903
903
  {
@@ -924,7 +924,7 @@
924
924
  },
925
925
  "max": {
926
926
  "type": "number",
927
- "description": "The value may be this and no more — a tolerance zone’s width, mm or degrees."
927
+ "description": "The most the value may be, mm or degrees."
928
928
  }
929
929
  },
930
930
  "required": [
@@ -949,12 +949,12 @@
949
949
  },
950
950
  "plus": {
951
951
  "type": "number",
952
- "description": "How far above it is allowed.",
952
+ "description": "Allowed above it.",
953
953
  "minimum": 0
954
954
  },
955
955
  "minus": {
956
956
  "type": "number",
957
- "description": "How far below it is allowed (a positive number).",
957
+ "description": "Allowed below it (positive).",
958
958
  "minimum": 0
959
959
  }
960
960
  },
@@ -967,7 +967,7 @@
967
967
  "additionalProperties": false
968
968
  }
969
969
  ],
970
- "description": "What the value is checked against; the readout and the report then carry a pass or fail verdict."
970
+ "description": "What the value is checked against, for a pass or fail verdict."
971
971
  },
972
972
  {
973
973
  "type": "null",
@@ -990,7 +990,7 @@
990
990
  {
991
991
  "name": "element.construct",
992
992
  "title": "Construct an element",
993
- "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 — a coordinate plane \"XY\", \"YZ\" or \"XZ\" in a plane’s slot is made a plane element through the origin first (one made so before is taken again) and listed under made; 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.",
993
+ "description": "Construct an element from others and typed-in numbers, as the panel’s creation methods do — 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 slots in order, by id or name (a section stands in a plane’s slot as its cut plane; \"XY\", \"YZ\", \"XZ\" become plane elements, listed under made); params are the numbers in order or by key. point-centroid and plane-symmetry measure the scan (vertices confines them, seed starts the symmetry search), plane-symmetry answering symmetry { rms, matched, sampled }. Returns the element. One undo step.",
994
994
  "input": {
995
995
  "type": "object",
996
996
  "properties": {
@@ -1019,16 +1019,16 @@
1019
1019
  "oneOf": [
1020
1020
  {
1021
1021
  "type": "integer",
1022
- "description": "The element’s id.",
1022
+ "description": "Its id.",
1023
1023
  "minimum": 1
1024
1024
  },
1025
1025
  {
1026
1026
  "type": "string",
1027
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1027
+ "description": "Its name — \"Sphere 1\".",
1028
1028
  "minLength": 1
1029
1029
  }
1030
1030
  ],
1031
- "description": "A source element — or, in a plane’s slot, a coordinate plane \"XY\", \"YZ\", \"XZ\"."
1031
+ "description": "A source element; in a plane’s slot also a section or \"XY\", \"YZ\", \"XZ\"."
1032
1032
  },
1033
1033
  "description": "The method’s source elements, slot by slot."
1034
1034
  },
@@ -1043,26 +1043,26 @@
1043
1043
  },
1044
1044
  {
1045
1045
  "type": "object",
1046
- "description": "The numbers by key.",
1046
+ "description": "The numbers by key (x, y, z; offset; nx, ny, nz, px, py, pz; d, cx, cy, cz).",
1047
1047
  "additionalProperties": true
1048
1048
  }
1049
1049
  ],
1050
- "description": "The method’s typed-in numbers, in millimetres."
1050
+ "description": "The method’s typed-in numbers, mm."
1051
1051
  },
1052
1052
  "seed": {
1053
1053
  "oneOf": [
1054
1054
  {
1055
1055
  "type": "integer",
1056
- "description": "The element’s id.",
1056
+ "description": "Its id.",
1057
1057
  "minimum": 1
1058
1058
  },
1059
1059
  {
1060
1060
  "type": "string",
1061
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1061
+ "description": "Its name — \"Sphere 1\".",
1062
1062
  "minLength": 1
1063
1063
  }
1064
1064
  ],
1065
- "description": "plane-symmetry: the plane the search starts from — a plane element or \"XY\", \"YZ\", \"XZ\"."
1065
+ "description": "plane-symmetry: the plane the search starts from."
1066
1066
  },
1067
1067
  "vertices": {
1068
1068
  "type": "array",
@@ -1070,12 +1070,12 @@
1070
1070
  "type": "integer",
1071
1071
  "minimum": 0
1072
1072
  },
1073
- "description": "point-centroid, plane-symmetry: confine the search to these scan vertices.",
1073
+ "description": "point-centroid, plane-symmetry: only these scan vertices.",
1074
1074
  "minItems": 3
1075
1075
  },
1076
1076
  "assumed": {
1077
1077
  "type": "number",
1078
- "description": "The diameter the feature was designed at, mm — a sphere, cylinder or circle is then drawn and exported at it, and still reported as measured.",
1078
+ "description": "The designed diameter, mm: drawn and exported at it, reported as measured.",
1079
1079
  "exclusiveMinimum": 0
1080
1080
  },
1081
1081
  "orient": {
@@ -1085,16 +1085,16 @@
1085
1085
  "oneOf": [
1086
1086
  {
1087
1087
  "type": "integer",
1088
- "description": "The element’s id.",
1088
+ "description": "Its id.",
1089
1089
  "minimum": 1
1090
1090
  },
1091
1091
  {
1092
1092
  "type": "string",
1093
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1093
+ "description": "Its name — \"Sphere 1\".",
1094
1094
  "minLength": 1
1095
1095
  }
1096
1096
  ],
1097
- "description": "The reference plane: a plane element, or a coordinate plane \"XY\", \"YZ\" or \"XZ\"."
1097
+ "description": "A plane element, a section, or \"XY\", \"YZ\", \"XZ\"."
1098
1098
  },
1099
1099
  "relation": {
1100
1100
  "type": "string",
@@ -1102,18 +1102,18 @@
1102
1102
  "normal",
1103
1103
  "inPlane"
1104
1104
  ],
1105
- "description": "normal (the default): the element’s direction is the plane’s normal — a parallel face, a perpendicular bore. inPlane: it lies in the plane."
1105
+ "description": "normal (the default): the direction is the plane’s normal. inPlane: it lies in the plane."
1106
1106
  }
1107
1107
  },
1108
1108
  "required": [
1109
1109
  "to"
1110
1110
  ],
1111
1111
  "additionalProperties": false,
1112
- "description": "Align the element’s direction to a reference plane, as designed; the fit as measured is kept beside it and reported."
1112
+ "description": "Align the direction to a plane, as designed; the measured fit is kept beside it."
1113
1113
  },
1114
1114
  "name": {
1115
1115
  "type": "string",
1116
- "description": "A name for it; otherwise it is numbered by kind — \"Sphere 2\".",
1116
+ "description": "A name; else numbered by kind — \"Sphere 2\".",
1117
1117
  "minLength": 1
1118
1118
  }
1119
1119
  },
@@ -1130,7 +1130,7 @@
1130
1130
  {
1131
1131
  "name": "element.fit",
1132
1132
  "title": "Fit an element",
1133
- "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). A seed near an edge can land on the wrong surface (a cup’s underside for its inside): say what is sought — side, radius, axis, within — and surfaces that do not match are passed over; a fit that finds none is refused with the radii it saw — a round turned down for its axis with that axis, a point on it, how far off it lay and its points, to give as axis or to drop axis for. Returns the element with its fit and the seed actually used (vertex and point), so a recipe can be replayed on another scan — several seeds each with inRegion (whether the surface grew from it: one surface grows, from the seeds on it), offMm (how far it lies off the fitted surface along its normal, a round one’s outward) and deg (how far its normal turns from the surface’s there), and a seed left out warns where it lies: on another surface (fit each, or mark both and fit the marked), or on this one outside the region; a surface also the region it grew to — region { area (mm²), box } and, a plane’s, normalSpreadDeg (95 % of its normals lie within it) — and a plane or a cylinder a warning when its points look like two surfaces, with region.second naming where the other lies (a cylinder’s: its share, band along the axis from the centre, axis angle, radius and how far each part’s normals lean off square to the axis). A cylinder whose region grew over two surfaces one after the other along the axis — a bore stepping wider below a flange — is parted where two cylinders fit it best and the part the seed is on answered, with note and second { radius, band (mm along the axis from the centre), share }; a refusal lists the radii it turned down and why (σ over its length, arc). A bore whose axis meets the scan at an end answers closed { from, to (mm along the axis from the centre, where the axis meets the scan and leaves it), at } with a warning — a floor, or a wrap bridging a hole. A plane warns, with region.fill (the share of the rectangle it spans that it fills) and region.sagitta (how far a quadric over the region curves across it, mm), when it fills under 15 %, or its normals spread past 10° and the region is curved — the sagitta over three times what the quadric leaves: the crown of a bead or round, not a face. Relief on a flat face (lettering) spreads the normals as wide and does not warn. mark: true leaves the region’s points marked for element.fit_marked { marked: true }. A circle may come off an open rim of the scan instead — rim: its number from scan.qa, in place of at: fitted through the rim’s whole loop, the answer giving rim { index, points, rms }. One undo step.",
1133
+ "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 (or places) in at and is best-fitted to it; a point is the place itself; a circle goes through three or more places, or round an open rim (rim, numbered by scan.qa). A place is { vertex } or { point: [x, y, z] } (mm, current frame; the nearest vertex is taken). Trap: a seed near an edge can land on the wrong surface — say what is sought with side, radius, axis or within, and surfaces that do not match are passed over. Returns the element with its fit, the seeds used (inRegion, offMm, deg), the region grown (area, box, normalSpreadDeg, fill, sagitta) and a warning when the points look like two surfaces, a bore steps or is closed at an end, or a plane is a bead’s crown — the measure-reference guide (Elements) says how to read each. One undo step.",
1134
1134
  "input": {
1135
1135
  "type": "object",
1136
1136
  "properties": {
@@ -1156,7 +1156,7 @@
1156
1156
  "properties": {
1157
1157
  "vertex": {
1158
1158
  "type": "integer",
1159
- "description": "A scan vertex, as a project file and session.state name it.",
1159
+ "description": "A scan vertex number.",
1160
1160
  "minimum": 0
1161
1161
  }
1162
1162
  },
@@ -1173,7 +1173,7 @@
1173
1173
  "items": {
1174
1174
  "type": "number"
1175
1175
  },
1176
- "description": "A point in millimetres, in the frame the part is measured in now; the scan vertex nearest it is taken.",
1176
+ "description": "[x, y, z] mm in the current frame; the nearest scan vertex is taken.",
1177
1177
  "minItems": 3,
1178
1178
  "maxItems": 3
1179
1179
  }
@@ -1191,7 +1191,7 @@
1191
1191
  "items": {
1192
1192
  "type": "number"
1193
1193
  },
1194
- "description": "A pixel of the viewport, x right and y down from its top left, as on a view.render picture.",
1194
+ "description": "A viewport pixel [x, y] (not available yet).",
1195
1195
  "minItems": 2,
1196
1196
  "maxItems": 2
1197
1197
  }
@@ -1206,7 +1206,7 @@
1206
1206
  "properties": {
1207
1207
  "candidate": {
1208
1208
  "type": "integer",
1209
- "description": "A feature from scan.candidates.",
1209
+ "description": "A feature from scan.candidates (not available yet).",
1210
1210
  "minimum": 0
1211
1211
  }
1212
1212
  },
@@ -1227,7 +1227,7 @@
1227
1227
  "properties": {
1228
1228
  "vertex": {
1229
1229
  "type": "integer",
1230
- "description": "A scan vertex, as a project file and session.state name it.",
1230
+ "description": "A scan vertex number.",
1231
1231
  "minimum": 0
1232
1232
  }
1233
1233
  },
@@ -1244,7 +1244,7 @@
1244
1244
  "items": {
1245
1245
  "type": "number"
1246
1246
  },
1247
- "description": "A point in millimetres, in the frame the part is measured in now; the scan vertex nearest it is taken.",
1247
+ "description": "[x, y, z] mm in the current frame; the nearest scan vertex is taken.",
1248
1248
  "minItems": 3,
1249
1249
  "maxItems": 3
1250
1250
  }
@@ -1262,7 +1262,7 @@
1262
1262
  "items": {
1263
1263
  "type": "number"
1264
1264
  },
1265
- "description": "A pixel of the viewport, x right and y down from its top left, as on a view.render picture.",
1265
+ "description": "A viewport pixel [x, y] (not available yet).",
1266
1266
  "minItems": 2,
1267
1267
  "maxItems": 2
1268
1268
  }
@@ -1277,7 +1277,7 @@
1277
1277
  "properties": {
1278
1278
  "candidate": {
1279
1279
  "type": "integer",
1280
- "description": "A feature from scan.candidates.",
1280
+ "description": "A feature from scan.candidates (not available yet).",
1281
1281
  "minimum": 0
1282
1282
  }
1283
1283
  },
@@ -1301,7 +1301,7 @@
1301
1301
  "inside",
1302
1302
  "outside"
1303
1303
  ],
1304
- "description": "Sphere, cylinder, cone: inside — concave, normals toward the axis or centre (a bore, a cup’s inside, a countersink); outside — convex (a shaft, a ball)."
1304
+ "description": "Sphere, cylinder, cone: inside (concave, a bore) or outside (convex, a shaft)."
1305
1305
  },
1306
1306
  "radius": {
1307
1307
  "type": "object",
@@ -1318,7 +1318,7 @@
1318
1318
  }
1319
1319
  },
1320
1320
  "additionalProperties": false,
1321
- "description": "Sphere, cylinder, cone: the radius range the surface lies in."
1321
+ "description": "Sphere, cylinder, cone: the radius range sought."
1322
1322
  },
1323
1323
  "axis": {
1324
1324
  "type": "array",
@@ -1360,11 +1360,11 @@
1360
1360
  },
1361
1361
  "mark": {
1362
1362
  "type": "boolean",
1363
- "description": "Leave the region the surface grew to marked, for element.fit_marked { marked: true }."
1363
+ "description": "Leave the grown region marked for element.fit_marked."
1364
1364
  },
1365
1365
  "rim": {
1366
1366
  "type": "integer",
1367
- "description": "A circle through an open rim of the scan, by its number from scan.qa — in place of at.",
1367
+ "description": "Circle: an open rim of the scan by its scan.qa number, in place of at.",
1368
1368
  "minimum": 0
1369
1369
  },
1370
1370
  "sigma": {
@@ -1375,16 +1375,16 @@
1375
1375
  1,
1376
1376
  0
1377
1377
  ],
1378
- "description": "The outlier cut-off: residuals beyond this many sigma are left out of the fit — 3 (the default the panel starts on), 2, 1, or 0 for all points."
1378
+ "description": "Outlier cut-off, sigma: 3 (the default), 2, 1, or 0 for all points."
1379
1379
  },
1380
1380
  "knownDiameter": {
1381
1381
  "type": "number",
1382
- "description": "Sphere: the ball’s known diameter, mm — a gauge ball, a ballbar’s balls. The fit holds it and places the centre alone, which keeps the centre right on a ball scanned only partly; fit.held then gives the diameter the same points fit freely (freeDiameter — it should be close: a scan reading off moves a held centre by about as much) and how far holding it moved the centre (shift). Refused when the surface fits a sphere more than 1 mm or 10 % off it.",
1382
+ "description": "Sphere: a known diameter held, mm (a gauge ball); the centre alone is fitted.",
1383
1383
  "exclusiveMinimum": 0
1384
1384
  },
1385
1385
  "assumed": {
1386
1386
  "type": "number",
1387
- "description": "The diameter the feature was designed at, mm — a sphere, cylinder or circle is then drawn and exported at it, and still reported as measured.",
1387
+ "description": "The designed diameter, mm: drawn and exported at it, reported as measured.",
1388
1388
  "exclusiveMinimum": 0
1389
1389
  },
1390
1390
  "orient": {
@@ -1394,16 +1394,16 @@
1394
1394
  "oneOf": [
1395
1395
  {
1396
1396
  "type": "integer",
1397
- "description": "The element’s id.",
1397
+ "description": "Its id.",
1398
1398
  "minimum": 1
1399
1399
  },
1400
1400
  {
1401
1401
  "type": "string",
1402
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1402
+ "description": "Its name — \"Sphere 1\".",
1403
1403
  "minLength": 1
1404
1404
  }
1405
1405
  ],
1406
- "description": "The reference plane: a plane element, or a coordinate plane \"XY\", \"YZ\" or \"XZ\"."
1406
+ "description": "A plane element, a section, or \"XY\", \"YZ\", \"XZ\"."
1407
1407
  },
1408
1408
  "relation": {
1409
1409
  "type": "string",
@@ -1411,49 +1411,49 @@
1411
1411
  "normal",
1412
1412
  "inPlane"
1413
1413
  ],
1414
- "description": "normal (the default): the element’s direction is the plane’s normal — a parallel face, a perpendicular bore. inPlane: it lies in the plane."
1414
+ "description": "normal (the default): the direction is the plane’s normal. inPlane: it lies in the plane."
1415
1415
  }
1416
1416
  },
1417
1417
  "required": [
1418
1418
  "to"
1419
1419
  ],
1420
1420
  "additionalProperties": false,
1421
- "description": "Align the element’s direction to a reference plane, as designed; the fit as measured is kept beside it and reported."
1421
+ "description": "Align the direction to a plane, as designed; the measured fit is kept beside it."
1422
1422
  },
1423
1423
  "extend": {
1424
1424
  "type": "object",
1425
1425
  "properties": {
1426
1426
  "start": {
1427
1427
  "type": "number",
1428
- "description": "Cylinder: millimetres past the start of the measured surface (negative pulls it in)."
1428
+ "description": "Cylinder: mm past the start (negative pulls it in)."
1429
1429
  },
1430
1430
  "end": {
1431
1431
  "type": "number",
1432
- "description": "Cylinder: millimetres past its end."
1432
+ "description": "Cylinder: mm past the end."
1433
1433
  },
1434
1434
  "uMin": {
1435
1435
  "type": "number",
1436
- "description": "Plane: millimetres past one edge of the patch along its first axis."
1436
+ "description": "Plane: mm past the edge along its first axis."
1437
1437
  },
1438
1438
  "uMax": {
1439
1439
  "type": "number",
1440
- "description": "Plane: past the opposite edge."
1440
+ "description": "Plane: the opposite edge."
1441
1441
  },
1442
1442
  "vMin": {
1443
1443
  "type": "number",
1444
- "description": "Plane: past one edge along its second axis."
1444
+ "description": "Plane: along its second axis."
1445
1445
  },
1446
1446
  "vMax": {
1447
1447
  "type": "number",
1448
- "description": "Plane: past the opposite edge."
1448
+ "description": "Plane: the opposite edge."
1449
1449
  }
1450
1450
  },
1451
1451
  "additionalProperties": false,
1452
- "description": "How far past the measured surface a cylinder or plane is drawn and exported. What is reported stays what was measured."
1452
+ "description": "Mm a cylinder or plane is drawn and exported past the measured surface."
1453
1453
  },
1454
1454
  "name": {
1455
1455
  "type": "string",
1456
- "description": "A name for it; otherwise it is numbered by kind — \"Sphere 2\".",
1456
+ "description": "A name; else numbered by kind — \"Sphere 2\".",
1457
1457
  "minLength": 1
1458
1458
  }
1459
1459
  },
@@ -1469,7 +1469,7 @@
1469
1469
  {
1470
1470
  "name": "element.fit_marked",
1471
1471
  "title": "Fit an element to a marked surface",
1472
- "description": "Fit a plane, sphere, cylinder, cone or torus to exactly the scan vertices given — a surface marked by hand in the panel, with no search for the surface — or, with marked: true in place of vertices, to the points the last element.fit { mark: true }, scan.segment { mark } or scan.query { mark: true } left marked, or with box (and normal: only those facing a way, within withinDeg, 30 by default) to every scan vertex inside it, as scan.fit_surface takes them. The element keeps the marking as its recipe. Returns the element, and with box how many points it took. One undo step.",
1472
+ "description": "Fit a plane, sphere, cylinder, cone or torus to exactly the scan vertices given, with no search for the surface — vertices, or marked: true for the points the last element.fit { mark: true }, scan.segment { mark } or scan.query { mark: true } left marked, or box (with normal: only those facing a way) for every vertex inside it. The element keeps the marking as its recipe. Returns the element, and with box how many points it took. One undo step.",
1473
1473
  "input": {
1474
1474
  "type": "object",
1475
1475
  "properties": {
@@ -1505,7 +1505,7 @@
1505
1505
  "items": {
1506
1506
  "type": "number"
1507
1507
  },
1508
- "description": "The lowest corner, mm.",
1508
+ "description": "Lowest corner, mm.",
1509
1509
  "minItems": 3,
1510
1510
  "maxItems": 3
1511
1511
  },
@@ -1514,7 +1514,7 @@
1514
1514
  "items": {
1515
1515
  "type": "number"
1516
1516
  },
1517
- "description": "The highest corner, mm.",
1517
+ "description": "Highest corner, mm.",
1518
1518
  "minItems": 3,
1519
1519
  "maxItems": 3
1520
1520
  }
@@ -1534,7 +1534,7 @@
1534
1534
  "items": {
1535
1535
  "type": "number"
1536
1536
  },
1537
- "description": "The direction, any length.",
1537
+ "description": "A direction, any length.",
1538
1538
  "minItems": 3,
1539
1539
  "maxItems": 3
1540
1540
  },
@@ -1559,16 +1559,16 @@
1559
1559
  1,
1560
1560
  0
1561
1561
  ],
1562
- "description": "The outlier cut-off: residuals beyond this many sigma are left out of the fit — 3 (the default the panel starts on), 2, 1, or 0 for all points."
1562
+ "description": "Outlier cut-off, sigma: 3 (the default), 2, 1, or 0 for all points."
1563
1563
  },
1564
1564
  "knownDiameter": {
1565
1565
  "type": "number",
1566
- "description": "Sphere: the ball’s known diameter, mm — a gauge ball, a ballbar’s balls. The fit holds it and places the centre alone, which keeps the centre right on a ball scanned only partly; fit.held then gives the diameter the same points fit freely (freeDiameter — it should be close: a scan reading off moves a held centre by about as much) and how far holding it moved the centre (shift). Refused when the surface fits a sphere more than 1 mm or 10 % off it.",
1566
+ "description": "Sphere: a known diameter held, mm (a gauge ball); the centre alone is fitted.",
1567
1567
  "exclusiveMinimum": 0
1568
1568
  },
1569
1569
  "assumed": {
1570
1570
  "type": "number",
1571
- "description": "The diameter the feature was designed at, mm — a sphere, cylinder or circle is then drawn and exported at it, and still reported as measured.",
1571
+ "description": "The designed diameter, mm: drawn and exported at it, reported as measured.",
1572
1572
  "exclusiveMinimum": 0
1573
1573
  },
1574
1574
  "orient": {
@@ -1578,16 +1578,16 @@
1578
1578
  "oneOf": [
1579
1579
  {
1580
1580
  "type": "integer",
1581
- "description": "The element’s id.",
1581
+ "description": "Its id.",
1582
1582
  "minimum": 1
1583
1583
  },
1584
1584
  {
1585
1585
  "type": "string",
1586
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1586
+ "description": "Its name — \"Sphere 1\".",
1587
1587
  "minLength": 1
1588
1588
  }
1589
1589
  ],
1590
- "description": "The reference plane: a plane element, or a coordinate plane \"XY\", \"YZ\" or \"XZ\"."
1590
+ "description": "A plane element, a section, or \"XY\", \"YZ\", \"XZ\"."
1591
1591
  },
1592
1592
  "relation": {
1593
1593
  "type": "string",
@@ -1595,49 +1595,49 @@
1595
1595
  "normal",
1596
1596
  "inPlane"
1597
1597
  ],
1598
- "description": "normal (the default): the element’s direction is the plane’s normal — a parallel face, a perpendicular bore. inPlane: it lies in the plane."
1598
+ "description": "normal (the default): the direction is the plane’s normal. inPlane: it lies in the plane."
1599
1599
  }
1600
1600
  },
1601
1601
  "required": [
1602
1602
  "to"
1603
1603
  ],
1604
1604
  "additionalProperties": false,
1605
- "description": "Align the element’s direction to a reference plane, as designed; the fit as measured is kept beside it and reported."
1605
+ "description": "Align the direction to a plane, as designed; the measured fit is kept beside it."
1606
1606
  },
1607
1607
  "extend": {
1608
1608
  "type": "object",
1609
1609
  "properties": {
1610
1610
  "start": {
1611
1611
  "type": "number",
1612
- "description": "Cylinder: millimetres past the start of the measured surface (negative pulls it in)."
1612
+ "description": "Cylinder: mm past the start (negative pulls it in)."
1613
1613
  },
1614
1614
  "end": {
1615
1615
  "type": "number",
1616
- "description": "Cylinder: millimetres past its end."
1616
+ "description": "Cylinder: mm past the end."
1617
1617
  },
1618
1618
  "uMin": {
1619
1619
  "type": "number",
1620
- "description": "Plane: millimetres past one edge of the patch along its first axis."
1620
+ "description": "Plane: mm past the edge along its first axis."
1621
1621
  },
1622
1622
  "uMax": {
1623
1623
  "type": "number",
1624
- "description": "Plane: past the opposite edge."
1624
+ "description": "Plane: the opposite edge."
1625
1625
  },
1626
1626
  "vMin": {
1627
1627
  "type": "number",
1628
- "description": "Plane: past one edge along its second axis."
1628
+ "description": "Plane: along its second axis."
1629
1629
  },
1630
1630
  "vMax": {
1631
1631
  "type": "number",
1632
- "description": "Plane: past the opposite edge."
1632
+ "description": "Plane: the opposite edge."
1633
1633
  }
1634
1634
  },
1635
1635
  "additionalProperties": false,
1636
- "description": "How far past the measured surface a cylinder or plane is drawn and exported. What is reported stays what was measured."
1636
+ "description": "Mm a cylinder or plane is drawn and exported past the measured surface."
1637
1637
  },
1638
1638
  "name": {
1639
1639
  "type": "string",
1640
- "description": "A name for it; otherwise it is numbered by kind — \"Sphere 2\".",
1640
+ "description": "A name; else numbered by kind — \"Sphere 2\".",
1641
1641
  "minLength": 1
1642
1642
  }
1643
1643
  },
@@ -1653,7 +1653,7 @@
1653
1653
  {
1654
1654
  "name": "element.remove",
1655
1655
  "title": "Delete an element",
1656
- "description": "Delete an element, as its row’s delete key does — and with it every construction built on it and every dimension that refers to any of them. Returns what went. One undo step.",
1656
+ "description": "Delete an element — and with it every construction built on it and every dimension on any of them. Returns what went. One undo step.",
1657
1657
  "input": {
1658
1658
  "type": "object",
1659
1659
  "properties": {
@@ -1661,12 +1661,12 @@
1661
1661
  "oneOf": [
1662
1662
  {
1663
1663
  "type": "integer",
1664
- "description": "The element’s id.",
1664
+ "description": "Its id.",
1665
1665
  "minimum": 1
1666
1666
  },
1667
1667
  {
1668
1668
  "type": "string",
1669
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1669
+ "description": "Its name — \"Sphere 1\".",
1670
1670
  "minLength": 1
1671
1671
  }
1672
1672
  ],
@@ -1693,12 +1693,12 @@
1693
1693
  "oneOf": [
1694
1694
  {
1695
1695
  "type": "integer",
1696
- "description": "The element’s id.",
1696
+ "description": "Its id.",
1697
1697
  "minimum": 1
1698
1698
  },
1699
1699
  {
1700
1700
  "type": "string",
1701
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1701
+ "description": "Its name — \"Sphere 1\".",
1702
1702
  "minLength": 1
1703
1703
  }
1704
1704
  ],
@@ -1731,12 +1731,12 @@
1731
1731
  "oneOf": [
1732
1732
  {
1733
1733
  "type": "integer",
1734
- "description": "The element’s id.",
1734
+ "description": "Its id.",
1735
1735
  "minimum": 1
1736
1736
  },
1737
1737
  {
1738
1738
  "type": "string",
1739
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
1739
+ "description": "Its name — \"Sphere 1\".",
1740
1740
  "minLength": 1
1741
1741
  }
1742
1742
  ],
@@ -1811,7 +1811,7 @@
1811
1811
  {
1812
1812
  "name": "export.step",
1813
1813
  "title": "Export the elements as STEP",
1814
- "description": "The measured elements as analytic STEP geometry for CAD — as drawn, extensions and assumed diameters included — and, in a group per section, what was measured on the sections. style: solids (the default the panel starts on: solids and faces) or surfaces (construction surfaces); it is remembered as the panel’s choice. Returns the file’s bytes and the name the panel would save it under.",
1814
+ "description": "The measured elements as analytic STEP geometry for CAD — as drawn, extensions and assumed diameters included — and, in a group per section, what was measured on the sections. style: solids (the default: solids and faces) or surfaces (construction surfaces), remembered as the panel’s choice. Returns the file’s bytes and the name the panel would save it under.",
1815
1815
  "input": {
1816
1816
  "type": "object",
1817
1817
  "properties": {
@@ -1832,11 +1832,20 @@
1832
1832
  },
1833
1833
  {
1834
1834
  "name": "export.stl",
1835
- "title": "Export the scan as STL",
1836
- "description": "The scan as a binary STL in the pose it is shown in — a datum alignment and a best fit onto the reference included. Needs the viewport. Returns the file’s bytes and the name the panel would save it under.",
1835
+ "title": "Export the scan as a mesh",
1836
+ "description": "The scan as a binary STL — or, format 3mf, a 3MF in millimetres with the scan’s own colours — in the pose it is shown in, a datum alignment and a best fit onto the reference included. Needs the viewport. Returns the file’s bytes and the name the panel would save it under.",
1837
1837
  "input": {
1838
1838
  "type": "object",
1839
- "properties": {},
1839
+ "properties": {
1840
+ "format": {
1841
+ "type": "string",
1842
+ "enum": [
1843
+ "stl",
1844
+ "3mf"
1845
+ ],
1846
+ "description": "stl (the default) or 3mf."
1847
+ }
1848
+ },
1840
1849
  "additionalProperties": false
1841
1850
  },
1842
1851
  "readOnly": true,
@@ -1859,7 +1868,7 @@
1859
1868
  {
1860
1869
  "name": "flat.calibrate",
1861
1870
  "title": "Calibrate the image",
1862
- "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.",
1871
+ "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 follows the new scale, and the edges are found again (their chain numbers change). Returns the calibration. One undo step.",
1863
1872
  "input": {
1864
1873
  "type": "object",
1865
1874
  "properties": {
@@ -1978,7 +1987,7 @@
1978
1987
  {
1979
1988
  "name": "flat.edges",
1980
1989
  "title": "List the detected edges",
1981
- "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.",
1990
+ "description": "The edge chains detected on the sheet, by number — what flat.fit takes as chains. Each with its length, whether it closes, its point count and box, in the sheet’s units; the longest first, or with near the nearest first (each with its nearest point and distance; within reach only, when given). box keeps the chains that enter it, minLength the long ones. tolerance adds each chain’s polyline thinned to that (5000 points at most over all). limit chains at most, 50 by default. Trap: the numbers change when the edges are found again. Changes nothing.",
1982
1991
  "input": {
1983
1992
  "type": "object",
1984
1993
  "properties": {
@@ -2051,7 +2060,7 @@
2051
2060
  {
2052
2061
  "name": "flat.edit",
2053
2062
  "title": "Change a 2D element, dimension, note or count",
2054
- "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.",
2063
+ "description": "Change one thing on the 2D sheet, by 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. Returns the 2D state. One undo step.",
2055
2064
  "input": {
2056
2065
  "type": "object",
2057
2066
  "properties": {
@@ -2138,7 +2147,7 @@
2138
2147
  {
2139
2148
  "name": "flat.fit",
2140
2149
  "title": "Fit a 2D element",
2141
- "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), flat-circle-centers (construct); 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.",
2150
+ "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), flat-circle-centers (construct); arc: flat-arc-pick (pick), flat-arc-edge (edge); spline: flat-spline-pick (pick). A pick method takes points, the places clicked (snapped to the nearest edge within reach unless snap: false; picks says where each landed); a seed method one place on an edge and grows along it; an edge method a place on an edge taken whole, or chains and box; a construct method refs, other 2D elements. Returns the element with its fit. One undo step.",
2142
2151
  "input": {
2143
2152
  "type": "object",
2144
2153
  "properties": {
@@ -2178,7 +2187,7 @@
2178
2187
  "type": "integer",
2179
2188
  "minimum": 0
2180
2189
  },
2181
- "description": "Edge chains by number, taken whole — for an edge or seed method.",
2190
+ "description": "Edge chains by number, taken whole (edge or seed methods).",
2182
2191
  "minItems": 1
2183
2192
  },
2184
2193
  "box": {
@@ -2208,7 +2217,7 @@
2208
2217
  "max"
2209
2218
  ],
2210
2219
  "additionalProperties": false,
2211
- "description": "Edge points inside this box, in the sheet’s units — for an edge or seed method."
2220
+ "description": "Edge points inside this box, sheet units (edge or seed methods)."
2212
2221
  },
2213
2222
  "refs": {
2214
2223
  "type": "array",
@@ -2236,11 +2245,11 @@
2236
2245
  },
2237
2246
  "snap": {
2238
2247
  "type": "boolean",
2239
- "description": "Picks snap to the nearest edge within reach — true by default, as the panel’s Snap box is."
2248
+ "description": "Picks snap to the nearest edge within reach; true by default."
2240
2249
  },
2241
2250
  "reach": {
2242
2251
  "type": "number",
2243
- "description": "How far a place reaches for an edge, in the sheet’s units — ten image pixels by default.",
2252
+ "description": "How far a place reaches for an edge, sheet units; ten image pixels by default.",
2244
2253
  "exclusiveMinimum": 0
2245
2254
  }
2246
2255
  },
@@ -2256,7 +2265,7 @@
2256
2265
  {
2257
2266
  "name": "flat.note_add",
2258
2267
  "title": "Write a note on the sheet",
2259
- "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.",
2268
+ "description": "Write a text note on the 2D sheet, as the Text tool does — one line, a line break written as \" / \"; at is its lower-left corner, sheet 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.",
2260
2269
  "input": {
2261
2270
  "type": "object",
2262
2271
  "properties": {
@@ -2288,7 +2297,7 @@
2288
2297
  {
2289
2298
  "name": "flat.objects",
2290
2299
  "title": "Find the parts on the image",
2291
- "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.",
2300
+ "description": "The separate parts on the flatbed image, parted from the background by a grey level (Otsu’s unless threshold is given) and numbered in reading order — what flat.profile takes by number. Returns each with area, holes, box, centroid, equivalentDiameter, feret (largest and smallest caliper widths with their directions), axisAngle, chains (the edge chains along its outline) and, with outline, its polygon. Trap: minArea drops smaller ones, 1 mm² by default. Changes nothing.",
2292
2301
  "input": {
2293
2302
  "type": "object",
2294
2303
  "properties": {
@@ -2339,7 +2348,7 @@
2339
2348
  },
2340
2349
  "name": {
2341
2350
  "type": "string",
2342
- "description": "The file's name with its extension — \"part.png\". It is what the session calls the model.",
2351
+ "description": "The file's name with its extension — \"part.png\".",
2343
2352
  "minLength": 1
2344
2353
  }
2345
2354
  },
@@ -2356,7 +2365,7 @@
2356
2365
  {
2357
2366
  "name": "flat.profile",
2358
2367
  "title": "Profile an outline and count its peaks",
2359
- "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.",
2368
+ "description": "An outline read against a centre (radial, the default: a part seen from above) or along an axis (axial: a part lying on its side, each side apart), and its peaks counted — the teeth of a knurl or a gear. The outline is an object of the last flat.objects by number, or edge chains by number; about is the element it is read about, else the outline’s own centre or long axis. Returns per side the count, pitch, envelope (max, min, mean peak, mean valley; radial also as diameters) and every peak’s position; points adds the sampled profile. Trap: a peak must stand prominence above the higher valley either side (0.3 of the profile’s spread by default). mark: true puts a count on the sheet — one undo step; otherwise nothing changes.",
2360
2369
  "input": {
2361
2370
  "type": "object",
2362
2371
  "properties": {
@@ -2387,7 +2396,7 @@
2387
2396
  "minLength": 1
2388
2397
  }
2389
2398
  ],
2390
- "description": "A circle, arc or point to read the radius about, or a line to read the distance from."
2399
+ "description": "A circle, arc or point (radial), or a line (axial)."
2391
2400
  },
2392
2401
  "axis": {
2393
2402
  "type": "string",
@@ -2399,13 +2408,13 @@
2399
2408
  },
2400
2409
  "samples": {
2401
2410
  "type": "integer",
2402
- "description": "Bins round the turn, or along the axis — from the point count by default.",
2411
+ "description": "Bins round the turn or along the axis; from the point count by default.",
2403
2412
  "minimum": 16,
2404
2413
  "maximum": 20000
2405
2414
  },
2406
2415
  "prominence": {
2407
2416
  "type": "number",
2408
- "description": "How far a peak must stand out, in the sheet’s units.",
2417
+ "description": "How far a peak must stand out, sheet units.",
2409
2418
  "exclusiveMinimum": 0
2410
2419
  },
2411
2420
  "mark": {
@@ -2426,7 +2435,7 @@
2426
2435
  {
2427
2436
  "name": "flat.remove",
2428
2437
  "title": "Remove from the 2D sheet",
2429
- "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.",
2438
+ "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, a dimension on one turns invalid; the answer names them. Returns what is left. One undo step.",
2430
2439
  "input": {
2431
2440
  "type": "object",
2432
2441
  "properties": {
@@ -2498,7 +2507,7 @@
2498
2507
  {
2499
2508
  "name": "flat.render",
2500
2509
  "title": "Picture the sheet",
2501
- "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.",
2510
+ "description": "A picture of the 2D sheet as a PNG, as the sheet lies in its own units — +X right, +Y up, whatever the alignment or turns — with a grid and its values 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]. frame zooms in on a box. show puts layers in or out: image, edges (the detected chains), chains (their numbers), elements (with counts and the alignment), dimensions, notes, labels, grid. 800 px on the long side by default, up to 2048. Needs the browser.",
2502
2511
  "input": {
2503
2512
  "type": "object",
2504
2513
  "properties": {
@@ -2676,7 +2685,7 @@
2676
2685
  {
2677
2686
  "name": "guide.read",
2678
2687
  "title": "Read a guide",
2679
- "description": "How to do a task with ScanRuler: the workflow, the judgement and the traps the tools’ own descriptions do not carry, written for this build — read the guide for your task, whole, before its first step, and a section again when you need it. The guides: measure — measuring a 3D scan: fitting elements, dimensions and GD&T-like checks, sections and the 2D sheet, deviation against a reference part, wall thickness, the report — by hand or as an automatic run over many scans; measure-reference — the measuring tools’ shapes with examples, what each answer costs, what each refusal means — a section at a time, as the measure guide sends you. topic: a guide, or several read in order (a guide and the ones it is read with, in one call) — as many as fit in about 80 k characters, the rest named in next, to read in the next call. section: one section of one guide, by its heading — the index lists them. A long section with ### parts under it — a reference’s list of command shapes — is best read by those parts: section takes a ### heading too, the one part you need. With no topic, the index: each guide with its sections and what each costs in tokens. Changes nothing.",
2688
+ "description": "How to do a task with ScanRuler: the workflow, the judgement and the traps the tools’ own descriptions do not carry, written for this build — read the guide for your task, whole, before its first step, and a section again when you need it. The guides: measure — measuring a 3D scan: fitting elements, dimensions and GD&T-like checks, sections and the 2D sheet, deviation against a reference part, wall thickness, the report — by hand or as an automatic run over many scans; measure-reference — the measuring tools’ shapes with examples, what each answer costs, what each refusal means — a section at a time, as the measure guide sends you. topic: a guide, or several read in order (a guide and the ones it is read with, in one call) — as many as fit in about 80 k characters, the rest named in next, to read in the next call. A guide longer than that by itself answers its sections in order while they fit, and names the rest in sectionsLeft, each to read by section. A guide’s sections for one moment of the task — measuring, building — are not in the whole read: later names each with when to read it, and the note says how; read it by section when that moment comes, before the step it is for. section: one section of one guide, by its heading — the index lists them, with when to read those a whole read leaves for later. A long section with ### parts under it — a reference’s list of command shapes — is best read by those parts: section takes a ### heading too, the one part you need. With no topic, the index: each guide with its sections and what each costs in tokens. Changes nothing.",
2680
2689
  "input": {
2681
2690
  "type": "object",
2682
2691
  "properties": {
@@ -2698,7 +2707,7 @@
2698
2707
  },
2699
2708
  "section": {
2700
2709
  "type": "string",
2701
- "description": "One section of the guide, by its heading — a ## section or a ### part of one (without its number, or a part of it that names one section). Only with one topic.",
2710
+ "description": "One section of the guide, by its heading — a ## section or a ### part of one (without its number, or a part of it that names one section), whole: a section the whole read named in later, when its moment comes, or one to read again. Only with one topic.",
2702
2711
  "minLength": 1
2703
2712
  }
2704
2713
  },
@@ -2724,10 +2733,19 @@
2724
2733
  {
2725
2734
  "name": "history.redo",
2726
2735
  "title": "Redo",
2727
- "description": "Redo the step undone last. Returns the step’s name and the session afterwards.",
2736
+ "description": "Redo the step undone last. Returns the step’s name and the session afterwards in brief (detail \"full\": the whole of it).",
2728
2737
  "input": {
2729
2738
  "type": "object",
2730
- "properties": {},
2739
+ "properties": {
2740
+ "detail": {
2741
+ "type": "string",
2742
+ "enum": [
2743
+ "brief",
2744
+ "full"
2745
+ ],
2746
+ "description": "brief (the default): what the steps change, in brief, as after; full: the whole session, as state."
2747
+ }
2748
+ },
2731
2749
  "additionalProperties": false
2732
2750
  },
2733
2751
  "readOnly": false,
@@ -2737,7 +2755,7 @@
2737
2755
  {
2738
2756
  "name": "history.restore",
2739
2757
  "title": "Back to a mark in the history",
2740
- "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.",
2758
+ "description": "Undo every step made since history.checkpoint gave this checkpoint, newest first — a run of changes that went wrong in the middle taken back whole. Refused, undoing nothing, when the mark is gone: undone past it, or the history started afresh (a scan or project opened). Returns the steps undone, newest first, and the session afterwards.",
2741
2759
  "input": {
2742
2760
  "type": "object",
2743
2761
  "properties": {
@@ -2745,6 +2763,14 @@
2745
2763
  "type": "string",
2746
2764
  "description": "What history.checkpoint returned.",
2747
2765
  "minLength": 1
2766
+ },
2767
+ "detail": {
2768
+ "type": "string",
2769
+ "enum": [
2770
+ "brief",
2771
+ "full"
2772
+ ],
2773
+ "description": "brief (the default): what the steps change, in brief, as after; full: the whole session, as state."
2748
2774
  }
2749
2775
  },
2750
2776
  "required": [
@@ -2759,10 +2785,19 @@
2759
2785
  {
2760
2786
  "name": "history.undo",
2761
2787
  "title": "Undo",
2762
- "description": "Undo the last step — one of the person’s or one of these commands, each of which is one step. Returns the step’s name and the session afterwards.",
2788
+ "description": "Undo the last step — one of the person’s or one of these commands, each of which is one step. Returns the step’s name and the session afterwards in brief (detail \"full\": the whole of it).",
2763
2789
  "input": {
2764
2790
  "type": "object",
2765
- "properties": {},
2791
+ "properties": {
2792
+ "detail": {
2793
+ "type": "string",
2794
+ "enum": [
2795
+ "brief",
2796
+ "full"
2797
+ ],
2798
+ "description": "brief (the default): what the steps change, in brief, as after; full: the whole session, as state."
2799
+ }
2800
+ },
2766
2801
  "additionalProperties": false
2767
2802
  },
2768
2803
  "readOnly": false,
@@ -2772,7 +2807,7 @@
2772
2807
  {
2773
2808
  "name": "project.load",
2774
2809
  "title": "Open a project",
2775
- "description": "Open a .scanruler project in place of the session — its models, then every measurement in it, refitted and remeasured. Refuses while the session holds measurements unless discard is true. Needs the browser. Returns the session. Not undoable: an opened project starts a new history.",
2810
+ "description": "Open a .scanruler project in place of the session — its models, then every measurement in it, remeasured, each fit as it was saved. Refuses while the session holds measurements unless discard is true. Needs the browser. Returns the session. Not undoable: an opened project starts a new history.",
2776
2811
  "input": {
2777
2812
  "type": "object",
2778
2813
  "properties": {
@@ -2788,7 +2823,7 @@
2788
2823
  },
2789
2824
  "discard": {
2790
2825
  "type": "boolean",
2791
- "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."
2826
+ "description": "true: replace the session though it holds measurements (lost unless saved as a project first). Refused otherwise when there is work to lose."
2792
2827
  }
2793
2828
  },
2794
2829
  "required": [
@@ -2824,7 +2859,7 @@
2824
2859
  {
2825
2860
  "name": "project.save",
2826
2861
  "title": "Save the project",
2827
- "description": "The session as a .scanruler project file, as Save Project downloads it: the scan, the reference, the image and every measurement, each rebuilt when it is opened. Needs the browser. Returns the file’s bytes and its name.",
2862
+ "description": "The session as a .scanruler project file, as Save Project downloads it: the scan, the reference, the image and every measurement, each rebuilt when it is opened. Needs the browser. Returns the file’s bytes and its name, holds (what is in it, counted — read it before calling the file a revision: a page reset holds no model), aligned (whether the scan stands in an aligned frame) and says (what a workspace wants said of the work saved).",
2828
2863
  "input": {
2829
2864
  "type": "object",
2830
2865
  "properties": {},
@@ -2837,7 +2872,7 @@
2837
2872
  {
2838
2873
  "name": "report.get",
2839
2874
  "title": "Get the report",
2840
- "description": "The measurement report. format \"text\" is word for word what the workspace’s Copy report button puts on the clipboard — measure (elements and dimensions with verdicts), deviation, thickness or flat (2D). format \"json\" (the default) is the whole session’s report structured: what the numbers rest on (units, scale, frame, applied alignment, fit method and each element’s outlier cut-off), every element with its fit, every dimension with value, unit, limit and pass/fail verdict, the tally of checks, the sections, and the deviation, thickness and 2D results with their settings.",
2875
+ "description": "The measurement report. format \"text\" is word for word what the workspace’s Copy report button gives — measure (elements and dimensions with verdicts), deviation, thickness or flat (2D). format \"json\" (the default) is the whole session’s report structured: what the numbers rest on (units, scale, frame, alignment, fit method, outlier cut-offs), every element with its fit, every dimension with value, unit, limit and verdict, the tally of checks, the sections, and the deviation, thickness and 2D results with their settings.",
2841
2876
  "input": {
2842
2877
  "type": "object",
2843
2878
  "properties": {
@@ -2869,7 +2904,7 @@
2869
2904
  {
2870
2905
  "name": "scan.draft",
2871
2906
  "title": "Read the draft against a pull",
2872
- "description": "The scan’s walls that run near a pull direction — the sides a mould opens along, a side core slides along — gathered into patches, each with the angle it leans off the pull: draftDeg, positive where the wall faces partly along the pull (it lets go as the tool moves that way), negative where it faces back (a back draft, an undercut to that pull); sigmaDeg its standard error, spreadDeg the points’ own spread (mostly the scan’s normal noise); with centroid, box, area (mm²), count, facing (which way the wall faces across the pull) and turnDeg (how far that turns across the patch). Neighbouring walls are parted where the way they face jumps, so a box’s four sides are four patches, and a thin wall’s two sides (a blade, a rib) two patches facing opposite ways; a point joins a patch only while it faces within 20° of the patch’s mean, so a smooth freeform wall comes in patches that turn 40° at most. A boss’s or a hole’s round side is one patch with round: true, its facing no one way. Read it early on a moulded or cast part, along each direction the tools open: walls that lean half a degree to a few explain fits that miss by the lean. pull: the direction, any length; box: only the scan inside it; nearDeg: how far off square to the pull a wall may lean and still count (10 by default); patches: how many, the largest first (12); minArea: smaller ones left out, mm² (1); split: no patch reaches across this plane — \"symmetry\" (the scan’s mirror plane: the last measured symmetry plane, else searched for), a plane element, \"XY\", \"YZ\", \"XZ\", or { point, normal } — each patch then says its side (1 along the plane’s normal, −1 against), and the answer the plane. Changes nothing.",
2907
+ "description": "The scan’s walls that run near a pull direction — the sides a mould opens along — gathered into patches, each with draftDeg, the angle it leans off the pull: positive where the wall faces partly along the pull, negative where it faces back (a back draft, an undercut); with sigmaDeg, spreadDeg, centroid, box, area (mm²), count, facing, turnDeg and round for a boss’s or hole’s round side. Needs pull; box, nearDeg (10), patches (12), minArea (1 mm²) and split (a plane no patch reaches across: \"symmetry\", a plane element, \"XY\", \"YZ\", \"XZ\" or { point, normal }) narrow it. Trap: read it early on a moulded or cast part, along each direction the tools open — walls that lean half a degree to a few explain fits that miss by the lean. Changes nothing.",
2873
2908
  "input": {
2874
2909
  "type": "object",
2875
2910
  "properties": {
@@ -2878,7 +2913,7 @@
2878
2913
  "items": {
2879
2914
  "type": "number"
2880
2915
  },
2881
- "description": "The pull direction, any length — the way the tool opens.",
2916
+ "description": "The pull direction, any length.",
2882
2917
  "minItems": 3,
2883
2918
  "maxItems": 3
2884
2919
  },
@@ -2890,7 +2925,7 @@
2890
2925
  "items": {
2891
2926
  "type": "number"
2892
2927
  },
2893
- "description": "The lowest corner, mm.",
2928
+ "description": "Lowest corner, mm.",
2894
2929
  "minItems": 3,
2895
2930
  "maxItems": 3
2896
2931
  },
@@ -2899,7 +2934,7 @@
2899
2934
  "items": {
2900
2935
  "type": "number"
2901
2936
  },
2902
- "description": "The highest corner, mm.",
2937
+ "description": "Highest corner, mm.",
2903
2938
  "minItems": 3,
2904
2939
  "maxItems": 3
2905
2940
  }
@@ -2984,7 +3019,7 @@
2984
3019
  {
2985
3020
  "name": "scan.fit_surface",
2986
3021
  "title": "Fit a sloped or curved patch",
2987
- "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.",
3022
+ "description": "A patch of the scan measured as a surface — a sloped side, a twisted ruled face, a dome, a saddle — from vertices or a box (normal keeps those facing a way). Returns the patch’s frame (origin, normal, basisU, basisV) and each model as a height over (u, v): plane (a + b·u + c·v), bilinear (+ d·u·v) and quadric (+ d·u² + e·u·v + f·v², with curvature { k1, k2, r1, r2, axis1, axis2, shape }), each with coefficients, rms and worst; model: best (the default) fits every one and names the simplest whose rms is within a tenth of the lowest. Trap: 7 points at least, at most limit (20000) spread evenly. Changes nothing.",
2988
3023
  "input": {
2989
3024
  "type": "object",
2990
3025
  "properties": {
@@ -3005,7 +3040,7 @@
3005
3040
  "items": {
3006
3041
  "type": "number"
3007
3042
  },
3008
- "description": "The lowest corner, mm.",
3043
+ "description": "Lowest corner, mm.",
3009
3044
  "minItems": 3,
3010
3045
  "maxItems": 3
3011
3046
  },
@@ -3014,7 +3049,7 @@
3014
3049
  "items": {
3015
3050
  "type": "number"
3016
3051
  },
3017
- "description": "The highest corner, mm.",
3052
+ "description": "Highest corner, mm.",
3018
3053
  "minItems": 3,
3019
3054
  "maxItems": 3
3020
3055
  }
@@ -3024,7 +3059,7 @@
3024
3059
  "max"
3025
3060
  ],
3026
3061
  "additionalProperties": false,
3027
- "description": "The patch as the scan inside a box, in place of vertices."
3062
+ "description": "The scan inside a box, in place of vertices."
3028
3063
  },
3029
3064
  "normal": {
3030
3065
  "type": "object",
@@ -3034,7 +3069,7 @@
3034
3069
  "items": {
3035
3070
  "type": "number"
3036
3071
  },
3037
- "description": "The direction, any length.",
3072
+ "description": "A direction, any length.",
3038
3073
  "minItems": 3,
3039
3074
  "maxItems": 3
3040
3075
  },
@@ -3077,7 +3112,7 @@
3077
3112
  {
3078
3113
  "name": "scan.heightmap",
3079
3114
  "title": "Map the scan’s heights",
3080
- "description": "Where the scan is first met looking along an axis, or square onto a plane, over a grid of cells: pocket floors, ledges, a step's height, a face's tilt, a pad's tiers, an icon on a key in one call. axis is the way looked: -z (the default) looks down from above and gives the top surface's z; +z looks up from below and gives the underside's; ±x, ±y likewise. Cells lie on the two other axes in order — x, y for z; y, z for x; x, z for y — as u and v. plane, in place of axis: a plane element (id or name; its normal turned to the side the scan is not, so it looks at the face it was fitted on), a coordinate plane \"XY\", \"YZ\", \"XZ\", or any other — a face of a model, say — as { origin, normal, u? }; the map then looks down the normal onto it, height is the distance from the plane along the normal, and u, v are the plane's own, laid as a sketch on that plane has them (section.render { plane } draws the same sheet) — u seeds its direction; flip turns the plane over. The answer's plane gives its frame in world: a cell's point is origin + u·U + v·V + height·normal — and, for an element or a plane given by its origin, center: where the element's centre (or that origin) lies in [u, v], for the frame's zero is the world origin's foot on the plane, not the element's centre. box: the part looked at, the scan's box by default; rays start at its face and stop at the far one. With plane, box is in the plane's frame: min and max are [u, v, height], and by default it takes in the whole scan; or box: { world: { min, max } } gives it in the world, [x, y, z] — the map takes the box round its corners in the plane's frame, so a box round a place on the part needs no working out. Where under a fifth of the cells meet the scan, scanLies says where the scan lies in the map's frame (min and max, [u, v, height] — or along the axis looked) beside the grid's span. of: height (the default); deviation — the scan's signed deviation where each ray lands (the map deviation.align or deviation.set_target measured, read off the triangle met), null where the map has no reading within its search distance; relief — the height less the surface round it (at each cell a plane fitted to its neighbours, weighed by a Gaussian smooth mm wide, three cells by default; make it about the width of what is looked for): icons, grooves, lettering and parting lines stand out of a face that curves or leans, positive proud and negative sunk. cell: mm (by default a round size that makes 40 cells on the longer side; widened to keep 1600 cells at most — and 160 and 25600 when the numbers are not returned). Returns along, across, cell, origin [u0, v0] (the grid's low corner), cols, rows and grid: rows of values (mm; heights to 0.01, deviation and relief to 0.001) from the low v up, null where there is none — grid[r][c] stands at u0 + (c + ½)·cell, v0 + (r + ½)·cell — with min, max, hit (cells met) and valued (cells with a value). levels: true returns, in place of the grid, the values gathered into levels — a pad's tiers, a pocket's floor, the face round them — the largest first (12 at most): each its height (the median), sigma, range, cells, area (mm²), sharePct of the cells counted, and box ([u, v] min and max). Of a height, the cells sloped more than slopeDeg (10° by default; 90 keeps every one) are left out first and counted as sloped — a fillet's ramp, a cone, a wall met at a glance — so two tiers a ramp joins stay two levels; a face that leans more is read by looking square onto it (plane). Two levels lie at least gap apart (mm; three times the cell-to-cell noise on the cells counted by default, 0.02 at least), and unassigned counts the cells counted that fall in none (walls, edges). Where the sloped cells are more than a fifth of those with a value, or one run of them borders a single level (a ramp off a tier that meets no other), ramps says so — \"ramps between tiers (sloped 34 %) — a section along them gives their profile\" — with the largest runs: cells, area, box and joins (the heights of the levels each borders). grid: true keeps the grid as well, false leaves it out and returns the picture. picture: true adds the map coloured by its values with coordinates in the margins and a scale (a deviation in the workspace's colour map over its range); needs the browser. Changes nothing.",
3115
+ "description": "Where the scan is first met looking along an axis (axis, -z by default: the top surface from above) or square onto a plane (plane: an element, \"XY\", \"YZ\", \"XZ\", or { origin, normal, u? }), over a grid of cells: pocket floors, ledges, a step's height, a face's tilt, a pad's tiers, an icon on a key in one call. of: height (the default), deviation (the map's reading where each ray lands) or relief (the height less the surface round it, for icons, grooves and lettering). Returns cell, origin [u0, v0], cols, rows, grid (rows of mm from the low v up, null where nothing; grid[r][c] stands at u0 + (c + ½)·cell, v0 + (r + ½)·cell), min, max, hit, valued; with plane also its frame (a cell's point is origin + u·U + v·V + height·normal). levels: true gives the values gathered into levels in place of the grid; picture: true adds the map coloured. Trap: with plane, box is [u, v, height] in the plane's frame (or { world }), and scanLies says where the scan lies when few cells meet it. Changes nothing.",
3081
3116
  "input": {
3082
3117
  "type": "object",
3083
3118
  "properties": {
@@ -3089,7 +3124,7 @@
3089
3124
  "items": {
3090
3125
  "type": "number"
3091
3126
  },
3092
- "description": "The lowest corner, mm — [u, v, height] with plane.",
3127
+ "description": "Lowest corner, mm ([u, v, height] with plane).",
3093
3128
  "minItems": 3,
3094
3129
  "maxItems": 3
3095
3130
  },
@@ -3098,7 +3133,7 @@
3098
3133
  "items": {
3099
3134
  "type": "number"
3100
3135
  },
3101
- "description": "The highest corner, mm — [u, v, height] with plane.",
3136
+ "description": "Highest corner, mm ([u, v, height] with plane).",
3102
3137
  "minItems": 3,
3103
3138
  "maxItems": 3
3104
3139
  },
@@ -3110,7 +3145,7 @@
3110
3145
  "items": {
3111
3146
  "type": "number"
3112
3147
  },
3113
- "description": "The lowest corner, [x, y, z] mm.",
3148
+ "description": "Lowest corner, [x, y, z] mm.",
3114
3149
  "minItems": 3,
3115
3150
  "maxItems": 3
3116
3151
  },
@@ -3119,7 +3154,7 @@
3119
3154
  "items": {
3120
3155
  "type": "number"
3121
3156
  },
3122
- "description": "The highest corner, [x, y, z] mm.",
3157
+ "description": "Highest corner, [x, y, z] mm.",
3123
3158
  "minItems": 3,
3124
3159
  "maxItems": 3
3125
3160
  }
@@ -3129,11 +3164,11 @@
3129
3164
  "max"
3130
3165
  ],
3131
3166
  "additionalProperties": false,
3132
- "description": "The box in the world, in place of min and max: with plane, the box round its corners in the plane’s frame."
3167
+ "description": "A box in the world, in place of min and max."
3133
3168
  }
3134
3169
  },
3135
3170
  "additionalProperties": false,
3136
- "description": "The part looked at; the scan’s box by default. In the plane’s frame with plane — or world: { min, max } in the world."
3171
+ "description": "The part looked at; the scan’s box by default. With plane: [u, v, height], or world: { min, max }."
3137
3172
  },
3138
3173
  "axis": {
3139
3174
  "type": "string",
@@ -3145,7 +3180,7 @@
3145
3180
  "+z",
3146
3181
  "-z"
3147
3182
  ],
3148
- "description": "The way looked: -z (the default) from above, +z from below, and so on."
3183
+ "description": "The way looked: -z (the default) from above, +z from below, ±x, ±y."
3149
3184
  },
3150
3185
  "plane": {
3151
3186
  "oneOf": [
@@ -3153,16 +3188,16 @@
3153
3188
  "oneOf": [
3154
3189
  {
3155
3190
  "type": "integer",
3156
- "description": "The element’s id.",
3191
+ "description": "Its id.",
3157
3192
  "minimum": 1
3158
3193
  },
3159
3194
  {
3160
3195
  "type": "string",
3161
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3196
+ "description": "Its name — \"Sphere 1\".",
3162
3197
  "minLength": 1
3163
3198
  }
3164
3199
  ],
3165
- "description": "A plane element, or a coordinate plane \"XY\", \"YZ\", \"XZ\"."
3200
+ "description": "A plane element, or \"XY\", \"YZ\", \"XZ\"."
3166
3201
  },
3167
3202
  {
3168
3203
  "type": "object",
@@ -3202,7 +3237,7 @@
3202
3237
  "additionalProperties": false
3203
3238
  }
3204
3239
  ],
3205
- "description": "Look square onto this plane instead of along an axis: heights along its normal, cells in its own u, v."
3240
+ "description": "Look square onto this plane instead of along an axis."
3206
3241
  },
3207
3242
  "flip": {
3208
3243
  "type": "boolean",
@@ -3215,11 +3250,11 @@
3215
3250
  "deviation",
3216
3251
  "relief"
3217
3252
  ],
3218
- "description": "What the cells hold: height (the default), deviation (the map’s, where the ray lands) or relief (height less the surface round it)."
3253
+ "description": "height (the default), deviation (the map’s, where the ray lands) or relief (height less the surface round it)."
3219
3254
  },
3220
3255
  "smooth": {
3221
3256
  "type": "number",
3222
- "description": "relief: the smoothing’s width (a Gaussian’s sigma), mm; three cells by default.",
3257
+ "description": "relief: the smoothing sigma, mm; three cells by default.",
3223
3258
  "exclusiveMinimum": 0
3224
3259
  },
3225
3260
  "cell": {
@@ -3229,11 +3264,11 @@
3229
3264
  },
3230
3265
  "grid": {
3231
3266
  "type": "boolean",
3232
- "description": "The grid of numbers: returned unless levels is asked for; false returns the picture alone."
3267
+ "description": "The grid of numbers (the default unless levels); false returns the picture alone."
3233
3268
  },
3234
3269
  "levels": {
3235
3270
  "type": "boolean",
3236
- "description": "Gather the values into levels with their areas, the largest first, in place of the grid."
3271
+ "description": "Gather the values into levels, largest first, in place of the grid."
3237
3272
  },
3238
3273
  "gap": {
3239
3274
  "type": "number",
@@ -3242,7 +3277,7 @@
3242
3277
  },
3243
3278
  "slopeDeg": {
3244
3279
  "type": "number",
3245
- "description": "levels of a height: cells steeper than this are left out, degrees; 10 by default, 90 keeps every one.",
3280
+ "description": "levels of a height: cells steeper are left out, degrees; 10 by default, 90 keeps every one.",
3246
3281
  "exclusiveMinimum": 0,
3247
3282
  "maximum": 90
3248
3283
  },
@@ -3260,7 +3295,7 @@
3260
3295
  {
3261
3296
  "name": "scan.nearest",
3262
3297
  "title": "Find a place on the scan",
3263
- "description": "Where a location lands on the scan: the vertex (a point snaps to the nearest one), its coordinates and outward normal, a triangle it is a corner of, and how far it is from the point asked about. Use it to check a point lies on the surface before fitting there.",
3298
+ "description": "Where a place lands on the scan: the vertex (a point snaps to the nearest), its coordinates and outward normal, a triangle it is a corner of, and how far it lies from the point asked about. Use it to check a point lies on the surface before fitting there.",
3264
3299
  "input": {
3265
3300
  "type": "object",
3266
3301
  "properties": {
@@ -3271,7 +3306,7 @@
3271
3306
  "properties": {
3272
3307
  "vertex": {
3273
3308
  "type": "integer",
3274
- "description": "A scan vertex, as a project file and session.state name it.",
3309
+ "description": "A scan vertex number.",
3275
3310
  "minimum": 0
3276
3311
  }
3277
3312
  },
@@ -3288,7 +3323,7 @@
3288
3323
  "items": {
3289
3324
  "type": "number"
3290
3325
  },
3291
- "description": "A point in millimetres, in the frame the part is measured in now; the scan vertex nearest it is taken.",
3326
+ "description": "[x, y, z] mm in the current frame; the nearest scan vertex is taken.",
3292
3327
  "minItems": 3,
3293
3328
  "maxItems": 3
3294
3329
  }
@@ -3306,7 +3341,7 @@
3306
3341
  "items": {
3307
3342
  "type": "number"
3308
3343
  },
3309
- "description": "A pixel of the viewport, x right and y down from its top left, as on a view.render picture.",
3344
+ "description": "A viewport pixel [x, y] (not available yet).",
3310
3345
  "minItems": 2,
3311
3346
  "maxItems": 2
3312
3347
  }
@@ -3321,7 +3356,7 @@
3321
3356
  "properties": {
3322
3357
  "candidate": {
3323
3358
  "type": "integer",
3324
- "description": "A feature from scan.candidates.",
3359
+ "description": "A feature from scan.candidates (not available yet).",
3325
3360
  "minimum": 0
3326
3361
  }
3327
3362
  },
@@ -3346,7 +3381,7 @@
3346
3381
  {
3347
3382
  "name": "scan.open",
3348
3383
  "title": "Open a scan",
3349
- "description": "Open a mesh as the scan to measure — STL, PLY or OBJ — in place of the one there is; everything measured on the old one goes with it, so it refuses while the session holds measurements unless discard is true — the refusal names what the session holds. A reference part opened from a file stays, its alignment and maps gone (referenceKept names it); one the app made from the session’s own work goes with that work (referenceDropped). Returns the scan: name, units, vertex and triangle counts, its bounding box (min and max corners), the box’s centre and its diagonal (size), in millimetres. Not undoable: a new scan starts a new history.",
3384
+ "description": "Open a mesh as the scan to measure — STL, PLY, OBJ or 3MF, or a STEP part cut into triangles — in place of the one there is; everything measured on the old one goes with it, so it refuses while the session holds measurements unless discard is true (the refusal names what is held). A reference part opened from a file stays, its alignment and maps gone (referenceKept); one made from the session’s own work goes (referenceDropped). Returns the scan: name, units, vertex and triangle counts, bounding box, centre and diagonal (size), mm. Not undoable: a new scan starts a new history.",
3350
3385
  "input": {
3351
3386
  "type": "object",
3352
3387
  "properties": {
@@ -3357,7 +3392,7 @@
3357
3392
  },
3358
3393
  "name": {
3359
3394
  "type": "string",
3360
- "description": "The file's name with its extension — \"ballbar.stl\". It is what the session calls the model.",
3395
+ "description": "The file's name with its extension — \"ballbar.stl\".",
3361
3396
  "minLength": 1
3362
3397
  },
3363
3398
  "units": {
@@ -3368,11 +3403,11 @@
3368
3403
  "m",
3369
3404
  "in"
3370
3405
  ],
3371
- "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."
3406
+ "description": "The file’s units: mm (the default), cm, m or in. Everything is measured in mm once read."
3372
3407
  },
3373
3408
  "discard": {
3374
3409
  "type": "boolean",
3375
- "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."
3410
+ "description": "true: replace the session though it holds measurements (lost unless saved as a project first). Refused otherwise when there is work to lose."
3376
3411
  }
3377
3412
  },
3378
3413
  "required": [
@@ -3388,7 +3423,7 @@
3388
3423
  {
3389
3424
  "name": "scan.outline",
3390
3425
  "title": "Read the scan’s outline",
3391
- "description": "The scan’s outline seen along an axis, or square onto a plane, read as a sketch would draw it: a flange’s plan, a bezel’s opening, a gasket’s shape. Rays over a grid of cells (half the tolerance, widened to keep 250000 at most) find where the scan is and where it is not; the line between is traced round and each loop read as the fewest lines and arcs that follow it within tolerance (mm, 0.2 by default): straight sides are fitted as lines and met at sharp corners; an arc between two sides is that corner’s round (rounds: at, the corner’s index in points, radius and center); any other arc is a side of its own (arcs: from, the index of the point it starts at, running to the next, radius and center) — a slot’s ends; and a loop that is round all the way is one circle. axis, plane, flip and box as scan.heightmap takes them, box: { world: { min, max } } too — the coordinates are u, v as it lays them (the two other axes in order, or the plane’s own; plane.center is the element’s centre in them). Returns loops, the largest first (loops: how many, 4 by default): each with hole (true for one inside another), area (mm²), box, points ([u, v] corners in order), rounds and arcs, or circle { center, radius, rms }, and worst — how far the traced outline strays from what is drawn, mm, with worstAt where, when it is past the tolerance. Changes nothing.",
3426
+ "description": "The scan’s outline seen along an axis, or square onto a plane, read as a sketch would draw it: a flange’s plan, a bezel’s opening, a gasket’s shape — each loop as the fewest lines and arcs that follow it within tolerance (mm, 0.2 by default), a round loop as one circle. axis, plane, flip and box as scan.heightmap takes them, u, v as it lays them. Returns loops, the largest first (4 by default): hole, area (mm²), box, points ([u, v] corners), rounds { at, radius, center }, arcs { from, radius, center } or circle { center, radius, rms }, and worst (mm the trace strays from what is drawn, worstAt when past the tolerance). Changes nothing.",
3392
3427
  "input": {
3393
3428
  "type": "object",
3394
3429
  "properties": {
@@ -3410,16 +3445,16 @@
3410
3445
  "oneOf": [
3411
3446
  {
3412
3447
  "type": "integer",
3413
- "description": "The element’s id.",
3448
+ "description": "Its id.",
3414
3449
  "minimum": 1
3415
3450
  },
3416
3451
  {
3417
3452
  "type": "string",
3418
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3453
+ "description": "Its name — \"Sphere 1\".",
3419
3454
  "minLength": 1
3420
3455
  }
3421
3456
  ],
3422
- "description": "A plane element, or a coordinate plane \"XY\", \"YZ\", \"XZ\"."
3457
+ "description": "A plane element, or \"XY\", \"YZ\", \"XZ\"."
3423
3458
  },
3424
3459
  {
3425
3460
  "type": "object",
@@ -3473,7 +3508,7 @@
3473
3508
  "items": {
3474
3509
  "type": "number"
3475
3510
  },
3476
- "description": "The lowest corner, mm — [u, v, height] with plane.",
3511
+ "description": "Lowest corner, mm ([u, v, height] with plane).",
3477
3512
  "minItems": 3,
3478
3513
  "maxItems": 3
3479
3514
  },
@@ -3482,7 +3517,7 @@
3482
3517
  "items": {
3483
3518
  "type": "number"
3484
3519
  },
3485
- "description": "The highest corner, mm — [u, v, height] with plane.",
3520
+ "description": "Highest corner, mm ([u, v, height] with plane).",
3486
3521
  "minItems": 3,
3487
3522
  "maxItems": 3
3488
3523
  },
@@ -3494,7 +3529,7 @@
3494
3529
  "items": {
3495
3530
  "type": "number"
3496
3531
  },
3497
- "description": "The lowest corner, [x, y, z] mm.",
3532
+ "description": "Lowest corner, [x, y, z] mm.",
3498
3533
  "minItems": 3,
3499
3534
  "maxItems": 3
3500
3535
  },
@@ -3503,7 +3538,7 @@
3503
3538
  "items": {
3504
3539
  "type": "number"
3505
3540
  },
3506
- "description": "The highest corner, [x, y, z] mm.",
3541
+ "description": "Highest corner, [x, y, z] mm.",
3507
3542
  "minItems": 3,
3508
3543
  "maxItems": 3
3509
3544
  }
@@ -3513,11 +3548,11 @@
3513
3548
  "max"
3514
3549
  ],
3515
3550
  "additionalProperties": false,
3516
- "description": "The box in the world, in place of min and max: with plane, the box round its corners in the plane’s frame."
3551
+ "description": "A box in the world, in place of min and max."
3517
3552
  }
3518
3553
  },
3519
3554
  "additionalProperties": false,
3520
- "description": "Only the scan inside it; the whole scan by default. In the plane’s frame with plane — or world: { min, max } in the world."
3555
+ "description": "Only the scan inside it; the whole scan by default. With plane: [u, v, height], or world: { min, max }."
3521
3556
  },
3522
3557
  "tolerance": {
3523
3558
  "type": "number",
@@ -3540,7 +3575,7 @@
3540
3575
  {
3541
3576
  "name": "scan.pattern",
3542
3577
  "title": "Count the repeats round an axis",
3543
- "description": "Rotational repeats about an axis — a fan's blades, a flange's holes and pads, a wheel's spokes, a gear's teeth — counted from the scan. The scan is cut square to the axis at each height in at, and each cut (only what lies between radius.min and radius.max) is turned against itself: count, the number of copies whose outlines land on each other going round (up to maxCount, 60 by default); pitchDeg, 360/count; phaseDeg, where the first copy's middle lies (under one pitch), and betweenDeg midway to the next — angles about the axis as section.cut { across: { axis, angleDeg } } takes them: 0° the coordinate axis next round (X about Z), turning by the right hand. score, 0 to 1, is how well the copies' outlines land on each other; under 0.5 nothing is taken to repeat and count is 1 (tried gives the best count and its score). Each copy in instances: angleDeg and radius of its outline's middle, offDeg from where an even spacing puts it, rms and worst — how far its outline lies from the other copies' turned onto it (the median over them), mm — and share, its outline's length against the median copy's (well under 1: the scan misses part of it, or the copy is not there). rms, worst and worstInstance over all the copies. Round outlines about the axis — a bore, a hub, a rim — are not copies: they come back as rings, each its radius, off (how far its centre lies off the axis, mm), towardDeg (which way) and rms. axis: a cylinder, cone, line or circle element, by id or name, a coordinate axis \"X\", \"Y\" or \"Z\" through the origin, or { origin, dir }. at: heights along the axis, mm, counted from the world origin's foot on it (the coordinate itself on a coordinate axis) — or points [x, y, z] in the world, each the height of its foot on the axis; by default 6 spread over the scan, 12 at most. Features lie at different heights and radii: cut through each, and keep radius to the ring one lies in where two share a height — in one cut the feature with the most outline sets the count, and the other reads as what its copies miss (worst). instances: false leaves the copies out. Changes nothing.",
3578
+ "description": "Rotational repeats about an axis — a fan's blades, a flange's holes, a wheel's spokes, a gear's teeth — counted from the scan: it is cut square to the axis at each height in at, and each cut (between radius.min and radius.max) is turned against itself. Needs axis: a cylinder, cone, line or circle element, \"X\", \"Y\", \"Z\", or { origin, dir }. Returns per height count, pitchDeg, phaseDeg, betweenDeg (angles as section.cut { across: { axis, angleDeg } } takes them), score (0 to 1; under 0.5 count is 1 and tried says the best), rms, worst, instances (each angleDeg, radius, offDeg, rms, worst, share) and rings (round outlines about the axis: radius, off, towardDeg, rms). Trap: features at different heights and radii need a cut through each, radius kept to one ring. Changes nothing.",
3544
3579
  "input": {
3545
3580
  "type": "object",
3546
3581
  "properties": {
@@ -3550,12 +3585,12 @@
3550
3585
  "oneOf": [
3551
3586
  {
3552
3587
  "type": "integer",
3553
- "description": "The element’s id.",
3588
+ "description": "Its id.",
3554
3589
  "minimum": 1
3555
3590
  },
3556
3591
  {
3557
3592
  "type": "string",
3558
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3593
+ "description": "Its name — \"Sphere 1\".",
3559
3594
  "minLength": 1
3560
3595
  }
3561
3596
  ],
@@ -3605,7 +3640,7 @@
3605
3640
  "items": {
3606
3641
  "type": "number"
3607
3642
  },
3608
- "description": "A point in the world, mm: the height of its foot on the axis.",
3643
+ "description": "A world point, mm: the height of its foot on the axis.",
3609
3644
  "minItems": 3,
3610
3645
  "maxItems": 3
3611
3646
  }
@@ -3640,7 +3675,7 @@
3640
3675
  },
3641
3676
  "instances": {
3642
3677
  "type": "boolean",
3643
- "description": "List each copy (the default true)."
3678
+ "description": "List each copy; true by default."
3644
3679
  }
3645
3680
  },
3646
3681
  "required": [
@@ -3655,7 +3690,7 @@
3655
3690
  {
3656
3691
  "name": "scan.qa",
3657
3692
  "title": "Check the scan before modelling",
3658
- "description": "One call before modelling, to know what the scan will and will not give: rims — the open edges of its holes (count, total length, the longest few with their number rim, length, centre and size, mm; circles: other rims a circle fits — a hole the scan did not see into); a rim that lies on a circle has circle { center, axis, radius, rms } (rms its scatter off the circle, mm), and element.fit { kind: \"circle\", rim } makes it an element; noise — the median scatter of small plane fits round a sample of vertices (mm; near 0 is a CAD tessellation) and its 90th percentile; thickness through the part along axis (x, y, z or a direction; by default the alignment’s z when the part is aligned, else the way most of the surface faces — a plate’s faces) over a grid — p5, p50, p95 (mm), and on the cells near the median (the main faces) the thickness’s linear trend as tiltDeg, how far apart faces that should be parallel are, with the way it thickens and its run from end to end; faces gives each face’s own tilt off square to the axis (topDeg, bottomDeg), so a lean of the whole part shows apart from faces out of parallel. notes: what looks wrong, plainly — a scanned skin with no rims at all among it, since a wrap bridges the holes it did not see through. Changes nothing.",
3693
+ "description": "One call before modelling, to know what the scan will and will not give. Returns rims (the open edges of its holes: count, total length, the longest few with rim number, centre, size and circle where one fits — element.fit { kind: \"circle\", rim } makes it an element), noise (the median scatter of small plane fits, mm; near 0 is a CAD tessellation), thickness through the part along axis (p5, p50, p95, the main faces’ tiltDeg and faces { topDeg, bottomDeg }) and notes, what looks wrong, plainly. Trap: a scanned skin with no rims, or only pinholes, is a wrap bridging the holes it did not see through. Changes nothing.",
3659
3694
  "input": {
3660
3695
  "type": "object",
3661
3696
  "properties": {
@@ -3680,7 +3715,7 @@
3680
3715
  "maxItems": 3
3681
3716
  }
3682
3717
  ],
3683
- "description": "The thickness axis; see above."
3718
+ "description": "The thickness axis."
3684
3719
  }
3685
3720
  },
3686
3721
  "additionalProperties": false
@@ -3692,7 +3727,7 @@
3692
3727
  {
3693
3728
  "name": "scan.query",
3694
3729
  "title": "Read the scan’s points",
3695
- "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. fields: count gives the numbers alone, without the vertices, points and normals; ids adds the vertices; all everything — the default, but with mark, where count is. mark: true leaves every vertex that matched marked — all of them, not the limit’s thinned list; marked.points counts them — for element.fit_marked { marked: true } and whatever else takes the marked points, so the list need not come back at all. Changes nothing on the part.",
3730
+ "description": "The scan’s vertices inside a box, or within a radius of a point (near), with their outward normals — the points on a face, to measure a dimension or a draft off; normal keeps only those facing a direction. Returns matched, the vertex numbers, points and normals (mm, current frame), the box round them, centroid and mean normal; fields: count, ids or all (the default) says how much. Trap: at most limit come back (1000 by default, 20000 at most), every k-th spread evenly, step saying k — mark: true marks every matching vertex, not the thinned list, for element.fit_marked { marked: true }. Changes nothing on the part.",
3696
3731
  "input": {
3697
3732
  "type": "object",
3698
3733
  "properties": {
@@ -3704,7 +3739,7 @@
3704
3739
  "items": {
3705
3740
  "type": "number"
3706
3741
  },
3707
- "description": "The lowest corner, mm.",
3742
+ "description": "Lowest corner, mm.",
3708
3743
  "minItems": 3,
3709
3744
  "maxItems": 3
3710
3745
  },
@@ -3713,7 +3748,7 @@
3713
3748
  "items": {
3714
3749
  "type": "number"
3715
3750
  },
3716
- "description": "The highest corner, mm.",
3751
+ "description": "Highest corner, mm.",
3717
3752
  "minItems": 3,
3718
3753
  "maxItems": 3
3719
3754
  }
@@ -3723,7 +3758,7 @@
3723
3758
  "max"
3724
3759
  ],
3725
3760
  "additionalProperties": false,
3726
- "description": "A box in the frame the part is measured in now."
3761
+ "description": "A box in the current frame."
3727
3762
  },
3728
3763
  "near": {
3729
3764
  "type": "object",
@@ -3739,7 +3774,7 @@
3739
3774
  },
3740
3775
  "radius": {
3741
3776
  "type": "number",
3742
- "description": "How far from it, mm.",
3777
+ "description": "mm.",
3743
3778
  "exclusiveMinimum": 0
3744
3779
  }
3745
3780
  },
@@ -3748,7 +3783,7 @@
3748
3783
  "radius"
3749
3784
  ],
3750
3785
  "additionalProperties": false,
3751
- "description": "A ball about a point — in place of box."
3786
+ "description": "A ball about a point, in place of box."
3752
3787
  },
3753
3788
  "normal": {
3754
3789
  "type": "object",
@@ -3758,13 +3793,13 @@
3758
3793
  "items": {
3759
3794
  "type": "number"
3760
3795
  },
3761
- "description": "The direction, any length.",
3796
+ "description": "A direction, any length.",
3762
3797
  "minItems": 3,
3763
3798
  "maxItems": 3
3764
3799
  },
3765
3800
  "withinDeg": {
3766
3801
  "type": "number",
3767
- "description": "How far from it a normal may lean, degrees; 30 by default.",
3802
+ "description": "Degrees; 30 by default.",
3768
3803
  "exclusiveMinimum": 0,
3769
3804
  "maximum": 180
3770
3805
  }
@@ -3773,7 +3808,7 @@
3773
3808
  "dir"
3774
3809
  ],
3775
3810
  "additionalProperties": false,
3776
- "description": "Keep only the vertices whose outward normal faces this way."
3811
+ "description": "Only the vertices whose outward normal faces this way."
3777
3812
  },
3778
3813
  "limit": {
3779
3814
  "type": "integer",
@@ -3783,7 +3818,7 @@
3783
3818
  },
3784
3819
  "mark": {
3785
3820
  "type": "boolean",
3786
- "description": "Leave every vertex that matched marked — not only those kept — for element.fit_marked { marked: true }."
3821
+ "description": "Leave every matching vertex marked, for element.fit_marked { marked: true }."
3787
3822
  },
3788
3823
  "fields": {
3789
3824
  "type": "string",
@@ -3792,7 +3827,7 @@
3792
3827
  "ids",
3793
3828
  "all"
3794
3829
  ],
3795
- "description": "What comes back: count (the numbers alone; the default with mark), ids (with the vertices), all (with points and normals too; the default otherwise)."
3830
+ "description": "count: the numbers alone (the default with mark); ids: with the vertices; all: with points and normals (the default)."
3796
3831
  }
3797
3832
  },
3798
3833
  "additionalProperties": false
@@ -3804,7 +3839,7 @@
3804
3839
  {
3805
3840
  "name": "scan.segment",
3806
3841
  "title": "Find the scan’s flat regions",
3807
- "description": "The scan’s planar regions, found all at once: grown from the flattest places outward, a vertex joining while its normal lies within maxDeg of the region’s plane (15° by default) and it lies inside the region’s noise band; each vertex goes to one region; a region rougher than maxRms off its plane (mm, 0.05 by default) or smaller than minArea (mm², by default a square 2 % of the scan’s diagonal on a side) is given back. box: only the scan inside it. The largest first, at most limit (20); each with id (1 is the largest), normal (out of the part), point (its centroid, on the plane), sigma (RMS off the plane, mm), area (mm²), box, vertices (a count) and neighbours: the regions it meets across an edge or its rounding, each { id, deg } with the angle between their normals. symmetric: a plane element, or \"XY\", \"YZ\", \"XZ\" — each region gets mirror { id, deg, mm }: its twin across that plane (\"self\" when it straddles it), how far their planes differ in angle once mirrored and in place. mark: a region’s id, or several (their points together), leaves its points marked — element.fit_marked { marked: true } fits to them; with the same options it reuses the last run, and answers marked { points, from } and region, the marked region (a list of them for several), without the list of regions unless list: true. Returns found (regions in all), considered and claimed (vertices looked at and held by regions). Changes nothing.",
3842
+ "description": "The scan’s planar regions, found all at once: grown from the flattest places outward within maxDeg (15°) and maxRms (0.05 mm), those smaller than minArea given back. Returns found, considered, claimed, noise and the regions, largest first, at most limit (20): id, normal, point, sigma, area (mm²), box, vertices, neighbours { id, deg, smooth } and, with symmetric, mirror (its twin across that plane). Trap: a round surface comes out as strips that look like facets — such a region says curved { sagitta } and run, and curvedRuns joins them into surfaces with a note saying what to model each as; read the runs before taking regions for faces. mark: a region’s id, or several, leaves their points marked for element.fit_marked { marked: true }. Changes nothing.",
3808
3843
  "input": {
3809
3844
  "type": "object",
3810
3845
  "properties": {
@@ -3823,7 +3858,7 @@
3823
3858
  "items": {
3824
3859
  "type": "number"
3825
3860
  },
3826
- "description": "The lowest corner, mm.",
3861
+ "description": "Lowest corner, mm.",
3827
3862
  "minItems": 3,
3828
3863
  "maxItems": 3
3829
3864
  },
@@ -3832,7 +3867,7 @@
3832
3867
  "items": {
3833
3868
  "type": "number"
3834
3869
  },
3835
- "description": "The highest corner, mm.",
3870
+ "description": "Highest corner, mm.",
3836
3871
  "minItems": 3,
3837
3872
  "maxItems": 3
3838
3873
  }
@@ -3846,17 +3881,17 @@
3846
3881
  },
3847
3882
  "minArea": {
3848
3883
  "type": "number",
3849
- "description": "mm².",
3884
+ "description": "mm²; by default a square 2 % of the scan’s diagonal on a side.",
3850
3885
  "minimum": 0
3851
3886
  },
3852
3887
  "maxRms": {
3853
3888
  "type": "number",
3854
- "description": "mm.",
3889
+ "description": "mm; 0.05 by default.",
3855
3890
  "exclusiveMinimum": 0
3856
3891
  },
3857
3892
  "maxDeg": {
3858
3893
  "type": "number",
3859
- "description": "Degrees.",
3894
+ "description": "Degrees; 15 by default.",
3860
3895
  "exclusiveMinimum": 0,
3861
3896
  "maximum": 60
3862
3897
  },
@@ -3870,12 +3905,12 @@
3870
3905
  "oneOf": [
3871
3906
  {
3872
3907
  "type": "integer",
3873
- "description": "The element’s id.",
3908
+ "description": "Its id.",
3874
3909
  "minimum": 1
3875
3910
  },
3876
3911
  {
3877
3912
  "type": "string",
3878
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3913
+ "description": "Its name — \"Sphere 1\".",
3879
3914
  "minLength": 1
3880
3915
  }
3881
3916
  ],
@@ -3894,15 +3929,15 @@
3894
3929
  "type": "integer",
3895
3930
  "minimum": 1
3896
3931
  },
3897
- "description": "Several regions’ ids: their points together.",
3932
+ "description": "Several regions’ ids, their points together.",
3898
3933
  "minItems": 1
3899
3934
  }
3900
3935
  ],
3901
- "description": "Leave this region’s points marked, by its id — or several regions’."
3936
+ "description": "Leave this region’s points marked, or several regions’."
3902
3937
  },
3903
3938
  "list": {
3904
3939
  "type": "boolean",
3905
- "description": "With mark: the list of regions too, as without it."
3940
+ "description": "With mark: the list of regions too."
3906
3941
  }
3907
3942
  },
3908
3943
  "additionalProperties": false
@@ -3914,7 +3949,7 @@
3914
3949
  {
3915
3950
  "name": "section.cut",
3916
3951
  "title": "Cut a section",
3917
- "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 \"XZ\" (also \"ZX\"), which is laid through the part’s centre. Or { axis, angleDeg }: a plane through an axis — a cylinder’s, cone’s, line’s or circle’s, by id or name, or the coordinate axis \"X\", \"Y\" or \"Z\" through the origin — turned angleDeg about it: a half section of a turned part, u the distance out from the axis and v up it (towards the + end of the coordinate axis it lies nearest, whichever way the element points), normal u × v, at every angle. 0° is the coordinate axis next round (X about Z, Y about X, Z about Y) and the angle turns by the right hand about the axis — about Z, from +X towards +Y. offset slides the plane along its normal, mm — from the element, or for a coordinate plane the coordinate itself; through an axis, 0 by default. Returns the section: its plane and how many chains the cut has. One undo step.",
3952
+ "description": "Cut the scan with a plane and keep the cut as a section, put on the 2D sheet. across: an element with a direction (plane, cylinder, cone, line, circle) by id or name; \"XY\", \"YZ\" or \"XZ\" through the part’s centre; or { axis, angleDeg }, a plane through an axis turned angleDeg about it — a half section of a turned part. offset slides the plane along its normal, mm (a coordinate plane: the coordinate itself). kind \"shadow\" keeps the scan’s shadow instead: the whole part projected onto the plane, its outer boundary as loops read as lines and arcs (tolerance, play, smoothDeg), stood up as a block for export.step (extrude). Trap: a shadow takes no offset. Returns the section: its plane and chain count — a shadow also its loops, area and band. One undo step.",
3918
3953
  "input": {
3919
3954
  "type": "object",
3920
3955
  "properties": {
@@ -3927,7 +3962,7 @@
3927
3962
  },
3928
3963
  {
3929
3964
  "type": "string",
3930
- "description": "An element’s name, or a coordinate plane \"XY\", \"YZ\", \"XZ\".",
3965
+ "description": "An element’s name, or \"XY\", \"YZ\", \"XZ\".",
3931
3966
  "minLength": 1
3932
3967
  },
3933
3968
  {
@@ -3937,12 +3972,12 @@
3937
3972
  "oneOf": [
3938
3973
  {
3939
3974
  "type": "integer",
3940
- "description": "The element’s id.",
3975
+ "description": "Its id.",
3941
3976
  "minimum": 1
3942
3977
  },
3943
3978
  {
3944
3979
  "type": "string",
3945
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
3980
+ "description": "Its name — \"Sphere 1\".",
3946
3981
  "minLength": 1
3947
3982
  }
3948
3983
  ],
@@ -3961,16 +3996,43 @@
3961
3996
  "description": "A plane through an axis."
3962
3997
  }
3963
3998
  ],
3964
- "description": "An element with a direction, a coordinate plane, or { axis, angleDeg } through an axis."
3999
+ "description": "An element with a direction, a coordinate plane, or { axis, angleDeg }."
3965
4000
  },
3966
4001
  "offset": {
3967
4002
  "type": "number",
3968
- "description": "Where along the normal the plane lies, mm."
4003
+ "description": "Along the normal, mm. A cut’s only."
3969
4004
  },
3970
4005
  "name": {
3971
4006
  "type": "string",
3972
- "description": "A name for it; otherwise it is numbered — \"Section 2\".",
4007
+ "description": "A name; otherwise numbered — \"Section 2\".",
3973
4008
  "minLength": 1
4009
+ },
4010
+ "kind": {
4011
+ "type": "string",
4012
+ "enum": [
4013
+ "cut",
4014
+ "shadow"
4015
+ ],
4016
+ "description": "cut (the default), or shadow: the whole scan projected onto the plane."
4017
+ },
4018
+ "play": {
4019
+ "type": "number",
4020
+ "description": "Shadow: clearance outside the part, mm; 1 by default, negative a press fit."
4021
+ },
4022
+ "tolerance": {
4023
+ "type": "number",
4024
+ "description": "Shadow: lines and arcs read to this, mm; 0.1 by default.",
4025
+ "exclusiveMinimum": 0
4026
+ },
4027
+ "smoothDeg": {
4028
+ "type": "number",
4029
+ "description": "Shadow: corners turning less than this are rounded, degrees; 30 by default, 0 keeps all sharp.",
4030
+ "minimum": 0,
4031
+ "maximum": 180
4032
+ },
4033
+ "extrude": {
4034
+ "type": "boolean",
4035
+ "description": "Shadow: stood up as a block through the part, for export.step; true by default."
3974
4036
  }
3975
4037
  },
3976
4038
  "required": [
@@ -3985,7 +4047,7 @@
3985
4047
  {
3986
4048
  "name": "section.get",
3987
4049
  "title": "Read a section’s polylines",
3988
- "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. skin: \"outer\" or \"inner\" reads one skin of a thin wall alone — outer, the points whose way out of the material (the scan’s triangles say which way that is) faces away from the middle of the cut and looks out past the rest of it; inner, the points facing the middle whose way back through the material comes out on the outer skin within about the wall’s thickness; ribs and bosses are neither, and a solid has no inner skin — and facing { dir: [u, v], withinDeg } the points whose way out lies within that angle of a direction on the sheet; with both, a point must pass both. Each chain then comes back as its runs on that side, each with run (its place along the chain) and four points at least. Changes nothing.",
4050
+ "description": "A section’s cut as polylines: each chain’s points in order — [u, v] mm on the sheet, what flat.fit and a sketch on the section take, or with space \"world\" or \"both\" [x, y, z] in the current frame — with the plane (origin, normal, basisU, basisV) and per chain closed, length, points, bounds. Trap: at most limit points over all chains (4000 by default, 50000 at most); past it every k-th point is kept and step says k. chains picks chains by index; skin \"outer\" or \"inner\" reads one skin of a thin wall alone, facing the points whose way out lies within withinDeg of dir, each chain then coming back as runs. Changes nothing.",
3989
4051
  "input": {
3990
4052
  "type": "object",
3991
4053
  "properties": {
@@ -3998,7 +4060,7 @@
3998
4060
  },
3999
4061
  {
4000
4062
  "type": "string",
4001
- "description": "The section’s name, as the list shows it — \"Section 1\".",
4063
+ "description": "Its name — \"Section 1\".",
4002
4064
  "minLength": 1
4003
4065
  }
4004
4066
  ],
@@ -4011,7 +4073,7 @@
4011
4073
  "description": "A chain’s index.",
4012
4074
  "minimum": 0
4013
4075
  },
4014
- "description": "Which chains; every one when left out.",
4076
+ "description": "Which chains; every one by default.",
4015
4077
  "minItems": 1
4016
4078
  },
4017
4079
  "space": {
@@ -4021,11 +4083,11 @@
4021
4083
  "world",
4022
4084
  "both"
4023
4085
  ],
4024
- "description": "sheet (the default): [u, v] on the section’s plane; world: [x, y, z]; both."
4086
+ "description": "sheet (the default): [u, v]; world: [x, y, z]; both."
4025
4087
  },
4026
4088
  "limit": {
4027
4089
  "type": "integer",
4028
- "description": "How many points at most, over every chain asked for; 4000 by default, 50000 at most.",
4090
+ "description": "Points at most over every chain; 4000 by default, 50000 at most.",
4029
4091
  "minimum": 2,
4030
4092
  "maximum": 50000
4031
4093
  },
@@ -4075,7 +4137,7 @@
4075
4137
  {
4076
4138
  "name": "section.render",
4077
4139
  "title": "Picture a section",
4078
- "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 — world coordinates where the sheet’s u or v runs along a world axis, sheet mm otherwise — the world direction across and up named in the margins (axes in the answer: per sheet axis the world axis it runs nearest, offDeg and, along it, at0, the world coordinate at the sheet’s 0), 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 with their ids where the sketch lies in that plane, whatever it was drawn on. 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 cuts the scan for the picture alone — no section is made, and the sheet is a sketch’s on that plane: zero at the world origin’s foot, u along the coordinate axis next round from the normal (YZ: u = Y, v = Z; XZ: u = Z, v = X; XY: u = X, v = Y), so on a coordinate plane [u, v] are world coordinates (the answer’s sheet gives them). plane is { origin, normal }, a coordinate plane \"XY\", \"YZ\" or \"XZ\" (also \"ZX\"; through the part’s centre, as section.cut lays it — the answer’s sheet gives its origin), an element by id or name (the plane through its centre square to its direction — a plane element’s normal, a cylinder’s axis — on the sheet a sketch on it takes, not the fitter’s own axes), or { sketch } by id or name: the scan cut on that sketch’s plane, in its own frame, so [u, v] are its pieces’. A section’s own sheet counts from the part’s centre instead (across an element or through its axis, from the element’s centre). up: \"x\", \"y\" or \"z\" turns the picture’s sheet in its plane so that world axis runs up it — a side view with Z up: v is that axis laid into the plane, u the direction square to it running + to the right, the plane seen from whichever side gives that (the XZ plane with up \"z\": u = X, v = Z, seen from −Y, as a front view; a section’s sheet keeps its zero) — and everything the picture says in [u, v] (frame, map, overBox, axes) is then on that turned sheet, which the answer gives as sheet. Without up the sheet lies as above. The answer’s sheet gives the sheet in the world every time — origin, normal, basisU and basisV: a sheet point [u, v] is origin + u·basisU + v·basisV. offsets: 2 to 9 cuts in one picture — the section’s or plane’s slid along its normal by each, mm — side by side, each tile labelled with its offset, all on one frame and scale (the square round every cut unless frame is given); the answer gives per tile its offset, origin and gap, and map.tile and map.cols (map holds for each tile from its own corner). frame { at, size } looks at a square of the sheet — at as [u, v] on the sheet, or as [x, y, z] in the world, laid square onto the sheet, so a place on the part needs no working out of where the sheet counts from (framed gives where it came out on the sheet, and offPlane how far off the plane the point lay, mm) — or frame { world: { min, max } } at the square round a box of the world laid onto the sheet, a tenth wider; 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.",
4140
+ "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 sheet ([u, v] mm, +u right, +v up), a mm grid with values in the margins, a scale bar, and the workspaces’ layers over it (a model’s cut as outlines, a sketch’s pieces). Scan points within ten tolerances of an outline are read against it: on it (grey) or off it (red). Needs section, or plane to cut the scan for the picture alone ({ origin, normal }, \"XY\"/\"YZ\"/\"XZ\", an element, or { sketch }). Returns gap { points, read, over, outside, inside, max, rms, overBox }, layers, axes, sheet (origin, normal, basisU, basisV) and map (pixel (c, r) is [left + c·unitsPerPx, top − r·unitsPerPx]). Trap: a plane’s sheet has its zero at the world origin’s foot, a section’s at the part’s centre — read sheet. 800 px by default, up to 2048. Needs the browser. Changes nothing.",
4079
4141
  "input": {
4080
4142
  "type": "object",
4081
4143
  "properties": {
@@ -4088,7 +4150,7 @@
4088
4150
  },
4089
4151
  {
4090
4152
  "type": "string",
4091
- "description": "The section’s name — \"Section 1\".",
4153
+ "description": "Its name — \"Section 1\".",
4092
4154
  "minLength": 1
4093
4155
  }
4094
4156
  ],
@@ -4131,7 +4193,7 @@
4131
4193
  },
4132
4194
  {
4133
4195
  "type": "string",
4134
- "description": "A coordinate plane \"XY\", \"YZ\", \"XZ\", or an element’s name.",
4196
+ "description": "\"XY\", \"YZ\", \"XZ\", or an element’s name.",
4135
4197
  "minLength": 1
4136
4198
  },
4137
4199
  {
@@ -4157,14 +4219,14 @@
4157
4219
  "additionalProperties": false
4158
4220
  }
4159
4221
  ],
4160
- "description": "A plane to cut the scan by for the picture alone, in place of a section: { origin, normal }, a coordinate plane, an element, or { sketch }."
4222
+ "description": "A plane to cut the scan by for the picture alone, in place of a section."
4161
4223
  },
4162
4224
  "offsets": {
4163
4225
  "type": "array",
4164
4226
  "items": {
4165
4227
  "type": "number"
4166
4228
  },
4167
- "description": "Several parallel cuts in one picture: mm along the normal from the section or plane.",
4229
+ "description": "Several parallel cuts in one picture: mm along the normal — on a coordinate plane by name, from the world’s zero, so \"XY\" with [0, 5] cuts at Z 0 and Z 5.",
4168
4230
  "minItems": 2,
4169
4231
  "maxItems": 9
4170
4232
  },
@@ -4185,7 +4247,7 @@
4185
4247
  "items": {
4186
4248
  "type": "number"
4187
4249
  },
4188
- "description": "The place in the middle: [u, v] mm on the sheet, or [x, y, z] mm in the world, laid square onto the sheet.",
4250
+ "description": "The middle: [u, v] mm on the sheet, or [x, y, z] mm in the world.",
4189
4251
  "minItems": 2,
4190
4252
  "maxItems": 3
4191
4253
  },
@@ -4202,7 +4264,7 @@
4202
4264
  "items": {
4203
4265
  "type": "number"
4204
4266
  },
4205
- "description": "The lowest corner, [x, y, z] mm.",
4267
+ "description": "Lowest corner, [x, y, z] mm.",
4206
4268
  "minItems": 3,
4207
4269
  "maxItems": 3
4208
4270
  },
@@ -4211,7 +4273,7 @@
4211
4273
  "items": {
4212
4274
  "type": "number"
4213
4275
  },
4214
- "description": "The highest corner, [x, y, z] mm.",
4276
+ "description": "Highest corner, [x, y, z] mm.",
4215
4277
  "minItems": 3,
4216
4278
  "maxItems": 3
4217
4279
  }
@@ -4221,7 +4283,7 @@
4221
4283
  "max"
4222
4284
  ],
4223
4285
  "additionalProperties": false,
4224
- "description": "A box in the world, in place of at and size: the square round it on the sheet."
4286
+ "description": "A world box, in place of at and size."
4225
4287
  }
4226
4288
  },
4227
4289
  "additionalProperties": false,
@@ -4229,7 +4291,7 @@
4229
4291
  },
4230
4292
  "tolerance": {
4231
4293
  "type": "number",
4232
- "description": "± mm a scan point may lie off the outlines and still be on them.",
4294
+ "description": "± mm a scan point may lie off an outline and still be on it; the Deviation workspace’s by default.",
4233
4295
  "exclusiveMinimum": 0
4234
4296
  },
4235
4297
  "layers": {
@@ -4238,7 +4300,7 @@
4238
4300
  "type": "string",
4239
4301
  "minLength": 1
4240
4302
  },
4241
- "description": "The layers to draw, by key; every one by default."
4303
+ "description": "The layers to draw, by key; every one by default, [] for the scan alone."
4242
4304
  },
4243
4305
  "width": {
4244
4306
  "type": "integer",
@@ -4293,7 +4355,7 @@
4293
4355
  "properties": {
4294
4356
  "discard": {
4295
4357
  "type": "boolean",
4296
- "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."
4358
+ "description": "true: replace the session though it holds measurements (lost unless saved as a project first). Refused otherwise when there is work to lose."
4297
4359
  }
4298
4360
  },
4299
4361
  "additionalProperties": false
@@ -4305,7 +4367,7 @@
4305
4367
  {
4306
4368
  "name": "session.state",
4307
4369
  "title": "Read the session",
4308
- "description": "The whole session as JSON: the app and its plugins, the project (its name; unsaved — whether it has changes not saved since it was last saved or opened, as the top bar’s \"Unsaved changes\" says, null with no page; holds — the work a new scan or project would replace, counted by what it is), 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.",
4370
+ "description": "The whole session as JSON: the app and its plugins, the project (name, unsaved, holds), the workspace on screen, busy, the scan (file, units, counts, bounding box, centre, size, alignment), every element with its fit, every dimension with value, limit and verdict, the sections, what is open in the panels, the deviation, wall thickness and 2D state with their statistics, the guided hint, the undo history and ui.units. Trap: the screen may show inches; every answer here is in millimetres, angles in degrees. Read it before acting and after.",
4309
4371
  "input": {
4310
4372
  "type": "object",
4311
4373
  "properties": {},
@@ -4328,7 +4390,7 @@
4328
4390
  "ray",
4329
4391
  "sphere"
4330
4392
  ],
4331
- "description": "ray: along the inward normal to the far wall (with coneRays, the shortest of a cone of rays). sphere: the largest sphere that fits at the point."
4393
+ "description": "ray: along the inward normal to the far wall (the shortest of a cone with coneRays). sphere: the largest sphere that fits at the point."
4332
4394
  },
4333
4395
  "maxThickness": {
4334
4396
  "type": "number",
@@ -4358,7 +4420,7 @@
4358
4420
  "description": "Not checked."
4359
4421
  }
4360
4422
  ],
4361
- "description": "How far the far wall may turn from facing back, degrees, or null to accept whatever is hit."
4423
+ "description": "How far the far wall may turn from facing back, degrees, or null for any."
4362
4424
  }
4363
4425
  },
4364
4426
  "additionalProperties": false
@@ -4380,7 +4442,7 @@
4380
4442
  "ray",
4381
4443
  "sphere"
4382
4444
  ],
4383
- "description": "ray: along the inward normal to the far wall (with coneRays, the shortest of a cone of rays). sphere: the largest sphere that fits at the point."
4445
+ "description": "ray: along the inward normal to the far wall (the shortest of a cone with coneRays). sphere: the largest sphere that fits at the point."
4384
4446
  },
4385
4447
  "maxThickness": {
4386
4448
  "type": "number",
@@ -4410,7 +4472,7 @@
4410
4472
  "description": "Not checked."
4411
4473
  }
4412
4474
  ],
4413
- "description": "How far the far wall may turn from facing back, degrees, or null to accept whatever is hit."
4475
+ "description": "How far the far wall may turn from facing back, degrees, or null for any."
4414
4476
  },
4415
4477
  "low": {
4416
4478
  "type": "number",
@@ -4450,7 +4512,7 @@
4450
4512
  {
4451
4513
  "name": "view.render",
4452
4514
  "title": "Picture the view",
4453
- "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), and lit from a little above and left of the camera with more fill than the screen, so a face square to the camera keeps its shading. Give view and/or fit to turn the view first, as view.set does, or frame to frame a box or a place — a place’s size is the side of a square fitted in the picture, its shorter side, and the answer’s mmAcross: [width, height] says what the picture spans, mm. Only fit: true fits: a view alone turns and keeps the zoom, and a frame stays for the pictures after it — the answer says fitted, and framedEarlier: { box | at, size } while the camera still stands on an earlier frame (fit: true pictures it whole). show puts the scan, the reference, the sections, the elements or the labels — or what a workspace adds — on screen or away for the picture alone, by key, and back as they were after it — { 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. views: two to six standard views in one picture, side by side, each fitted and named in its corner — iso, top, bottom and a side as one picture to look at instead of four (width and height are then the whole sheet’s; 1200 px across by default); the view stays at the last. In the Deviation workspace the answer says which map the picture shows — map: { on: \"scan\" | \"reference\", colormap, range } — or map: null and mapWhy, why none is painted (the map switch off, no map measured, the surface it is on put away) and what puts it there. With the scan shown, a reference shown with it is drawn over it as a ghost and dulls the colours (mapNote says so): show: { reference: false } gives the clean map. In another workspace, with a deviation map measured, map: null and mapWhy say it paints in the Deviation workspace alone (workspace.set deviation); a workspace that colours the part its own way answers map or mapWhy for its own. A workspace’s key that is off in the picture, and not put away by show, may say why and what shows it under <key>Why. Waits for the session to settle first — a map being measured, on the scan or on the reference, too. Pictures and view.set take the viewport one at a time: two asked for together come back as two, one after the other. Needs the viewport.",
4515
+ "description": "A picture of the 3D view as a PNG — what the viewport shows, without the HTML labels (dimension values, names). view and/or fit turn the view first, as view.set does; frame frames a box or a place (mmAcross says what the picture spans). Trap: only fit: true fits — a view alone keeps the zoom, and a frame stays for the pictures after it (fitted and framedEarlier say so). show puts keys on screen or away for the picture alone ({ scan: false } pictures what was built on the scan); a key that has to be read, a workspace’s map, is waited for up to 35 s, and the answer says how far it got if not; section cuts it open for the picture alone. 800 px on the long side by default, up to 2048; views: two to six standard views in one picture. In the Deviation workspace the answer says which map is painted (map) or why none (mapWhy; mapNote when the reference ghost dulls the colours). Waits for the session to settle. Needs the viewport.",
4454
4516
  "input": {
4455
4517
  "type": "object",
4456
4518
  "properties": {
@@ -4470,6 +4532,9 @@
4470
4532
  "type": "string",
4471
4533
  "enum": [
4472
4534
  "iso",
4535
+ "iso-front-left",
4536
+ "iso-rear-left",
4537
+ "iso-rear-right",
4473
4538
  "top",
4474
4539
  "bottom",
4475
4540
  "front",
@@ -4477,7 +4542,7 @@
4477
4542
  "left",
4478
4543
  "right"
4479
4544
  ],
4480
- "description": "A standard view, the camera turned about the middle of the screen: iso (from the front, right and above), top (down the Z axis, Y up the screen), bottom, front (from −Y, Z up), rear (from +Y), left (from −X), right (from +X)."
4545
+ "description": "A standard view: iso (front, right, above) and the other iso corners, top (down Z, Y up), bottom, front (from −Y, Z up), rear, left (from −X), right."
4481
4546
  },
4482
4547
  "views": {
4483
4548
  "type": "array",
@@ -4485,6 +4550,9 @@
4485
4550
  "type": "string",
4486
4551
  "enum": [
4487
4552
  "iso",
4553
+ "iso-front-left",
4554
+ "iso-rear-left",
4555
+ "iso-rear-right",
4488
4556
  "top",
4489
4557
  "bottom",
4490
4558
  "front",
@@ -4492,19 +4560,19 @@
4492
4560
  "left",
4493
4561
  "right"
4494
4562
  ],
4495
- "description": "A standard view, the camera turned about the middle of the screen: iso (from the front, right and above), top (down the Z axis, Y up the screen), bottom, front (from −Y, Z up), rear (from +Y), left (from −X), right (from +X)."
4563
+ "description": "A standard view: iso (front, right, above) and the other iso corners, top (down Z, Y up), bottom, front (from −Y, Z up), rear, left (from −X), right."
4496
4564
  },
4497
- "description": "Several standard views in one picture, each fitted, in this order.",
4565
+ "description": "Several standard views in one picture, each fitted.",
4498
4566
  "minItems": 2,
4499
4567
  "maxItems": 6
4500
4568
  },
4501
4569
  "fit": {
4502
4570
  "type": "boolean",
4503
- "description": "Bring everything shown into the frame, keeping the direction looked from."
4571
+ "description": "Fit everything shown into the frame, keeping the direction."
4504
4572
  },
4505
4573
  "show": {
4506
4574
  "type": "object",
4507
- "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. false on a workspace’s key not on screen now does nothing and is answered under absent.",
4575
+ "description": "Keys to show (true) or put away (false): scan, reference, sections, elements (with dimensions), labels, and a workspace’s own (view.set lists every key standing now).",
4508
4576
  "properties": {
4509
4577
  "scan": {
4510
4578
  "type": "boolean"
@@ -4533,7 +4601,7 @@
4533
4601
  "items": {
4534
4602
  "type": "number"
4535
4603
  },
4536
- "description": "The lowest corner, mm.",
4604
+ "description": "Lowest corner, mm.",
4537
4605
  "minItems": 3,
4538
4606
  "maxItems": 3
4539
4607
  },
@@ -4542,7 +4610,7 @@
4542
4610
  "items": {
4543
4611
  "type": "number"
4544
4612
  },
4545
- "description": "The highest corner, mm.",
4613
+ "description": "Highest corner, mm.",
4546
4614
  "minItems": 3,
4547
4615
  "maxItems": 3
4548
4616
  }
@@ -4552,7 +4620,7 @@
4552
4620
  "max"
4553
4621
  ],
4554
4622
  "additionalProperties": false,
4555
- "description": "A box, in the frame the part is measured in now, framed whole as seen from the view’s direction."
4623
+ "description": "A box in the current frame, framed whole."
4556
4624
  },
4557
4625
  {
4558
4626
  "type": "object",
@@ -4568,7 +4636,7 @@
4568
4636
  },
4569
4637
  "size": {
4570
4638
  "type": "number",
4571
- "description": "The side of the square the picture is fitted round, mm — its shorter side, in any view, the iso too: 40 in an 800 × 450 picture is 40 tall and 71 wide (mmAcross in the answer).",
4639
+ "description": "The side of the square fitted in the picture’s shorter side, mm.",
4572
4640
  "exclusiveMinimum": 0
4573
4641
  }
4574
4642
  },
@@ -4577,16 +4645,16 @@
4577
4645
  "size"
4578
4646
  ],
4579
4647
  "additionalProperties": false,
4580
- "description": "A place in the middle of a view, a square `size` mm on a side fitted in it."
4648
+ "description": "A place, a square size mm on a side fitted round it."
4581
4649
  }
4582
4650
  ],
4583
- "description": "Frame a box or a place instead of everything shown — a corner or a fillet looked at closely; the direction looked from stays, and fit is left alone."
4651
+ "description": "Frame a box or a place instead of everything shown; the direction stays, fit is left alone."
4584
4652
  },
4585
4653
  "section": {
4586
4654
  "oneOf": [
4587
4655
  {
4588
4656
  "type": "boolean",
4589
- "description": "true opens it as the Section key does — square to the view, through the part’s middle; false puts it away."
4657
+ "description": "true: cut square to the view through the part’s middle; false: put it away."
4590
4658
  },
4591
4659
  {
4592
4660
  "type": "object",
@@ -4595,24 +4663,24 @@
4595
4663
  "oneOf": [
4596
4664
  {
4597
4665
  "type": "integer",
4598
- "description": "The element’s id.",
4666
+ "description": "Its id.",
4599
4667
  "minimum": 1
4600
4668
  },
4601
4669
  {
4602
4670
  "type": "string",
4603
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
4671
+ "description": "Its name — \"Sphere 1\".",
4604
4672
  "minLength": 1
4605
4673
  }
4606
4674
  ],
4607
- "description": "A coordinate plane \"XY\", \"YZ\", \"XZ\", or an element with a direction."
4675
+ "description": "\"XY\", \"YZ\", \"XZ\", or an element with a direction."
4608
4676
  },
4609
4677
  "offset": {
4610
4678
  "type": "number",
4611
- "description": "Where along its normal, mm: for a coordinate plane the coordinate, for an element from its centre."
4679
+ "description": "Along its normal, mm: a coordinate plane’s coordinate, or from an element’s centre."
4612
4680
  },
4613
4681
  "flip": {
4614
4682
  "type": "boolean",
4615
- "description": "Take away the half away from the camera instead."
4683
+ "description": "Take away the far half instead."
4616
4684
  }
4617
4685
  },
4618
4686
  "required": [
@@ -4621,7 +4689,7 @@
4621
4689
  "additionalProperties": false
4622
4690
  }
4623
4691
  ],
4624
- "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."
4692
+ "description": "The section view: cut open at a plane, the near half taken away, closed parts capped. Set after any turn."
4625
4693
  }
4626
4694
  },
4627
4695
  "additionalProperties": false
@@ -4633,7 +4701,7 @@
4633
4701
  {
4634
4702
  "name": "view.set",
4635
4703
  "title": "Turn the view",
4636
- "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); the zoom a frame leaves stays for what comes after it, a standard view without fit included. 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, fitted (whether it fitted), framed (the frame asked), framedEarlier (the frame of an earlier call the camera still stands on, not fitted since), mmAcross ([width, height], mm the viewport spans), the section view (null when off) and, under shown, every key that can be shown now and whether it is — a workspace’s key that is off, and not put away by show, may say why and what shows it under <key>Why.",
4704
+ "description": "Turn the 3D view to a standard view and/or fit everything shown — with neither, it fits — or frame a box or a place; the zoom a frame leaves stays for what comes after. show puts keys on screen or away and leaves them so; section cuts everything open at a plane and leaves it so. Waits for the session to settle first. Not a step of the history. Needs the viewport. Returns view, fitted, framed, framedEarlier, mmAcross ([width, height] mm), section (null when off) and shown: every key and whether it is, with <key>Why for a workspace key that is off.",
4637
4705
  "input": {
4638
4706
  "type": "object",
4639
4707
  "properties": {
@@ -4641,6 +4709,9 @@
4641
4709
  "type": "string",
4642
4710
  "enum": [
4643
4711
  "iso",
4712
+ "iso-front-left",
4713
+ "iso-rear-left",
4714
+ "iso-rear-right",
4644
4715
  "top",
4645
4716
  "bottom",
4646
4717
  "front",
@@ -4648,15 +4719,15 @@
4648
4719
  "left",
4649
4720
  "right"
4650
4721
  ],
4651
- "description": "A standard view, the camera turned about the middle of the screen: iso (from the front, right and above), top (down the Z axis, Y up the screen), bottom, front (from −Y, Z up), rear (from +Y), left (from −X), right (from +X)."
4722
+ "description": "A standard view: iso (front, right, above) and the other iso corners, top (down Z, Y up), bottom, front (from −Y, Z up), rear, left (from −X), right."
4652
4723
  },
4653
4724
  "fit": {
4654
4725
  "type": "boolean",
4655
- "description": "Bring everything shown into the frame, keeping the direction looked from."
4726
+ "description": "Fit everything shown into the frame, keeping the direction."
4656
4727
  },
4657
4728
  "show": {
4658
4729
  "type": "object",
4659
- "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. false on a workspace’s key not on screen now does nothing and is answered under absent.",
4730
+ "description": "Keys to show (true) or put away (false): scan, reference, sections, elements (with dimensions), labels, and a workspace’s own (view.set lists every key standing now).",
4660
4731
  "properties": {
4661
4732
  "scan": {
4662
4733
  "type": "boolean"
@@ -4685,7 +4756,7 @@
4685
4756
  "items": {
4686
4757
  "type": "number"
4687
4758
  },
4688
- "description": "The lowest corner, mm.",
4759
+ "description": "Lowest corner, mm.",
4689
4760
  "minItems": 3,
4690
4761
  "maxItems": 3
4691
4762
  },
@@ -4694,7 +4765,7 @@
4694
4765
  "items": {
4695
4766
  "type": "number"
4696
4767
  },
4697
- "description": "The highest corner, mm.",
4768
+ "description": "Highest corner, mm.",
4698
4769
  "minItems": 3,
4699
4770
  "maxItems": 3
4700
4771
  }
@@ -4704,7 +4775,7 @@
4704
4775
  "max"
4705
4776
  ],
4706
4777
  "additionalProperties": false,
4707
- "description": "A box, in the frame the part is measured in now, framed whole as seen from the view’s direction."
4778
+ "description": "A box in the current frame, framed whole."
4708
4779
  },
4709
4780
  {
4710
4781
  "type": "object",
@@ -4720,7 +4791,7 @@
4720
4791
  },
4721
4792
  "size": {
4722
4793
  "type": "number",
4723
- "description": "The side of the square the picture is fitted round, mm — its shorter side, in any view, the iso too: 40 in an 800 × 450 picture is 40 tall and 71 wide (mmAcross in the answer).",
4794
+ "description": "The side of the square fitted in the picture’s shorter side, mm.",
4724
4795
  "exclusiveMinimum": 0
4725
4796
  }
4726
4797
  },
@@ -4729,16 +4800,16 @@
4729
4800
  "size"
4730
4801
  ],
4731
4802
  "additionalProperties": false,
4732
- "description": "A place in the middle of a view, a square `size` mm on a side fitted in it."
4803
+ "description": "A place, a square size mm on a side fitted round it."
4733
4804
  }
4734
4805
  ],
4735
- "description": "Frame a box or a place instead of everything shown — a corner or a fillet looked at closely; the direction looked from stays, and fit is left alone."
4806
+ "description": "Frame a box or a place instead of everything shown; the direction stays, fit is left alone."
4736
4807
  },
4737
4808
  "section": {
4738
4809
  "oneOf": [
4739
4810
  {
4740
4811
  "type": "boolean",
4741
- "description": "true opens it as the Section key does — square to the view, through the part’s middle; false puts it away."
4812
+ "description": "true: cut square to the view through the part’s middle; false: put it away."
4742
4813
  },
4743
4814
  {
4744
4815
  "type": "object",
@@ -4747,24 +4818,24 @@
4747
4818
  "oneOf": [
4748
4819
  {
4749
4820
  "type": "integer",
4750
- "description": "The element’s id.",
4821
+ "description": "Its id.",
4751
4822
  "minimum": 1
4752
4823
  },
4753
4824
  {
4754
4825
  "type": "string",
4755
- "description": "The element’s name, as the list shows it — \"Sphere 1\".",
4826
+ "description": "Its name — \"Sphere 1\".",
4756
4827
  "minLength": 1
4757
4828
  }
4758
4829
  ],
4759
- "description": "A coordinate plane \"XY\", \"YZ\", \"XZ\", or an element with a direction."
4830
+ "description": "\"XY\", \"YZ\", \"XZ\", or an element with a direction."
4760
4831
  },
4761
4832
  "offset": {
4762
4833
  "type": "number",
4763
- "description": "Where along its normal, mm: for a coordinate plane the coordinate, for an element from its centre."
4834
+ "description": "Along its normal, mm: a coordinate plane’s coordinate, or from an element’s centre."
4764
4835
  },
4765
4836
  "flip": {
4766
4837
  "type": "boolean",
4767
- "description": "Take away the half away from the camera instead."
4838
+ "description": "Take away the far half instead."
4768
4839
  }
4769
4840
  },
4770
4841
  "required": [
@@ -4773,7 +4844,7 @@
4773
4844
  "additionalProperties": false
4774
4845
  }
4775
4846
  ],
4776
- "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."
4847
+ "description": "The section view: cut open at a plane, the near half taken away, closed parts capped. Set after any turn."
4777
4848
  }
4778
4849
  },
4779
4850
  "additionalProperties": false