1
/****************************************************************************
3
** This file is part of the LibreCAD project, a 2D CAD program
5
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
9
** This program is free software; you can redistribute it and/or modify
10
** it under the terms of the GNU General Public License as published by
11
** the Free Software Foundation; either version 2 of the License, or
12
** (at your option) any later version.
14
** This program is distributed in the hope that it will be useful,
15
** but WITHOUT ANY WARRANTY; without even the implied warranty of
16
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
** GNU General Public License for more details.
19
** You should have received a copy of the GNU General Public License
20
** along with this program; if not, write to the Free Software
21
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
** This copyright notice MUST APPEAR in all copies of the script!
25
**********************************************************************/
37
* Converts a DXF integer () to a Unit enum.
39
RS2::Unit RS_Units::dxfint2unit(int dxfint) {
40
return (RS2::Unit)dxfint;
53
return RS2::Millimeter;
55
return RS2::Centimeter;
59
return RS2::Kilometer;
61
return RS2::Microinch;
69
return RS2::Nanometer;
73
return RS2::Decimeter;
75
return RS2::Decameter;
77
return RS2::Hectometer;
79
return RS2::Gigameter;
83
return RS2::Lightyear;
91
* @return a short string representing the given unit (e.g. "mm")
93
RS_String RS_Units::unitToSign(RS2::Unit u) {
109
case RS2::Millimeter:
112
case RS2::Centimeter:
145
case RS2::Hectometer:
172
* @return a string representing the given unit (e.g. "Millimeter").
173
* translated if @a t is true (the default).
175
RS_String RS_Units::unitToString(RS2::Unit u, bool t) {
180
ret = t ? QObject::tr("None") : RS_String("None");
183
ret = t ? QObject::tr("Inch") : RS_String("Inch");
186
ret = t ? QObject::tr("Foot") : RS_String("Foot");
189
ret = t ? QObject::tr("Mile") : RS_String("Mile");
191
case RS2::Millimeter:
192
ret = t ? QObject::tr("Millimeter") : RS_String("Millimeter");
194
case RS2::Centimeter:
195
ret = t ? QObject::tr("Centimeter") : RS_String("Centimeter");
198
ret = t ? QObject::tr("Meter") : RS_String("Meter");
201
ret = t ? QObject::tr("Kilometer") : RS_String("Kilometer");
204
ret = t ? QObject::tr("Microinch") : RS_String("Microinch");
207
ret = t ? QObject::tr("Mil") : RS_String("Mil");
210
ret = t ? QObject::tr("Yard") : RS_String("Yard");
213
ret = t ? QObject::tr("Angstrom") : RS_String("Angstrom");
216
ret = t ? QObject::tr("Nanometer") : RS_String("Nanometer");
219
ret = t ? QObject::tr("Micron") : RS_String("Micron");
222
ret = t ? QObject::tr("Decimeter") : RS_String("Decimeter");
225
ret = t ? QObject::tr("Decameter") : RS_String("Decameter");
227
case RS2::Hectometer:
228
ret = t ? QObject::tr("Hectometer") : RS_String("Hectometer");
231
ret = t ? QObject::tr("Gigameter") : RS_String("Gigameter");
234
ret = t ? QObject::tr("Astro") : RS_String("Astro");
237
ret = t ? QObject::tr("Lightyear") : RS_String("Lightyear");
240
ret = t ? QObject::tr("Parsec") : RS_String("Parsec");
254
* Converts a string into a unit enum.
256
RS2::Unit RS_Units::stringToUnit(const RS_String& u) {
257
RS2::Unit ret = RS2::None;
261
} else if (u==QObject::tr("Inch")) {
263
} else if (u==QObject::tr("Foot")) {
265
} else if (u==QObject::tr("Mile")) {
267
} else if (u==QObject::tr("Millimeter")) {
268
ret = RS2::Millimeter;
269
} else if (u==QObject::tr("Centimeter")) {
270
ret = RS2::Centimeter;
271
} else if (u==QObject::tr("Meter")) {
273
} else if (u==QObject::tr("Kilometer")) {
274
ret = RS2::Kilometer;
275
} else if (u==QObject::tr("Microinch")) {
276
ret = RS2::Microinch;
277
} else if (u==QObject::tr("Mil")) {
279
} else if (u==QObject::tr("Yard")) {
281
} else if (u==QObject::tr("Angstrom")) {
283
} else if (u==QObject::tr("Nanometer")) {
284
ret = RS2::Nanometer;
285
} else if (u==QObject::tr("Micron")) {
287
} else if (u==QObject::tr("Decimeter")) {
288
ret = RS2::Decimeter;
289
} else if (u==QObject::tr("Decameter")) {
290
ret = RS2::Decameter;
291
} else if (u==QObject::tr("Hectometer")) {
292
ret = RS2::Hectometer;
293
} else if (u==QObject::tr("Gigameter")) {
294
ret = RS2::Gigameter;
295
} else if (u==QObject::tr("Astro")) {
297
} else if (u==QObject::tr("Lightyear")) {
298
ret = RS2::Lightyear;
299
} else if (u==QObject::tr("Parsec")) {
310
* @return true: the unit is metric, false: the unit is imperial.
312
bool RS_Units::isMetric(RS2::Unit u) {
313
if (u==RS2::Millimeter ||
314
u==RS2::Centimeter ||
322
u==RS2::Hectometer ||
337
* @return factor to convert the given unit to Millimeters.
339
double RS_Units::getFactorToMM(RS2::Unit u) {
355
case RS2::Millimeter:
358
case RS2::Centimeter:
391
case RS2::Hectometer:
398
ret = 149600000000000.0;
401
ret = 9460731798000000000.0;
404
ret = 30857000000000000000.0;
416
* Converts the given value 'val' from unit 'src' to unit 'dest'.
418
double RS_Units::convert(double val, RS2::Unit src, RS2::Unit dest) {
419
if (getFactorToMM(dest)>0.0) {
420
return (val*getFactorToMM(src))/getFactorToMM(dest);
422
RS_DEBUG->print(RS_Debug::D_WARNING,
423
"RS_Units::convert: invalid factor");
431
* Converts the given vector 'val' from unit 'src' to unit 'dest'.
433
RS_Vector RS_Units::convert(const RS_Vector val, RS2::Unit src, RS2::Unit dest) {
434
return RS_Vector(convert(val.x, src, dest),
435
convert(val.y, src, dest),
436
convert(val.z, src, dest));
442
* Formats the given length in the given format.
444
* @param length The length in the current unit of the drawing.
445
* @param format Format of the string.
446
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
447
& @param showUnit Append unit to the value.
449
RS_String RS_Units::formatLinear(double length, RS2::Unit unit,
450
RS2::LinearFormat format,
451
int prec, bool showUnit) {
454
// unit appended to value (e.g. 'mm'):
455
/*RS_String unitString = "";
457
unitString = unitToSign(unit);
460
// barbarian display: show as fraction:
462
case RS2::Scientific:
463
ret = formatScientific(length, unit, prec, showUnit);
467
ret = formatDecimal(length, unit, prec, showUnit);
470
case RS2::Engineering:
471
ret = formatEngineering(length, unit, prec, showUnit);
474
case RS2::Architectural:
475
ret = formatArchitectural(length, unit, prec, showUnit);
478
case RS2::Fractional:
479
ret = formatFractional(length, unit, prec, showUnit);
483
RS_DEBUG->print(RS_Debug::D_WARNING,
484
"RS_Units::formatLinear: Unknown format");
495
* Formats the given length in scientific format (e.g. 2.5E7).
497
* @param length The length in the current unit of the drawing.
498
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
499
& @param showUnit Append unit to the value.
501
RS_String RS_Units::formatScientific(double length, RS2::Unit unit,
502
int prec, bool showUnit) {
506
// unit appended to value (e.g. 'mm'):
507
RS_String unitString = "";
509
unitString = unitToSign(unit);
513
sprintf(format, "%%.%dE%%s", prec);
514
ret.sprintf(format, length, (const char*)unitString.local8Bit());
522
* Formats the given length in decimal (normal) format (e.g. 2.5).
524
* @param length The length in the current unit of the drawing.
525
* @param prec Precisision of the value (e.g. 0.001)
526
& @param showUnit Append unit to the value.
528
RS_String RS_Units::formatDecimal(double length, RS2::Unit unit,
529
int prec, bool showUnit) {
533
// unit appended to value (e.g. 'mm'):
534
RS_String unitString = "";
536
unitString = unitToSign(unit);
539
ret = RS_Math::doubleToString(length, prec);
550
* Formats the given length in engineering format (e.g. 5' 4.5").
552
* @param length The length in the current unit of the drawing.
553
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
554
& @param showUnit Append unit to the value.
556
RS_String RS_Units::formatEngineering(double length, RS2::Unit /*unit*/,
557
int prec, bool /*showUnit*/) {
560
bool sign = (length<0.0);
561
int feet = (int)floor(fabs(length)/12);
562
double inches = fabs(length) - feet*12;
564
RS_String sInches = RS_Math::doubleToString(inches, prec);
572
ret.sprintf("%d'-%s\"", feet, (const char*)sInches.local8Bit());
574
ret.sprintf("%s\"", (const char*)sInches.local8Bit());
587
* Formats the given length in architectural format (e.g. 5' 4 1/2").
589
* @param length The length in the current unit of the drawing.
590
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
591
& @param showUnit Append unit to the value.
593
RS_String RS_Units::formatArchitectural(double length, RS2::Unit /*unit*/,
594
int prec, bool showUnit) {
596
bool neg = (length<0.0);
598
int feet = (int)floor(fabs(length)/12);
599
double inches = fabs(length) - feet*12;
601
RS_String sInches = formatFractional(inches, RS2::Inch, prec, showUnit);
609
ret.sprintf("-%d'-%s\"", feet, (const char*)sInches.local8Bit());
611
ret.sprintf("%d'-%s\"", feet, (const char*)sInches.local8Bit());
620
* Formats the given length in fractional (barbarian) format (e.g. 5' 3 1/64").
622
* @param length The length in the current unit of the drawing.
623
* @param unit Should be inches.
624
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
625
& @param showUnit Append unit to the value.
627
RS_String RS_Units::formatFractional(double length, RS2::Unit /*unit*/,
628
int prec, bool /*showUnit*/) {
632
int num; // number of complete inches (num' 7/128")
633
int nominator; // number of fractions (nominator/128)
634
int denominator; // (4/denominator)
640
length = fabs(length);
643
num = (int)floor(length);
645
denominator = (int)RS_Math::pow(2, prec);
646
nominator = RS_Math::round((length-num)*denominator);
648
// fraction rounds up to 1:
649
if (nominator==denominator) {
655
// Simplify the fraction
656
if (nominator!=0 && denominator!=0) {
657
int gcd = RS_Math::findGCD(nominator, denominator);
659
nominator = nominator / gcd;
660
denominator = denominator / gcd;
662
RS_DEBUG->print(RS_Debug::D_WARNING,
663
"RS_Units::formatFractional: invalid gcd");
669
if( num!=0 && nominator!=0 ) {
670
ret.sprintf("%s%d %d/%d",
671
(const char*)neg.local8Bit(), num,
672
nominator, denominator);
673
} else if(nominator!=0) {
674
ret.sprintf("%s%d/%d",
675
(const char*)neg.local8Bit(),
676
nominator, denominator);
679
(const char*)neg.local8Bit(),
693
* Formats the given angle with the given format.
695
* @param angle The angle (always in rad).
696
* @param format Format of the string.
697
* @param prec Precisision of the value (e.g. 0.001 or 1/128 = 0.0078125)
699
* @ret String with the formatted angle.
701
RS_String RS_Units::formatAngle(double angle, RS2::AngleFormat format,
708
case RS2::DegreesDecimal:
709
case RS2::DegreesMinutesSeconds:
710
value = RS_Math::rad2deg(angle);
716
value = RS_Math::rad2gra(angle);
719
RS_DEBUG->print(RS_Debug::D_WARNING,
720
"RS_Units::formatAngle: Unknown Angle Unit");
726
case RS2::DegreesDecimal:
729
ret = RS_Math::doubleToString(value, prec);
730
if (format==RS2::DegreesDecimal)
732
if (format==RS2::Radians)
734
if (format==RS2::Gradians)
738
case RS2::DegreesMinutesSeconds: {
739
int vDegrees, vMinutes;
741
RS_String degrees, minutes, seconds;
743
vDegrees = (int)floor(value);
744
vMinutes = (int)floor((value - vDegrees) * 60.0);
745
vSeconds = (value - vDegrees - (vMinutes/60.0)) * 3600.0;
747
seconds = RS_Math::doubleToString(vSeconds, (prec>1 ? prec-2 : 0));
758
if (prec==0 && vMinutes>=30.0) {
760
} else if (prec==1 && vSeconds>=30.0) {
764
degrees.setNum(vDegrees);
765
minutes.setNum(vMinutes);
769
ret = degrees + QChar(0xB0);
772
ret = degrees + QChar(0xB0) + " " + minutes + "'";
775
ret = degrees + QChar(0xB0) + " " + minutes + "' "
792
* @return Size of the given paper format.
794
RS_Vector RS_Units::paperFormatToSize(RS2::PaperFormat p) {
795
RS_Vector ret(false);
799
ret = RS_Vector(0.0, 0.0);
802
ret = RS_Vector(215.9, 279.4);
805
ret = RS_Vector(215.9, 355.6);
808
ret = RS_Vector(190.5, 254.0);
811
ret = RS_Vector(841.0, 1189.0);
814
ret = RS_Vector(594.0, 841.0);
817
ret = RS_Vector(420.0, 594.0);
820
ret = RS_Vector(297.0, 420.0);
823
ret = RS_Vector(210.0, 297.0);
826
ret = RS_Vector(148.0, 210.0);
829
ret = RS_Vector(105.0, 148.0);
832
ret = RS_Vector(74.0, 105.0);
835
ret = RS_Vector(52.0, 74.0);
838
ret = RS_Vector(37.0, 52.0);
841
ret = RS_Vector(26.0, 37.0);
844
ret = RS_Vector(1000.0, 1414.0);
847
ret = RS_Vector(707.0, 1000.0);
850
ret = RS_Vector(500.0, 707.0);
853
ret = RS_Vector(353.0, 500.0);
856
ret = RS_Vector(250.0, 353.0);
859
ret = RS_Vector(176.0, 250.0);
862
ret = RS_Vector(125.0, 176.0);
865
ret = RS_Vector(88.0, 125.0);
868
ret = RS_Vector(62.0, 88.0);
871
ret = RS_Vector(44.0, 62.0);
874
ret = RS_Vector(31.0, 44.0);
878
ret = RS_Vector(917.0, 1297.0);
881
ret = RS_Vector(648.0, 917.0);
884
ret = RS_Vector(458.0, 648.0);
887
ret = RS_Vector(324.0, 458.0);
890
ret = RS_Vector(229.0, 324.0);
893
ret = RS_Vector(162.0, 229.0);
896
ret = RS_Vector(114.0, 162.0);
899
ret = RS_Vector(81.0, 114.0);
902
ret = RS_Vector(57.0, 81.0);
905
ret = RS_Vector(40.0, 57.0);
908
ret = RS_Vector(28.0, 40.0);
912
ret = RS_Vector(163.0, 229.0);
915
ret = RS_Vector(105.0, 241.0);
918
ret = RS_Vector(110.0, 220.0);
921
ret = RS_Vector(210.0, 330.0);
924
// ret = RS_Vector(432.0, 279.0);
927
ret = RS_Vector(279.0, 432.0);
930
ret = RS_Vector(0.0, 0.0);
942
* Gets the paper format which matches the given size. If no
943
* format matches, RS2::Custom is returned.
945
RS2::PaperFormat RS_Units::paperSizeToFormat(const RS_Vector s) {
949
for (int i=(int)RS2::Custom; i<=(int)RS2::NPageSize; ++i) {
950
ts1 = RS_Units::paperFormatToSize((RS2::PaperFormat)i);
951
ts2 = RS_Vector(ts1.y, ts1.x);
953
if (ts1.distanceTo(s)<1.0e-4 || ts2.distanceTo(s)<1.0e-4) {
954
return (RS2::PaperFormat)i;
964
* Converts a paper format to a string (e.g. for a combobox).
966
RS_String RS_Units::paperFormatToString(RS2::PaperFormat p) {
1098
case RS2::NPageSize:
1111
* Converts a string to a paper format.
1113
RS2::PaperFormat RS_Units::stringToPaperFormat(const RS_String& p) {
1114
RS_String ls = p.lower();
1115
RS2::PaperFormat ret = RS2::Custom;
1119
} else if (p=="letter") {
1121
} else if (p=="legal") {
1123
} else if (p=="executive") {
1124
ret = RS2::Executive;
1125
} else if (p=="a0") {
1127
} else if (p=="a1") {
1129
} else if (p=="a2") {
1131
} else if (p=="a3") {
1133
} else if (p=="a4") {
1135
} else if (p=="a5") {
1137
} else if (p=="a6") {
1139
} else if (p=="a7") {
1141
} else if (p=="a8") {
1143
} else if (p=="a9") {
1145
} else if (p=="b0") {
1147
} else if (p=="b1") {
1149
} else if (p=="b2") {
1151
} else if (p=="b3") {
1153
} else if (p=="b4") {
1155
} else if (p=="b5") {
1157
} else if (p=="b6") {
1159
} else if (p=="b7") {
1161
} else if (p=="b8") {
1163
} else if (p=="b9") {
1165
} else if (p=="b10") {
1168
/*else if (p=="c0") {
1170
} else if (p=="c1") {
1172
} else if (p=="c2") {
1174
} else if (p=="c3") {
1176
} else if (p=="c4") {
1178
} else if (p=="c5") {
1180
} else if (p=="c6") {
1182
} else if (p=="c7") {
1184
} else if (p=="c8") {
1186
} else if (p=="c9") {
1188
} else if (p=="c10") {
1191
else if (p=="c5e") {
1193
} else if (p=="comm10e") {
1195
} else if (p=="dle") {
1197
} else if (p=="folio") {
1199
//} else if (p=="ledger") {
1200
// ret = RS2::Ledger;
1201
} else if (p=="tabloid") {
1203
} else if (p=="npagesize") {
1204
ret = RS2::NPageSize;
1212
* Performs some testing for the math class.
1214
void RS_Units::test() {
1219
std::cout << "RS_Units::test: formatLinear (decimal):\n";
1221
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1223
std::cout << "s: " << s << "\n";
1226
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1228
std::cout << "s: " << s << "\n";
1231
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1233
std::cout << "s: " << s << "\n";
1236
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1238
std::cout << "s: " << s << "\n";
1241
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1243
std::cout << "s: " << s << "\n";
1246
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1248
std::cout << "s: " << s << "\n";
1252
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Decimal,
1254
std::cout << "s: " << s << "\n";
1258
std::cout << "RS_Units::test: formatLinear (fractional):\n";
1260
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1262
std::cout << "s: " << s << "\n";
1263
assert(s=="1 13/64");
1266
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1268
std::cout << "s: " << s << "\n";
1269
assert(s=="1 51/256");
1272
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1274
std::cout << "s: " << s << "\n";
1275
assert(s=="51/256");
1278
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1280
std::cout << "s: " << s << "\n";
1284
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1286
std::cout << "s: " << s << "\n";
1290
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1292
std::cout << "s: " << s << "\n";
1296
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1298
std::cout << "s: " << s << "\n";
1302
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1304
std::cout << "s: " << s << "\n";
1308
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Fractional,
1310
std::cout << "s: " << s << "\n";
1314
for (v=11.9999; v<12.0001; v+=0.0000001) {
1315
for (int prec=0; prec<=6; ++prec) {
1316
s = RS_Units::formatLinear(v, RS2::Inch, RS2::Architectural,
1318
// RVT_PORT changed << s to s.ascii()
1319
std::cout << "prec: " << prec << " v: " << v << " s: " << s.ascii() << "\n";
1323
/*for (v=0.0; v<10.0; v+=0.001) {
1324
s = RS_Units::formatLinear(v, RS2::Foot, RS2::Fractional,
1326
std::cout << "v: " << v << " s: " << s << "\n";
1330
std::cout << "RS_Units::test: formatLinear (scientific):\n";
1332
s = RS_Units::formatLinear(v, RS2::Millimeter, RS2::Scientific,
1334
std::cout << "s: " << s << "\n";
1335
assert(s=="1.0e-3");
1340
std::cout << "RS_Units::test: formatAngle (deg / decimal):\n";
1342
s = RS_Units::formatAngle(v, RS2::DegreesDecimal, 2);
1343
std::cout << "s: " << s << "\n";
1347
s = RS_Units::formatAngle(v, RS2::DegreesDecimal, 2);
1348
std::cout << "s: " << s << "\n";
1352
s = RS_Units::formatAngle(v, RS2::DegreesDecimal, 2);
1353
std::cout << "s: " << s << "\n";
1356
std::cout << "RS_Units::test: formatAngle (deg / d/m/s):\n";
1359
s = RS_Units::formatAngle(v, RS2::DegreesMinutesSeconds, 1);
1360
std::cout << "s: " << s << "\n";
1361
assert(s=="1∞ 29' 42\"");
1364
s = RS_Units::formatAngle(v, RS2::DegreesMinutesSeconds, 1);
1365
std::cout << "s: " << s << "\n";
1366
assert(s=="1∞ 30' 0\"");