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