-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmath.h
238 lines (193 loc) · 5.95 KB
/
math.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
* Math functions
*/
#ifndef H_MATHFUNCTIONS
#define H_MATHFUNCTIONS
#include <cmath>
#include <vector>
#include <numeric>
#include <algorithm>
#include "data.h"
static const double pi = 3.14159265358979323846264338327950;
inline double distance(const double x1, const double y1, const double x2, const double y2);
inline double distance(const Coord& p1, const Coord& p2);
// Distance squared, i.e. don't take square root
inline int distance2(const int x1, const int y1, const int x2, const int y2);
inline int distance2(const Coord& p1, const Coord& p2);
// Perpendicular distance between p3 and the line from p1 to p2
inline double distance(const Coord& p1, const Coord& p2, const Coord& p3);
inline double average(const std::vector<double>& v);
inline double average(const std::vector<double>& v,
std::vector<double>::const_iterator start,
std::vector<double>::const_iterator end);
inline double max_value(const std::vector<double>& v);
inline double min_value(const std::vector<double>& v);
inline double min(double, double, double);
inline double max(double, double, double);
inline int round(const int x, const int r);
inline int smartFloor(const double value, const double epsilon = 0.00001);
inline int smartCeil(const double value, const double epsilon = 0.00001);
inline int lineFunctionX(const Coord& a, const Coord& b, int y);
inline int lineFunctionY(const Coord& a, const Coord& b, int x);
inline double slopeYX(const Coord& a, const Coord& b);
inline double slopeXY(const Coord& a, const Coord& b);
inline Coord findMidpoint(const Coord& a, const Coord& b);
// Used to find corners of boxes and bubbles
Coord farthestFromPoint(const Coord& p,
const std::vector<Coord>& points);
Coord farthestFromLine(const Coord& p1, const Coord& p2,
const std::vector<Coord>& points);
// Instead of taking the diagonal distance for finding boxes, we can add the
// horizontal and vertical distance. This will tend to get rid of the odd
// extruded pixels on the side of a box.
Coord farthestFromPointSquare(const Coord& p,
const std::vector<Coord>& points);
// Determine "center" by averaging all points
Coord findCenter(const std::vector<Coord>& points);
// Standard Deviation:
// sqrt(1/n*((x1 - avg)^2 + (x2 - avg)^2 + ... (xn - avg)^2))
//
// Type should probably be std::vector<double>
template<class Type>
double stdev(const Type& v)
{
if (v.size() == 0)
return 0;
double total = std::accumulate(v.begin(), v.end(), 0);
double mean = total/v.size();
double inroot = 0;
for (const double elem : v)
inroot += std::pow(mean - elem, 2);
return std::sqrt(inroot/v.size());
}
/*
* Inline stuff since these are tiny
*/
// Distance formula
inline double distance(const double x1, const double y1, const double x2, const double y2)
{
return std::sqrt(std::pow(x2-x1, 2) + std::pow(y2-y1, 2));
}
inline double distance(const Coord& p1, const Coord& p2)
{
return std::sqrt(std::pow((1.0*p2.x-p1.x), 2) + std::pow((1.0*p2.y-p1.y), 2));
}
// Distance formula without the square root
inline int distance2(const int x1, const int y1, const int x2, const int y2)
{
return std::pow(x2-x1, 2) + std::pow(y2-y1, 2);
}
inline int distance2(const Coord& p1, const Coord& p2)
{
return std::pow(p2.x-p1.x, 2) + std::pow(p2.y-p1.y, 2);
}
// Perpendicular distance
inline double distance(const Coord& p1, const Coord& p2, const Coord& p3)
{
// Only look at horizontal distance if line is vertical
if (p2.x == p1.x)
{
return std::abs(p1.x - p3.x);
}
else
{
// Find the equation for the line in the form y = mx + b
double m = 1.0*(p2.y - p1.y)/(p2.x - p1.x);
double b = p1.y - m*p1.x;
return std::abs(m*p3.x - p3.y + b)/std::sqrt(m*m + 1);
}
}
// Calculate mean
inline double average(const std::vector<double>& v)
{
if (v.size() > 0)
return std::accumulate(v.begin(), v.end(), 0.0)/v.size();
return 0;
}
inline double average(const std::vector<double>& v,
std::vector<double>::const_iterator start,
std::vector<double>::const_iterator end)
{
if (v.size() > 0)
return std::accumulate(start, end, 0.0)/v.size();
return 0;
}
// Check for blank vector
inline double max_value(const std::vector<double>& v)
{
if (v.size() > 0)
return *std::max_element(v.begin(), v.end());
return 0;
}
// Check for blank vector
inline double min_value(const std::vector<double>& v)
{
if (v.size() > 0)
return *std::min_element(v.begin(), v.end());
return 0;
}
// Round x to the nearest r
// see: http://stackoverflow.com/a/3407254
inline int round(const int x, const int r)
{
int remainder = x%r;
if (remainder == 0)
return x;
return x + r - remainder;
}
// Floor but after adding a bit
inline int smartFloor(const double value, const double epsilon)
{
return std::floor(value + epsilon);
}
// Ceil but after subtracting a bit
inline int smartCeil(const double value, const double epsilon)
{
return std::ceil(value - epsilon);
}
// y = m(x-x1)+y1
inline int lineFunctionY(const Coord& a, const Coord& b, int x)
{
return smartFloor(slopeYX(a,b)*(x - a.x) + a.y);
}
// x = (y-y1)/m+x1
inline int lineFunctionX(const Coord& a, const Coord& b, int y)
{
return smartFloor(slopeXY(a,b)*(y - a.y) + a.x);
}
// Rise over run
inline double slopeYX(const Coord& a, const Coord& b)
{
if (b.x - a.x == 0)
return 0;
else
return 1.0*(b.y - a.y)/(b.x - a.x);
}
// Run over rise
inline double slopeXY(const Coord& a, const Coord& b)
{
if (b.y - a.y == 0)
return 0;
else
return 1.0*(b.x - a.x)/(b.y - a.y);
}
inline Coord findMidpoint(const Coord& a, const Coord& b)
{
return Coord((a.x+b.x)/2, (a.y+b.y)/2);
}
// 3 way compares
inline double min(double a, double b, double c)
{
double m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
}
inline double max(double a, double b, double c)
{
double m = a;
if (m < b) m = b;
if (m < c) m = c;
return m;
}
#endif