@toolpath/tool-drawing 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -4
- package/dist/{chunk-UBENO6GN.js → chunk-WYHJGR7P.js} +21 -13
- package/dist/clearance/index.d.ts +10 -32
- package/dist/clearance/index.js +1 -8
- package/dist/geometry/index.d.ts +44 -78
- package/dist/geometry/index.js +1 -1
- package/dist/index.d.ts +83 -132
- package/dist/index.js +293 -352
- package/dist/{sheet-D0LSO7qP.d.ts → sheet-DicKQYfF.d.ts} +10 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -14,6 +14,12 @@ in 3D; this one draws a catalog tool in 2D.
|
|
|
14
14
|
npm install @toolpath/tool-drawing react react-dom
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
Its one runtime dependency is [`@toolpath/tool-support`](../tool-support), the
|
|
18
|
+
shared cutting-tool domain, which itself depends on nothing. `Provenance`,
|
|
19
|
+
`ViewerTool`, `ViewerHolder` and `ViewerHolderProfile` are aliases of its types
|
|
20
|
+
and are re-exported here, so a consumer that also uses `@toolpath/tool-support`
|
|
21
|
+
gets the same types and needs no adapter between them.
|
|
22
|
+
|
|
17
23
|
## Exports
|
|
18
24
|
|
|
19
25
|
| Entry point | What it is |
|
|
@@ -24,6 +30,7 @@ npm install @toolpath/tool-drawing react react-dom
|
|
|
24
30
|
|
|
25
31
|
`/geometry` is pure and server-safe: it touches no DOM and imports no React, so
|
|
26
32
|
a Node server can measure an assembly without paying for a renderer.
|
|
33
|
+
`tests/subpaths.test.ts` asserts that from the import graph.
|
|
27
34
|
|
|
28
35
|
## Geometry
|
|
29
36
|
|
|
@@ -92,13 +99,47 @@ as a plausible cylinder.
|
|
|
92
99
|
## Dimensions
|
|
93
100
|
|
|
94
101
|
```tsx
|
|
95
|
-
<ToolDrawing
|
|
102
|
+
<ToolDrawing
|
|
103
|
+
assembly={assembly}
|
|
104
|
+
dimensions
|
|
105
|
+
dimensionSides="both"
|
|
106
|
+
highlight={hovered}
|
|
107
|
+
onDimensionHover={setHovered}
|
|
108
|
+
/>
|
|
96
109
|
```
|
|
97
110
|
|
|
98
111
|
Every stated length and width, each in its own lane, nested shortest-innermost
|
|
99
|
-
so no two lines cross
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
so no two lines cross. Only stated numbers are dimensioned.
|
|
113
|
+
|
|
114
|
+
**The drawing letters none of them.** The numbers belong in your own table,
|
|
115
|
+
where they can be read; six two-line figures fighting for the margin said the
|
|
116
|
+
same numbers a second time and worse. Which line is which is answered by
|
|
117
|
+
pointing at it instead:
|
|
118
|
+
|
|
119
|
+
- `highlight` names the dimension or dimensions to draw in the sheet's accent,
|
|
120
|
+
by ISO 13399 code — `DC`, `LCF`, `OAL`, `SFDM`, `LBH`, `stickout`, `SIG`, and
|
|
121
|
+
the two `shoulder-` codes. A code the tool does not dimension highlights
|
|
122
|
+
nothing.
|
|
123
|
+
- `onDimensionHover` is told the code under the pointer and `null` when it
|
|
124
|
+
leaves, so your table can be lit from the drawing as well as the other way
|
|
125
|
+
about. Passing it puts hit targets on the lines; leaving it off draws none.
|
|
126
|
+
|
|
127
|
+
Where two codes are one span the drawing carries one line, not two. A shop that
|
|
128
|
+
clamps to its own rule states the stickout and the below-holder length as the
|
|
129
|
+
same number, and a tool stood out to its flutes states it again as the flute
|
|
130
|
+
length; with nothing lettered, identical lines in two lanes cannot be told
|
|
131
|
+
apart. The first code named keeps the line — the tool's own number ahead of the
|
|
132
|
+
shop's — and the others light it too. Hover reports the code the line is drawn
|
|
133
|
+
under.
|
|
134
|
+
|
|
135
|
+
**The stickout is yours.** `assembly.stickout` is where the holder nose goes,
|
|
136
|
+
and nothing here derives it — pass `LBH` as the stickout if standing the tool
|
|
137
|
+
out to its below-holder length is the rule you want drawn. Where the two
|
|
138
|
+
disagree and `LBH` ends up inside the holder, it is not dimensioned: the
|
|
139
|
+
drawing will not run a line to a face it has drawn a holder over.
|
|
140
|
+
|
|
141
|
+
A highlighted line is drawn in the accent **and heavier**, so the highlight
|
|
142
|
+
survives a reader who cannot tell the two colours apart.
|
|
102
143
|
|
|
103
144
|
## Clearance overlay
|
|
104
145
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// src/model/types.ts
|
|
2
|
-
|
|
2
|
+
import { isHolderProfile } from "@toolpath/tool-support";
|
|
3
3
|
|
|
4
4
|
// src/model/outline.ts
|
|
5
|
+
import { hasNeck } from "@toolpath/tool-support";
|
|
5
6
|
var EPSILON = 1e-6;
|
|
6
7
|
var stated = (tool, code) => tool.provenance?.[code] ?? "vendor-stated";
|
|
7
8
|
var arc = (centre, radius, fromDeg, toDeg, steps = 6) => Array.from({ length: steps + 1 }, (_, index) => {
|
|
@@ -12,16 +13,6 @@ var arc = (centre, radius, fromDeg, toDeg, steps = 6) => Array.from({ length: st
|
|
|
12
13
|
z: exact(centre.z + radius * Math.sin(angle))
|
|
13
14
|
};
|
|
14
15
|
});
|
|
15
|
-
var hasNeck = (tool) => {
|
|
16
|
-
const { LCF, SFDM, DC } = tool.geometry;
|
|
17
|
-
const shoulder = tool.geometry["shoulder-length"];
|
|
18
|
-
const relief = tool.geometry["shoulder-diameter"];
|
|
19
|
-
if (shoulder === void 0 || relief === void 0 || LCF === void 0 || shoulder <= LCF) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
const shank = SFDM ?? DC;
|
|
23
|
-
return shank === void 0 ? true : relief < shank - EPSILON;
|
|
24
|
-
};
|
|
25
16
|
var cone = (tool, r, whenUnstated) => {
|
|
26
17
|
const angle = tool.geometry.SIG;
|
|
27
18
|
const half = (angle ?? whenUnstated) / 2 * (Math.PI / 180);
|
|
@@ -261,9 +252,26 @@ var assemblyOutline = (assembly) => {
|
|
|
261
252
|
const radius = Math.max(...segments.flatMap((segment) => segment.points.map((point2) => point2.r)));
|
|
262
253
|
return { segments, height: top, radius };
|
|
263
254
|
};
|
|
255
|
+
var edgeRadius = (from, to, z) => {
|
|
256
|
+
const low = Math.min(from.z, to.z);
|
|
257
|
+
const high = Math.max(from.z, to.z);
|
|
258
|
+
if (z < low - EPSILON || z > high + EPSILON) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
if (high - low <= EPSILON) {
|
|
262
|
+
return Math.max(from.r, to.r);
|
|
263
|
+
}
|
|
264
|
+
return from.r + (z - from.z) / (to.z - from.z) * (to.r - from.r);
|
|
265
|
+
};
|
|
266
|
+
var radiusAt = (outline, z) => Math.max(
|
|
267
|
+
0,
|
|
268
|
+
...outline.segments.flatMap(
|
|
269
|
+
(segment) => segment.points.slice(1).map((point, index) => edgeRadius(segment.points[index], point, z)).filter((radius) => radius !== null)
|
|
270
|
+
)
|
|
271
|
+
);
|
|
264
272
|
|
|
265
273
|
export {
|
|
266
274
|
isHolderProfile,
|
|
267
|
-
|
|
268
|
-
|
|
275
|
+
assemblyOutline,
|
|
276
|
+
radiusAt
|
|
269
277
|
};
|
|
@@ -1,47 +1,25 @@
|
|
|
1
|
+
import { ReachCurve } from '@toolpath/tool-support';
|
|
2
|
+
export { ReachCurve, heightAt } from '@toolpath/tool-support';
|
|
1
3
|
import { OutlinePart, OutlineSegment, OutlinePoint } from '../geometry/index.js';
|
|
2
4
|
import * as react from 'react';
|
|
3
|
-
import { F as Frame, E as Extent, S as Sheet } from '../sheet-
|
|
5
|
+
import { F as Frame, E as Extent, S as Sheet } from '../sheet-DicKQYfF.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* The feature's reach curve, and how the drawing reads it.
|
|
7
9
|
*
|
|
8
|
-
* **
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* **Still declared structurally, one package up.** `@toolpath/tool-support`
|
|
11
|
+
* names the shape and imports no Toolpath schema to do it, which is one of the
|
|
12
|
+
* three senses in which this overlay stays optional: a consumer that draws a
|
|
13
|
+
* tool alone pulls in no OpenAPI contract. A `ReachCurve` off a report
|
|
14
|
+
* satisfies it by structure, with no adapter, exactly as before.
|
|
13
15
|
*/
|
|
14
|
-
|
|
15
|
-
* The worst-case material around a feature, as a staircase.
|
|
16
|
-
*
|
|
17
|
-
* Read as "material within `horizontalOffset[i]` of the cut rises to
|
|
18
|
-
* `verticalOffset[i]`". Both are in millimetres; the offsets run outward from
|
|
19
|
-
* the cutting edge and the heights up from the bottom of the feature.
|
|
20
|
-
*/
|
|
21
|
-
interface ReachCurve {
|
|
22
|
-
readonly horizontalOffset: ReadonlyArray<number>;
|
|
23
|
-
readonly verticalOffset: ReadonlyArray<number>;
|
|
24
|
-
}
|
|
16
|
+
|
|
25
17
|
/** Room the shop wants kept between the stack and the part, in millimetres. */
|
|
26
18
|
interface Margins {
|
|
27
19
|
readonly radial: number;
|
|
28
20
|
readonly axial: number;
|
|
29
21
|
}
|
|
30
22
|
declare const NO_MARGINS: Margins;
|
|
31
|
-
/**
|
|
32
|
-
* The tallest material within `offset` mm of the cut, above the feature's bottom.
|
|
33
|
-
*
|
|
34
|
-
* **The one piece of the verdict's own arithmetic that had to travel.** The
|
|
35
|
-
* decision — whether an assembly clears — stays with the catalog's
|
|
36
|
-
* tool-selection engine, which has a dozen callers that never draw anything.
|
|
37
|
-
* This is not that decision: it is the reading of the curve that the drawn
|
|
38
|
-
* staircase is drawn from, and the gaps this overlay dimensions are measured
|
|
39
|
-
* against. It is here because {@link tightestGaps} cannot be written without
|
|
40
|
-
* it, and it must keep agreeing with whatever draws the material profile — the
|
|
41
|
-
* rise comes at the *start* of each run, so everything out to a knot is
|
|
42
|
-
* already as tall as that knot says.
|
|
43
|
-
*/
|
|
44
|
-
declare const heightAt: (curve: ReachCurve, offset: number) => number;
|
|
45
23
|
/**
|
|
46
24
|
* Where the wall face stands at a given height, as an offset from the cut:
|
|
47
25
|
* the start of the first run of the staircase that rises above that height.
|
|
@@ -202,4 +180,4 @@ declare const ClearanceOverlay: ({ profile, frame: framed, outline: extent, cutt
|
|
|
202
180
|
*/
|
|
203
181
|
declare const describeGaps: (gaps: Gaps, margins: Margins, formatLength: (millimetres: number) => string) => string | null;
|
|
204
182
|
|
|
205
|
-
export { type AxialGap, ClearanceOverlay, type ClearanceOverlayProps, type Gap, type Gaps, type Margins, NO_MARGINS,
|
|
183
|
+
export { type AxialGap, ClearanceOverlay, type ClearanceOverlayProps, type Gap, type Gaps, type Margins, NO_MARGINS, clipped, describeGaps, lastRise, tightestGaps, wallCorners, wallFaceAt, wallPath, zigzag };
|
package/dist/clearance/index.js
CHANGED
|
@@ -8,16 +8,9 @@ import {
|
|
|
8
8
|
} from "../chunk-7ZID4QRO.js";
|
|
9
9
|
|
|
10
10
|
// src/clearance/model/curve.ts
|
|
11
|
+
import { heightAt } from "@toolpath/tool-support";
|
|
11
12
|
var NO_MARGINS = { radial: 0, axial: 0 };
|
|
12
13
|
var GAP_TOLERANCE = 1e-6;
|
|
13
|
-
var heightAt = (curve, offset) => {
|
|
14
|
-
for (let index = 0; index < curve.horizontalOffset.length; index += 1) {
|
|
15
|
-
if ((curve.horizontalOffset[index] ?? 0) >= offset) {
|
|
16
|
-
return curve.verticalOffset[index] ?? 0;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return curve.verticalOffset[curve.verticalOffset.length - 1] ?? 0;
|
|
20
|
-
};
|
|
21
14
|
var wallFaceAt = (curve, z) => {
|
|
22
15
|
let from = 0;
|
|
23
16
|
for (let index = 0; index < curve.horizontalOffset.length; index += 1) {
|
package/dist/geometry/index.d.ts
CHANGED
|
@@ -1,97 +1,63 @@
|
|
|
1
|
+
import { Tool, Holder, HolderProfile, Provenance } from '@toolpath/tool-support';
|
|
2
|
+
export { Provenance, isHolderProfile } from '@toolpath/tool-support';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
* What this package needs to draw an assembly
|
|
5
|
+
* What this package needs to draw an assembly — which is the shared cutting-tool
|
|
6
|
+
* domain, under the names this package has always published.
|
|
7
|
+
*
|
|
8
|
+
* These four were declared here until `@toolpath/tool-support` existed, and the
|
|
9
|
+
* declarations were three-way duplicates: the same provenance strings, the same
|
|
10
|
+
* geometry codes and three shapes called "holder" of which no two agreed on
|
|
11
|
+
* which fields exist. A drawing and the number printed beside it were free to
|
|
12
|
+
* disagree about one tool, and once did — the stickout the details table showed
|
|
13
|
+
* was not the stickout the dimension line drew.
|
|
14
|
+
*
|
|
15
|
+
* So the shapes now come from the one declaration and these are **aliases**,
|
|
16
|
+
* exported from `.` and from `/geometry` exactly as before. A consumer's adapter
|
|
17
|
+
* does not move: `ViewerTool` is `Tool`, and a catalog record that satisfied one
|
|
18
|
+
* satisfies the other by structure.
|
|
19
|
+
*
|
|
20
|
+
* ## Why the alias and not a rename
|
|
3
21
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
22
|
+
* A consumer's adapter is the single file that fails loudly when either side
|
|
23
|
+
* moves, and renaming the type it targets would be that failure for no gain. The
|
|
24
|
+
* `Viewer*` names are also what the two entry points publish, so dropping them
|
|
25
|
+
* is a major bump this change has no reason to spend. `@toolpath/tool-support`
|
|
26
|
+
* is where the domain is documented; this file is the seam.
|
|
8
27
|
*
|
|
9
|
-
* `geometry` keeps the scraper's own field names — `DC`, `SFDM`, `OAL`,
|
|
10
|
-
* `RE`, `SIG`, `NOF`, `shoulder-diameter`, `shoulder-length
|
|
11
|
-
*
|
|
12
|
-
*
|
|
28
|
+
* `geometry` still keeps the scraper's own field names — `DC`, `SFDM`, `OAL`,
|
|
29
|
+
* `LCF`, `RE`, `SIG`, `NOF`, `shoulder-diameter`, `shoulder-length` — and
|
|
30
|
+
* `@toolpath/tool-support`'s `GEOMETRY_FIELDS` is now the dictionary behind
|
|
31
|
+
* them.
|
|
13
32
|
*
|
|
14
33
|
* All lengths are in millimetres and all angles in degrees, and every generator
|
|
15
34
|
* works in whatever unit system it is handed: an inch tool yields an inch
|
|
16
35
|
* outline. Converting is the caller's, at the seam where a tool meets a holder.
|
|
17
36
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
readonly label?: string;
|
|
24
|
-
readonly geometry: Readonly<Record<string, number | undefined>>;
|
|
25
|
-
readonly provenance?: Readonly<Record<string, Provenance>>;
|
|
26
|
-
}
|
|
27
|
-
interface ViewerHolder {
|
|
28
|
-
readonly noseDiameter: number | null;
|
|
29
|
-
readonly noseLength: number | null;
|
|
30
|
-
readonly bodyDiameter: number | null;
|
|
31
|
-
readonly bodyLength: number | null;
|
|
32
|
-
readonly projection: number | null;
|
|
33
|
-
readonly flangeDiameter: number | null;
|
|
34
|
-
readonly gaugeLength: number | null;
|
|
35
|
-
readonly colletSeries: string | null;
|
|
36
|
-
readonly colletProtrusion: number | null;
|
|
37
|
-
readonly provenance?: Readonly<Record<string, Provenance>>;
|
|
38
|
-
}
|
|
37
|
+
|
|
38
|
+
/** A cutting tool, as the drawing needs one. */
|
|
39
|
+
type ViewerTool = Tool;
|
|
40
|
+
/** A holder as its vendor publishes it: a nose, a body, a projection. */
|
|
41
|
+
type ViewerHolder = Holder;
|
|
39
42
|
/**
|
|
40
43
|
* A holder as its own CAD model measures it: the silhouette, and nothing
|
|
41
44
|
* parametric.
|
|
42
45
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* hundred-odd vertices carrying the V-flange groove and the thread relief that
|
|
47
|
-
* a machinist actually looks for. **It is not a refinement of the parametric
|
|
48
|
-
* form and does not project onto it**: reducing it to a nose and a body throws
|
|
49
|
-
* away the only reason to measure.
|
|
50
|
-
*
|
|
51
|
-
* So the two are a union rather than one shape with optional extras, and
|
|
52
|
-
* {@link isHolderProfile} tells them apart. A consumer that has both picks one;
|
|
46
|
+
* Not a refinement of {@link ViewerHolder} and it does not project onto one —
|
|
47
|
+
* reducing a measured envelope to a nose and a body throws away the only reason
|
|
48
|
+
* to measure. The two are a union and {@link isHolderProfile} tells them apart;
|
|
53
49
|
* a consumer that has neither passes `null` and the tool is drawn alone.
|
|
54
50
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* The silhouette as `[z, r]` in millimetres, `z` ascending.
|
|
58
|
-
*
|
|
59
|
-
* Two vertices share a `z` where the solid steps, so this is a polyline and
|
|
60
|
-
* not a function of `z`. Fewer than two vertices is no holder and draws none.
|
|
61
|
-
*/
|
|
62
|
-
readonly points: ReadonlyArray<readonly [z: number, r: number]>;
|
|
63
|
-
/**
|
|
64
|
-
* What `z = 0` means.
|
|
65
|
-
*
|
|
66
|
-
* `gage-line` is the spindle face, with `z` increasing toward the cutting end
|
|
67
|
-
* — so the taper is negative, the nose positive, and the holder's gauge
|
|
68
|
-
* length is the last vertex's `z`. `nose` is the frame a holder with no taper
|
|
69
|
-
* to solve a gauge plane on is measured in, and it is stated rather than
|
|
70
|
-
* silently referenced to an arbitrary end: there is no gauge length to read
|
|
71
|
-
* off it, and the drawing says so instead of printing one.
|
|
72
|
-
*/
|
|
73
|
-
readonly datum: 'gage-line' | 'nose';
|
|
74
|
-
/** The series the holder takes, as {@link ViewerHolder} means it. */
|
|
75
|
-
readonly colletSeries: string | null;
|
|
76
|
-
/** How far the seated collet stands proud of the nose, in millimetres. */
|
|
77
|
-
readonly colletProtrusion: number | null;
|
|
78
|
-
/**
|
|
79
|
-
* Keyed as {@link ViewerHolder}'s is, plus `points` for the measurement
|
|
80
|
-
* itself — which is `vendor-stated` unless a caller says otherwise, because
|
|
81
|
-
* the shape measured is the vendor's own model rather than a derivation from
|
|
82
|
-
* its table.
|
|
83
|
-
*/
|
|
84
|
-
readonly provenance?: Readonly<Record<string, Provenance>>;
|
|
85
|
-
}
|
|
51
|
+
type ViewerHolderProfile = HolderProfile;
|
|
52
|
+
|
|
86
53
|
/**
|
|
87
|
-
*
|
|
54
|
+
* A tool, the holder it is clamped in, and how far it stands out.
|
|
88
55
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
56
|
+
* Deliberately **not** `@toolpath/tool-support`'s `Assembly`, which also carries
|
|
57
|
+
* the collet: a drawing reads a collet only through the holder's own series and
|
|
58
|
+
* protrusion, and taking one it never reads would be a field every adapter has
|
|
59
|
+
* to fill for nothing.
|
|
93
60
|
*/
|
|
94
|
-
declare const isHolderProfile: (holder: ViewerHolder | ViewerHolderProfile) => holder is ViewerHolderProfile;
|
|
95
61
|
interface ViewerAssembly {
|
|
96
62
|
readonly tool: ViewerTool;
|
|
97
63
|
readonly holder: ViewerHolder | ViewerHolderProfile | null;
|
|
@@ -155,4 +121,4 @@ interface Outline {
|
|
|
155
121
|
*/
|
|
156
122
|
declare const assemblyOutline: (assembly: ViewerAssembly) => Outline | null;
|
|
157
123
|
|
|
158
|
-
export { type Outline, type OutlinePart, type OutlinePoint, type OutlineSegment, type
|
|
124
|
+
export { type Outline, type OutlinePart, type OutlinePoint, type OutlineSegment, type ViewerAssembly, type ViewerHolder, type ViewerHolderProfile, type ViewerTool, assemblyOutline };
|