mechanical-tolerance-calculator 1.0.3 → 1.0.5
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 +1 -1
- package/index.js +286 -26
- package/package.json +1 -1
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -96,40 +96,299 @@ function returnTolerancesFor(executableMaterialType, spec = "") {
|
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
function parseNominalFromMeasurement(measurement) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
function parseNominalFromMeasurement(measurement, materialType) {
|
|
100
|
+
// For shafts: upper_deviation is 0, so measurement ≤ nominal
|
|
101
|
+
// Therefore, nominal must be ceiling of measurement
|
|
102
|
+
if (materialType === "shafts") {
|
|
103
|
+
return Math.ceil(measurement);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// For bores: lower_deviation is 0, so measurement ≥ nominal
|
|
107
|
+
// Therefore, nominal must be floor of measurement
|
|
108
|
+
if (materialType === "housingBores" || materialType === "shellBores") {
|
|
109
|
+
return Math.floor(measurement);
|
|
107
110
|
}
|
|
108
|
-
|
|
111
|
+
|
|
112
|
+
// Default: round to nearest
|
|
113
|
+
return Math.round(measurement);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const MATERIAL_TYPE_CONFIG = {
|
|
117
|
+
shafts: {
|
|
118
|
+
specification: "h9",
|
|
119
|
+
itGrade: "IT5",
|
|
120
|
+
|
|
121
|
+
rangeMatch: (nominal, spec) =>
|
|
122
|
+
nominal > spec.minimum_diameter && nominal <= spec.maximum_diameter,
|
|
123
|
+
},
|
|
124
|
+
housingBores: {
|
|
125
|
+
specification: "H8",
|
|
126
|
+
itGrade: "IT6",
|
|
127
|
+
|
|
128
|
+
rangeMatch: (nominal, spec) =>
|
|
129
|
+
nominal >= spec.minimum_diameter && nominal < spec.maximum_diameter,
|
|
130
|
+
},
|
|
131
|
+
shellBores: {
|
|
132
|
+
specification: "H9",
|
|
133
|
+
itGrade: "IT6",
|
|
134
|
+
rangeMatch: (nominal, spec) =>
|
|
135
|
+
nominal >= spec.minimum_diameter && nominal < spec.maximum_diameter,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function findMatchingSpec(nominal, specs, rangeMatchFn) {
|
|
140
|
+
return specs.find((spec) => rangeMatchFn(nominal, spec)) || null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function calculateComputedBounds(nominal, spec) {
|
|
144
|
+
return {
|
|
145
|
+
upperBound: parseComputedBound(nominal, spec.upper_deviation, 3),
|
|
146
|
+
lowerBound: parseComputedBound(nominal, spec.lower_deviation, 3),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function calculateUncomputedBounds(nominal, spec) {
|
|
151
|
+
return {
|
|
152
|
+
upperBound: parseUncomputedBound(nominal, spec.upper_deviation, "+"),
|
|
153
|
+
lowerBound: parseUncomputedBound(nominal, spec.lower_deviation, "-"),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function checkMeetsSpecification(measurement, bounds) {
|
|
158
|
+
const measure = parseStringFloat(measurement);
|
|
159
|
+
const upper = parseStringFloat(bounds.upperBound);
|
|
160
|
+
const lower = parseStringFloat(bounds.lowerBound);
|
|
161
|
+
|
|
162
|
+
return measure >= lower && measure <= upper;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function processMeasurement(materialType, measurement, tolerances) {
|
|
166
|
+
const config = MATERIAL_TYPE_CONFIG[materialType];
|
|
167
|
+
|
|
168
|
+
if (!config) {
|
|
169
|
+
return {
|
|
170
|
+
error: true,
|
|
171
|
+
message: `Unknown material type: ${materialType}`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Calculate nominal diameter
|
|
176
|
+
const nominal = parseNominalFromMeasurement(measurement, materialType);
|
|
177
|
+
|
|
178
|
+
// Find matching specification
|
|
179
|
+
const matchedSpec = findMatchingSpec(
|
|
180
|
+
nominal,
|
|
181
|
+
tolerances.specification,
|
|
182
|
+
config.rangeMatch
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (!matchedSpec) {
|
|
186
|
+
return {
|
|
187
|
+
error: true,
|
|
188
|
+
message: `No specification found for nominal diameter: ${nominal}`,
|
|
189
|
+
nominal,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Calculate bounds
|
|
194
|
+
const computedBounds = calculateComputedBounds(nominal, matchedSpec);
|
|
195
|
+
const uncomputedBounds = calculateUncomputedBounds(nominal, matchedSpec);
|
|
196
|
+
|
|
197
|
+
// Check if measurement meets specification
|
|
198
|
+
const meetsSpec = checkMeetsSpecification(measurement, computedBounds);
|
|
199
|
+
const specMeetingReason = meetsSpec
|
|
200
|
+
? `${parseToFixedThreeString(measurement)} falls between ${
|
|
201
|
+
computedBounds.lowerBound
|
|
202
|
+
} and ${computedBounds.upperBound}`
|
|
203
|
+
: `${parseToFixedThreeString(measurement)} doesn't fall between ${
|
|
204
|
+
computedBounds.lowerBound
|
|
205
|
+
} and ${computedBounds.upperBound}`;
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
measurement: parseStringFloat(measurement),
|
|
209
|
+
nominal,
|
|
210
|
+
specification: config.specification,
|
|
211
|
+
IT_grade: config.itGrade,
|
|
212
|
+
computed_specification_bounds: computedBounds,
|
|
213
|
+
uncomputed_specification_bounds: uncomputedBounds,
|
|
214
|
+
matched_spec: matchedSpec,
|
|
215
|
+
|
|
216
|
+
meets_specification: { meetsSpec, reason: specMeetingReason },
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function processOneMeasurement(materialType, measurement, tolerances) {
|
|
221
|
+
const processedMeasurement = processMeasurement(
|
|
222
|
+
materialType,
|
|
223
|
+
measurement,
|
|
224
|
+
tolerances
|
|
225
|
+
);
|
|
226
|
+
return {
|
|
227
|
+
...processedMeasurement,
|
|
228
|
+
meets_IT_tolerance: processedMeasurement.meet_specification,
|
|
229
|
+
};
|
|
109
230
|
}
|
|
110
231
|
|
|
111
232
|
function checkOneMeasurementFor(materialType, measurement) {
|
|
112
233
|
const camcoStandardTolerances = getCamcoStandardTolerancesFor(materialType);
|
|
113
|
-
let nominal = parseNominalFromMeasurement(measurement);
|
|
114
|
-
let matchedSpec = {};
|
|
115
|
-
if (camcoStandardTolerances.type === "shafts") {
|
|
116
|
-
const shaftNominal = nominal + 1;
|
|
117
|
-
const specs = camcoStandardTolerances["specification"];
|
|
118
|
-
Array.from(specs).forEach((spec) => {
|
|
119
|
-
if (
|
|
120
|
-
shaftNominal > spec.minimum_diameter &&
|
|
121
|
-
shaftNominal <= spec.maximum_diameter
|
|
122
|
-
) {
|
|
123
|
-
matchedSpec = spec;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
234
|
|
|
127
|
-
|
|
128
|
-
|
|
235
|
+
if (camcoStandardTolerances.error) {
|
|
236
|
+
return camcoStandardTolerances;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (typeof measurement !== "number" || isNaN(measurement)) {
|
|
240
|
+
return {
|
|
241
|
+
error: true,
|
|
242
|
+
message: "Invalid measurement value",
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return processOneMeasurement(
|
|
247
|
+
camcoStandardTolerances.type,
|
|
248
|
+
measurement,
|
|
249
|
+
camcoStandardTolerances
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function parseComputedBound(base, value, decimalCount) {
|
|
254
|
+
return Number(base + parseStringFloat(value)).toFixed(decimalCount);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function parseUncomputedBound(value1, value2, sign) {
|
|
258
|
+
if (value2.startsWith("-")) {
|
|
259
|
+
return (
|
|
260
|
+
parseToFixedThreeString(value1) +
|
|
261
|
+
" " +
|
|
262
|
+
sign +
|
|
263
|
+
" " +
|
|
264
|
+
parseToFixedThreeString(value2.slice(1, value2.length))
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
parseToFixedThreeString(value1) +
|
|
270
|
+
" " +
|
|
271
|
+
sign +
|
|
272
|
+
" " +
|
|
273
|
+
parseToFixedThreeString(value2)
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function parseToFixedThreeString(value) {
|
|
278
|
+
if (typeof value === "number") {
|
|
279
|
+
return value.toFixed(3);
|
|
280
|
+
}
|
|
281
|
+
return value;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Converts string float values to actual float numbers
|
|
286
|
+
* @param {string} value - The string representation of a float number
|
|
287
|
+
* @returns {number} - The parsed float number
|
|
288
|
+
*/
|
|
289
|
+
function parseStringFloat(value) {
|
|
290
|
+
// Handle edge cases
|
|
291
|
+
if (value === null || value === undefined) {
|
|
292
|
+
return 0;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// If it's already a number, return it
|
|
296
|
+
if (typeof value === "number") {
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Convert string to float
|
|
301
|
+
const parsed = parseFloat(value);
|
|
302
|
+
|
|
303
|
+
// Return 0 if parsing fails (NaN)
|
|
304
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
305
|
+
}
|
|
306
|
+
function processIndividualMeasurement(
|
|
307
|
+
materialType,
|
|
308
|
+
measurement,
|
|
309
|
+
tolerances,
|
|
310
|
+
meetsIT,
|
|
311
|
+
ITMeetingReason
|
|
312
|
+
) {
|
|
313
|
+
const processedMeasurement = processMeasurement(
|
|
314
|
+
materialType,
|
|
315
|
+
measurement,
|
|
316
|
+
tolerances
|
|
317
|
+
);
|
|
318
|
+
return {
|
|
319
|
+
...processedMeasurement,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function checkMultipleMeasurementsFor(materialType, measurements) {
|
|
324
|
+
const validation = validateMeasurements(measurements);
|
|
325
|
+
if (validation?.error) {
|
|
326
|
+
return validation;
|
|
327
|
+
}
|
|
328
|
+
const camcoStandardTolerances = getCamcoStandardTolerancesFor(materialType);
|
|
329
|
+
|
|
330
|
+
let largestMeasurement = Math.max(...measurements);
|
|
331
|
+
let smallestMeasurement = Math.min(...measurements);
|
|
332
|
+
let ITDifference = parseToFixedThreeString(
|
|
333
|
+
largestMeasurement - smallestMeasurement
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const ITs = {
|
|
337
|
+
IT5: 0,
|
|
338
|
+
IT6: 0,
|
|
339
|
+
IT7: 0,
|
|
340
|
+
IT8: 0,
|
|
341
|
+
IT9: 0,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const results = measurements.map((measurement) => {
|
|
345
|
+
const result = processIndividualMeasurement(
|
|
346
|
+
camcoStandardTolerances.type,
|
|
347
|
+
measurement,
|
|
348
|
+
camcoStandardTolerances
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
ITs[result.IT_grade]++;
|
|
352
|
+
|
|
353
|
+
return result;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const baseSpec = results[0];
|
|
357
|
+
const baseITValue = baseSpec.matched_spec[baseSpec.IT_grade];
|
|
358
|
+
|
|
359
|
+
const meetsIT = ITDifference <= baseITValue;
|
|
360
|
+
const itMeetingReason = meetsIT
|
|
361
|
+
? `The difference between ${parseToFixedThreeString(
|
|
362
|
+
largestMeasurement
|
|
363
|
+
)} and ${parseToFixedThreeString(
|
|
364
|
+
smallestMeasurement
|
|
365
|
+
)} is less than or equal to ${baseITValue}.`
|
|
366
|
+
: `The difference between ${parseToFixedThreeString(
|
|
367
|
+
largestMeasurement
|
|
368
|
+
)} and ${parseToFixedThreeString(
|
|
369
|
+
smallestMeasurement
|
|
370
|
+
)} is greater than to ${baseITValue}.`;
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
baseSpec,
|
|
374
|
+
meets_IT_Tolerance: { meetsIT, reason: itMeetingReason },
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function validateMeasurements(measurements) {
|
|
379
|
+
if (!Array.isArray(measurements)) {
|
|
380
|
+
return {
|
|
381
|
+
error: "Measurements must be an array of numbers",
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (measurements.length === 0) {
|
|
386
|
+
return {
|
|
387
|
+
error: "Measurements array cannot be empty",
|
|
388
|
+
};
|
|
129
389
|
}
|
|
130
|
-
console.log(nominal);
|
|
131
390
|
|
|
132
|
-
|
|
391
|
+
return null;
|
|
133
392
|
}
|
|
134
393
|
|
|
135
394
|
module.exports = {
|
|
@@ -137,4 +396,5 @@ module.exports = {
|
|
|
137
396
|
getCamcoStandardTolerancesFor,
|
|
138
397
|
parseNominalFromMeasurement,
|
|
139
398
|
checkOneMeasurementFor,
|
|
399
|
+
checkMultipleMeasurementsFor,
|
|
140
400
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mechanical-tolerance-calculator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Calculates international standard specification and tolerances for bores, round bars and metals of mechanical units. For examples; H7, H8, H9, h8, h9 specifications and IT5/IT6 tolerances.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|