Engauge Digitizer 2
Loading...
Searching...
No Matches
Point.cpp
Go to the documentation of this file.
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 "DocumentSerialize.h"
8#include "EngaugeAssert.h"
9#include "Logger.h"
10#include "Point.h"
11#include <QObject>
12#include <QStringList>
13#include <QTextStream>
14#include "QtToString.h"
15#include <QXmlStreamReader>
16#include <QXmlStreamWriter>
17#include "Xml.h"
18
19unsigned int Point::m_identifierIndex = 0;
20
21extern const QString AXIS_CURVE_NAME;
22extern const QString DUMMY_CURVE_NAME;
23const QString POINT_IDENTIFIER_DELIMITER_SAFE ("\t"); // Character that could never be entered when editing curve names
24const QString POINT_IDENTIFIER_DELIMITER_XML ("_"); // From incoming xml that does not like tabs
25
26const double MISSING_ORDINAL_VALUE = 0;
27const double MISSING_POSGRAPH_VALUE = 0;
28
30{
31}
32
33Point::Point(const QString &curveName,
34 const QPointF &posScreen) :
35 m_isAxisPoint (curveName == AXIS_CURVE_NAME),
36 m_identifier (uniqueIdentifierGenerator(curveName)),
37 m_posScreen (posScreen),
38 m_hasPosGraph (false),
40 m_hasOrdinal (false),
41 m_ordinal (MISSING_ORDINAL_VALUE),
42 m_isXOnly (false)
43{
44 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point"
45 << " curveName=" << curveName.toLatin1().data()
46 << " identifierGenerated=" << m_identifier.toLatin1().data()
47 << " posScreen=" << QPointFToString (posScreen).toLatin1().data();
48
49 ENGAUGE_ASSERT (!curveName.isEmpty ());
50}
51
52Point::Point(const QString &curveName,
53 const QPointF &posScreen,
54 const QPointF &posGraph,
55 bool isXOnly) :
56 m_isAxisPoint (true),
57 m_identifier (uniqueIdentifierGenerator(curveName)),
58 m_posScreen (posScreen),
59 m_hasPosGraph (true),
60 m_posGraph (posGraph),
61 m_hasOrdinal (false),
62 m_ordinal (MISSING_ORDINAL_VALUE),
63 m_isXOnly (isXOnly)
64{
65 ENGAUGE_ASSERT (curveName == AXIS_CURVE_NAME ||
66 curveName == DUMMY_CURVE_NAME);
67
68 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point"
69 << " curveName=" << curveName.toLatin1().data()
70 << " identifierGenerated=" << m_identifier.toLatin1().data()
71 << " posScreen=" << QPointFToString (posScreen).toLatin1().data()
72 << " posGraph=" << QPointFToString (posGraph).toLatin1().data()
73 << " isXOnly=" << (isXOnly ? "true" : "false");
74
75 ENGAUGE_ASSERT (!curveName.isEmpty ());
76}
77
78Point::Point(const QString &curveName,
79 const QString &identifier,
80 const QPointF &posScreen,
81 const QPointF &posGraph,
82 double ordinal,
83 bool isXOnly) :
84 m_isAxisPoint (true),
85 m_identifier (identifier),
86 m_posScreen (posScreen),
87 m_hasPosGraph (true),
88 m_posGraph (posGraph),
89 m_hasOrdinal (true),
90 m_ordinal (ordinal),
91 m_isXOnly (isXOnly)
92{
93 ENGAUGE_ASSERT (curveName == AXIS_CURVE_NAME);
94
95 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point"
96 << " curveName=" << curveName.toLatin1().data()
97 << " identifier=" << m_identifier.toLatin1().data()
98 << " posScreen=" << QPointFToString (posScreen).toLatin1().data()
99 << " posGraph=" << QPointFToString (posGraph).toLatin1().data()
100 << " ordinal=" << ordinal
101 << " isXOnly=" << (isXOnly ? "true" : "false");
102
103 ENGAUGE_ASSERT (!curveName.isEmpty ());
104}
105
106Point::Point(const QString &curveName,
107 const QPointF &posScreen,
108 const QPointF &posGraph,
109 double ordinal,
110 bool isXOnly) :
111 m_isAxisPoint (true),
112 m_identifier (uniqueIdentifierGenerator(curveName)),
113 m_posScreen (posScreen),
114 m_hasPosGraph (true),
115 m_posGraph (posGraph),
116 m_hasOrdinal (true),
117 m_ordinal (ordinal),
118 m_isXOnly (isXOnly)
119{
120 ENGAUGE_ASSERT (curveName == AXIS_CURVE_NAME);
121
122 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point"
123 << " curveName=" << curveName.toLatin1().data()
124 << " identifierGenerated=" << m_identifier.toLatin1().data()
125 << " posScreen=" << QPointFToString (posScreen).toLatin1().data()
126 << " posGraph=" << QPointFToString (posGraph).toLatin1().data()
127 << " ordinal=" << ordinal
128 << " isXOnly=" << (isXOnly ? "true" : "false");
129
130 ENGAUGE_ASSERT (!curveName.isEmpty ());
131}
132
133Point::Point(const QString &curveName,
134 const QString &identifier,
135 const QPointF &posScreen,
136 double ordinal) :
137 m_isAxisPoint (false),
138 m_identifier (identifier),
139 m_posScreen (posScreen),
140 m_hasPosGraph (false),
142 m_hasOrdinal (true),
143 m_ordinal (ordinal),
144 m_isXOnly (false)
145{
146 ENGAUGE_ASSERT (curveName != AXIS_CURVE_NAME);
147
148 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point"
149 << " curveName=" << curveName.toLatin1().data()
150 << " identifier=" << identifier.toLatin1().data()
151 << " posScreen=" << QPointFToString (posScreen).toLatin1().data()
152 << " ordinal=" << ordinal;
153
154 ENGAUGE_ASSERT (!curveName.isEmpty ());
155}
156
157Point::Point (const QString &curveName,
158 const QPointF &posScreen,
159 double ordinal) :
160 m_isAxisPoint (false),
161 m_identifier (uniqueIdentifierGenerator(curveName)),
162 m_posScreen (posScreen),
163 m_hasPosGraph (false),
165 m_hasOrdinal (true),
166 m_ordinal (ordinal),
167 m_isXOnly (false)
168{
169 ENGAUGE_ASSERT (curveName != AXIS_CURVE_NAME);
170
171 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point(identifier,posScreen,posGraph,ordinal)"
172 << " identifierGenerated=" << m_identifier.toLatin1().data()
173 << " posScreen=" << QPointFToString (posScreen).toLatin1().data()
174 << " ordinal=" << ordinal;
175}
176
178{
179 loadXml(reader);
180}
181
183{
184 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::Point(const Point &other)"
185 << " isAxisPoint=" << (other.isAxisPoint() ? "true" : "false")
186 << " identifier=" << other.identifier ().toLatin1().data()
187 << " posScreen=" << QPointFToString (other.posScreen ()).toLatin1().data()
188 << " hasPosGraph=" << (other.hasPosGraph() ? "true" : "false")
189 << " posGraph=" << QPointFToString (other.posGraph (SKIP_HAS_CHECK)).toLatin1().data()
190 << " hasOrdinal=" << (other.hasOrdinal() ? "true" : "false")
191 << " ordinal=" << other.ordinal (SKIP_HAS_CHECK)
192 << " isXOnly=" << other.isXOnly ();
193
194 m_isAxisPoint = other.isAxisPoint ();
195 m_identifier = other.identifier ();
196 m_posScreen = other.posScreen ();
197 m_hasPosGraph = other.hasPosGraph ();
198 m_posGraph = other.posGraph (SKIP_HAS_CHECK);
199 m_hasOrdinal = other.hasOrdinal ();
200 m_ordinal = other.ordinal (SKIP_HAS_CHECK);
201 m_isXOnly = other.isXOnly ();
202}
203
205{
206 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::operator="
207 << " isAxisPoint=" << (point.isAxisPoint() ? "true" : "false")
208 << " identifier=" << point.identifier ().toLatin1().data()
209 << " posScreen=" << QPointFToString (point.posScreen ()).toLatin1().data()
210 << " hasPosGraph=" << (point.hasPosGraph() ? "true" : "false")
211 << " posGraph=" << QPointFToString (point.posGraph (SKIP_HAS_CHECK)).toLatin1().data()
212 << " hasOrdinal=" << (point.hasOrdinal() ? "true" : "false")
213 << " ordinal=" << point.ordinal (SKIP_HAS_CHECK);
214
215 m_isAxisPoint = point.isAxisPoint ();
216 m_identifier = point.identifier ();
217 m_posScreen = point.posScreen ();
218 m_hasPosGraph = point.hasPosGraph ();
219 m_posGraph = point.posGraph (SKIP_HAS_CHECK);
220 m_hasOrdinal = point.hasOrdinal ();
221 m_ordinal = point.ordinal (SKIP_HAS_CHECK);
222 m_isXOnly = point.isXOnly ();
223
224 return *this;
225}
226
228{
230
232
234
235 } else {
236
237 // Yes, this is a hack - underscores could have been inserted by user (in the curve name) and/or this source code,
238 // but there are many dig files laying around that have underscores so we need to support them
240
241 }
242
243 return tokens.value (0);
244}
245
246QString Point::fixUnderscores (const QString &identifier) const
247{
249
253 }
254
255 return rtn;
256}
257
258bool Point::hasOrdinal () const
259{
260 return m_hasOrdinal;
261}
262
264{
265 return m_hasPosGraph;
266}
267
269{
270 return m_identifier;
271}
272
274{
275 LOG4CPP_INFO_S ((*mainCat)) << "Point::identifierIndex"
276 << " identifierIndex=" << m_identifierIndex;
277
278 return m_identifierIndex;
279}
280
282{
283 return m_isAxisPoint;
284}
285
286bool Point::isXOnly() const
287{
288 return m_isXOnly;
289}
290
291void Point::loadXml(QXmlStreamReader &reader)
292{
293 LOG4CPP_INFO_S ((*mainCat)) << "Point::loadXml";
294
295 bool success = true;
296
298
299 // Note that DOCUMENT_SERIALIZE_POINT_IS_X_ONLY is optional since it is not used in Version 6
300 // but is used in Version 7
304
305 m_hasOrdinal = attributes.hasAttribute(DOCUMENT_SERIALIZE_POINT_ORDINAL);
306 if (m_hasOrdinal) {
307 m_ordinal = attributes.value(DOCUMENT_SERIALIZE_POINT_ORDINAL).toDouble();
308 } else {
309 m_ordinal = MISSING_ORDINAL_VALUE;
310 }
311
313 QString isXOnly; // Default is anything but DOCUMENT_SERIALIZE_BOOL_TRUE
316 }
317
318 m_identifier = fixUnderscores (attributes.value(DOCUMENT_SERIALIZE_POINT_IDENTIFIER).toString());
319 m_identifierIndex = attributes.value(DOCUMENT_SERIALIZE_POINT_IDENTIFIER_INDEX).toUInt();
320 m_isAxisPoint = (isAxisPoint == DOCUMENT_SERIALIZE_BOOL_TRUE);
321 m_hasPosGraph = false;
322 m_posGraph.setX (MISSING_POSGRAPH_VALUE);
323 m_posGraph.setY (MISSING_POSGRAPH_VALUE);
324 m_isXOnly = (isXOnly == DOCUMENT_SERIALIZE_BOOL_TRUE);
325
326 while ((reader.tokenType() != QXmlStreamReader::EndElement) ||
327 (reader.name () != DOCUMENT_SERIALIZE_POINT)) {
328
330 if (reader.atEnd()) {
331 success = false;
332 break;
333 }
334
335 if (reader.tokenType () == QXmlStreamReader::StartElement) {
336
338
339 attributes = reader.attributes();
340
341 if (attributes.hasAttribute(DOCUMENT_SERIALIZE_POINT_X) &&
343
344 m_posScreen.setX (attributes.value(DOCUMENT_SERIALIZE_POINT_X).toDouble());
345 m_posScreen.setY (attributes.value(DOCUMENT_SERIALIZE_POINT_Y).toDouble());
346
347 } else {
348 success = false;
349 break;
350 }
351 } else if (reader.name() == DOCUMENT_SERIALIZE_POINT_POSITION_GRAPH) {
352
353 m_hasPosGraph = true;
354 attributes = reader.attributes();
355
356 if (attributes.hasAttribute(DOCUMENT_SERIALIZE_POINT_X) &&
358
359 m_posGraph.setX (attributes.value(DOCUMENT_SERIALIZE_POINT_X).toDouble());
360 m_posGraph.setY (attributes.value(DOCUMENT_SERIALIZE_POINT_Y).toDouble());
361
362 } else {
363 success = false;
364 break;
365 }
366 }
367 }
368 }
369
370 LOG4CPP_INFO_S ((*mainCat)) << "Point::loadXml"
371 << " identifier=" << m_identifier.toLatin1().data()
372 << " identifierIndex=" << m_identifierIndex
373 << " posScreen=" << QPointFToString (m_posScreen).toLatin1().data()
374 << " posGraph=" << QPointFToString (m_posGraph).toLatin1().data()
375 << " ordinal=" << m_ordinal;
376
377 } else {
378 success = false;
379 }
380
381 if (!success) {
382 reader.raiseError(QObject::tr ("Cannot read point data"));
383 }
384}
385
387{
389 ENGAUGE_ASSERT (m_hasOrdinal);
390 }
391
392 return m_ordinal;
393}
394
396{
398 ENGAUGE_ASSERT (m_hasPosGraph);
399 }
400
401 return m_posGraph;
402}
403
405{
406 return m_posScreen;
407}
408
410 QTextStream &str) const
411{
412 const QString UNDEFINED ("undefined");
413
414 str << indentation << "Point\n";
415
417
418 str << indentation << "identifier=" << m_identifier << "\n";
419 str << indentation << "posScreen=" << QPointFToString (m_posScreen) << "\n";
420 if (m_hasPosGraph) {
421 str << indentation << "posGraph=" << QPointFToString (m_posGraph) << "\n";
422 } else {
423 str << indentation << "posGraph=" << UNDEFINED << "\n";
424 }
425 if (m_hasOrdinal) {
426 str << indentation << "ordinal=" << m_ordinal << "\n";
427 } else {
428 str << indentation << "ordinal=" << UNDEFINED << "\n";
429 }
430}
431
433{
434 LOG4CPP_INFO_S ((*mainCat)) << "Point::saveXml";
435
436 writer.writeStartElement(DOCUMENT_SERIALIZE_POINT);
437 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_IDENTIFIER, m_identifier);
438 if (m_hasOrdinal) {
439 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_ORDINAL, QString::number (m_ordinal));
440 }
445
446 // Variable m_identifierIndex is static, but for simplicity this is handled like other values. Those values are all
447 // the same, but simplicity wins over a few extra bytes of storage
448 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_IDENTIFIER_INDEX, QString::number (m_identifierIndex));
449
451 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_X, QString::number (m_posScreen.x()));
452 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_Y, QString::number (m_posScreen.y()));
453 writer.writeEndElement();
454
455 if (m_hasPosGraph) {
456
457 // For time coordinates, many digits of precision are needed since a typical date is 1,246,870,000 = July 6, 2009
458 // and we want seconds of precision
459 const char FORMAT = 'g';
460 const int PRECISION = 16;
461
463 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_X, QString::number (m_posGraph.x(), FORMAT, PRECISION));
464 writer.writeAttribute(DOCUMENT_SERIALIZE_POINT_Y, QString::number (m_posGraph.y(), FORMAT, PRECISION));
465 writer.writeEndElement();
466 }
467
468 writer.writeEndElement();
469}
470
472{
473 // Replace the old curve name at the start of the string
475 m_identifier = curveNameNew + m_identifier.mid (curveNameOld.length());
476}
477
478void Point::setIdentifierIndex (unsigned int identifierIndex)
479{
480 LOG4CPP_INFO_S ((*mainCat)) << "Point::setIdentifierIndex"
481 << " identifierIndex=" << identifierIndex;
482
483 m_identifierIndex = identifierIndex;
484}
485
486void Point::setOrdinal(double ordinal)
487{
488 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::setOrdinal"
489 << " identifier=" << m_identifier.toLatin1().data()
490 << " ordinal=" << ordinal;
491
492 m_hasOrdinal = true;
493 m_ordinal = ordinal;
494}
495
496void Point::setPosGraph (const QPointF &posGraph)
497{
498 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::setPosGraph"
499 << " identifier=" << m_identifier.toLatin1().data()
500 << " posGraph=" << QPointFToString(posGraph).toLatin1().data();
501
502 // Curve point graph coordinates should always be computed on the fly versus stored in this class, to reduce the
503 // chances for stale information
504 ENGAUGE_ASSERT (m_isAxisPoint);
505
506 m_hasPosGraph = true;
507 m_posGraph = posGraph;
508}
509
510void Point::setPosScreen (const QPointF &posScreen)
511{
512 LOG4CPP_DEBUG_S ((*mainCat)) << "Point::setPosScreen"
513 << " identifier=" << m_identifier.toLatin1().data()
514 << " posScreen=" << QPointFToString(posScreen).toLatin1().data();
515
516 m_posScreen = posScreen;
517}
518
520{
521 return QString ("%1%2%3")
522 .arg (AXIS_CURVE_NAME)
524 .arg (0);
525}
526
527QString Point::uniqueIdentifierGenerator (const QString &curveName)
528{
529 LOG4CPP_INFO_S ((*mainCat)) << "Point::uniqueIdentifierGenerator"
530 << " curveName=" << curveName.toLatin1().data()
531 << " identifierIndex=" << m_identifierIndex;
532
533 return QString ("%1%2point%3%4")
534 .arg (curveName)
537 .arg (m_identifierIndex++);
538}
const QString AXIS_CURVE_NAME
const QString DUMMY_CURVE_NAME
const int INNER_RADIUS_MIN
const QString DOCUMENT_SERIALIZE_POINT_POSITION_GRAPH
const QString DOCUMENT_SERIALIZE_POINT_Y
const QString DOCUMENT_SERIALIZE_POINT_IDENTIFIER
const QString DOCUMENT_SERIALIZE_POINT_POSITION_SCREEN
const QString DOCUMENT_SERIALIZE_POINT_IS_AXIS_POINT
const QString DOCUMENT_SERIALIZE_POINT
const QString DOCUMENT_SERIALIZE_POINT_X
const QString DOCUMENT_SERIALIZE_POINT_ORDINAL
const QString DOCUMENT_SERIALIZE_POINT_IS_X_ONLY
const QString DOCUMENT_SERIALIZE_BOOL_TRUE
const QString DOCUMENT_SERIALIZE_BOOL_FALSE
const QString DOCUMENT_SERIALIZE_POINT_IDENTIFIER_INDEX
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) define ENGAUGE...
log4cpp::Category * mainCat
Definition Logger.cpp:14
const QString INDENTATION_DELTA
const QString AXIS_CURVE_NAME
const QString POINT_IDENTIFIER_DELIMITER_XML("_")
const double MISSING_ORDINAL_VALUE
Definition Point.cpp:26
const QString DUMMY_CURVE_NAME
const double MISSING_POSGRAPH_VALUE
Definition Point.cpp:27
const QString POINT_IDENTIFIER_DELIMITER_SAFE
ApplyHasCheck
Definition Point.h:17
@ SKIP_HAS_CHECK
Definition Point.h:19
@ KEEP_HAS_CHECK
Definition Point.h:18
QString QPointFToString(const QPointF &pos)
QXmlStreamReader::TokenType loadNextFromReader(QXmlStreamReader &reader)
Load next token from xml reader.
Definition Xml.cpp:14
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition Point.h:26
void setOrdinal(double ordinal)
Set the ordinal used for ordering Points.
Definition Point.cpp:486
void setCurveName(const QString &curveName)
Update the point identifer to match the specified curve name.
Definition Point.cpp:471
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
Definition Point.cpp:409
void setPosScreen(const QPointF &posScreen)
Set method for position in screen coordinates.
Definition Point.cpp:510
static QString curveNameFromPointIdentifier(const QString &pointIdentifier)
Parse the curve name from the specified point identifier. This does the opposite of uniqueIdentifierG...
Definition Point.cpp:227
bool hasPosGraph() const
True if graph position is defined.
Definition Point.cpp:263
QPointF posGraph(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Accessor for graph position. Skip check if copying one instance to another.
Definition Point.cpp:395
static unsigned int identifierIndex()
Return the current index for storage in case we need to reset it later while performing a Redo.
Definition Point.cpp:273
QPointF posScreen() const
Accessor for screen position.
Definition Point.cpp:404
QString identifier() const
Unique identifier for a specific Point.
Definition Point.cpp:268
static void setIdentifierIndex(unsigned int identifierIndex)
Reset the current index while performing a Redo.
Definition Point.cpp:478
double ordinal(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Get method for ordinal. Skip check if copying one instance to another.
Definition Point.cpp:386
void saveXml(QXmlStreamWriter &writer) const
Serialize to stream.
Definition Point.cpp:432
void setPosGraph(const QPointF &posGraph)
Set method for position in graph coordinates.
Definition Point.cpp:496
bool hasOrdinal() const
True if ordinal is defined.
Definition Point.cpp:258
Point & operator=(const Point &point)
Assignment constructor.
Definition Point.cpp:204
static QString temporaryPointIdentifier()
Point identifier for temporary point that is used by DigitzeStateAxis.
Definition Point.cpp:519
bool isAxisPoint() const
True if point is an axis point. This is used only for sanity checks.
Definition Point.cpp:281
Point()
Default constructor so this class can be used inside a container.
Definition Point.cpp:29
bool isXOnly() const
In DOCUMENT_AXES_POINTS_REQUIRED_4 modes, this is true/false if y/x coordinate is undefined.
Definition Point.cpp:286
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18
#define LOG4CPP_DEBUG_S(logger)
Definition convenience.h:20