]> Shamusworld >> Repos - architektonas/blob - src/base/units.cpp
Bugfixes related to removing Snapper class.
[architektonas] / src / base / units.cpp
1 // units.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  05/05/2010  Moved implementation from header to this file. :-)
15 //
16
17 #include "units.h"
18
19 #include <stdio.h>
20 #include "mathextra.h"
21 #include "debug.h"
22
23 /**
24  * Converts a DXF integer () to a Unit enum.
25  */
26 RS2::Unit Units::dxfint2unit(int dxfint)
27 {
28     return (RS2::Unit)dxfint;
29
30     /*switch(dxfint) {
31     default:
32     case  0:
33         return RS2::None;
34     case  1:
35         return RS2::Inch;
36     case  2:
37         return RS2::Foot;
38     case  3:
39         return RS2::Mile;
40     case  4:
41         return RS2::Millimeter;
42     case  5:
43         return RS2::Centimeter;
44     case  6:
45         return RS2::Meter;
46     case  7:
47         return RS2::Kilometer;
48     case  8:
49         return RS2::Microinch;
50     case  9:
51         return RS2::Mil;
52     case 10:
53         return RS2::Yard;
54     case 11:
55         return RS2::Angstrom;
56     case 12:
57         return RS2::Nanometer;
58     case 13:
59         return RS2::Micron;
60     case 14:
61         return RS2::Decimeter;
62     case 15:
63         return RS2::Decameter;
64     case 16:
65         return RS2::Hectometer;
66     case 17:
67         return RS2::Gigameter;
68     case 18:
69         return RS2::Astro;
70     case 19:
71         return RS2::Lightyear;
72     case 20:
73         return RS2::Parsec;
74 }*/
75 }
76
77 /**
78  * @return a short string representing the given unit (e.g. "mm")
79  */
80 QString Units::unitToSign(RS2::Unit u)
81 {
82     QString ret = "";
83
84     switch (u)
85         {
86     case RS2::None:
87         ret = "";
88         break;
89     case RS2::Inch:
90         ret = "\"";
91         break;
92     case RS2::Foot:
93         ret = "'";
94         break;
95     case RS2::Mile:
96         ret = "mi";
97         break;
98     case RS2::Millimeter:
99         ret = "mm";
100         break;
101     case RS2::Centimeter:
102         ret = "cm";
103         break;
104     case RS2::Meter:
105         ret = "m";
106         break;
107     case RS2::Kilometer:
108         ret = "km";
109         break;
110     case RS2::Microinch:
111         ret = "�\"";
112         break;
113     case RS2::Mil:
114         ret = "mil";
115         break;
116     case RS2::Yard:
117         ret = "yd";
118         break;
119     case RS2::Angstrom:
120         ret = "A";
121         break;
122     case RS2::Nanometer:
123         ret = "nm";
124         break;
125     case RS2::Micron:
126         ret = "�m";
127         break;
128     case RS2::Decimeter:
129         ret = "dm";
130         break;
131     case RS2::Decameter:
132         ret = "dam";
133         break;
134     case RS2::Hectometer:
135         ret = "hm";
136         break;
137     case RS2::Gigameter:
138         ret = "Gm";
139         break;
140     case RS2::Astro:
141         ret = "astro";
142         break;
143     case RS2::Lightyear:
144         ret = "ly";
145         break;
146     case RS2::Parsec:
147         ret = "pc";
148         break;
149
150     default:
151         ret = "";
152         break;
153     }
154
155     return ret;
156 }
157
158 /**
159  * @return a string representing the given unit (e.g. "Millimeter").
160  *      translated if @a t is true (the default).
161  */
162 QString Units::unitToString(RS2::Unit u, bool t)
163 {
164     QString ret = "";
165
166     switch (u)
167         {
168     case RS2::None:
169         ret = t ? QObject::tr("None") : QString("None");
170         break;
171     case RS2::Inch:
172         ret = t ? QObject::tr("Inch") : QString("Inch");
173         break;
174     case RS2::Foot:
175         ret = t ? QObject::tr("Foot") : QString("Foot");
176         break;
177     case RS2::Mile:
178         ret = t ? QObject::tr("Mile") : QString("Mile");
179         break;
180     case RS2::Millimeter:
181         ret = t ? QObject::tr("Millimeter") : QString("Millimeter");
182         break;
183     case RS2::Centimeter:
184         ret = t ? QObject::tr("Centimeter") : QString("Centimeter");
185         break;
186     case RS2::Meter:
187         ret = t ? QObject::tr("Meter") : QString("Meter");
188         break;
189     case RS2::Kilometer:
190         ret = t ? QObject::tr("Kilometer") : QString("Kilometer");
191         break;
192     case RS2::Microinch:
193         ret = t ? QObject::tr("Microinch") : QString("Microinch");
194         break;
195     case RS2::Mil:
196         ret = t ? QObject::tr("Mil") : QString("Mil");
197         break;
198     case RS2::Yard:
199         ret = t ? QObject::tr("Yard") : QString("Yard");
200         break;
201     case RS2::Angstrom:
202         ret = t ? QObject::tr("Angstrom") : QString("Angstrom");
203         break;
204     case RS2::Nanometer:
205         ret = t ? QObject::tr("Nanometer") : QString("Nanometer");
206         break;
207     case RS2::Micron:
208         ret = t ? QObject::tr("Micron") : QString("Micron");
209         break;
210     case RS2::Decimeter:
211         ret = t ? QObject::tr("Decimeter") : QString("Decimeter");
212         break;
213     case RS2::Decameter:
214         ret = t ? QObject::tr("Decameter") : QString("Decameter");
215         break;
216     case RS2::Hectometer:
217         ret = t ? QObject::tr("Hectometer") : QString("Hectometer");
218         break;
219     case RS2::Gigameter:
220         ret = t ? QObject::tr("Gigameter") : QString("Gigameter");
221         break;
222     case RS2::Astro:
223         ret = t ? QObject::tr("Astro") : QString("Astro");
224         break;
225     case RS2::Lightyear:
226         ret = t ? QObject::tr("Lightyear") : QString("Lightyear");
227         break;
228     case RS2::Parsec:
229         ret = t ? QObject::tr("Parsec") : QString("Parsec");
230         break;
231
232     default:
233         ret = "";
234         break;
235     }
236
237     return ret;
238 }
239
240 /**
241  * Converts a string into a unit enum.
242  */
243 RS2::Unit Units::stringToUnit(const QString & u)
244 {
245         RS2::Unit ret = RS2::None;
246
247         if (u == "None")
248                 ret = RS2::None;
249         else if (u == QObject::tr("Inch"))
250                 ret = RS2::Inch;
251         else if (u == QObject::tr("Foot"))
252                 ret = RS2::Foot;
253         else if (u == QObject::tr("Mile"))
254                 ret = RS2::Mile;
255         else if (u == QObject::tr("Millimeter"))
256                 ret = RS2::Millimeter;
257         else if (u == QObject::tr("Centimeter"))
258                 ret = RS2::Centimeter;
259         else if (u == QObject::tr("Meter"))
260                 ret = RS2::Meter;
261         else if (u == QObject::tr("Kilometer"))
262                 ret = RS2::Kilometer;
263         else if (u == QObject::tr("Microinch"))
264                 ret = RS2::Microinch;
265         else if (u == QObject::tr("Mil"))
266                 ret = RS2::Mil;
267         else if (u == QObject::tr("Yard"))
268                 ret = RS2::Yard;
269         else if (u == QObject::tr("Angstrom"))
270                 ret = RS2::Angstrom;
271         else if (u == QObject::tr("Nanometer"))
272                 ret = RS2::Nanometer;
273         else if (u == QObject::tr("Micron"))
274                 ret = RS2::Micron;
275         else if (u == QObject::tr("Decimeter"))
276                 ret = RS2::Decimeter;
277         else if (u == QObject::tr("Decameter"))
278                 ret = RS2::Decameter;
279         else if (u == QObject::tr("Hectometer"))
280                 ret = RS2::Hectometer;
281         else if (u == QObject::tr("Gigameter"))
282                 ret = RS2::Gigameter;
283         else if (u == QObject::tr("Astro"))
284                 ret = RS2::Astro;
285         else if (u == QObject::tr("Lightyear"))
286                 ret = RS2::Lightyear;
287         else if (u == QObject::tr("Parsec"))
288                 ret = RS2::Parsec;
289
290         return ret;
291 }
292
293 /**
294  * @return true: the unit is metric, false: the unit is imperial.
295  */
296 bool Units::isMetric(RS2::Unit u)
297 {
298         if (u == RS2::Millimeter || u == RS2::Centimeter || u == RS2::Meter
299                 || u == RS2::Kilometer || u == RS2::Angstrom || u == RS2::Nanometer
300                 || u == RS2::Micron || u == RS2::Decimeter || u == RS2::Decameter
301                 || u == RS2::Hectometer || u == RS2::Gigameter || u == RS2::Astro
302                 || u == RS2::Lightyear || u == RS2::Parsec)
303                 return true;
304
305         return false;
306 }
307
308 /**
309  * @return factor to convert the given unit to Millimeters.
310  */
311 double Units::getFactorToMM(RS2::Unit u)
312 {
313         double ret = 1.0;
314
315         switch (u)
316         {
317         case RS2::None:
318                 ret = 1.0;
319                 break;
320         case RS2::Inch:
321                 ret = 25.4;
322                 break;
323         case RS2::Foot:
324                 ret = 304.8;
325                 break;
326         case RS2::Mile:
327                 ret = 1609344;
328                 break;
329         case RS2::Millimeter:
330                 ret = 1.0;
331                 break;
332         case RS2::Centimeter:
333                 ret = 10;
334                 break;
335         case RS2::Meter:
336                 ret = 1000;
337                 break;
338         case RS2::Kilometer:
339                 ret = 1000000;
340                 break;
341         case RS2::Microinch:
342                 ret = 0.0000254;
343                 break;
344         case RS2::Mil:
345                 ret = 0.0254;
346                 break;
347         case RS2::Yard:
348                 ret = 914.4;
349                 break;
350         case RS2::Angstrom:
351                 ret = 0.0000001;
352                 break;
353         case RS2::Nanometer:
354                 ret = 0.000001;
355                 break;
356         case RS2::Micron:
357                 ret = 0.001;
358                 break;
359         case RS2::Decimeter:
360                 ret = 100.0;
361                 break;
362         case RS2::Decameter:
363                 ret = 10000.0;
364                 break;
365         case RS2::Hectometer:
366                 ret = 100000.0;
367                 break;
368         case RS2::Gigameter:
369                 ret = 1000000000.0;
370                 break;
371         case RS2::Astro:
372                 ret = 149600000000000.0;
373                 break;
374         case RS2::Lightyear:
375                 ret = 9460731798000000000.0;
376                 break;
377         case RS2::Parsec:
378                 ret = 30857000000000000000.0;
379                 break;
380         default:
381                 ret = 1.0;
382                 break;
383         }
384
385         return ret;
386 }
387
388 /**
389  * Converts the given value 'val' from unit 'src' to unit 'dest'.
390  */
391 double Units::convert(double val, RS2::Unit src, RS2::Unit dest)
392 {
393         if (getFactorToMM(dest) > 0.0)
394         {
395                 return (val * getFactorToMM(src)) / getFactorToMM(dest);
396         }
397         else
398         {
399                 DEBUG->print(Debug::D_WARNING, "Units::convert: invalid factor");
400                 return val;
401         }
402 }
403
404 /**
405  * Converts the given vector 'val' from unit 'src' to unit 'dest'.
406  */
407 Vector Units::convert(const Vector val, RS2::Unit src, RS2::Unit dest)
408 {
409         return Vector(convert(val.x, src, dest), convert(val.y, src, dest), convert(val.z, src, dest));
410 }
411
412 /**
413  * Formats the given length in the given format.
414  *
415  * @param length The length in the current unit of the drawing.
416  * @param format Format of the string.
417  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
418  & @param showUnit Append unit to the value.
419  */
420 QString Units::formatLinear(double length, RS2::Unit unit, RS2::LinearFormat format,
421         int prec, bool showUnit)
422 {
423     QString ret;
424
425     // unit appended to value (e.g. 'mm'):
426     /*QString unitString = "";
427     if (showUnit) {
428         unitString = unitToSign(unit);
429 }*/
430
431         // Barbarian display: Show as fraction:
432         switch (format)
433         {
434         case RS2::Scientific:
435                 ret = formatScientific(length, unit, prec, showUnit);
436                 break;
437
438         case RS2::Decimal:
439                 ret = formatDecimal(length, unit, prec, showUnit);
440                 break;
441
442         case RS2::Engineering:
443                 ret = formatEngineering(length, unit, prec, showUnit);
444                 break;
445
446         case RS2::Architectural:
447                 ret = formatArchitectural(length, unit, prec, showUnit);
448                 break;
449
450         case RS2::Fractional:
451                 ret = formatFractional(length, unit, prec, showUnit);
452                 break;
453
454         default:
455                 DEBUG->print(Debug::D_WARNING,
456                         "Units::formatLinear: Unknown format");
457                 ret = "";
458                 break;
459         }
460
461         return ret;
462 }
463
464 /**
465  * Formats the given length in scientific format (e.g. 2.5E7).
466  *
467  * @param length The length in the current unit of the drawing.
468  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
469  & @param showUnit Append unit to the value.
470  */
471 QString Units::formatScientific(double length, RS2::Unit unit, int prec, bool showUnit)
472 {
473         QString ret;
474
475         // unit appended to value (e.g. 'mm'):
476         QString unitString = "";
477
478         if (showUnit)
479                 unitString = unitToSign(unit);
480
481         char format[128];
482         sprintf(format, "%%.%dE%%s", prec);
483         ret.sprintf(format, length, (const char *)unitString.toLocal8Bit());
484
485         return ret;
486 }
487
488 /**
489  * Formats the given length in decimal (normal) format (e.g. 2.5).
490  *
491  * @param length The length in the current unit of the drawing.
492  * @param prec Precisision of the value (e.g. 0.001)
493  & @param showUnit Append unit to the value.
494  */
495 QString Units::formatDecimal(double length, RS2::Unit unit, int prec, bool showUnit)
496 {
497         QString ret;
498
499         // unit appended to value (e.g. 'mm'):
500         QString unitString = "";
501
502         if (showUnit)
503                 unitString = unitToSign(unit);
504
505         ret = Math::doubleToString(length, prec);
506
507         if (showUnit)
508                 ret += unitString;
509
510         return ret;
511 }
512
513 /**
514  * Formats the given length in engineering format (e.g. 5' 4.5").
515  *
516  * @param length The length in the current unit of the drawing.
517  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
518  & @param showUnit Append unit to the value.
519  */
520 QString Units::formatEngineering(double length, RS2::Unit /*unit*/, int prec, bool /*showUnit*/)
521 {
522         QString ret;
523
524         bool sign = (length < 0.0);
525         int feet = (int)floor(fabs(length) / 12);
526         double inches = fabs(length) - feet * 12;
527
528         QString sInches = Math::doubleToString(inches, prec);
529
530         if (sInches == "12")
531         {
532                 feet++;
533                 sInches = "0";
534         }
535
536         if (feet != 0)
537         {
538                 ret.sprintf("%d'-%s\"", feet, (const char *)sInches.toLocal8Bit());
539         }
540         else
541         {
542                 ret.sprintf("%s\"", (const char *)sInches.toLocal8Bit());
543         }
544
545         if (sign)
546                 ret = "-" + ret;
547
548         return ret;
549 }
550
551 /**
552  * Formats the given length in architectural format (e.g. 5' 4 1/2").
553  *
554  * @param length The length in the current unit of the drawing.
555  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
556  & @param showUnit Append unit to the value.
557  */
558 QString Units::formatArchitectural(double length, RS2::Unit /*unit*/, int prec, bool showUnit)
559 {
560         QString ret;
561         bool neg = (length < 0.0);
562         int feet = (int)floor(fabs(length) / 12);
563         double inches = fabs(length) - feet * 12;
564
565         QString sInches = formatFractional(inches, RS2::Inch, prec, showUnit);
566
567         if (sInches == "12")
568         {
569                 feet++;
570                 sInches = "0";
571         }
572
573         if (neg)
574         {
575                 ret.sprintf("-%d'-%s\"", feet, (const char *)sInches.toLocal8Bit());
576         }
577         else
578         {
579                 ret.sprintf("%d'-%s\"", feet, (const char *)sInches.toLocal8Bit());
580         }
581
582         return ret;
583 }
584
585 /**
586  * Formats the given length in fractional (barbarian) format (e.g. 5' 3 1/64").
587  *
588  * @param length The length in the current unit of the drawing.
589  * @param unit Should be inches.
590  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
591  & @param showUnit Append unit to the value.
592  */
593 QString Units::formatFractional(double length, RS2::Unit /*unit*/, int prec, bool /*showUnit*/)
594 {
595         QString ret;
596
597         int num;            // number of complete inches (num' 7/128")
598         int nominator;      // number of fractions (nominator/128)
599         int denominator;    // (4/denominator)
600
601         // sign:
602         QString neg = "";
603
604         if (length < 0)
605         {
606                 neg = "-";
607                 length = fabs(length);
608         }
609
610         num = (int)floor(length);
611
612         denominator = (int)Math::pow(2, prec);
613         nominator = Math::round((length - num) * denominator);
614
615         // fraction rounds up to 1:
616         if (nominator == denominator)
617         {
618                 nominator = 0;
619                 denominator = 0;
620                 ++num;
621         }
622
623         // Simplify the fraction
624         if (nominator != 0 && denominator != 0)
625         {
626                 int gcd = Math::findGCD(nominator, denominator);
627
628                 if (gcd != 0)
629                 {
630                         nominator = nominator / gcd;
631                         denominator = denominator / gcd;
632                 }
633                 else
634                 {
635                         DEBUG->print(Debug::D_WARNING, "Units::formatFractional: invalid gcd");
636                         nominator = 0;
637                         denominator = 0;
638                 }
639         }
640
641         if (num != 0 && nominator != 0)
642         {
643                 ret.sprintf("%s%d %d/%d", (const char *)neg.toLocal8Bit(), num, nominator, denominator);
644         }
645         else if (nominator != 0)
646         {
647                 ret.sprintf("%s%d/%d", (const char *)neg.toLocal8Bit(), nominator, denominator);
648         }
649         else if (num != 0)
650         {
651                 ret.sprintf("%s%d", (const char *)neg.toLocal8Bit(), num);
652         }
653         else
654         {
655                 ret.sprintf("0");
656         }
657
658         return ret;
659 }
660
661 /**
662  * Formats the given angle with the given format.
663  *
664  * @param angle The angle (always in rad).
665  * @param format Format of the string.
666  * @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
667  *
668  * @ret String with the formatted angle.
669  */
670 QString Units::formatAngle(double angle, RS2::AngleFormat format, int prec)
671 {
672         QString ret;
673         double value;
674
675         switch (format)
676         {
677         case RS2::DegreesDecimal:
678         case RS2::DegreesMinutesSeconds:
679                 value = Math::rad2deg(angle);
680                 break;
681         case RS2::Radians:
682                 value = angle;
683                 break;
684         case RS2::Gradians:
685                 value = Math::rad2gra(angle);
686                 break;
687         default:
688                 DEBUG->print(Debug::D_WARNING, "Units::formatAngle: Unknown Angle Unit");
689                 return "";
690                 break;
691         }
692
693         switch (format)
694         {
695         case RS2::DegreesDecimal:
696         case RS2::Radians:
697         case RS2::Gradians:
698                 ret = Math::doubleToString(value, prec);
699
700                 if (format == RS2::DegreesDecimal)
701                         ret += QChar(0xB0);
702                 if (format == RS2::Radians)
703                         ret += "r";
704                 if (format == RS2::Gradians)
705                         ret += "g";
706                 break;
707
708         case RS2::DegreesMinutesSeconds:
709         {
710                 int vDegrees, vMinutes;
711                 double vSeconds;
712                 QString degrees, minutes, seconds;
713
714                 vDegrees = (int)floor(value);
715                 vMinutes = (int)floor((value - vDegrees) * 60.0);
716                 vSeconds = (value - vDegrees - (vMinutes / 60.0)) * 3600.0;
717
718                 seconds = Math::doubleToString(vSeconds, (prec > 1 ? prec - 2 : 0));
719
720                 if (seconds == "60")
721                 {
722                         seconds = "0";
723                         ++vMinutes;
724
725                         if (vMinutes == 60)
726                         {
727                                 vMinutes = 0;
728                                 ++vDegrees;
729                         }
730                 }
731
732                 if (prec == 0 && vMinutes >= 30.0)
733                 {
734                         vDegrees++;
735                 }
736                 else if (prec == 1 && vSeconds >= 30.0)
737                 {
738                         vMinutes++;
739                 }
740
741                 degrees.setNum(vDegrees);
742                 minutes.setNum(vMinutes);
743
744                 switch (prec)
745                 {
746                 case 0:
747                         ret = degrees + QChar(0xB0);
748                         break;
749                 case 1:
750                         ret = degrees + QChar(0xB0) + " " + minutes + "'";
751                         break;
752                 default:
753                         ret = degrees + QChar(0xB0) + " " + minutes + "' " + seconds + "\"";
754                         break;
755                 }
756         }
757                 break;
758
759         default:
760                 break;
761         }
762
763         return ret;
764 }
765
766 /**
767  * @return Size of the given paper format.
768  */
769 Vector Units::paperFormatToSize(RS2::PaperFormat p)
770 {
771         Vector ret(false);
772
773         switch (p)
774         {
775         case RS2::Custom:
776                 ret = Vector(0.0, 0.0);
777                 break;
778         case RS2::Letter:
779                 ret = Vector(215.9, 279.4);
780                 break;
781         case RS2::Legal:
782                 ret = Vector(215.9, 355.6);
783                 break;
784         case RS2::Executive:
785                 ret = Vector(190.5, 254.0);
786                 break;
787         case RS2::A0:
788                 ret = Vector(841.0, 1189.0);
789                 break;
790         case RS2::A1:
791                 ret = Vector(594.0, 841.0);
792                 break;
793         case RS2::A2:
794                 ret = Vector(420.0, 594.0);
795                 break;
796         case RS2::A3:
797                 ret = Vector(297.0, 420.0);
798                 break;
799         case RS2::A4:
800                 ret = Vector(210.0, 297.0);
801                 break;
802         case RS2::A5:
803                 ret = Vector(148.0, 210.0);
804                 break;
805         case RS2::A6:
806                 ret = Vector(105.0, 148.0);
807                 break;
808         case RS2::A7:
809                 ret = Vector(74.0, 105.0);
810                 break;
811         case RS2::A8:
812                 ret = Vector(52.0, 74.0);
813                 break;
814         case RS2::A9:
815                 ret = Vector(37.0, 52.0);
816                 break;
817                 /*case RS2::A10:
818                         ret = Vector(26.0, 37.0);
819                         break;*/
820         case RS2::B0:
821                 ret = Vector(1000.0, 1414.0);
822                 break;
823         case RS2::B1:
824                 ret = Vector(707.0, 1000.0);
825                 break;
826         case RS2::B2:
827                 ret = Vector(500.0, 707.0);
828                 break;
829         case RS2::B3:
830                 ret = Vector(353.0, 500.0);
831                 break;
832         case RS2::B4:
833                 ret = Vector(250.0, 353.0);
834                 break;
835         case RS2::B5:
836                 ret = Vector(176.0, 250.0);
837                 break;
838         case RS2::B6:
839                 ret = Vector(125.0, 176.0);
840                 break;
841         case RS2::B7:
842                 ret = Vector(88.0, 125.0);
843                 break;
844         case RS2::B8:
845                 ret = Vector(62.0, 88.0);
846                 break;
847         case RS2::B9:
848                 ret = Vector(44.0, 62.0);
849                 break;
850         case RS2::B10:
851                 ret = Vector(31.0, 44.0);
852                 break;
853                 /*
854                         case RS2::C0:
855                                 ret = Vector(917.0, 1297.0);
856                                 break;
857                         case RS2::C1:
858                                 ret = Vector(648.0, 917.0);
859                                 break;
860                         case RS2::C2:
861                                 ret = Vector(458.0, 648.0);
862                                 break;
863                         case RS2::C3:
864                                 ret = Vector(324.0, 458.0);
865                                 break;
866                         case RS2::C4:
867                                 ret = Vector(229.0, 324.0);
868                                 break;
869                         case RS2::C5:
870                                 ret = Vector(162.0, 229.0);
871                                 break;
872                         case RS2::C6:
873                                 ret = Vector(114.0, 162.0);
874                                 break;
875                         case RS2::C7:
876                                 ret = Vector(81.0, 114.0);
877                                 break;
878                         case RS2::C8:
879                                 ret = Vector(57.0, 81.0);
880                                 break;
881                         case RS2::C9:
882                                 ret = Vector(40.0, 57.0);
883                                 break;
884                         case RS2::C10:
885                                 ret = Vector(28.0, 40.0);
886                                 break;
887                 */
888         case RS2::C5E:
889                 ret = Vector(163.0, 229.0);
890                 break;
891         case RS2::Comm10E:
892                 ret = Vector(105.0, 241.0);
893                 break;
894         case RS2::DLE:
895                 ret = Vector(110.0, 220.0);
896                 break;
897         case RS2::Folio:
898                 ret = Vector(210.0, 330.0);
899                 break;
900         //case RS2::Ledger:
901         //    ret = Vector(432.0, 279.0);
902         //    break;
903         case RS2::Tabloid:
904                 ret = Vector(279.0, 432.0);
905                 break;
906         case RS2::NPageSize:
907                 ret = Vector(0.0, 0.0);
908                 break;
909         default:
910                 break;
911         }
912
913         return ret;
914 }
915
916 /**
917  * Gets the paper format which matches the given size. If no
918  * format matches, RS2::Custom is returned.
919  */
920 RS2::PaperFormat Units::paperSizeToFormat(const Vector s)
921 {
922         Vector ts1;
923         Vector ts2;
924
925         for(int i=(int)RS2::Custom; i<=(int)RS2::NPageSize; ++i)
926         {
927                 ts1 = Units::paperFormatToSize((RS2::PaperFormat)i);
928                 ts2 = Vector(ts1.y, ts1.x);
929
930                 if (ts1.distanceTo(s) < 1.0e-4 || ts2.distanceTo(s) < 1.0e-4)
931                         return (RS2::PaperFormat)i;
932         }
933
934         return RS2::Custom;
935 }
936
937 /**
938  * Converts a paper format to a string (e.g. for a combobox).
939  */
940 QString Units::paperFormatToString(RS2::PaperFormat p)
941 {
942         QString ret = "";
943
944         switch (p)
945         {
946         case RS2::Custom:
947                 ret = "Custom";
948                 break;
949         case RS2::Letter:
950                 ret = "Letter";
951                 break;
952         case RS2::Legal:
953                 ret = "Legal";
954                 break;
955         case RS2::Executive:
956                 ret = "Executive";
957                 break;
958         case RS2::A0:
959                 ret = "A0";
960                 break;
961         case RS2::A1:
962                 ret = "A1";
963                 break;
964         case RS2::A2:
965                 ret = "A2";
966                 break;
967         case RS2::A3:
968                 ret = "A3";
969                 break;
970         case RS2::A4:
971                 ret = "A4";
972                 break;
973         case RS2::A5:
974                 ret = "A5";
975                 break;
976         case RS2::A6:
977                 ret = "A6";
978                 break;
979         case RS2::A7:
980                 ret = "A7";
981                 break;
982         case RS2::A8:
983                 ret = "A8";
984                 break;
985         case RS2::A9:
986                 ret = "A9";
987                 break;
988         case RS2::B0:
989                 ret = "B0";
990                 break;
991         case RS2::B1:
992                 ret = "B1";
993                 break;
994         case RS2::B2:
995                 ret = "B2";
996                 break;
997         case RS2::B3:
998                 ret = "B3";
999                 break;
1000         case RS2::B4:
1001                 ret = "B4";
1002                 break;
1003         case RS2::B5:
1004                 ret = "B5";
1005                 break;
1006         case RS2::B6:
1007                 ret = "B6";
1008                 break;
1009         case RS2::B7:
1010                 ret = "B7";
1011                 break;
1012         case RS2::B8:
1013                 ret = "B8";
1014                 break;
1015         case RS2::B9:
1016                 ret = "B9";
1017                 break;
1018         case RS2::B10:
1019                 ret = "B10";
1020                 break;
1021                 /*
1022                         case RS2::C0:
1023                                 ret = "C0";
1024                                 break;
1025                         case RS2::C1:
1026                                 ret = "C1";
1027                                 break;
1028                         case RS2::C2:
1029                                 ret = "C2";
1030                                 break;
1031                         case RS2::C3:
1032                                 ret = "C3";
1033                                 break;
1034                         case RS2::C4:
1035                                 ret = "C4";
1036                                 break;
1037                         case RS2::C5:
1038                                 ret = "C5";
1039                                 break;
1040                         case RS2::C6:
1041                                 ret = "C6";
1042                                 break;
1043                         case RS2::C7:
1044                                 ret = "C7";
1045                                 break;
1046                         case RS2::C8:
1047                                 ret = "C8";
1048                                 break;
1049                         case RS2::C9:
1050                                 ret = "C9";
1051                                 break;
1052                         case RS2::C10:
1053                                 ret = "C10";
1054                                 break;
1055                 */
1056         case RS2::C5E:
1057                 ret = "C5E";
1058                 break;
1059         case RS2::Comm10E:
1060                 ret = "Comm10E";
1061                 break;
1062         case RS2::DLE:
1063                 ret = "DLE";
1064                 break;
1065         case RS2::Folio:
1066                 ret = "Folio";
1067                 break;
1068         //case RS2::Ledger:
1069         //    ret = "Ledger";
1070         //    break;
1071         case RS2::Tabloid:
1072                 ret = "Tabloid";
1073                 break;
1074         case RS2::NPageSize:
1075                 ret = "NPageSize";
1076                 break;
1077         default:
1078                 break;
1079         }
1080
1081         return ret;
1082 }
1083
1084 /**
1085  * Converts a string to a paper format.
1086  */
1087 RS2::PaperFormat Units::stringToPaperFormat(const QString & p)
1088 {
1089         QString ls = p.toLower();
1090         RS2::PaperFormat ret = RS2::Custom;
1091
1092         if (p == "custom")
1093                 ret = RS2::Custom;
1094         else if (p == "letter")
1095                 ret = RS2::Letter;
1096         else if (p == "legal")
1097                 ret = RS2::Legal;
1098         else if (p == "executive")
1099                 ret = RS2::Executive;
1100         else if (p == "a0")
1101                 ret = RS2::A0;
1102         else if (p == "a1")
1103                 ret = RS2::A1;
1104         else if (p == "a2")
1105                 ret = RS2::A2;
1106         else if (p == "a3")
1107                 ret = RS2::A3;
1108         else if (p == "a4")
1109                 ret = RS2::A4;
1110         else if (p == "a5")
1111                 ret = RS2::A5;
1112         else if (p == "a6")
1113                 ret = RS2::A6;
1114         else if (p == "a7")
1115                 ret = RS2::A7;
1116         else if (p == "a8")
1117                 ret = RS2::A8;
1118         else if (p == "a9")
1119                 ret = RS2::A9;
1120         else if (p == "b0")
1121                 ret = RS2::B0;
1122         else if (p == "b1")
1123                 ret = RS2::B1;
1124         else if (p == "b2")
1125                 ret = RS2::B2;
1126         else if (p == "b3")
1127                 ret = RS2::B3;
1128         else if (p == "b4")
1129                 ret = RS2::B4;
1130         else if (p == "b5")
1131                 ret = RS2::B5;
1132         else if (p == "b6")
1133                 ret = RS2::B6;
1134         else if (p == "b7")
1135                 ret = RS2::B7;
1136         else if (p == "b8")
1137                 ret = RS2::B8;
1138         else if (p == "b9")
1139                 ret = RS2::B9;
1140         else if (p == "b10")
1141                 ret = RS2::B10;
1142         /*else if (p=="c0") {
1143                 ret = RS2::C0;
1144         } else if (p=="c1") {
1145                 ret = RS2::C1;
1146         } else if (p=="c2") {
1147                 ret = RS2::C2;
1148         } else if (p=="c3") {
1149                 ret = RS2::C3;
1150         } else if (p=="c4") {
1151                 ret = RS2::C4;
1152         } else if (p=="c5") {
1153                 ret = RS2::C5;
1154         } else if (p=="c6") {
1155                 ret = RS2::C6;
1156         } else if (p=="c7") {
1157                 ret = RS2::C7;
1158         } else if (p=="c8") {
1159                 ret = RS2::C8;
1160         } else if (p=="c9") {
1161                 ret = RS2::C9;
1162         } else if (p=="c10") {
1163                 ret = RS2::C10;
1164         }*/
1165         else if (p == "c5e")
1166                 ret = RS2::C5E;
1167         else if (p == "comm10e")
1168                 ret = RS2::Comm10E;
1169         else if (p == "dle")
1170                 ret = RS2::DLE;
1171         else if (p == "folio")
1172                 ret = RS2::Folio;
1173         //else if (p=="ledger")
1174         //    ret = RS2::Ledger;
1175         else if (p == "tabloid")
1176                 ret = RS2::Tabloid;
1177         else if (p == "npagesize")
1178                 ret = RS2::NPageSize;
1179
1180         return ret;
1181 }
1182
1183 /**
1184  * Performs some testing for the math class.
1185  */
1186 void Units::test()
1187 {
1188         QString s;
1189         double v;
1190
1191         /*
1192         std::cout << "Units::test: formatLinear (decimal):\n";
1193         v = 0.1;
1194         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1195                                                                 3, false);
1196         std::cout << "s: " << s << "\n";
1197         assert(s=="0.1");
1198         v = 0.01;
1199         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1200                                                                 3, false);
1201         std::cout << "s: " << s << "\n";
1202         assert(s=="0.01");
1203         v = 0.001;
1204         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1205                                                                 3, false);
1206         std::cout << "s: " << s << "\n";
1207         assert(s=="0.001");
1208         v = 0.009;
1209         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1210                                                                 2, false);
1211         std::cout << "s: " << s << "\n";
1212         assert(s=="0.01");
1213         v = 0.005;
1214         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1215                                                                 2, false);
1216         std::cout << "s: " << s << "\n";
1217         assert(s=="0.01");
1218         v = 0.0049999;
1219         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1220                                                                 2, false);
1221         std::cout << "s: " << s << "\n";
1222         assert(s=="0");
1223
1224         v = 0.1;
1225         s = Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1226                                                                 4, true);
1227         std::cout << "s: " << s << "\n";
1228         assert(s=="0.1mm");
1229
1230
1231         std::cout << "Units::test: formatLinear (fractional):\n";
1232         v = 1.2;
1233         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1234                                                                 6, false);
1235         std::cout << "s: " << s << "\n";
1236         assert(s=="1 13/64");
1237
1238         v = 1.2;
1239         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1240                                                                 8, false);
1241         std::cout << "s: " << s << "\n";
1242         assert(s=="1 51/256");
1243
1244         v = 0.2;
1245         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1246                                                                 8, false);
1247         std::cout << "s: " << s << "\n";
1248         assert(s=="51/256");
1249
1250         v = 4.5;
1251         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1252                                                                 6, true);
1253         std::cout << "s: " << s << "\n";
1254         assert(s=="4 1/2");
1255
1256         v = 0.001;
1257         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1258                                                                 0, false);
1259         std::cout << "s: " << s << "\n";
1260         assert(s=="0");
1261
1262         v = 0.01;
1263         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1264                                                                 8, false);
1265         std::cout << "s: " << s << "\n";
1266         assert(s=="3/256");
1267
1268         v = 0.0078125;
1269         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1270                                                                 8, false);
1271         std::cout << "s: " << s << "\n";
1272         assert(s=="1/128");
1273
1274         v = 0.001;
1275         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1276                                                                 8, false);
1277         std::cout << "s: " << s << "\n";
1278         assert(s=="0");
1279
1280         v = 9.9999;
1281         s = Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1282                                                                 6, false);
1283         std::cout << "s: " << s << "\n";
1284         assert(s=="10");
1285         */
1286
1287         for(v=11.9999; v<12.0001; v+=0.0000001)
1288         {
1289                 for(int prec=0; prec<=6; ++prec)
1290                 {
1291                         s = Units::formatLinear(v, RS2::Inch, RS2::Architectural, prec, true);
1292                         std::cout << "prec: " << prec << " v: " << v << " s: " << s.toAscii().data() << "\n";
1293                 }
1294         }
1295
1296         /*for (v=0.0; v<10.0; v+=0.001) {
1297                 s = Units::formatLinear(v, RS2::Foot, RS2::Fractional,
1298                                                                 1.0/128.0, true);
1299                 std::cout << "v: " << v << " s: " << s << "\n";
1300 }*/
1301
1302         /*
1303         std::cout << "Units::test: formatLinear (scientific):\n";
1304         v = 0.001;
1305         s = Units::formatLinear(v, RS2::Millimeter, RS2::Scientific,
1306                                                         0.0001, false);
1307         std::cout << "s: " << s << "\n";
1308         assert(s=="1.0e-3");
1309         */
1310
1311
1312         /*
1313         std::cout << "Units::test: formatAngle (deg / decimal):\n";
1314         v = 0.0261799;
1315         s = Units::formatAngle(v, RS2::DegreesDecimal, 2);
1316         std::cout << "s: " << s << "\n";
1317         assert(s=="1.5�");
1318
1319         v = 0;
1320         s = Units::formatAngle(v, RS2::DegreesDecimal, 2);
1321         std::cout << "s: " << s << "\n";
1322         assert(s=="0�");
1323
1324         v = 1.5707963;
1325         s = Units::formatAngle(v, RS2::DegreesDecimal, 2);
1326         std::cout << "s: " << s << "\n";
1327         assert(s=="90�");
1328
1329         std::cout << "Units::test: formatAngle (deg / d/m/s):\n";
1330
1331         v = 0.0260926;
1332         s = Units::formatAngle(v, RS2::DegreesMinutesSeconds, 1);
1333         std::cout << "s: " << s << "\n";
1334         assert(s=="1� 29' 42\"");
1335
1336         v = 0.0261799;
1337         s = Units::formatAngle(v, RS2::DegreesMinutesSeconds, 1);
1338         std::cout << "s: " << s << "\n";
1339         assert(s=="1� 30' 0\"");
1340         */
1341 }