Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
GeometryWindow.cpp
1 /******************************************************************************************************
2  * (C) 2016 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 "CallbackGatherXThetaValuesFunctions.h"
8 #include "CmdMediator.h"
9 #include "Curve.h"
10 #include "CurveConnectAs.h"
11 #include "CurveStyle.h"
12 #include "EngaugeAssert.h"
13 #include "GeometryModel.h"
14 #include "GeometryWindow.h"
15 #include "Logger.h"
16 #include <QApplication>
17 #include <QClipboard>
18 #include <QHeaderView>
19 #include <QItemSelectionModel>
20 #include <QTableView>
21 #include <QTextStream>
22 
23 // Token constraints:
24 // (1) should fit nicely into narrow columns. This eliminates details like Forward and Backward in the distance parameter tokens
25 // (2) should not have any spaces. This simplifies copying and pasting into spreadsheet programs
26 const QString TokenName (QObject::tr ("CurveName:"));
27 const QString TokenFunctionArea (QObject::tr ("FunctionArea:"));
28 const QString TokenPolygonArea (QObject::tr ("PolygonArea:"));
29 const QString TokenX (QObject::tr ("X"));
30 const QString TokenY (QObject::tr ("Y"));
31 const QString TokenIndex (QObject::tr ("Index"));
32 const QString TokenDistanceGraph (QObject::tr ("Distance"));
33 const QString TokenDistancePercent (QObject::tr ("Percent"));
34 
35 GeometryWindow::GeometryWindow (QWidget *parent) :
36  QDockWidget (parent)
37 {
38  setVisible (false);
39  setAllowedAreas (Qt::AllDockWidgetAreas);
40  setWindowTitle (tr ("Geometry Window")); // Appears in title bar when undocked
41  setStatusTip (tr ("Geometry Window"));
42  setWhatsThis (tr ("Geometry Window\n\n"
43  "This table displays the following geometry data for the currently selected curve:\n\n"
44  "Function area = Area under the curve if it is a function\n\n"
45  "Polygon area = Area inside the curve if it is a relation. This value is only correct "
46  "if none of the curve lines intersect each other\n\n"
47  "X = X coordinate of each point\n\n"
48  "Y = Y coordinate of each point\n\n"
49  "Index = Point number\n\n"
50  "Distance = Distance along the curve in forward or backward direction, in either graph units "
51  "or as a percentage"));
52 
53  m_model = new GeometryModel;
54 
55  m_view = new QTableView;
56  m_view->setModel (m_model); // Call before setSelectionModel since this also overrides the selection model
57  m_view->horizontalHeader()->hide();
58  m_view->verticalHeader()->hide();
59  m_view->setEditTriggers(QAbstractItemView::NoEditTriggers); // Control is read only
60  connect (m_view->selectionModel(), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)),
61  this, SLOT (slotSelectionChanged (const QItemSelection &, const QItemSelection &)));
62 
63  setWidget (m_view);
64 
65  loadStrategies();
66 
67  initializeHeader ();
68 }
69 
70 GeometryWindow::~GeometryWindow()
71 {
72 }
73 
75 {
76  // Resize table to remove stale body data
77  resizeTable (NUM_HEADER_ROWS);
78 
79  // Clear stale header data values
80  for (int row = 0; row < NUM_HEADER_ROWS - 1; row++) {
81  m_model->setItem (row, COLUMN_HEADER_VALUE, new QStandardItem (""));
82  }
83 }
84 
85 void GeometryWindow::closeEvent(QCloseEvent * /* event */)
86 {
87  LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::closeEvent";
88 
90 }
91 
92 int GeometryWindow::fold2dIndexes (int row,
93  int col,
94  int rowLow,
95  int colLow,
96  int colHigh) const
97 {
98  return (row - rowLow) * (colHigh - colLow + 1) + (col - colLow);
99 }
100 
102 {
103  return COLUMN_BODY_POINT_IDENTIFIERS;
104 }
105 
106 void GeometryWindow::initializeHeader ()
107 {
108  LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::initializeHeader";
109 
110  resizeTable (NUM_HEADER_ROWS);
111 
112  m_model->setItem (HEADER_ROW_NAME, COLUMN_HEADER_LABEL, new QStandardItem (TokenName));
113  m_model->setItem (HEADER_ROW_FUNC_AREA, COLUMN_HEADER_LABEL, new QStandardItem (TokenFunctionArea));
114  m_model->setItem (HEADER_ROW_POLY_AREA, COLUMN_HEADER_LABEL, new QStandardItem (TokenPolygonArea));
115  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_X, new QStandardItem (TokenX));
116  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_Y, new QStandardItem (TokenY));
117  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_INDEX, new QStandardItem (TokenIndex));
118  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_GRAPH_FORWARD, new QStandardItem (TokenDistanceGraph));
119  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_PERCENT_FORWARD, new QStandardItem (TokenDistancePercent));
120  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_GRAPH_BACKWARD, new QStandardItem (TokenDistanceGraph));
121  m_model->setItem (HEADER_ROW_COLUMN_NAMES, COLUMN_BODY_DISTANCE_PERCENT_BACKWARD, new QStandardItem (TokenDistancePercent));
122 }
123 
124 void GeometryWindow::loadStrategies ()
125 {
126  LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::loadStrategies";
127 }
128 
129 void GeometryWindow::resizeTable (int rowCount)
130 {
131  LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::resizeTable";
132 
133  unselectAll();
134 
135  m_model->setRowCount (rowCount);
136  m_model->setColumnCount (NUM_BODY_COLUMNS);
137 
138 }
139 
140 void GeometryWindow::slotPointHoverEnter (QString pointIdentifier)
141 {
142  m_model->setCurrentPointIdentifier (pointIdentifier);
143 }
144 
145 void GeometryWindow::slotPointHoverLeave (QString /* pointIdentifier */)
146 {
147  m_model->setCurrentPointIdentifier ("");
148 }
149 
150 void GeometryWindow::slotSelectionChanged (const QItemSelection & /* selected */,
151  const QItemSelection & /* deselected */)
152 {
153  const bool NOT_GNUPLOT = false;
154 
155  QItemSelectionModel *selectionModel = m_view->selectionModel ();
156  QModelIndexList selection = selectionModel->selectedIndexes ();
157 
158  if (selection.size () > 0) {
159 
160  // Gather input. A rectangular grid that encompasses all selected indexes will be copied
161  int rowLow = 0, rowHigh = 0, colLow = 0, colHigh = 0;
162  bool isFirst = true;
163  for (QModelIndexList::const_iterator itr = selection.begin(); itr != selection.end(); itr++) {
164  QModelIndex index = *itr;
165  if (isFirst || index.row () < rowLow ) rowLow = index.row ();
166  if (isFirst || index.row () > rowHigh) rowHigh = index.row ();
167  if (isFirst || index.column () < colLow ) colLow = index.column ();
168  if (isFirst || index.column () > colHigh) colHigh = index.column ();
169  isFirst = false;
170  }
171 
172  int numRows = rowHigh - rowLow + 1;
173  int numCols = colHigh - colLow + 1;
174 
175  // Put data into two dimensional rowXcolumn table is handled as a flattened vector. Table is initialized
176  // with empty strings
177  QVector<QString> table (numRows * numCols);
178 
179  for (int i = 0; i < selection.size (); i++) {
180  QModelIndex index = selection [i];
181  QVariant data = m_model->data (index);
182  QString text = data.toString ();
183  table [fold2dIndexes (index.row(), index.column(), rowLow, colLow, colHigh)] = text;
184  }
185 
186  // Concatenate table into output string
187  QString output;
188  QTextStream str (&output);
189  for (int row = rowLow; row <= rowHigh; row++) {
190  QString delimiter;
191  for (int col = colLow; col <= colHigh; col++) {
192  str << delimiter << table [fold2dIndexes (row, col, rowLow, colLow, colHigh)];
193  delimiter = exportDelimiterToText (m_modelExport.delimiter(),
194  NOT_GNUPLOT);
195  }
196  str << "\n";
197  }
198 
199  // Save to clipboard
200  QApplication::clipboard ()->setText (output);
201  }
202 }
203 
204 void GeometryWindow::update (const CmdMediator &cmdMediator,
205  const MainWindowModel &modelMainWindow,
206  const QString &curveSelected,
207  const Transformation &transformation)
208 {
209  LOG4CPP_INFO_S ((*mainCat)) << "GeometryWindow::update";
210 
211  // Save export format
212  m_modelExport = cmdMediator.document().modelExport();
213 
214  // Gather and calculate geometry data
215  const Curve *curve = cmdMediator.document().curveForCurveName (curveSelected);
216 
217  ENGAUGE_CHECK_PTR (curve);
218 
219  const Points points = curve->points();
220 
221  QString funcArea, polyArea;
222  QVector<QString> x, y, distanceGraphForward, distancePercentForward, distanceGraphBackward, distancePercentBackward;
223 
224  CurveStyle curveStyle = cmdMediator.document().modelCurveStyles().curveStyle (curveSelected);
225  m_geometryStrategyContext.calculateGeometry (points,
226  cmdMediator.document().modelCoords(),
227  cmdMediator.document().modelGeneral(),
228  modelMainWindow,
229  transformation,
230  curveStyle.lineStyle().curveConnectAs(),
231  funcArea,
232  polyArea,
233  x,
234  y,
235  distanceGraphForward,
236  distancePercentForward,
237  distanceGraphBackward,
238  distancePercentBackward);
239 
240  // Output to table
241  resizeTable (NUM_HEADER_ROWS + points.count());
242 
243  m_model->setItem (HEADER_ROW_NAME, COLUMN_HEADER_VALUE, new QStandardItem (curveSelected));
244  m_model->setItem (HEADER_ROW_FUNC_AREA, COLUMN_HEADER_VALUE, new QStandardItem (funcArea));
245  m_model->setItem (HEADER_ROW_POLY_AREA, COLUMN_HEADER_VALUE, new QStandardItem (polyArea));
246 
247  if (transformation.transformIsDefined()) {
248 
249  int row = NUM_HEADER_ROWS;
250  int index = 0;
251  for (; index < points.count(); row++, index++) {
252 
253  const Point &point = points.at (index);
254 
255  QPointF posGraph;
256  transformation.transformScreenToRawGraph (point.posScreen (),
257  posGraph);
258 
259  m_model->setItem (row, COLUMN_BODY_X, new QStandardItem (x [index]));
260  m_model->setItem (row, COLUMN_BODY_Y, new QStandardItem (y [index]));
261  m_model->setItem (row, COLUMN_BODY_INDEX, new QStandardItem (QString::number (index + 1)));
262  m_model->setItem (row, COLUMN_BODY_DISTANCE_GRAPH_FORWARD, new QStandardItem (distanceGraphForward [index]));
263  m_model->setItem (row, COLUMN_BODY_DISTANCE_PERCENT_FORWARD, new QStandardItem (distancePercentForward [index]));
264  m_model->setItem (row, COLUMN_BODY_DISTANCE_GRAPH_BACKWARD, new QStandardItem (distanceGraphBackward [index]));
265  m_model->setItem (row, COLUMN_BODY_DISTANCE_PERCENT_BACKWARD, new QStandardItem (distancePercentBackward [index]));
266  m_model->setItem (row, COLUMN_BODY_POINT_IDENTIFIERS, new QStandardItem (point.identifier()));
267  }
268  }
269 
270  // Unselect everything
271  unselectAll ();
272 
273  // Make sure the hidden column stays hidden
274  m_view->setColumnHidden (COLUMN_BODY_POINT_IDENTIFIERS, true);
275 }
276 
277 void GeometryWindow::unselectAll ()
278 {
279  QItemSelectionModel *selectionModel = m_view->selectionModel ();
280 
281  selectionModel->clearSelection ();
282 }
void slotSelectionChanged(const QItemSelection &, const QItemSelection &)
Prepare for copy after selection has changed.
void setCurrentPointIdentifier(const QString &pointIdentifier)
Set the point identifier to be highlighted. Value is empty for no highlighting.
virtual void closeEvent(QCloseEvent *event)
Catch close event so corresponding menu item in MainWindow can be updated accordingly.
const Points points() const
Return a shallow copy of the Points.
Definition: Curve.cpp:442
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Override for special processing.
LineStyle lineStyle() const
Get method for LineStyle.
Definition: CurveStyle.cpp:26
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:665
void slotPointHoverEnter(QString)
Highlight the row for the specified point.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition: Point.h:23
QPointF posScreen() const
Accessor for screen position.
Definition: Point.cpp:392
void update(const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow, const QString &curveSelected, const Transformation &transformation)
Populate the table with the specified Curve.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
QString identifier() const
Unique identifier for a specific Point.
Definition: Point.cpp:256
void calculateGeometry(const Points &points, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &modelMainWindow, const Transformation &transformation, CurveConnectAs connectAs, QString &funcArea, QString &polyArea, QVector< QString > &x, QVector< QString > &y, QVector< QString > &distanceGraphForward, QVector< QString > &distancePercentForward, QVector< QString > &distanceGraphBackward, QVector< QString > &distancePercentBackward) const
Calculate geometry parameters.
void slotPointHoverLeave(QString)
Unhighlight the row for the specified point.
Affine transformation between screen and graph coordinates, based on digitized axis points...
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:672
Model for DlgSettingsMainWindow.
ExportDelimiter delimiter() const
Get method for delimiter.
void signalGeometryWindowClosed()
Signal that this QDockWidget was just closed.
static int columnBodyPointIdentifiers()
Hidden column that has the point identifiers.
Container for LineStyle and PointStyle for one Curve.
Definition: CurveStyle.h:18
Container for one set of digitized Points.
Definition: Curve.h:32
CurveStyle curveStyle(const QString &curveName) const
CurveStyle in specified curve.
Definition: CurveStyles.cpp:79
Command queue stack.
Definition: CmdMediator.h:23
const Curve * curveForCurveName(const QString &curveName) const
See CurvesGraphs::curveForCurveNames, although this also works for AXIS_CURVE_NAME.
Definition: Document.cpp:305
CurveConnectAs curveConnectAs() const
Get method for connect type.
Definition: LineStyle.cpp:63
Model that adds row highlighting according to the currently select point identifier.
Definition: GeometryModel.h:14
DocumentModelExportFormat modelExport() const
Get method for DocumentModelExportFormat.
Definition: Document.cpp:686
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:693
void clear()
Clear stale information.
GeometryWindow(QWidget *parent)
Single constructor. Parent is needed or else this widget cannot be redocked after being undocked...