@reekon-tools/boldr-utils 1.10.1 → 1.10.2

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.
@@ -24,6 +24,27 @@ export const roundToT1Values = (value, u) => {
24
24
  return Math.round(value / 500) * 500;
25
25
  }
26
26
  };
27
+ /**
28
+ * Lowest terms. A fraction is read off a tape, so the denominator has to be
29
+ * the smallest one that names the value: 2/16 is written 1/8, never "6 2/16".
30
+ * The tolerance sets the PRECISION the value is rounded to, not the
31
+ * denominator it prints with.
32
+ */
33
+ const reduceFraction = (numerator, denominator) => {
34
+ let a = numerator;
35
+ let b = denominator;
36
+ while (b !== 0) {
37
+ [a, b] = [b, a % b];
38
+ }
39
+ const divisor = a || 1;
40
+ return [numerator / divisor, denominator / divisor];
41
+ };
42
+ /**
43
+ * Re-apply the sign to a composite string built from a magnitude. Guards the
44
+ * `-0` case: a value that rounds to nothing at the current tolerance reads as
45
+ * plain zero, not as a negative.
46
+ */
47
+ const signPrefix = (signed, body) => signed < 0 && /[1-9]/.test(body) ? `-${body}` : body;
27
48
  export const convertMicrometers = (micrometers, unit, fractionalTolerance, decimalTolerance) => {
28
49
  if (micrometers == null || isNaN(micrometers)) {
29
50
  return { value: 'NaN', unit: '' };
@@ -39,18 +60,22 @@ export const convertMicrometers = (micrometers, unit, fractionalTolerance, decim
39
60
  displayUnit = 'in';
40
61
  if (unit === Units.FractionalInches) {
41
62
  const denominator = parseInt(fractionalTolerance, 10);
42
- const whole = Math.floor(inches);
43
- const fractional = inches - whole;
44
- const numerator = Math.round(fractional * denominator);
63
+ // Split the MAGNITUDE, then re-apply the sign: Math.floor walks away
64
+ // from zero on a negative, so -6 1/8 came out as `-7 7/8`.
65
+ const magnitude = Math.abs(inches);
66
+ const whole = Math.floor(magnitude);
67
+ const numerator = Math.round((magnitude - whole) * denominator);
45
68
  if (numerator === denominator) {
46
69
  value = `${whole + 1}`;
47
70
  }
71
+ else if (numerator === 0) {
72
+ value = `${whole}`;
73
+ }
48
74
  else {
49
- value =
50
- numerator === 0
51
- ? `${whole}`
52
- : `${whole} ${numerator}/${denominator}`;
75
+ const [num, den] = reduceFraction(numerator, denominator);
76
+ value = `${whole} ${num}/${den}`;
53
77
  }
78
+ value = signPrefix(inches, value);
54
79
  }
55
80
  else {
56
81
  value = inches.toFixed(decimalTolerance.length - 2);
@@ -61,28 +86,45 @@ export const convertMicrometers = (micrometers, unit, fractionalTolerance, decim
61
86
  case Units.FeetInchesFractional:
62
87
  case Units.FeetInchesDecimal: {
63
88
  const feet = converted.toNumber('ft');
64
- const wholeFeet = Math.floor(feet);
65
- const fractionalFeet = feet - wholeFeet;
89
+ // Both COMPOSITE feet-inches units split the magnitude and re-apply the
90
+ // sign (see the fractional-inch branch) — otherwise -5' 6" printed as
91
+ // `-6' 6"`. Plain decimal feet keeps the signed value: toFixed renders
92
+ // that correctly on its own.
93
+ const composite = unit === Units.FeetInchesFractional ||
94
+ unit === Units.FeetInchesDecimal;
95
+ const magnitudeFeet = composite ? Math.abs(feet) : feet;
96
+ const wholeFeet = Math.floor(magnitudeFeet);
97
+ const fractionalFeet = magnitudeFeet - wholeFeet;
66
98
  displayUnit = 'ft';
67
99
  if (unit === Units.FeetInchesFractional) {
68
100
  const inches = fractionalFeet * 12;
69
- const wholeInches = Math.floor(inches);
70
- const fractional = inches - wholeInches;
71
101
  const denominator = parseInt(fractionalTolerance, 10);
72
- const numerator = Math.round(fractional * denominator);
102
+ let wholeInches = Math.floor(inches);
103
+ let numerator = Math.round((inches - wholeInches) * denominator);
104
+ // Carry, twice: a fraction that rounds up to a whole inch becomes an
105
+ // inch, and a twelfth inch becomes a foot. Without the second carry
106
+ // 5.9999 ft printed as `5' 12"`.
73
107
  if (numerator === denominator) {
74
- value = `${wholeFeet}' ${wholeInches + 1}"`;
108
+ numerator = 0;
109
+ wholeInches += 1;
110
+ }
111
+ let displayFeet = wholeFeet;
112
+ if (wholeInches === 12) {
113
+ wholeInches = 0;
114
+ displayFeet += 1;
115
+ }
116
+ if (numerator === 0) {
117
+ value = `${displayFeet}' ${wholeInches}"`;
75
118
  }
76
119
  else {
77
- value =
78
- numerator === 0
79
- ? `${wholeFeet}' ${wholeInches}"`
80
- : `${wholeFeet}' ${wholeInches} ${numerator}/${denominator}"`;
120
+ const [num, den] = reduceFraction(numerator, denominator);
121
+ value = `${displayFeet}' ${wholeInches} ${num}/${den}"`;
81
122
  }
123
+ value = signPrefix(feet, value);
82
124
  }
83
125
  else if (unit === Units.FeetInchesDecimal) {
84
126
  const inches = (fractionalFeet * 12).toFixed(decimalTolerance.length - 2);
85
- value = `${wholeFeet}' ${inches}"`;
127
+ value = signPrefix(feet, `${wholeFeet}' ${inches}"`);
86
128
  }
87
129
  else {
88
130
  value = feet.toFixed(decimalTolerance.length - 2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",