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