1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released      *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission.     *
5  ******************************************************************************************************/
6 
7 #include "CmdMediator.h"
8 #include "CoordUnitsDate.h"
9 #include "CoordUnitsTime.h"
10 #include "DocumentModelCoords.h"
11 #include "DocumentSerialize.h"
12 #include "EngaugeAssert.h"
13 #include "Logger.h"
14 #include <QObject>
15 #include <QTextStream>
16 #include "QtToString.h"
17 #include <QXmlStreamWriter>
18 #include "Xml.h"
19 
20 const double PI = 3.1415926535;
21 const double TWO_PI = 2.0 * PI;
22 
23 // Zero default for origin radius, which is usually wanted for COORD_SCALE_LINEAR, it is illegal
24 // for COORD_SCALE_LOG (for which 1.0 is probably preferred as the default. Note linear is more common than log
25 const double DEFAULT_ORIGIN_RADIUS_LINEAR = 0.0;
26 
DocumentModelCoords()27 DocumentModelCoords::DocumentModelCoords() :
28   m_coordsType (COORDS_TYPE_CARTESIAN),
29   m_originRadius (DEFAULT_ORIGIN_RADIUS_LINEAR),
30   m_coordScaleXTheta (COORD_SCALE_LINEAR),
31   m_coordScaleYRadius (COORD_SCALE_LINEAR),
32   m_coordUnitsX (COORD_UNITS_NON_POLAR_THETA_NUMBER),
33   m_coordUnitsY (COORD_UNITS_NON_POLAR_THETA_NUMBER),
34   m_coordUnitsTheta (COORD_UNITS_POLAR_THETA_DEGREES),
35   m_coordUnitsRadius (COORD_UNITS_NON_POLAR_THETA_NUMBER),
36   m_coordUnitsDate (COORD_UNITS_DATE_YEAR_MONTH_DAY),
37   m_coordUnitsTime (COORD_UNITS_TIME_HOUR_MINUTE_SECOND)
38 {
39 }
40 
DocumentModelCoords(const Document & document)41 DocumentModelCoords::DocumentModelCoords(const Document &document) :
42   m_coordsType (document.modelCoords().coordsType()),
43   m_originRadius(document.modelCoords().originRadius()),
44   m_coordScaleXTheta(document.modelCoords().coordScaleXTheta()),
45   m_coordScaleYRadius(document.modelCoords().coordScaleYRadius()),
46   m_coordUnitsX(document.modelCoords().coordUnitsX()),
47   m_coordUnitsY(document.modelCoords().coordUnitsY()),
48   m_coordUnitsTheta(document.modelCoords().coordUnitsTheta()),
49   m_coordUnitsRadius(document.modelCoords().coordUnitsRadius()),
50   m_coordUnitsDate(document.modelCoords().coordUnitsDate()),
51   m_coordUnitsTime(document.modelCoords().coordUnitsTime())
52 {
53 }
54 
DocumentModelCoords(const DocumentModelCoords & other)55 DocumentModelCoords::DocumentModelCoords(const DocumentModelCoords &other) :
56   m_coordsType (other.coordsType ()),
57   m_originRadius (other.originRadius ()),
58   m_coordScaleXTheta (other.coordScaleXTheta()),
59   m_coordScaleYRadius (other.coordScaleYRadius ()),
60   m_coordUnitsX (other.coordUnitsX()),
61   m_coordUnitsY (other.coordUnitsY()),
62   m_coordUnitsTheta (other.coordUnitsTheta ()),
63   m_coordUnitsRadius (other.coordUnitsRadius ()),
64   m_coordUnitsDate (other.coordUnitsDate ()),
65   m_coordUnitsTime (other.coordUnitsTime ())
66 {
67 }
68 
operator =(const DocumentModelCoords & other)69 DocumentModelCoords &DocumentModelCoords::operator=(const DocumentModelCoords &other)
70 {
71   m_coordsType = other.coordsType();
72   m_originRadius = other.originRadius();
73   m_coordScaleXTheta = other.coordScaleXTheta();
74   m_coordScaleYRadius = other.coordScaleYRadius();
75   m_coordUnitsX = other.coordUnitsX();
76   m_coordUnitsY = other.coordUnitsY();
77   m_coordUnitsTheta = other.coordUnitsTheta();
78   m_coordUnitsRadius = other.coordUnitsRadius();
79   m_coordUnitsDate = other.coordUnitsDate();
80   m_coordUnitsTime = other.coordUnitsTime();
81 
82   return *this;
83 }
84 
coordScaleXTheta() const85 CoordScale DocumentModelCoords::coordScaleXTheta () const
86 {
87   return m_coordScaleXTheta;
88 }
89 
coordScaleYRadius() const90 CoordScale DocumentModelCoords::coordScaleYRadius () const
91 {
92   return m_coordScaleYRadius;
93 }
94 
coordsType() const95 CoordsType DocumentModelCoords::coordsType () const
96 {
97   return m_coordsType;
98 }
99 
coordUnitsDate() const100 CoordUnitsDate DocumentModelCoords::coordUnitsDate() const
101 {
102   return m_coordUnitsDate;
103 }
104 
coordUnitsRadius() const105 CoordUnitsNonPolarTheta DocumentModelCoords::coordUnitsRadius() const
106 {
107   return m_coordUnitsRadius;
108 }
109 
coordUnitsTheta() const110 CoordUnitsPolarTheta DocumentModelCoords::coordUnitsTheta() const
111 {
112   return m_coordUnitsTheta;
113 }
114 
coordUnitsTime() const115 CoordUnitsTime DocumentModelCoords::coordUnitsTime() const
116 {
117   return m_coordUnitsTime;
118 }
119 
coordUnitsX() const120 CoordUnitsNonPolarTheta DocumentModelCoords::coordUnitsX() const
121 {
122   return m_coordUnitsX;
123 }
124 
coordUnitsY() const125 CoordUnitsNonPolarTheta DocumentModelCoords::coordUnitsY() const
126 {
127   return m_coordUnitsY;
128 }
129 
loadXml(QXmlStreamReader & reader)130 void DocumentModelCoords::loadXml(QXmlStreamReader &reader)
131 {
132   LOG4CPP_INFO_S ((*mainCat)) << "DocumentModelCoords::loadXml";
133 
134   bool success = true;
135 
136   QXmlStreamAttributes attributes = reader.attributes();
137 
138   if (attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_TYPE) &&
139       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_ORIGIN_RADIUS) &&
140       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_X_THETA) &&
141       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_Y_RADIUS) &&
142       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_X) &&
143       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_Y) &&
144       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_THETA) &&
145       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_RADIUS) &&
146       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_DATE) &&
147       attributes.hasAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_TIME)) {
148 
149     setCoordsType (static_cast<CoordsType> (attributes.value(DOCUMENT_SERIALIZE_COORDS_TYPE).toInt()));
150     setOriginRadius (attributes.value(DOCUMENT_SERIALIZE_COORDS_ORIGIN_RADIUS).toDouble());
151     setCoordScaleXTheta (static_cast<CoordScale> (attributes.value(DOCUMENT_SERIALIZE_COORDS_SCALE_X_THETA).toInt()));
152     setCoordScaleYRadius (static_cast<CoordScale> (attributes.value(DOCUMENT_SERIALIZE_COORDS_SCALE_Y_RADIUS).toInt()));
153     setCoordUnitsX (static_cast<CoordUnitsNonPolarTheta> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_X).toInt()));
154     setCoordUnitsY (static_cast<CoordUnitsNonPolarTheta> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_Y).toInt()));
155     setCoordUnitsTheta (static_cast<CoordUnitsPolarTheta> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_THETA).toInt()));
156     setCoordUnitsRadius (static_cast<CoordUnitsNonPolarTheta> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_RADIUS).toInt()));
157     setCoordUnitsDate (static_cast<CoordUnitsDate> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_DATE).toInt()));
158     setCoordUnitsTime (static_cast<CoordUnitsTime> (attributes.value(DOCUMENT_SERIALIZE_COORDS_UNITS_TIME).toInt()));
159 
160     // Read until end of this subtree
161     while ((reader.tokenType() != QXmlStreamReader::EndElement) ||
162     (reader.name() != DOCUMENT_SERIALIZE_COORDS)){
163       loadNextFromReader(reader);
164       if (reader.atEnd()) {
165         success = false;
166         break;
167       }
168     }
169   }
170 
171   if (!success) {
172     reader.raiseError (QObject::tr ("Cannot read coordinates data"));
173   }
174 }
175 
originRadius() const176 double DocumentModelCoords::originRadius() const
177 {
178   return m_originRadius;
179 }
180 
printStream(QString indentation,QTextStream & str) const181 void DocumentModelCoords::printStream(QString indentation,
182                                       QTextStream &str) const
183 {
184   str << indentation << "DocumentModelCoords\n";
185 
186   indentation += INDENTATION_DELTA;
187 
188   str << indentation << "coordsType=" << coordsTypeToString (m_coordsType) << "\n";
189   str << indentation << "originRadius=" << m_originRadius << "\n";
190   str << indentation << "coordScaleXTheta=" << coordScaleToString (m_coordScaleXTheta) << "\n";
191   str << indentation << "coordScaleYRadius=" << coordScaleToString (m_coordScaleYRadius) << "\n";
192   str << indentation << "coordUnitsX=" << coordUnitsNonPolarThetaToString (m_coordUnitsX) << "\n";
193   str << indentation << "coordUnitsY=" << coordUnitsNonPolarThetaToString (m_coordUnitsY) << "\n";
194   str << indentation << "coordUnitsTheta=" << coordUnitsPolarThetaToString (m_coordUnitsTheta) << "\n";
195   str << indentation << "coordUnitsRadius=" << coordUnitsNonPolarThetaToString (m_coordUnitsRadius) << "\n";
196   str << indentation << "coordUnitsDate=" << coordUnitsDateToString (m_coordUnitsDate) << "\n";
197   str << indentation << "coordUnitsTime=" << coordUnitsTimeToString (m_coordUnitsTime) << "\n";
198 }
199 
saveXml(QXmlStreamWriter & writer) const200 void DocumentModelCoords::saveXml(QXmlStreamWriter &writer) const
201 {
202   LOG4CPP_INFO_S ((*mainCat)) << "DocumentModelCoords::saveXml";
203 
204   writer.writeStartElement(DOCUMENT_SERIALIZE_COORDS);
205   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_TYPE, QString::number (m_coordsType));
206   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_TYPE_STRING, coordsTypeToString (m_coordsType));
207   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_ORIGIN_RADIUS, QString::number (m_originRadius));
208   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_X_THETA, QString::number (m_coordScaleXTheta));
209   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_X_THETA_STRING, coordScaleToString (m_coordScaleXTheta));
210   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_Y_RADIUS, QString::number (m_coordScaleYRadius));
211   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_SCALE_Y_RADIUS_STRING, coordScaleToString (m_coordScaleYRadius));
212   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_X, QString::number (m_coordUnitsX));
213   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_X_STRING, coordUnitsNonPolarThetaToString (m_coordUnitsX));
214   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_Y, QString::number (m_coordUnitsY));
215   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_Y_STRING, coordUnitsNonPolarThetaToString (m_coordUnitsY));
216   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_THETA, QString::number (m_coordUnitsTheta));
217   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_THETA_STRING, coordUnitsPolarThetaToString (m_coordUnitsTheta));
218   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_RADIUS, QString::number (m_coordUnitsRadius));
219   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_RADIUS_STRING, coordUnitsNonPolarThetaToString (m_coordUnitsRadius));
220   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_DATE, QString::number (m_coordUnitsDate));
221   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_DATE_STRING, coordUnitsDateToString (m_coordUnitsDate));
222   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_TIME, QString::number (m_coordUnitsTime));
223   writer.writeAttribute(DOCUMENT_SERIALIZE_COORDS_UNITS_TIME_STRING, coordUnitsTimeToString (m_coordUnitsTime));
224   writer.writeEndElement();
225 }
226 
setCoordScaleXTheta(CoordScale coordScale)227 void DocumentModelCoords::setCoordScaleXTheta (CoordScale coordScale)
228 {
229   m_coordScaleXTheta = coordScale;
230 }
231 
setCoordScaleYRadius(CoordScale coordScale)232 void DocumentModelCoords::setCoordScaleYRadius (CoordScale coordScale)
233 {
234   m_coordScaleYRadius = coordScale;
235 }
236 
setCoordsType(CoordsType coordsType)237 void DocumentModelCoords::setCoordsType (CoordsType coordsType)
238 {
239   m_coordsType = coordsType;
240 }
241 
setCoordUnitsDate(CoordUnitsDate coordUnits)242 void DocumentModelCoords::setCoordUnitsDate(CoordUnitsDate coordUnits)
243 {
244   m_coordUnitsDate = coordUnits;
245 }
246 
setCoordUnitsRadius(CoordUnitsNonPolarTheta coordUnits)247 void DocumentModelCoords::setCoordUnitsRadius (CoordUnitsNonPolarTheta coordUnits)
248 {
249   m_coordUnitsRadius = coordUnits;
250 }
251 
setCoordUnitsTheta(CoordUnitsPolarTheta coordUnits)252 void DocumentModelCoords::setCoordUnitsTheta (CoordUnitsPolarTheta coordUnits)
253 {
254   m_coordUnitsTheta = coordUnits;
255 }
256 
setCoordUnitsTime(CoordUnitsTime coordUnits)257 void DocumentModelCoords::setCoordUnitsTime(CoordUnitsTime coordUnits)
258 {
259   m_coordUnitsTime = coordUnits;
260 }
261 
setCoordUnitsX(CoordUnitsNonPolarTheta coordUnits)262 void DocumentModelCoords::setCoordUnitsX (CoordUnitsNonPolarTheta coordUnits)
263 {
264   m_coordUnitsX = coordUnits;
265 }
266 
setCoordUnitsY(CoordUnitsNonPolarTheta coordUnits)267 void DocumentModelCoords::setCoordUnitsY (CoordUnitsNonPolarTheta coordUnits)
268 {
269   m_coordUnitsY = coordUnits;
270 }
271 
setOriginRadius(double originRadius)272 void DocumentModelCoords::setOriginRadius(double originRadius)
273 {
274   m_originRadius = originRadius;
275 }
276 
thetaPeriod() const277 double DocumentModelCoords::thetaPeriod () const
278 {
279   switch (m_coordUnitsTheta) {
280     case COORD_UNITS_POLAR_THETA_DEGREES:
281     case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
282     case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
283     case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
284       return 360;
285 
286     case COORD_UNITS_POLAR_THETA_GRADIANS:
287       return 400;
288 
289     case COORD_UNITS_POLAR_THETA_RADIANS:
290       return TWO_PI;
291 
292     case COORD_UNITS_POLAR_THETA_TURNS:
293       return 1;
294 
295     default:
296       break;
297   }
298 
299   LOG4CPP_ERROR_S ((*mainCat)) << "DocumentModelCoords::thetaPeriod";
300 
301   ENGAUGE_ASSERT(false);
302   return 0;
303 }
304