Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
FormatDegreesMinutesSecondsBase.cpp
1 #include "CoordSymbol.h"
2 #include "FormatDegreesMinutesSecondsBase.h"
3 #include "Logger.h"
4 #include <QDoubleValidator>
5 #include <qmath.h>
6 #include <QRegExp>
7 #include <QStringList>
8 #include <QValidator>
9 
10 const double DEGREES_TO_MINUTES = 60.0;
11 const double MINUTES_TO_SECONDS = 60.0;
12 const double DEGREES_TO_SECONDS = DEGREES_TO_MINUTES * MINUTES_TO_SECONDS;
13 const double MINUTES_TO_DEGREES = 1.0 / DEGREES_TO_MINUTES;
14 const double SECONDS_TO_DEGREES = 1.0 / (DEGREES_TO_MINUTES * MINUTES_TO_SECONDS);
15 
17 {
18 }
19 
20 FormatDegreesMinutesSecondsBase::~FormatDegreesMinutesSecondsBase()
21 {
22 }
23 
25 {
26  LOG4CPP_INFO_S ((*mainCat)) << "FormatDegreesMinutesSecondsBase::formatOutputDegreesMinutesSeconds"
27  << " value=" << value;
28 
29  // Only smallest resolution value is floating point
30  bool negative = (value < 0);
31  value = qAbs (value);
32  int degrees = qFloor (value);
33  value -= degrees;
34  int minutes = value * DEGREES_TO_MINUTES;
35  value -= minutes * MINUTES_TO_DEGREES;
36  double seconds = value * DEGREES_TO_SECONDS;
37  degrees *= (negative ? -1.0 : 1.0);
38 
39  return QString ("%1%2 %3%4 %5%6")
40  .arg (degrees)
41  .arg (QChar (COORD_SYMBOL_DEGREES))
42  .arg (minutes)
43  .arg (QChar (COORD_SYMBOL_MINUTES_PRIME))
44  .arg (seconds)
45  .arg (QChar (COORD_SYMBOL_SECONDS_DOUBLE_PRIME));
46 }
47 
49  bool isNsHemisphere) const
50 {
51  LOG4CPP_INFO_S ((*mainCat)) << "FormatDegreesMinutesSecondsBase::formatOutputDegreesMinutesSecondsNsew"
52  << " value=" << value
53  << " isNsHemisphere=" << (isNsHemisphere ? "true" : "false");
54 
55  // Only smallest resolution value is floating point
56  bool negative = (value < 0);
57  value = qAbs (value);
58  int degrees = qFloor (value);
59  value -= degrees;
60  int minutes = value * DEGREES_TO_MINUTES;
61  value -= minutes * MINUTES_TO_DEGREES;
62  double seconds = value * DEGREES_TO_SECONDS;
63 
64  QString hemisphere;
65  if (isNsHemisphere) {
66  hemisphere = (negative ? "S" : "N");
67  } else {
68  hemisphere = (negative ? "W" : "E");
69  }
70 
71  return QString ("%1%2 %3%4 %5%6 %7")
72  .arg (degrees)
73  .arg (QChar (COORD_SYMBOL_DEGREES))
74  .arg (minutes)
75  .arg (QChar (COORD_SYMBOL_MINUTES_PRIME))
76  .arg (seconds)
77  .arg (QChar (COORD_SYMBOL_SECONDS_DOUBLE_PRIME))
78  .arg (hemisphere);
79 }
80 
81 QValidator::State FormatDegreesMinutesSecondsBase::parseInput (const QString &stringUntrimmed,
82  double &value) const
83 {
84  LOG4CPP_INFO_S ((*mainCat)) << "FormatDegreesMinutesSecondsBase::parseInput"
85  << " string=" << stringUntrimmed.toLatin1().data();
86 
87  const QString string = stringUntrimmed.trimmed ();
88 
89  if (string.isEmpty()) {
90 
91  return QValidator::Intermediate;
92  }
93 
94  // Split on spaces
95  QStringList fields = string.split (QRegExp ("\\s+"),
96  QString::SkipEmptyParts);
97 
98  QString field0, field1, field2; // Degrees, minutes and seconds components
99  if (fields.count() == 0) {
100  return QValidator::Invalid; // Empty
101  } else {
102  field0 = fields.at(0);
103  if (fields.count() > 1) {
104  field1 = fields.at(1);
105  if (fields.count() > 2) {
106  field2 = fields.at(2);
107  if (fields.count() > 3) {
108  return QValidator::Invalid; // Too many values
109  }
110  }
111  }
112  }
113 
114  stripSymbols (field0,
115  field1,
116  field2);
117 
118  int pos;
119 
120  // Validators
121  QDoubleValidator valDegrees;
122  QDoubleValidator valMinutesOrSeconds;
123  valMinutesOrSeconds.setBottom (0);
124 
125  double valueDegrees = 0, valueMinutes = 0, valueSeconds = 0;
126 
127  // Required degrees
128  QValidator::State state = valDegrees.validate (field0,
129  pos);
130  if (state == QValidator::Acceptable) {
131 
132  valueDegrees = field0.toDouble();
133 
134  if (fields.count() > 1) {
135 
136  // Optional minutes
137  state = valMinutesOrSeconds.validate (field1,
138  pos);
139  if (state == QValidator::Acceptable) {
140 
141  valueMinutes = field1.toDouble();
142 
143  if (fields.count() > 2) {
144 
145  // Optional seconds
146  state = valMinutesOrSeconds.validate (field2,
147  pos);
148  if (state == QValidator::Acceptable) {
149 
150  valueSeconds = field2.toDouble();
151 
152  }
153  }
154  }
155  }
156  }
157 
158  if (state == QValidator::Acceptable) {
159  if (valueDegrees < 0) {
160 
161  // Apply the negative sign on the degrees components to minutes and seconds components also
162  value = valueDegrees - valueMinutes * MINUTES_TO_DEGREES - valueSeconds * SECONDS_TO_DEGREES;
163 
164  } else {
165 
166  // All components are positive
167  value = valueDegrees + valueMinutes * MINUTES_TO_DEGREES + valueSeconds * SECONDS_TO_DEGREES;
168 
169  }
170  }
171 
172  return state;
173 }
174 
175 void FormatDegreesMinutesSecondsBase::stripSymbols (QString &field0,
176  QString &field1,
177  QString &field2) const
178 {
179  const int FIELD_WIDTH = 0, BASE_8 = 8, BASE_16 = 16;
180 
181  // Clean up degrees symbols (167 or 248 in base 10 which are 247 and 370 in base 8) and single quotes
182  QString strExpDegrees = QString (".*\\0%1$")
183  .arg (COORD_SYMBOL_DEGREES, FIELD_WIDTH, BASE_8);
184 
185  QRegExp regExpDegrees (strExpDegrees);
186 
187  if (regExpDegrees.exactMatch (field0)) {
188  field0 = field0.left (field0.count() - 1);
189  }
190 
191  // Clean up minutes
192  QString strExpMinutes = QString (".*[\\0%1\\x%2]$")
193  .arg (COORD_SYMBOL_MINUTES_APOSTROPHE, FIELD_WIDTH, BASE_8)
194  .arg (COORD_SYMBOL_MINUTES_PRIME, FIELD_WIDTH, BASE_16);
195 
196  QRegExp regExpMinutes (strExpMinutes);
197 
198  if (regExpMinutes.exactMatch (field1)) {
199  field1 = field1.left (field1.count() - 1);
200  }
201 
202  // Clean up seconds
203  QString strExpSeconds1Char = QString (".*[\\x%1\\x%2]$")
204  .arg (COORD_SYMBOL_SECONDS_DOUBLE_PRIME, FIELD_WIDTH, BASE_16)
205  .arg (COORD_SYMBOL_SECONDS_QUOTATIONS, FIELD_WIDTH, BASE_16);
206  QString strExpSeconds2Chars = QString (".*\\0%1\\0%2$")
207  .arg (COORD_SYMBOL_MINUTES_PRIME, FIELD_WIDTH, BASE_8)
208  .arg (COORD_SYMBOL_MINUTES_PRIME, FIELD_WIDTH, BASE_8);
209 
210  QRegExp regExpSeconds1Char (strExpSeconds1Char), regExpSeconds2Chars (strExpSeconds2Chars);
211 
212  if (regExpSeconds1Char.exactMatch (field2)) {
213  field2 = field2.left (field2.count() - 1);
214  }
215  if (regExpSeconds2Chars.exactMatch (field2)) {
216  field2 = field2.left (field2.count() - 2);
217  }
218 }
QString formatOutputDegreesMinutesSeconds(double value) const
Format as degrees, minutes and seconds without hemisphere.
QValidator::State parseInput(const QString &stringUntrimmed, double &value) const
Parse the input string into a number value.
QString formatOutputDegreesMinutesSecondsNsew(double value, bool isNsHemisphere) const
Format as degrees, minutes and seconds with hemisphere.