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 "Curve.h"
8 #include "CurvesGraphs.h"
9 #include "CurveStyles.h"
10 #include "DocumentSerialize.h"
11 #include "EngaugeAssert.h"
12 #include "Logger.h"
13 #include "Point.h"
14 #include <qdebug.h>
15 #include <QTextStream>
16 #include <QXmlStreamWriter>
17 #include "Transformation.h"
18 #include "Xml.h"
19
CurvesGraphs()20 CurvesGraphs::CurvesGraphs()
21 {
22 }
23
addGraphCurveAtEnd(const Curve & curve)24 void CurvesGraphs::addGraphCurveAtEnd (const Curve &curve)
25 {
26 m_curvesGraphs.push_back (curve);
27 }
28
addPoint(const Point & point)29 void CurvesGraphs::addPoint (const Point &point)
30 {
31 QString curveName = Point::curveNameFromPointIdentifier (point.identifier());
32
33 Curve *curve = curveForCurveName (curveName);
34 curve->addPoint (point);
35 }
36
curveForCurveName(const QString & curveName)37 Curve *CurvesGraphs::curveForCurveName (const QString &curveName)
38 {
39 // Search for curve with matching name
40 CurveList::iterator itr;
41 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
42
43 Curve &curve = *itr;
44 if (curveName == curve.curveName ()) {
45 return &curve;
46 }
47 }
48
49 return nullptr;
50 }
51
curveForCurveName(const QString & curveName) const52 const Curve *CurvesGraphs::curveForCurveName (const QString &curveName) const
53 {
54 // Search for curve with matching name
55 CurveList::const_iterator itr;
56 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
57
58 const Curve &curve = *itr;
59 if (curveName == curve.curveName ()) {
60 return &curve;
61 }
62 }
63
64 return nullptr;
65 }
66
curvesGraphsNames() const67 QStringList CurvesGraphs::curvesGraphsNames () const
68 {
69 QStringList names;
70
71 CurveList::const_iterator itr;
72 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
73
74 const Curve &curve = *itr;
75 names << curve.curveName ();
76 }
77
78 return names;
79 }
80
curvesGraphsNumPoints(const QString & curveName) const81 int CurvesGraphs::curvesGraphsNumPoints (const QString &curveName) const
82 {
83 // Search for curve with matching name
84 CurveList::const_iterator itr;
85 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
86
87 const Curve &curve = *itr;
88 if (curve.curveName () == curveName) {
89 return curve.numPoints ();
90 }
91 }
92
93 return 0;
94 }
95
editPointGraph(bool isX,bool isY,double x,double y,const QStringList & identifiers,const Transformation & transformation)96 void CurvesGraphs::editPointGraph (bool isX,
97 bool isY,
98 double x,
99 double y,
100 const QStringList &identifiers,
101 const Transformation &transformation)
102 {
103 CurveList::iterator itr;
104 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
105
106 Curve &curve = *itr;
107 curve.editPointGraph (isX,
108 isY,
109 x,
110 y,
111 identifiers,
112 transformation);
113 }
114 }
115
iterateThroughCurvePoints(const QString & curveNameWanted,const Functor2wRet<const QString &,const Point &,CallbackSearchReturn> & ftorWithCallback)116 void CurvesGraphs::iterateThroughCurvePoints (const QString &curveNameWanted,
117 const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback)
118 {
119 // Search for curve with matching name
120 CurveList::const_iterator itr;
121 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
122
123 const Curve &curve = *itr;
124 if (curve.curveName () == curveNameWanted) {
125
126 curve.iterateThroughCurvePoints (ftorWithCallback);
127 return;
128 }
129 }
130
131 LOG4CPP_ERROR_S ((*mainCat)) << "CurvesGraphs::iterateThroughCurvePoints encountered unexpected curve "
132 << curveNameWanted.toLatin1().data();
133 ENGAUGE_ASSERT (false);
134 }
135
iterateThroughCurveSegments(const QString & curveNameWanted,const Functor2wRet<const Point &,const Point &,CallbackSearchReturn> & ftorWithCallback) const136 void CurvesGraphs::iterateThroughCurveSegments (const QString &curveNameWanted,
137 const Functor2wRet<const Point &, const Point &, CallbackSearchReturn> &ftorWithCallback) const
138 {
139 // Search for curve with matching name
140 CurveList::const_iterator itr;
141 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
142
143 const Curve &curve = *itr;
144 if (curve.curveName () == curveNameWanted) {
145
146 curve.iterateThroughCurveSegments (ftorWithCallback);
147 return;
148 }
149 }
150
151 LOG4CPP_ERROR_S ((*mainCat)) << "CurvesGraphs::iterateThroughCurveSegments encountered unexpected curve "
152 << curveNameWanted.toLatin1().data();
153 ENGAUGE_ASSERT (false);
154 }
155
iterateThroughCurvesPoints(const Functor2wRet<const QString &,const Point &,CallbackSearchReturn> & ftorWithCallback)156 void CurvesGraphs::iterateThroughCurvesPoints (const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback)
157 {
158 CurveList::const_iterator itr;
159 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
160
161 const Curve &curve = *itr;
162 curve.iterateThroughCurvePoints (ftorWithCallback);
163 }
164 }
165
iterateThroughCurvesPoints(const Functor2wRet<const QString &,const Point &,CallbackSearchReturn> & ftorWithCallback) const166 void CurvesGraphs::iterateThroughCurvesPoints (const Functor2wRet<const QString &, const Point &, CallbackSearchReturn> &ftorWithCallback) const
167 {
168 CurveList::const_iterator itr;
169 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
170
171 const Curve &curve = *itr;
172 curve.iterateThroughCurvePoints (ftorWithCallback);
173 }
174 }
175
loadPreVersion6(QDataStream & str)176 void CurvesGraphs::loadPreVersion6(QDataStream &str)
177 {
178 LOG4CPP_INFO_S ((*mainCat)) << "CurvesGraphs::loadPreVersion6";
179
180 int i;
181
182 // Remove previous Curves. There is a DEFAULT_GRAPH_CURVE_NAME by default
183 m_curvesGraphs.clear();
184
185 qint32 numberCurvesGraphs;
186 str >> numberCurvesGraphs;
187 for (i = 0; i < numberCurvesGraphs; i++) {
188 Curve curve (str);
189 m_curvesGraphs.append (curve);
190 }
191
192 qint32 numberCurvesMeasures;
193 str >> numberCurvesMeasures;
194 for (i = 0; i < numberCurvesMeasures; i++) {
195 Curve curve (str);
196
197 // Measures get dropped on the floor
198 }
199 }
200
loadXml(QXmlStreamReader & reader)201 void CurvesGraphs::loadXml(QXmlStreamReader &reader)
202 {
203 LOG4CPP_INFO_S ((*mainCat)) << "CurvesGraphs::loadXml";
204
205 bool success = true;
206
207 // Remove previous Curves. There is a DEFAULT_GRAPH_CURVE_NAME by default
208 m_curvesGraphs.clear();
209
210 // Read until end of this subtree
211 while ((reader.tokenType() != QXmlStreamReader::EndElement) ||
212 (reader.name() != DOCUMENT_SERIALIZE_CURVES_GRAPHS)){
213
214 loadNextFromReader(reader);
215 if (reader.atEnd()) {
216 success = false;
217 break;
218 }
219
220 if ((reader.tokenType() == QXmlStreamReader::StartElement) &&
221 (reader.name () == DOCUMENT_SERIALIZE_CURVE)) {
222
223 Curve curve (reader);
224
225 // Version 6 of Engauge let users create multiple curves with the same name. Reading a file with duplicate
226 // curve names can result in crashes and/or corruption, so we deconflict duplicate curve names here
227 QString DUPLICATE = QString ("-%1").arg (QObject::tr ("DUPLICATE"));
228 QString curveName = curve.curveName();
229 while (curvesGraphsNames().contains (curveName)) {
230 curveName += DUPLICATE;
231 }
232 curve.setCurveName (curveName); // No effect if curve name was not a duplicate
233
234 // Add the curve
235 m_curvesGraphs.push_back (curve);
236
237 }
238 }
239
240 if (!success) {
241 reader.raiseError (QObject::tr ("Cannot read graph curves data"));
242 }
243 }
244
numCurves() const245 int CurvesGraphs::numCurves () const
246 {
247 return m_curvesGraphs.count ();
248 }
249
printStream(QString indentation,QTextStream & str) const250 void CurvesGraphs::printStream (QString indentation,
251 QTextStream &str) const
252 {
253 str << indentation << "CurvesGraphs\n";
254
255 indentation += INDENTATION_DELTA;
256
257 CurveList::const_iterator itr;
258 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
259
260 const Curve &curve = *itr;
261 curve.printStream (indentation,
262 str);
263 }
264 }
265
removePoint(const QString & pointIdentifier)266 void CurvesGraphs::removePoint (const QString &pointIdentifier)
267 {
268 QString curveName = Point::curveNameFromPointIdentifier(pointIdentifier);
269
270 Curve *curve = curveForCurveName (curveName);
271 curve->removePoint (pointIdentifier);
272 }
273
saveXml(QXmlStreamWriter & writer) const274 void CurvesGraphs::saveXml(QXmlStreamWriter &writer) const
275 {
276 LOG4CPP_INFO_S ((*mainCat)) << "CurvesGraphs::saveXml";
277
278 writer.writeStartElement(DOCUMENT_SERIALIZE_CURVES_GRAPHS);
279
280 CurveList::const_iterator itr;
281 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
282
283 const Curve &curve = *itr;
284 curve.saveXml (writer);
285 }
286
287 writer.writeEndElement();
288 }
289
updatePointOrdinals(const Transformation & transformation)290 void CurvesGraphs::updatePointOrdinals (const Transformation &transformation)
291 {
292 LOG4CPP_INFO_S ((*mainCat)) << "CurvesGraphs::updatePointOrdinals";
293
294 CurveList::iterator itr;
295 for (itr = m_curvesGraphs.begin (); itr != m_curvesGraphs.end (); itr++) {
296
297 Curve &curve = *itr;
298 curve.updatePointOrdinals (transformation);
299 }
300 }
301