Engauge Digitizer  2
mmsubs.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 "mmsubs.h"
8 #include <QImage>
9 #include <QPointF>
10 #include <qmath.h>
11 
12 const double PI = 3.1415926535;
13 
14 double angleBetweenVectors (const QPointF &v1,
15  const QPointF &v2)
16 {
17  double v1Mag = qSqrt (v1.x() * v1.x() + v1.y() * v1.y());
18  double v2Mag = qSqrt (v2.x() * v2.x() + v2.y() * v2.y());
19 
20  double angle = 0;
21  if ((v1Mag > 0) || (v2Mag > 0)) {
22 
23  double cosArg = (v1.x() * v2.x() + v1.y() * v2.y()) / (v1Mag * v2Mag);
24  cosArg = qMin (qMax (cosArg, -1.0), 1.0);
25  angle = qAcos (cosArg);
26  }
27 
28  return angle;
29 }
30 
31 double angleFromVectorToVector (const QPointF &vFrom,
32  const QPointF &vTo)
33 {
34  double angleFrom = qAtan2 (vFrom.y(), vFrom.x());
35  double angleTo = qAtan2 (vTo.y() , vTo.x());
36 
37  // Rotate both angles to put from vector along x axis. Note that angleFrom-angleFrom is zero,
38  // and angleTo-angleFrom is -pi to +pi radians
39  double angleSeparation = angleTo - angleFrom;
40 
41  while (angleSeparation < -1.0 * PI) {
42  angleSeparation += 2.0 * PI;
43  }
44  while (angleSeparation > PI) {
45  angleSeparation -= 2.0 * PI;
46  }
47 
48  return angleSeparation;
49 }
50 
51 QRgb pixelRGB(const QImage &image, int x, int y)
52 {
53  switch (image.depth())
54  {
55  case 1:
56  return pixelRGB1(image, x, y);
57  case 8:
58  return pixelRGB8(image, x, y);
59  default:
60  return pixelRGB32(image, x, y);
61  }
62 }
63 
64 QRgb pixelRGB1(const QImage &image1Bit, int x, int y)
65 {
66  unsigned int bit;
67  if (image1Bit.format () == QImage::Format_MonoLSB) {
68  bit = *(image1Bit.scanLine (y) + (x >> 3)) & (1 << (x & 7));
69  } else {
70  bit = *(image1Bit.scanLine (y) + (x >> 3)) & (1 << (7 - (x & 7)));
71  }
72 
73  unsigned int tableIndex = ((bit == 0) ? 0 : 1);
74  return image1Bit.color(tableIndex);
75 }
76 
77 QRgb pixelRGB8(const QImage &image8Bit, int x, int y)
78 {
79  unsigned int tableIndex = *(image8Bit.scanLine(y) + x);
80  return image8Bit.color(tableIndex);
81 }
82 
83 QRgb pixelRGB32(const QImage &image32Bit, int x, int y)
84 {
85  unsigned int* p = (unsigned int *) image32Bit.scanLine(y) + x;
86  return *p;
87 }
88 
89 void projectPointOntoLine(double xToProject,
90  double yToProject,
91  double xStart,
92  double yStart,
93  double xStop,
94  double yStop,
95  double *xProjection,
96  double *yProjection,
97  double *projectedDistanceOutsideLine,
98  double *distanceToLine)
99 {
100  double s;
101  if (qAbs (yStart - yStop) > qAbs (xStart - xStop)) {
102 
103  // More vertical than horizontal. Compute slope and intercept of y=slope*x+yintercept line through (xToProject, yToProject)
104  double slope = (xStop - xStart) / (yStart - yStop);
105  double yintercept = yToProject - slope * xToProject;
106 
107  // Intersect projected point line (slope-intercept form) with start-stop line (parametric form x=(1-s)*x1+s*x2, y=(1-s)*y1+s*y2)
108  s = (slope * xStart + yintercept - yStart) /
109  (yStop - yStart + slope * (xStart - xStop));
110 
111  } else {
112 
113  // More horizontal than vertical. Compute slope and intercept of x=slope*y+xintercept line through (xToProject, yToProject)
114  double slope = (yStop - yStart) / (xStart - xStop);
115  double xintercept = xToProject - slope * yToProject;
116 
117  // Intersect projected point line (slope-intercept form) with start-stop line (parametric form x=(1-s)*x1+s*x2, y=(1-s)*y1+s*y2)
118  s = (slope * yStart + xintercept - xStart) /
119  (xStop - xStart + slope * (yStart - yStop));
120 
121  }
122 
123  *xProjection = (1.0 - s) * xStart + s * xStop;
124  *yProjection = (1.0 - s) * yStart + s * yStop;
125 
126  if (s < 0) {
127 
128  *projectedDistanceOutsideLine = qSqrt ((*xProjection - xStart) * (*xProjection - xStart) +
129  (*yProjection - yStart) * (*yProjection - yStart));
130  *distanceToLine = qSqrt ((xToProject - xStart) * (xToProject - xStart) +
131  (yToProject - yStart) * (yToProject - yStart));
132 
133  // Bring projection point to inside line
134  *xProjection = xStart;
135  *yProjection = yStart;
136 
137  } else if (s > 1) {
138 
139  *projectedDistanceOutsideLine = qSqrt ((*xProjection - xStop) * (*xProjection - xStop) +
140  (*yProjection - yStop) * (*yProjection - yStop));
141  *distanceToLine = qSqrt ((xToProject - xStop) * (xToProject - xStop) +
142  (yToProject - yStop) * (yToProject - yStop));
143 
144  // Bring projection point to inside line
145  *xProjection = xStop;
146  *yProjection = yStop;
147 
148  } else {
149 
150  *distanceToLine = qSqrt ((xToProject - *xProjection) * (xToProject - *xProjection) +
151  (yToProject - *yProjection) * (yToProject - *yProjection));
152 
153  // Projected point is aleady inside line
154  *projectedDistanceOutsideLine = 0.0;
155 
156  }
157 }
158 
159 void setPixelRGB(QImage &image, int x, int y, QRgb q)
160 {
161  switch (image.depth())
162  {
163  case 1:
164  setPixelRGB1(image, x, y, q);
165  return;
166  case 8:
167  setPixelRGB8(image, x, y, q);
168  return;
169  case 32:
170  setPixelRGB32(image, x, y, q);
171  return;
172  }
173 }
174 
175 void setPixelRGB1(QImage &image1Bit, int x, int y, QRgb q)
176 {
177  for (int index = 0; index < image1Bit.colorCount(); index++) {
178  if (q == image1Bit.color(index))
179  {
180  if (image1Bit.format () == QImage::Format_MonoLSB)
181  {
182  *(image1Bit.scanLine (y) + (x >> 3)) &= ~(1 << (x & 7));
183  if (index > 0)
184  *(image1Bit.scanLine (y) + (x >> 3)) |= index << (x & 7);
185  }
186  else
187  {
188  *(image1Bit.scanLine (y) + (x >> 3)) &= ~(1 << (7 - (x & 7)));
189  if (index > 0)
190  *(image1Bit.scanLine (y) + (x >> 3)) |= index << (7 - (x & 7));
191  }
192  return;
193  }
194  }
195 }
196 
197 void setPixelRGB8(QImage &image8Bit, int x, int y, QRgb q)
198 {
199  for (int index = 0; index < image8Bit.colorCount(); index++) {
200  if (q == image8Bit.color(index))
201  {
202  *(image8Bit.scanLine(y) + x) = index;
203  return;
204  }
205  }
206 }
207 
208 void setPixelRGB32(QImage &image32Bit, int x, int y, QRgb q)
209 {
210  int* p = (int *)image32Bit.scanLine(y) + x;
211  *p = q;
212 }