Engauge Digitizer  2
 All Classes Functions Variables Typedefs Enumerations Friends Pages
GridRemoval.cpp
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 "DocumentModelGridRemoval.h"
8 #include "EngaugeAssert.h"
9 #include "GridHealer.h"
10 #include "GridRemoval.h"
11 #include "Logger.h"
12 #include <qdebug.h>
13 #include <QImage>
14 #include <qmath.h>
15 #include "Transformation.h"
16 
17 const double EPSILON = 0.000001;
18 
20 {
21 }
22 
23 QPointF GridRemoval::clipX (const QPointF &posUnprojected,
24  double xBoundary,
25  const QPointF &posOther) const
26 {
27  double s = 0;
28  if (posOther.x() != posUnprojected.x()) {
29  s = (xBoundary - posUnprojected.x()) / (posOther.x() - posUnprojected.x());
30  }
31  ENGAUGE_ASSERT ((-1.0 * EPSILON < s) && (s < 1.0 + EPSILON));
32 
33  return QPointF ((1.0 - s) * posUnprojected.x() + s * posOther.x(),
34  (1.0 - s) * posUnprojected.y() + s * posOther.y());
35 }
36 
37 QPointF GridRemoval::clipY (const QPointF &posUnprojected,
38  double yBoundary,
39  const QPointF &posOther) const
40 {
41  double s = 0;
42  if (posOther.y() != posUnprojected.y()) {
43  s = (yBoundary - posUnprojected.y()) / (posOther.y() - posUnprojected.y());
44  }
45  ENGAUGE_ASSERT ((-1.0 * EPSILON < s) && (s < 1.0 + EPSILON));
46 
47  return QPointF ((1.0 - s) * posUnprojected.x() + s * posOther.x(),
48  (1.0 - s) * posUnprojected.y() + s * posOther.y());
49 }
50 
51 QPixmap GridRemoval::remove (const Transformation &transformation,
52  const DocumentModelGridRemoval &modelGridRemoval,
53  const QImage &imageBefore)
54 {
55  LOG4CPP_INFO_S ((*mainCat)) << "GridRemoval::remove"
56  << " transformationIsDefined=" << (transformation.transformIsDefined() ? "true" : "false")
57  << " removeDefinedGridLines=" << (modelGridRemoval.removeDefinedGridLines() ? "true" : "false");
58 
59  QImage image = imageBefore;
60 
61  // Make sure grid line removal is wanted, and possible. Otherwise all processing is skipped
62  if (modelGridRemoval.removeDefinedGridLines() &&
63  transformation.transformIsDefined()) {
64 
65  GridHealer gridHealer (imageBefore,
66  modelGridRemoval);
67 
68  double yGraphMin = modelGridRemoval.startY();
69  double yGraphMax = modelGridRemoval.stopY();
70  for (int i = 0; i < modelGridRemoval.countX(); i++) {
71  double xGraph = modelGridRemoval.startX() + i * modelGridRemoval.stepX();
72 
73  // Convert line between graph coordinates (xGraph,yGraphMin) and (xGraph,yGraphMax) to screen coordinates
74  QPointF posScreenMin, posScreenMax;
75  transformation.transformRawGraphToScreen (QPointF (xGraph,
76  yGraphMin),
77  posScreenMin);
78  transformation.transformRawGraphToScreen (QPointF (xGraph,
79  yGraphMax),
80  posScreenMax);
81 
82  removeLine (posScreenMin,
83  posScreenMax,
84  image,
85  gridHealer);
86  }
87 
88  double xGraphMin = modelGridRemoval.startX();
89  double xGraphMax = modelGridRemoval.stopX();
90  for (int j = 0; j < modelGridRemoval.countY(); j++) {
91  double yGraph = modelGridRemoval.startY() + j * modelGridRemoval.stepY();
92 
93  // Convert line between graph coordinates (xGraphMin,yGraph) and (xGraphMax,yGraph) to screen coordinates
94  QPointF posScreenMin, posScreenMax;
95  transformation.transformRawGraphToScreen (QPointF (xGraphMin,
96  yGraph),
97  posScreenMin);
98  transformation.transformRawGraphToScreen (QPointF (xGraphMax,
99  yGraph),
100  posScreenMax);
101 
102  removeLine (posScreenMin,
103  posScreenMax,
104  image,
105  gridHealer);
106  }
107 
108  // Apply the healing process to the image
109  gridHealer.heal (image);
110  }
111 
112  return QPixmap::fromImage (image);
113 }
114 
115 void GridRemoval::removeLine (const QPointF &posMin,
116  const QPointF &posMax,
117  QImage &image,
118  GridHealer &gridHealer)
119 {
120  double w = image.width() - 1; // Inclusive width = exclusive width - 1
121  double h = image.height() - 1; // Inclusive height = exclusive height - 1
122 
123  QPointF pos1 = posMin;
124  QPointF pos2 = posMax;
125 
126  // Throw away all lines that are entirely above or below or left or right to the screen, since
127  // they cannot intersect the screen
128  bool onLeft = (pos1.x() < 0 && pos2.x () < 0);
129  bool onTop = (pos1.y() < 0 && pos2.y () < 0);
130  bool onRight = (pos1.x() > w && pos2.x () > w);
131  bool onBottom = (pos1.y() > h && pos2.y () > h);
132  if (!onLeft && !onTop && !onRight && !onBottom) {
133 
134  // Clip to within the four sides
135  if (pos1.x() < 0) { pos1 = clipX (pos1, 0, pos2); }
136  if (pos2.x() < 0) { pos2 = clipX (pos2, 0, pos1); }
137  if (pos1.y() < 0) { pos1 = clipY (pos1, 0, pos2); }
138  if (pos2.y() < 0) { pos2 = clipY (pos2, 0, pos1); }
139  if (pos1.x() > w) { pos1 = clipX (pos1, w, pos2); }
140  if (pos2.x() > w) { pos2 = clipX (pos2, w, pos1); }
141  if (pos1.y() > h) { pos1 = clipY (pos1, h, pos2); }
142  if (pos2.y() > h) { pos2 = clipY (pos2, h, pos1); }
143 
144  // Is line more horizontal or vertical?
145  double deltaX = qAbs (pos1.x() - pos2.x());
146  double deltaY = qAbs (pos1.y() - pos2.y());
147  if (deltaX > deltaY) {
148 
149  // More horizontal
150  int xMin = qMin (pos1.x(), pos2.x());
151  int xMax = qMax (pos1.x(), pos2.x());
152  int yAtXMin = (pos1.x() < pos2.x() ? pos1.y() : pos2.y());
153  int yAtXMax = (pos1.x() < pos2.x() ? pos2.y() : pos1.y());
154  for (int x = xMin; x <= xMax; x++) {
155  double s = (double) (x - xMin) / (double) (xMax - xMin);
156  double yLine = (1.0 - s) * yAtXMin + s * yAtXMax;
157  for (int yOffset = -1; yOffset <= 1; yOffset++) {
158  int y = (int) (0.5 + yLine + yOffset);
159  image.setPixel (x, y, QColor(Qt::white).rgb());
160  gridHealer.erasePixel (x, y);
161  }
162  }
163  } else {
164 
165  // More vertical
166  int yMin = qMin (pos1.y(), pos2.y());
167  int yMax = qMax (pos1.y(), pos2.y());
168  int xAtYMin = (pos1.y() < pos2.y() ? pos1.x() : pos2.x());
169  int xAtYMax = (pos1.y() < pos2.y() ? pos2.x() : pos1.x());
170  for (int y = yMin; y <= yMax; y++) {
171  double s = (double) (y - yMin) / (double) (yMax - yMin);
172  double xLine = (1.0 - s) * xAtYMin + s * xAtYMax;
173  for (int xOffset = -1; xOffset <= 1; xOffset++) {
174  int x = (int) (0.5 + xLine + xOffset);
175  image.setPixel (x, y, QColor(Qt::white).rgb());
176  gridHealer.erasePixel (x, y);
177  }
178  }
179  }
180  }
181 }
182 
bool removeDefinedGridLines() const
Get method for removing defined grid lines.
double startY() const
Get method for y start.
void erasePixel(int xCol, int yRow)
Remember that pixel was erased since it belongs to an grid line.
Definition: GridHealer.cpp:98
double stepY() const
Get method for y step.
Class that &#39;heals&#39; the curves after grid lines have been removed.
Definition: GridHealer.h:37
Affine transformation between screen and graph coordinates, based on digitized axis points...
double stopX() const
Get method for x stop.
QPixmap remove(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const QImage &imageBefore)
Process QImage into QPixmap, removing the grid lines.
Definition: GridRemoval.cpp:51
double startX() const
Get method for x start.
double stopY() const
Get method for y stop.
int countX() const
Get method for x count.
int countY() const
Get method for y count.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
double stepX() const
Get method for x step.
void transformRawGraphToScreen(const QPointF &pointRaw, QPointF &pointScreen) const
Transform from raw graph coordinates to linear cartesian graph coordinates, then to screen coordinate...
Model for DlgSettingsGridRemoval and CmdSettingsGridRemoval. The settings are unstable until the user...
GridRemoval()
Single constructor.
Definition: GridRemoval.cpp:19
void heal(QImage &imageToHeal)
Heal the broken curve lines by spanning the gaps across the newly-removed grid lines.
Definition: GridHealer.cpp:157