]> Shamusworld >> Repos - architektonas/blob - src/units.cpp
Added base units & display style to drawing.
[architektonas] / src / units.cpp
1 //
2 // units.cpp: Unit conversion/description
3 //
4 // Part of the Architektonas Project
5 // (C) 2022 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // WHO  WHEN        WHAT
11 // ---  ----------  ------------------------------------------------------------
12 // JLH  01/04/2022  Created this file
13
14 #include "units.h"
15
16 QString GetDimensionText(Container * c, double length)
17 {
18         QString dimText;
19
20         if (c->unitStyle == 0)
21         {
22                 // Decimal style
23                 int decPrecision = c->decimalPrecision + 1;
24
25                 if (c->baseUnit == BUInch)
26                 {
27                         dimText = QString("%1\"").arg(length, 0, 'f', decPrecision);
28                 }
29                 else if (c->baseUnit == BUFoot)
30                 {
31                         double feet = (double)((int)length);
32                         double inches = (length - feet) * 12.0;
33
34                         QString ftText = (feet != 0 ? QString("%1'").arg(feet) : "");
35                         QString inText = (inches != 0 ? QString(" %1\"").arg(inches, 0, 'f', decPrecision) : "");
36
37                         dimText = QString("%1%2").arg(ftText).arg(inText).trimmed();
38                 }
39                 else if (c->baseUnit == BUYard)
40                 {
41                         double yards = (double)((int)length);
42                         double feet = (length - yards) * 3.0;
43                         double inches = (feet - ((int)feet)) * 12.0;
44                         feet = (double)((int)feet); // Integerize the feet now...
45
46                         QString ydText = (yards != 0 ? QString("%1 yd").arg(yards) : "");
47                         QString ftText = (feet != 0 ? QString(" %1'").arg(feet) : "");
48                         QString inText = (inches != 0 ? QString(" %1\"").arg(inches, 0, 'f', decPrecision) : "");
49
50                         dimText = QString("%1%2%3")
51                                 .arg(ydText)
52                                 .arg(ftText)
53                                 .arg(inText)
54                                 .trimmed();
55                 }
56                 else // mile, mm, cm, m, km
57                 {
58                         dimText = QString("%1 %2")
59                                 .arg(length, 0, 'f', decPrecision)
60                                 .arg(buShortName[c->baseUnit]);
61                 }
62         }
63         else
64         {
65                 // Fractional style
66                 int fracPrecision = 1 << (c->fractionalPrecision + 1);
67
68                 if (c->baseUnit == BUInch)
69                 {
70                         dimText = MakeFraction(length, fracPrecision) + QChar('"');
71                 }
72                 else if (c->baseUnit == BUFoot)
73                 {
74                         double feet = (double)((int)length);
75                         double inches = (length - feet) * 12.0;
76
77                         QString ftText = (feet != 0 ? QString("%1'").arg(feet) : "");
78                         QString inText = (inches != 0 ? MakeFraction(inches, fracPrecision) + QChar('"') : "");
79
80                         dimText = QString("%1 %2").arg(ftText).arg(inText).trimmed();
81                 }
82                 else
83                 {
84                         dimText = QString("%1 %2").arg(MakeFraction(length, fracPrecision)).arg(buShortName[c->baseUnit]);
85                 }
86         }
87
88         return dimText;
89 }
90
91 //
92 // Create a string that represents the passed in double as a proper fraction
93 // with the given precision.  Fractions are rounded to the given precision
94 // (which represents the denominator of the fraction).
95 //
96 QString MakeFraction(double num, int precision)
97 {
98         int intPart = (int)num;
99         double fraction = num - (double)intPart;
100         int numerator = (int)(((double)precision * fraction) + 0.5);
101
102         // There's a chance we rounded up to the next whole number; if so, we fix
103         // that here.
104         if (numerator == precision)
105         {
106                 intPart++;
107                 numerator = 0;
108         }
109
110         // Reduce the fraction by casting out factors of two (we assume the
111         // precision will always be a power of two); that is, if there is a
112         // denominator to reduce.
113         if (numerator > 0)
114         {
115                 // Divide fraction by two while the denominator is not odd.  N.B.: This
116                 // will always end, as any non-zero number will eventually have a 1-bit
117                 // in it somewhere, which we shift down to the low bit position with
118                 // each iteration.
119                 while ((numerator & 0x01) == 0)
120                 {
121                         numerator /= 2;
122                         precision /= 2;
123                 }
124         }
125
126         QString intText = (intPart != 0 ? QString("%1").arg(intPart) : "");
127         QString fracText = (numerator != 0 ? QString(" %1/%2").arg(numerator).arg(precision) : "");
128
129         return QString("%1%2").arg(intText).arg(fracText).trimmed();
130 }