@toolpath/tool-support 0.1.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/LICENSE +21 -0
- package/README.md +184 -0
- package/dist/assembly-fit.d.ts +54 -0
- package/dist/assembly-fit.js +55 -0
- package/dist/clamping.d.ts +55 -0
- package/dist/clamping.js +70 -0
- package/dist/clearance.d.ts +115 -0
- package/dist/clearance.js +209 -0
- package/dist/demand.d.ts +51 -0
- package/dist/demand.js +23 -0
- package/dist/fit.d.ts +69 -0
- package/dist/fit.js +90 -0
- package/dist/forms.d.ts +130 -0
- package/dist/forms.js +44 -0
- package/dist/geometry.d.ts +191 -0
- package/dist/geometry.js +124 -0
- package/dist/holding.d.ts +266 -0
- package/dist/holding.js +203 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +62 -0
- package/dist/material.d.ts +29 -0
- package/dist/material.js +30 -0
- package/dist/parts.d.ts +56 -0
- package/dist/parts.js +38 -0
- package/dist/profile.d.ts +104 -0
- package/dist/profile.js +68 -0
- package/dist/provenance.d.ts +25 -0
- package/dist/provenance.js +15 -0
- package/dist/reach.d.ts +46 -0
- package/dist/reach.js +37 -0
- package/dist/section.d.ts +67 -0
- package/dist/section.js +185 -0
- package/dist/stickout.d.ts +187 -0
- package/dist/stickout.js +161 -0
- package/dist/tool.d.ts +80 -0
- package/dist/tool.js +89 -0
- package/dist/units.d.ts +73 -0
- package/dist/units.js +82 -0
- package/package.json +48 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interchange dictionary: what a geometry code measures, and whether the
|
|
3
|
+
* number under it converts.
|
|
4
|
+
*
|
|
5
|
+
* Most of these are ISO 13399's own codes with the standard's meanings — the
|
|
6
|
+
* machine-tool industry's interchange vocabulary, which is also why they appear
|
|
7
|
+
* in Fusion's tool JSON. Three are Autodesk's names for measurements ISO codes
|
|
8
|
+
* differently, and {@link GeometryField.iso} records the standard's counterpart
|
|
9
|
+
* rather than quietly renaming them: a consumer recognises the name the scraper
|
|
10
|
+
* emitted, and a reader can still find the standard's.
|
|
11
|
+
*
|
|
12
|
+
* ## Why the dictionary carries a unit kind and not a label
|
|
13
|
+
*
|
|
14
|
+
* The unit kind is the part that changes behaviour: it is what decides whether
|
|
15
|
+
* a stated number converts with {@link UnitSystem} or is the same number in
|
|
16
|
+
* both systems. A flute count and a point angle do not convert, an L/D ratio
|
|
17
|
+
* does not convert, and a length does — and a consumer that converts the wrong
|
|
18
|
+
* one prints a 60-degree drill point as 2.36.
|
|
19
|
+
*
|
|
20
|
+
* Human-facing labels and descriptions are presentational: which words a detail
|
|
21
|
+
* page puts beside `SFDM` is that page's decision and changes with its
|
|
22
|
+
* audience. {@link GeometryField.definition} is not one of those — it is the
|
|
23
|
+
* phrase a diagnostic quotes back at whoever mapped a column to the wrong code,
|
|
24
|
+
* which is why the scraper already carries it.
|
|
25
|
+
*
|
|
26
|
+
* ## An unknown code is not given a meaning
|
|
27
|
+
*
|
|
28
|
+
* {@link geometryField} answers `null` rather than inventing an entry, and
|
|
29
|
+
* {@link isLengthField} answers `false`. A consumer shows an unrecognised code
|
|
30
|
+
* as the vendor's own and does not convert it — the alternative is guessing a
|
|
31
|
+
* unit for a column nobody has checked, and a guessed conversion is a wrong
|
|
32
|
+
* number that looks right.
|
|
33
|
+
*/
|
|
34
|
+
import { type UnitSystem } from './units.js';
|
|
35
|
+
/**
|
|
36
|
+
* What kind of quantity a code states.
|
|
37
|
+
*
|
|
38
|
+
* `mm` is the only one that moves with a unit system. `deg` and `count` are the
|
|
39
|
+
* same number in both; `ratio` is dimensionless by construction, and an `LD` of
|
|
40
|
+
* 4 is 4 whichever sheet it came off.
|
|
41
|
+
*/
|
|
42
|
+
export type GeometryUnit = 'mm' | 'deg' | 'count' | 'ratio';
|
|
43
|
+
export interface GeometryField {
|
|
44
|
+
readonly unit: GeometryUnit;
|
|
45
|
+
/**
|
|
46
|
+
* What the field measures, phrased so it can be quoted back at whoever
|
|
47
|
+
* mapped a column to the wrong one.
|
|
48
|
+
*/
|
|
49
|
+
readonly definition: string;
|
|
50
|
+
/**
|
|
51
|
+
* The ISO 13399 code for this measurement, or `null` where the standard's
|
|
52
|
+
* counterpart has not been pinned. Equal to the key itself on every field
|
|
53
|
+
* that *is* the standard's code.
|
|
54
|
+
*/
|
|
55
|
+
readonly iso: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The codes this domain knows, keyed by the name the scraper emits.
|
|
59
|
+
*
|
|
60
|
+
* **This vocabulary is the scraper's, not this package's invention.** Renaming
|
|
61
|
+
* a field here would put a translation table between two vocabularies, and a
|
|
62
|
+
* translation table is where an `SFDM` becomes a `DC` in one direction and
|
|
63
|
+
* nobody notices.
|
|
64
|
+
*/
|
|
65
|
+
export declare const GEOMETRY_FIELDS: {
|
|
66
|
+
readonly DC: {
|
|
67
|
+
readonly unit: "mm";
|
|
68
|
+
readonly definition: "cutting diameter";
|
|
69
|
+
readonly iso: "DC";
|
|
70
|
+
};
|
|
71
|
+
readonly SFDM: {
|
|
72
|
+
readonly unit: "mm";
|
|
73
|
+
readonly definition: "shank diameter — what the holder grips";
|
|
74
|
+
readonly iso: "DMM";
|
|
75
|
+
};
|
|
76
|
+
readonly OAL: {
|
|
77
|
+
readonly unit: "mm";
|
|
78
|
+
readonly definition: "overall length, tip to the end of the shank";
|
|
79
|
+
readonly iso: "OAL";
|
|
80
|
+
};
|
|
81
|
+
readonly LCF: {
|
|
82
|
+
readonly unit: "mm";
|
|
83
|
+
readonly definition: "flute length — the length of the cutting edge";
|
|
84
|
+
readonly iso: "LCF";
|
|
85
|
+
};
|
|
86
|
+
readonly RE: {
|
|
87
|
+
readonly unit: "mm";
|
|
88
|
+
readonly definition: "corner radius; 0 on a square-end tool";
|
|
89
|
+
readonly iso: "RE";
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* **`unit: 'mm'` is not the whole truth, and a caller converting a `TP` off
|
|
93
|
+
* an inch tap should know it.** A metric tap's pitch is a length; an inch
|
|
94
|
+
* tap's is conventionally threads-per-inch, which is a *reciprocal*, and
|
|
95
|
+
* converting one as a length gives a number that looks like a pitch and is
|
|
96
|
+
* wrong by a factor of its own value. No consumer in this tree converts it —
|
|
97
|
+
* the scraper reads it from a single column already in the tool's own system,
|
|
98
|
+
* and the catalog drops the code on ingest for exactly this reason — so the
|
|
99
|
+
* hazard is recorded rather than resolved. Resolving it means either
|
|
100
|
+
* confirming the inch convention against a real tap table or giving the
|
|
101
|
+
* dictionary a unit kind for "not decidable from the code alone".
|
|
102
|
+
*/
|
|
103
|
+
readonly TP: {
|
|
104
|
+
readonly unit: "mm";
|
|
105
|
+
readonly definition: "thread pitch, in the tool’s own unit system";
|
|
106
|
+
readonly iso: "TP";
|
|
107
|
+
};
|
|
108
|
+
readonly NOF: {
|
|
109
|
+
readonly unit: "count";
|
|
110
|
+
readonly definition: "number of flutes";
|
|
111
|
+
readonly iso: "NOF";
|
|
112
|
+
};
|
|
113
|
+
readonly SIG: {
|
|
114
|
+
readonly unit: "deg";
|
|
115
|
+
readonly definition: "point angle, degrees included";
|
|
116
|
+
readonly iso: "SIG";
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* ISO 13399's clamping length minimum: the shank a manufacturer wants held.
|
|
120
|
+
*
|
|
121
|
+
* No vendor scraped so far publishes it, and the day one does this is where
|
|
122
|
+
* it lands — read in preference to any rule of thumb about how much shank a
|
|
123
|
+
* shop keeps clamped.
|
|
124
|
+
*/
|
|
125
|
+
readonly LSCN: {
|
|
126
|
+
readonly unit: "mm";
|
|
127
|
+
readonly definition: "least of the shank the manufacturer wants clamped";
|
|
128
|
+
readonly iso: "LSCN";
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Not a vendor's column: how far the tool is set out of the holder.
|
|
132
|
+
*
|
|
133
|
+
* The number the drawing draws and the details table prints, and the one
|
|
134
|
+
* quantity that was computed in four unconnected places and disagreed by a
|
|
135
|
+
* factor of two on an ordinary tool. It is derived, and its provenance says
|
|
136
|
+
* so.
|
|
137
|
+
*/
|
|
138
|
+
readonly LBH: {
|
|
139
|
+
readonly unit: "mm";
|
|
140
|
+
readonly definition: "length below holder — how far the tool is set out of the holder nose";
|
|
141
|
+
readonly iso: null;
|
|
142
|
+
};
|
|
143
|
+
/** Length below holder over cutting diameter — the "×D" a shop reads reach in. */
|
|
144
|
+
readonly LD: {
|
|
145
|
+
readonly unit: "ratio";
|
|
146
|
+
readonly definition: "length below holder over cutting diameter — the ×D a shop reads reach in";
|
|
147
|
+
readonly iso: null;
|
|
148
|
+
};
|
|
149
|
+
readonly 'shoulder-length': {
|
|
150
|
+
readonly unit: "mm";
|
|
151
|
+
readonly definition: "usable length below the full shank";
|
|
152
|
+
readonly iso: null;
|
|
153
|
+
};
|
|
154
|
+
readonly 'shoulder-diameter': {
|
|
155
|
+
readonly unit: "mm";
|
|
156
|
+
readonly definition: "diameter at the shoulder — the neck, where necked";
|
|
157
|
+
readonly iso: null;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
/** A code {@link GEOMETRY_FIELDS} knows. */
|
|
161
|
+
export type GeometryCode = keyof typeof GEOMETRY_FIELDS;
|
|
162
|
+
/**
|
|
163
|
+
* A tool's stated geometry: code to value, lengths in millimetres and angles in
|
|
164
|
+
* degrees whatever system the vendor published in.
|
|
165
|
+
*
|
|
166
|
+
* Keyed by `string` and not by {@link GeometryCode}, because a vendor states
|
|
167
|
+
* columns this dictionary has not pinned yet and dropping them on ingest would
|
|
168
|
+
* lose data that is still the vendor's. `undefined` is admitted so that a
|
|
169
|
+
* record with a narrower `Record<string, number>` geometry satisfies this by
|
|
170
|
+
* structure, with no adapter.
|
|
171
|
+
*/
|
|
172
|
+
export type Geometry = Readonly<Record<string, number | undefined>>;
|
|
173
|
+
/** What a code measures, or `null` where this dictionary has not pinned it. */
|
|
174
|
+
export declare const geometryField: (code: string) => GeometryField | null;
|
|
175
|
+
/**
|
|
176
|
+
* Whether a value under this code is a length, and so moves with a unit system.
|
|
177
|
+
*
|
|
178
|
+
* The single question the dictionary's unit kind exists to answer. `false` for
|
|
179
|
+
* an unknown code, which is the same refusal {@link geometryField} makes: a
|
|
180
|
+
* code nobody has classified is not converted, because a guessed conversion is
|
|
181
|
+
* worse than an unconverted number a reader can still recognise.
|
|
182
|
+
*/
|
|
183
|
+
export declare const isLengthField: (code: string) => boolean;
|
|
184
|
+
/**
|
|
185
|
+
* `value`, stated under `code`, converted between systems — or unchanged where
|
|
186
|
+
* the code does not state a length.
|
|
187
|
+
*
|
|
188
|
+
* The conversion and the decision whether to convert in one call, so a caller
|
|
189
|
+
* cannot get the second one right and the first one wrong.
|
|
190
|
+
*/
|
|
191
|
+
export declare const convertGeometry: (code: string, value: number, from: UnitSystem, to: UnitSystem) => number;
|
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interchange dictionary: what a geometry code measures, and whether the
|
|
3
|
+
* number under it converts.
|
|
4
|
+
*
|
|
5
|
+
* Most of these are ISO 13399's own codes with the standard's meanings — the
|
|
6
|
+
* machine-tool industry's interchange vocabulary, which is also why they appear
|
|
7
|
+
* in Fusion's tool JSON. Three are Autodesk's names for measurements ISO codes
|
|
8
|
+
* differently, and {@link GeometryField.iso} records the standard's counterpart
|
|
9
|
+
* rather than quietly renaming them: a consumer recognises the name the scraper
|
|
10
|
+
* emitted, and a reader can still find the standard's.
|
|
11
|
+
*
|
|
12
|
+
* ## Why the dictionary carries a unit kind and not a label
|
|
13
|
+
*
|
|
14
|
+
* The unit kind is the part that changes behaviour: it is what decides whether
|
|
15
|
+
* a stated number converts with {@link UnitSystem} or is the same number in
|
|
16
|
+
* both systems. A flute count and a point angle do not convert, an L/D ratio
|
|
17
|
+
* does not convert, and a length does — and a consumer that converts the wrong
|
|
18
|
+
* one prints a 60-degree drill point as 2.36.
|
|
19
|
+
*
|
|
20
|
+
* Human-facing labels and descriptions are presentational: which words a detail
|
|
21
|
+
* page puts beside `SFDM` is that page's decision and changes with its
|
|
22
|
+
* audience. {@link GeometryField.definition} is not one of those — it is the
|
|
23
|
+
* phrase a diagnostic quotes back at whoever mapped a column to the wrong code,
|
|
24
|
+
* which is why the scraper already carries it.
|
|
25
|
+
*
|
|
26
|
+
* ## An unknown code is not given a meaning
|
|
27
|
+
*
|
|
28
|
+
* {@link geometryField} answers `null` rather than inventing an entry, and
|
|
29
|
+
* {@link isLengthField} answers `false`. A consumer shows an unrecognised code
|
|
30
|
+
* as the vendor's own and does not convert it — the alternative is guessing a
|
|
31
|
+
* unit for a column nobody has checked, and a guessed conversion is a wrong
|
|
32
|
+
* number that looks right.
|
|
33
|
+
*/
|
|
34
|
+
import { convertLength } from './units.js';
|
|
35
|
+
/**
|
|
36
|
+
* The codes this domain knows, keyed by the name the scraper emits.
|
|
37
|
+
*
|
|
38
|
+
* **This vocabulary is the scraper's, not this package's invention.** Renaming
|
|
39
|
+
* a field here would put a translation table between two vocabularies, and a
|
|
40
|
+
* translation table is where an `SFDM` becomes a `DC` in one direction and
|
|
41
|
+
* nobody notices.
|
|
42
|
+
*/
|
|
43
|
+
export const GEOMETRY_FIELDS = {
|
|
44
|
+
DC: { unit: 'mm', definition: 'cutting diameter', iso: 'DC' },
|
|
45
|
+
SFDM: { unit: 'mm', definition: 'shank diameter — what the holder grips', iso: 'DMM' },
|
|
46
|
+
OAL: { unit: 'mm', definition: 'overall length, tip to the end of the shank', iso: 'OAL' },
|
|
47
|
+
LCF: { unit: 'mm', definition: 'flute length — the length of the cutting edge', iso: 'LCF' },
|
|
48
|
+
RE: { unit: 'mm', definition: 'corner radius; 0 on a square-end tool', iso: 'RE' },
|
|
49
|
+
/**
|
|
50
|
+
* **`unit: 'mm'` is not the whole truth, and a caller converting a `TP` off
|
|
51
|
+
* an inch tap should know it.** A metric tap's pitch is a length; an inch
|
|
52
|
+
* tap's is conventionally threads-per-inch, which is a *reciprocal*, and
|
|
53
|
+
* converting one as a length gives a number that looks like a pitch and is
|
|
54
|
+
* wrong by a factor of its own value. No consumer in this tree converts it —
|
|
55
|
+
* the scraper reads it from a single column already in the tool's own system,
|
|
56
|
+
* and the catalog drops the code on ingest for exactly this reason — so the
|
|
57
|
+
* hazard is recorded rather than resolved. Resolving it means either
|
|
58
|
+
* confirming the inch convention against a real tap table or giving the
|
|
59
|
+
* dictionary a unit kind for "not decidable from the code alone".
|
|
60
|
+
*/
|
|
61
|
+
TP: { unit: 'mm', definition: 'thread pitch, in the tool’s own unit system', iso: 'TP' },
|
|
62
|
+
NOF: { unit: 'count', definition: 'number of flutes', iso: 'NOF' },
|
|
63
|
+
SIG: { unit: 'deg', definition: 'point angle, degrees included', iso: 'SIG' },
|
|
64
|
+
/**
|
|
65
|
+
* ISO 13399's clamping length minimum: the shank a manufacturer wants held.
|
|
66
|
+
*
|
|
67
|
+
* No vendor scraped so far publishes it, and the day one does this is where
|
|
68
|
+
* it lands — read in preference to any rule of thumb about how much shank a
|
|
69
|
+
* shop keeps clamped.
|
|
70
|
+
*/
|
|
71
|
+
LSCN: {
|
|
72
|
+
unit: 'mm',
|
|
73
|
+
definition: 'least of the shank the manufacturer wants clamped',
|
|
74
|
+
iso: 'LSCN',
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* Not a vendor's column: how far the tool is set out of the holder.
|
|
78
|
+
*
|
|
79
|
+
* The number the drawing draws and the details table prints, and the one
|
|
80
|
+
* quantity that was computed in four unconnected places and disagreed by a
|
|
81
|
+
* factor of two on an ordinary tool. It is derived, and its provenance says
|
|
82
|
+
* so.
|
|
83
|
+
*/
|
|
84
|
+
LBH: {
|
|
85
|
+
unit: 'mm',
|
|
86
|
+
definition: 'length below holder — how far the tool is set out of the holder nose',
|
|
87
|
+
iso: null,
|
|
88
|
+
},
|
|
89
|
+
/** Length below holder over cutting diameter — the "×D" a shop reads reach in. */
|
|
90
|
+
LD: {
|
|
91
|
+
unit: 'ratio',
|
|
92
|
+
definition: 'length below holder over cutting diameter — the ×D a shop reads reach in',
|
|
93
|
+
iso: null,
|
|
94
|
+
},
|
|
95
|
+
'shoulder-length': {
|
|
96
|
+
unit: 'mm',
|
|
97
|
+
definition: 'usable length below the full shank',
|
|
98
|
+
iso: null,
|
|
99
|
+
},
|
|
100
|
+
'shoulder-diameter': {
|
|
101
|
+
unit: 'mm',
|
|
102
|
+
definition: 'diameter at the shoulder — the neck, where necked',
|
|
103
|
+
iso: null,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
/** What a code measures, or `null` where this dictionary has not pinned it. */
|
|
107
|
+
export const geometryField = (code) => Object.hasOwn(GEOMETRY_FIELDS, code) ? GEOMETRY_FIELDS[code] : null;
|
|
108
|
+
/**
|
|
109
|
+
* Whether a value under this code is a length, and so moves with a unit system.
|
|
110
|
+
*
|
|
111
|
+
* The single question the dictionary's unit kind exists to answer. `false` for
|
|
112
|
+
* an unknown code, which is the same refusal {@link geometryField} makes: a
|
|
113
|
+
* code nobody has classified is not converted, because a guessed conversion is
|
|
114
|
+
* worse than an unconverted number a reader can still recognise.
|
|
115
|
+
*/
|
|
116
|
+
export const isLengthField = (code) => geometryField(code)?.unit === 'mm';
|
|
117
|
+
/**
|
|
118
|
+
* `value`, stated under `code`, converted between systems — or unchanged where
|
|
119
|
+
* the code does not state a length.
|
|
120
|
+
*
|
|
121
|
+
* The conversion and the decision whether to convert in one call, so a caller
|
|
122
|
+
* cannot get the second one right and the first one wrong.
|
|
123
|
+
*/
|
|
124
|
+
export const convertGeometry = (code, value, from, to) => (isLengthField(code) ? convertLength(value, from, to) : value);
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What holds a tool, and the stack the two make together.
|
|
3
|
+
*
|
|
4
|
+
* ## The holder is a union, not one shape with optional extras
|
|
5
|
+
*
|
|
6
|
+
* A holder arrives in one of two forms and they are alternatives rather than a
|
|
7
|
+
* refinement of one by the other: {@link Holder} is what a vendor *publishes*
|
|
8
|
+
* about it, and {@link HolderProfile} is what its own CAD model *measures*.
|
|
9
|
+
* {@link isHolderProfile} tells them apart. A consumer that has both picks one;
|
|
10
|
+
* a consumer that has neither passes `null` and the tool stands alone.
|
|
11
|
+
*
|
|
12
|
+
* ## What is here and what is not
|
|
13
|
+
*
|
|
14
|
+
* Three shapes in this tree called themselves a holder and no two agreed on
|
|
15
|
+
* which fields exist — sixteen, nine and nineteen. What they *did* agree on is
|
|
16
|
+
* the geometry below, which is also exactly what a drawing and a clearance
|
|
17
|
+
* sweep read. Identity and commerce — a guid, a brand, a catalog number, the
|
|
18
|
+
* vendor's own CAD download — belong to a catalog's record, which extends this.
|
|
19
|
+
*
|
|
20
|
+
* ## How a holder grips is optional, and the absence is load bearing
|
|
21
|
+
*
|
|
22
|
+
* {@link Holder.clamping}, {@link Holder.boreDiameter} and {@link Holder.taper}
|
|
23
|
+
* arrived with the functions that read them, and they are optional because a
|
|
24
|
+
* drawing has never needed them: a consumer that hands over nine numbers to get
|
|
25
|
+
* a picture must not have to invent a clamping mode to do it.
|
|
26
|
+
*
|
|
27
|
+
* **Absent means nobody has said, and nobody-has-said refuses.** A holder that
|
|
28
|
+
* does not state how it clamps takes no tool, offers no grip range and matches
|
|
29
|
+
* no taper. That is the same rule {@link holderTakesTool} applies to a tool
|
|
30
|
+
* with no stated shank, and for the same reason: the unchecked case here is a
|
|
31
|
+
* cutter falling out of a spindle.
|
|
32
|
+
*/
|
|
33
|
+
import type { HolderProfile } from './profile.js';
|
|
34
|
+
import type { ProvenanceMap } from './provenance.js';
|
|
35
|
+
import type { Tool } from './tool.js';
|
|
36
|
+
import { type StickoutPolicy, type StickoutRange, type StickoutTool } from './stickout.js';
|
|
37
|
+
import { type ClampingRule } from './clamping.js';
|
|
38
|
+
/**
|
|
39
|
+
* How a holder grips what it holds.
|
|
40
|
+
*
|
|
41
|
+
* `hydraulic` is here rather than folded into `bore` because vendors classify
|
|
42
|
+
* parts as hydraulic outright, and folding it in would be this package
|
|
43
|
+
* reclassifying a family its vendor already named.
|
|
44
|
+
*/
|
|
45
|
+
export type Clamping = 'bore' | 'collet' | 'shrink' | 'hydraulic';
|
|
46
|
+
/**
|
|
47
|
+
* What goes in the spindle, as its vendor publishes it.
|
|
48
|
+
*
|
|
49
|
+
* Every field is nullable because a DIN 4000 sheet is not a promise: each is
|
|
50
|
+
* `null` where the vendor states nothing, and nothing is drawn or swept for it
|
|
51
|
+
* then. An absent number is not a zero — a holder with no stated body diameter
|
|
52
|
+
* is not a holder with no body.
|
|
53
|
+
*/
|
|
54
|
+
export interface Holder {
|
|
55
|
+
/** The nose, where a holder fouls the part before the tool runs out of reach. */
|
|
56
|
+
readonly noseDiameter: number | null;
|
|
57
|
+
readonly noseLength: number | null;
|
|
58
|
+
/** The body behind the nose, where the vendor states it step by step. */
|
|
59
|
+
readonly bodyDiameter: number | null;
|
|
60
|
+
readonly bodyLength: number | null;
|
|
61
|
+
/** Nose face to flange face, in millimetres. */
|
|
62
|
+
readonly projection: number | null;
|
|
63
|
+
readonly flangeDiameter: number | null;
|
|
64
|
+
/**
|
|
65
|
+
* Spindle face to holder nose, in millimetres.
|
|
66
|
+
*
|
|
67
|
+
* Not the same as reach: what sticks out past the nose is the tool's, and
|
|
68
|
+
* that is the number a feature depth is measured against.
|
|
69
|
+
*/
|
|
70
|
+
readonly gaugeLength: number | null;
|
|
71
|
+
/** For a collet holder: which collet series it takes — `ER16`, `PG10`. */
|
|
72
|
+
readonly colletSeries: string | null;
|
|
73
|
+
/**
|
|
74
|
+
* How the holder grips: through a collet, a bore, a shrink fit or hydraulic
|
|
75
|
+
* pressure.
|
|
76
|
+
*
|
|
77
|
+
* A shrink-fit holder and a hydraulic chuck grip the shank directly, the same
|
|
78
|
+
* way a bore does, and they stay apart because the distinction is one a buyer
|
|
79
|
+
* makes — a shrink fit needs an induction heater on the bench and a hydraulic
|
|
80
|
+
* chuck an actuation screw — and because a vendor states which it published.
|
|
81
|
+
*/
|
|
82
|
+
readonly clamping?: Clamping;
|
|
83
|
+
/**
|
|
84
|
+
* For a bore, shrink or hydraulic holder: the one shank diameter it takes, in
|
|
85
|
+
* millimetres.
|
|
86
|
+
*
|
|
87
|
+
* **One diameter, not an upper bound.** A shrink-fit holder bored for 12 mm
|
|
88
|
+
* does not hold a 10 mm shank at all, and treating it as a maximum would put
|
|
89
|
+
* a tool in a holder that drops it.
|
|
90
|
+
*/
|
|
91
|
+
readonly boreDiameter?: number | null;
|
|
92
|
+
/** The spindle interface — `BT30`. A holder only fits the machine that takes it. */
|
|
93
|
+
readonly taper?: string | null;
|
|
94
|
+
/**
|
|
95
|
+
* How far the seated collet stands proud of the nose face, in millimetres.
|
|
96
|
+
*
|
|
97
|
+
* A powRgrip collet is pressed in and its front protrudes; the tool sees the
|
|
98
|
+
* collet's own diameter for that much before the nose.
|
|
99
|
+
*/
|
|
100
|
+
readonly colletProtrusion: number | null;
|
|
101
|
+
readonly provenance?: ProvenanceMap;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Which of the two holder forms this is.
|
|
105
|
+
*
|
|
106
|
+
* On the presence of `points` rather than on a `kind` tag, because a tag would
|
|
107
|
+
* have to be added to {@link Holder} as well and every existing adapter would
|
|
108
|
+
* stop compiling to gain nothing a structural check does not already give.
|
|
109
|
+
*/
|
|
110
|
+
export declare const isHolderProfile: (holder: Holder | HolderProfile) => holder is HolderProfile;
|
|
111
|
+
/**
|
|
112
|
+
* What grips the shank inside a collet holder.
|
|
113
|
+
*
|
|
114
|
+
* As with {@link Holder}, this is the gripping and nothing else. `series` has to
|
|
115
|
+
* equal the holder's exactly — a series is a mechanical interface, not a size
|
|
116
|
+
* class, and an `ER16` collet does not go in an `ER20` nose.
|
|
117
|
+
*/
|
|
118
|
+
export interface Collet {
|
|
119
|
+
/** `ER16`, `PG10` — must equal the holder's series exactly. */
|
|
120
|
+
readonly series: string;
|
|
121
|
+
/** The shank diameters it grips, in millimetres. */
|
|
122
|
+
readonly clampMin: number;
|
|
123
|
+
readonly clampMax: number;
|
|
124
|
+
/**
|
|
125
|
+
* How much shank the collet actually holds, in millimetres.
|
|
126
|
+
*
|
|
127
|
+
* `null` where the vendor does not publish it, and that absence is load
|
|
128
|
+
* bearing: without it there is no honest maximum stickout, and the answer has
|
|
129
|
+
* to be "nobody has said" rather than an invented grip rule.
|
|
130
|
+
*/
|
|
131
|
+
readonly clampLength: number | null;
|
|
132
|
+
readonly provenance?: ProvenanceMap;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A tool, what holds it, and how far it stands out.
|
|
136
|
+
*
|
|
137
|
+
* **The whole reason this package exists is that `stickout` cannot be a bare
|
|
138
|
+
* number a caller worked out on its own.** How far a tool stands out of its
|
|
139
|
+
* holder is a pure function of the tool, the collet and a shop's policy, and
|
|
140
|
+
* before this it had no home: it was computed in four unconnected places, they
|
|
141
|
+
* disagreed by a factor of two on an ordinary tool, and the details table
|
|
142
|
+
* printed one number while the drawing beside it drew another.
|
|
143
|
+
*
|
|
144
|
+
* The arithmetic that resolves it — the clamping rule, the hold share, the
|
|
145
|
+
* collet's cap — is {@link stickoutRange}, and {@link stickoutLimits} is the
|
|
146
|
+
* collet-shaped way into it. A consumer that has already chosen a stickout
|
|
147
|
+
* passes the one it holds; a consumer that has not asks for it here rather than
|
|
148
|
+
* working out a fifth answer of its own.
|
|
149
|
+
*/
|
|
150
|
+
export interface Assembly {
|
|
151
|
+
readonly tool: Tool;
|
|
152
|
+
readonly holder: Holder | HolderProfile | null;
|
|
153
|
+
/** Null for a bore or shrink holder, which grips the shank directly, and for no holder at all. */
|
|
154
|
+
readonly collet: Collet | null;
|
|
155
|
+
/**
|
|
156
|
+
* Tool tip to holder nose, in millimetres — the reach of the stack, as set.
|
|
157
|
+
*
|
|
158
|
+
* `null` draws the tool alone and checks nothing against a part: it is "nobody
|
|
159
|
+
* has decided", not zero.
|
|
160
|
+
*/
|
|
161
|
+
readonly stickout: number | null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A collet fits a holder when the holder takes collets of exactly its series.
|
|
165
|
+
*
|
|
166
|
+
* A series is a mechanical interface and not a size class: an `ER16` collet
|
|
167
|
+
* does not go in an `ER20` nose.
|
|
168
|
+
*/
|
|
169
|
+
export declare const colletFitsHolder: (collet: Pick<Collet, "series">, holder: Pick<Holder, "clamping" | "colletSeries">) => boolean;
|
|
170
|
+
/** Whether a collet grips a given shank diameter, in millimetres. */
|
|
171
|
+
export declare const gripsShank: (collet: Pick<Collet, "clampMin" | "clampMax">, shank: number) => boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Whether a holder takes this tool's shank, with the collet if it needs one.
|
|
174
|
+
*
|
|
175
|
+
* **A tool whose shank the vendor does not state is refused, not assumed to
|
|
176
|
+
* fit.** This is the one place the domain differs from "what is not stated is
|
|
177
|
+
* not checked", because here the unchecked case is a cutter falling out of a
|
|
178
|
+
* spindle.
|
|
179
|
+
*/
|
|
180
|
+
export declare const holderTakesTool: (holder: Pick<Holder, "clamping" | "colletSeries" | "boreDiameter">, collet: Collet | null, tool: Pick<Tool, "geometry">) => boolean;
|
|
181
|
+
/**
|
|
182
|
+
* The furthest a tool can stand out of its holder, in millimetres: overall
|
|
183
|
+
* length less the length that has to stay gripped.
|
|
184
|
+
*
|
|
185
|
+
* `null` when either is unstated. A maximum stickout is exactly the number
|
|
186
|
+
* somebody would use to decide a deep pocket is reachable, and a guessed one is
|
|
187
|
+
* worse than an absent one. A bore or shrink holder's grip length is the
|
|
188
|
+
* holder's rather than a collet's, and this package does not carry it — so
|
|
189
|
+
* those answer `null` too, honestly, until the contract gains it.
|
|
190
|
+
*/
|
|
191
|
+
export declare const maxStickout: (tool: Pick<Tool, "geometry">, collet: Pick<Collet, "clampLength"> | null) => number | null;
|
|
192
|
+
export type HoldBand = 'good' | 'medium' | 'bad';
|
|
193
|
+
/**
|
|
194
|
+
* How well the holder has hold of the tool at this stickout, by the share of
|
|
195
|
+
* the overall length left in the holder.
|
|
196
|
+
*
|
|
197
|
+
* At or above `good` is good; between `least` and that is possible but bad;
|
|
198
|
+
* below `least` is not compatible. The thresholds are a shop's, handed in as
|
|
199
|
+
* fractions rather than named here, because they are the same knob
|
|
200
|
+
* {@link StickoutPolicy.heldShare} is and a package must not carry two.
|
|
201
|
+
*/
|
|
202
|
+
export declare const holdBand: (tool: Pick<Tool, "geometry">, stickout: number, thresholds: {
|
|
203
|
+
readonly good: number;
|
|
204
|
+
readonly least: number;
|
|
205
|
+
}) => HoldBand | null;
|
|
206
|
+
/**
|
|
207
|
+
* How far this tool may stand out of this holder — the collet-shaped way into
|
|
208
|
+
* {@link stickoutRange}.
|
|
209
|
+
*
|
|
210
|
+
* **The arithmetic is not here.** This was one of the four places that worked
|
|
211
|
+
* out a stickout, and the one that capped at a share of the overall length
|
|
212
|
+
* while the clamping rule capped at a length of shank and neither knew about
|
|
213
|
+
* the other. `stickout.ts` owns the quantity and combines the two knobs in one
|
|
214
|
+
* place; this maps a collet onto the grip length that module asks for, which is
|
|
215
|
+
* all a collet was ever contributing.
|
|
216
|
+
*/
|
|
217
|
+
export declare const stickoutLimits: (tool: StickoutTool, collet: Pick<Collet, "clampLength"> | null,
|
|
218
|
+
/** What the holder needs to clear the part, from the sweep: the setup stands out at least this far. */
|
|
219
|
+
required?: number | null, policy?: StickoutPolicy, rule?: ClampingRule) => StickoutRange | null;
|
|
220
|
+
/**
|
|
221
|
+
* The stickout an assembly starts at: the setup length for this tool, held
|
|
222
|
+
* within what the grip allows.
|
|
223
|
+
*
|
|
224
|
+
* A tool whose setup outruns its grip is gripped as short as the grip lets it
|
|
225
|
+
* and no shorter — rather than refused, because the shop is the one who knows
|
|
226
|
+
* whether that is a problem.
|
|
227
|
+
*/
|
|
228
|
+
export declare const defaultStickout: (tool: StickoutTool & Pick<Tool, "geometry">, collet: Pick<Collet, "clampLength"> | null) => number | null;
|
|
229
|
+
/**
|
|
230
|
+
* The shank diameters a crib can grip, given what it is asked to hold with.
|
|
231
|
+
*
|
|
232
|
+
* Every rule above reduces to one number — the shank — so "can anything here
|
|
233
|
+
* hold this tool" is a question about a set of diameters. Working that set out
|
|
234
|
+
* once and asking it per tool is what makes holding usable as a filter: asked
|
|
235
|
+
* tool by tool it is holders × collets × tools, which on a real catalog is tens
|
|
236
|
+
* of millions of comparisons per keystroke.
|
|
237
|
+
*/
|
|
238
|
+
export interface GripRanges {
|
|
239
|
+
/** Closed intervals a collet grips, in millimetres. */
|
|
240
|
+
readonly spans: ReadonlyArray<readonly [number, number]>;
|
|
241
|
+
/** Exact diameters a bore or shrink holder takes. */
|
|
242
|
+
readonly bores: ReadonlyArray<number>;
|
|
243
|
+
}
|
|
244
|
+
/** `taper` narrows to one spindle interface, `colletSeries` to one collet family; either left out means "any". */
|
|
245
|
+
export declare const gripRanges: (holders: readonly Pick<Holder, "clamping" | "colletSeries" | "boreDiameter" | "taper">[], collets: readonly Collet[], want?: {
|
|
246
|
+
readonly taper?: string | null;
|
|
247
|
+
readonly colletSeries?: string | null;
|
|
248
|
+
}) => GripRanges;
|
|
249
|
+
/**
|
|
250
|
+
* Whether anything in {@link gripRanges} holds this shank, in millimetres.
|
|
251
|
+
*
|
|
252
|
+
* **Through {@link gripsShank} and {@link boreTakesShank}, not a second
|
|
253
|
+
* comparison.** This is the fast filter and `holderTakesTool` is the exact
|
|
254
|
+
* check, and the two must agree: asked strictly, a ⅜" shank that converts to
|
|
255
|
+
* 9.524999999999999 misses a collet whose sheet says 9.525, so the crib reports
|
|
256
|
+
* no holder for a tool the holder plainly takes. That is the failure the
|
|
257
|
+
* tolerance above was introduced for, and it belongs on both paths.
|
|
258
|
+
*/
|
|
259
|
+
export declare const gripsAnyShank: (ranges: GripRanges, shank: number) => boolean;
|
|
260
|
+
/**
|
|
261
|
+
* Whether the crib can hold this tool at all.
|
|
262
|
+
*
|
|
263
|
+
* A tool whose shank the vendor does not state is refused, for the same reason
|
|
264
|
+
* {@link holderTakesTool} refuses it.
|
|
265
|
+
*/
|
|
266
|
+
export declare const canHold: (ranges: GripRanges, tool: Pick<Tool, "geometry">) => boolean;
|