Engauge Digitizer  2
 All Classes Functions Variables 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 = (xBoundary - posUnprojected.x()) / (posOther.x() - posUnprojected.x());
28  ENGAUGE_ASSERT ((-1.0 * EPSILON < s) && (s < 1.0 + EPSILON));
29 
30  return QPointF ((1.0 - s) * posUnprojected.x() + s * posOther.x(),
31  (1.0 - s) * posUnprojected.y() + s * posOther.y());
32 }
33 
34 QPointF GridRemoval::clipY (const QPointF &posUnprojected,
35  double yBoundary,
36  const QPointF &posOther) const
37 {
38  double s = (yBoundary - posUnprojected.y()) / (posOther.y() - posUnprojected.y());
39  ENGAUGE_ASSERT ((-1.0 * EPSILON < s) && (s < 1.0 + EPSILON));
40 
41  return QPointF ((1.0 - s) * posUnprojected.x() + s * posOther.x(),
42  (1.0 - s) * posUnprojected.y() + s * posOther.y());
43 }
44 
45 QPixmap GridRemoval::remove (const Transformation &transformation,
46  const DocumentModelGridRemoval &modelGridRemoval,
47  const QImage &imageBefore)
48 {
49  LOG4CPP_INFO_S ((*mainCat)) << "GridRemoval::remove"
50  << " transformationIsDefined=" << (transformation.transformIsDefined() ? "true" : "false")
51  << " removeDefinedGridLines=" << (modelGridRemoval.removeDefinedGridLines() ? "true" : "false");
52 
53  QImage image = imageBefore;
54 
55  // Make sure grid line removal is wanted, and possible. Otherwise all processing is skipped
56  if (modelGridRemoval.removeDefinedGridLines() &&
57  transformation.transformIsDefined()) {
58 
59  GridHealer gridHealer (imageBefore,
60  modelGridRemoval);
61 
62  double yGraphMin = modelGridRemoval.startY();
63  double yGraphMax = modelGridRemoval.stopY();
64  for (int i = 0; i < modelGridRemoval.countX(); i++) {
65  double xGraph = modelGridRemoval.startX() + i * modelGridRemoval.stepX();
66 
67  // Convert line between graph coordinates (xGraph,yGraphMin) and (xGraph,yGraphMax) to screen coordinates
68  QPointF posScreenMin, posScreenMax;
69  transformation.transformRawGraphToScreen (QPointF (xGraph,
70  yGraphMin),
71  posScreenMin);
72  transformation.transformRawGraphToScreen (QPointF (xGraph,
73  yGraphMax),
74  posScreenMax);
75 
76  removeLine (posScreenMin,
77  posScreenMax,
78  image,
79  gridHealer);
80  }
81 
82  double xGraphMin = modelGridRemoval.startX();
83  double xGraphMax = modelGridRemoval.stopX();
84  for (int j = 0; j < modelGridRemoval.countY(); j++) {
85  double yGraph = modelGridRemoval.startY() + j * modelGridRemoval.stepY();
86 
87  // Convert line between graph coordinates (xGraphMin,yGraph) and (xGraphMax,yGraph) to screen coordinates
88  QPointF posScreenMin, posScreenMax;
89  transformation.transformRawGraphToScreen (QPointF (xGraphMin,
90  yGraph),
91  posScreenMin);
92  transformation.transformRawGraphToScreen (QPointF (xGraphMax,
93  yGraph),
94  posScreenMax);
95 
96  removeLine (posScreenMin,
97  posScreenMax,
98  image,
99  gridHealer);
100  }
101 
102  // Apply the healing process to the image
103  gridHealer.heal (image);
104  }
105 
106  return QPixmap::fromImage (image);
107 }
108 
109 void GridRemoval::removeLine (const QPointF &posMin,
110  const QPointF &posMax,
111  QImage &image,
112  GridHealer &gridHealer)
113 {
114  double w = image.width() - 1; // Inclusive width = exclusive width - 1
115  double h = image.height() - 1; // Inclusive height = exclusive height - 1
116 
117  QPointF pos1 = posMin;
118  QPointF pos2 = posMax;
119 
120  // Throw away all lines that are entirely above or below or left or right to the screen, since
121  // they cannot intersect the screen
122  bool onLeft = (pos1.x() < 0 && pos2.x () < 0);
123  bool onTop = (pos1.y() < 0 && pos2.y () < 0);
124  bool onRight = (pos1.x() > w && pos2.x () > w);
125  bool onBottom = (pos1.y() > h && pos2.y () > h);
126  if (!onLeft && !onTop && !onRight && !onBottom) {
127 
128  // Clip to within the four sides
129  if (pos1.x() < 0) { pos1 = clipX (pos1, 0, pos2); }
130  if (pos2.x() < 0) { pos2 = clipX (pos2, 0, pos1); }
131  if (pos1.y() < 0) { pos1 = clipY (pos1, 0, pos2); }
132  if (pos2.y() < 0) { pos2 = clipY (pos2, 0, pos1); }
133  if (pos1.x() > w) { pos1 = clipX (pos1, w, pos2); }
134  if (pos2.x() > w) { pos2 = clipX (pos2, w, pos1); }
135  if (pos1.y() > h) { pos1 = clipY (pos1, h, pos2); }
136  if (pos2.y() > h) { pos2 = clipY (pos2, h, pos1); }
137 
138  // Is line more horizontal or vertical?
139  double deltaX = qAbs (pos1.x() - pos2.x());
140  double deltaY = qAbs (pos1.y() - pos2.y());
141  if (deltaX > deltaY) {
142 
143  // More horizontal
144  int xMin = qMin (pos1.x(), pos2.x());
145  int xMax = qMax (pos1.x(), pos2.x());
146  int yAtXMin = (pos1.x() < pos2.x() ? pos1.y() : pos2.y());
147  int yAtXMax = (pos1.x() < pos2.x() ? pos2.y() : pos1.y());
148  for (int x = xMin; x <= xMax; x++) {
149  double s = (double) (x - xMin) / (double) (xMax - xMin);
150  double yLine = (1.0 - s) * yAtXMin + s * yAtXMax;
151  for (int yOffset = -1; yOffset <= 1; yOffset++) {
152  int y = (int) (0.5 + yLine + yOffset);
153  image.setPixel (x, y, QColor(Qt::white).rgb());
154  gridHealer.erasePixel (x, y);
155  }
156  }
157  } else {
158 
159  // More vertical
160  int yMin = qMin (pos1.y(), pos2.y());
161  int yMax = qMax (pos1.y(), pos2.y());
162  int xAtYMin = (pos1.y() < pos2.y() ? pos1.x() : pos2.x());
163  int xAtYMax = (pos1.y() < pos2.y() ? pos2.x() : pos1.x());
164  for (int y = yMin; y <= yMax; y++) {
165  double s = (double) (y - yMin) / (double) (yMax - yMin);
166  double xLine = (1.0 - s) * xAtYMin + s * xAtYMax;
167  for (int xOffset = -1; xOffset <= 1; xOffset++) {
168  int x = (int) (0.5 + xLine + xOffset);
169  image.setPixel (x, y, QColor(Qt::white).rgb());
170  gridHealer.erasePixel (x, y);
171  }
172  }
173  }
174  }
175 }
176 
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:96
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:45
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:153