Engauge Digitizer 2
Loading...
Searching...
No Matches
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
12const double PI = 3.1415926535;
13
14double 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
31double 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
51QRgb 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
64QRgb 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
77QRgb pixelRGB8(const QImage &image8Bit, int x, int y)
78{
79 unsigned int tableIndex = *(image8Bit.scanLine(y) + x);
80 return image8Bit.color(tableIndex);
81}
82
83QRgb pixelRGB32(const QImage &image32Bit, int x, int y)
84{
85 unsigned int* p = (unsigned int *) image32Bit.scanLine(y) + x;
86 return *p;
87}
88
89void 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
159void 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
175void 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
197void 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
208void setPixelRGB32(QImage &image32Bit, int x, int y, QRgb q)
209{
210 int* p = (int *)image32Bit.scanLine(y) + x;
211 *p = q;
212}