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