Roomba Controller Dashboard 1
A GUI and TCP client application that is used to control a Roomba for Computer Engineering 2880 @ Iowa State
Loading...
Searching...
No Matches
Hole.cpp
Go to the documentation of this file.
1
5#include <iostream>
6#include "Hole.hpp"
7
8
9Hole::Hole(const Pose2D& positionOne, const Pose2D& positionTwo, double holeSize) {
10 Pose2D o1 = positionOne.clone();
11 Pose2D o2 = positionTwo.clone();
12 threshold = o1.distanceTo(o2) / sqrt(2);
13 this->holeSize = holeSize;
14 this->registerPointsToHole(o1, o2);
15 this->points = std::make_unique<std::vector<Pose2D>>();
16 this->pointHoles = std::make_unique<std::vector<Hole>>();
17}
18
19Hole::Hole(const Pose2D& positionOne, const Pose2D& positionTwo, bool foundHole, const std::vector<Pose2D>& points, double holeSize) {
20 threshold = positionOne.distanceTo(positionTwo) / sqrt(2);
21 if (foundHole) {
22 this->registerPointsToHole(positionOne, positionTwo);
23 }
24 else {
25 this->foundHole = false;
26 }
27
28 this->points = std::make_unique<std::vector<Pose2D>>();
29 for (const auto & point : points) {
30 this->points->push_back(point);
31 }
32 this->pointHoles = std::make_unique<std::vector<Hole>>();
33}
34
36 return this->cornerOne;
37}
38
40 return this->cornerTwo;
41}
42
43Pose2D Hole::copyDoOperation(const Pose2D& position) const {
44 Pose2D center(this->cornerOne);
45 center.setHeading(center.angleTo(this->cornerTwo));
46 center.translateByMagnitude(center.distanceTo(this->cornerTwo) / 2);
47
48 Pose2D pos(position);
49 pos.minus(center);
50
51 pos.rotateByAngle(phi);
52 pos.plus(Pose2D(x_translation_two, y_translation_two));
53 return pos;
54}
55
56std::vector<Pose2D> Hole::getSuggestedNodePlacements() {
57 // the nodes that we will generate will be around the hole, One hole length * 1.5 45 degrees offset to each corner from the center of the hole
58 std::vector<Pose2D> toReturn;
59
60 if (this->foundHole) {
61 Pose2D center(this->cornerOne);
62 center.setHeading(center.angleTo(this->cornerTwo));
63 Pose2D temp(center);
64 double magnitude = HOLE_SIZE * 1.5;
65 for (uint8_t i = 0; i < 8; i++) {
66 Pose2D toAdd(temp);
67 toAdd.translateByMagnitude(magnitude);
68 toReturn.push_back(toAdd);
69 temp.addAngle(M_PI / 4);
70 }
71 }
72 else {
73 for (uint16_t i = 0; i < this->points->size(); i++) {
74 Pose2D suggested(this->points->at(i));
75 suggested.addAngle(M_PI);
77 toReturn.push_back(suggested);
78 }
79 }
80 return toReturn;
81 }
82
83 bool Hole::isInSquare(Pose2D& position) const {
84 // std::cout << "starting position: " << position << std::endl;
85 // general idea: we use the operations in the object to translate objects for checks
86
87 Pose2D pos = copyDoOperation(position);
88
89 // std::cout << "translated position: " << pos << std::endl;
90
91 if (pos.getX() > 0 && pos.getX() < threshold && pos.getY() > 0 && pos.getY() < threshold) {
92 return true;
93 }
94 if (pos.getX() - BOT_RADIUS > 0 && pos.getX() - BOT_RADIUS < threshold && pos.getY() > 0 && pos.getY() < threshold) {
95 return true;
96 }
97 if (pos.getX() + BOT_RADIUS > 0 && pos.getX() + BOT_RADIUS < threshold && pos.getY() > 0 && pos.getY() < threshold) {
98 return true;
99 }
100 if (pos.getX() > 0 && pos.getX() < threshold && pos.getY() + BOT_RADIUS > 0 && pos.getY() + BOT_RADIUS < threshold) {
101 return true;
102 }
103 if (pos.getX() > 0 && pos.getX() < threshold && pos.getY() - BOT_RADIUS > 0 && pos.getY() - BOT_RADIUS < threshold) {
104 return true;
105 }
106 return false;
107
108}
109
110Hole::Hole(double X1, double Y1, double X2, double Y2, double holeSize) {
111 Pose2D o1(X1, Y1);
112 Pose2D o2(X2, Y2);
113 this->threshold = o1.distanceTo(o2) / sqrt(2);
114 this->holeSize = holeSize;
115 registerPointsToHole(o1, o2);
116
117 this->points = std::make_unique<std::vector<Pose2D>>();
118 this->pointHoles = std::make_unique<std::vector<Hole>>();
119}
120
122 this->holeSize = HOLE_SIZE;
123 this->threshold = HOLE_SIZE;
124 this->foundHole = false;
125 this->points = std::make_unique<std::vector<Pose2D>>();
126 this->pointHoles = std::make_unique<std::vector<Hole>>();
127}
128
129Hole::Hole(const Pose2D& initialPoint, double holeSize) {
130 this->foundHole = false;
131 this->points = std::make_unique<std::vector<Pose2D>>();
132 this->points->push_back(initialPoint);
133 this->pointHoles = std::make_unique<std::vector<Hole>>();
134 this->holeSize = holeSize;
135 this->threshold = holeSize;
136}
137
138bool Hole::pointCouldBeMemberOfHole(const Pose2D& measurment) {
139 for (const auto& point : *this->points) {
140 if (point.distanceTo(measurment) > holeSize * std::sqrt(2)) {
141 return false;
142 }
143 }
144 return true;
145}
146
147Hole::Hole(const Hole& hole) {
148 this->cornerOne = hole.cornerOne;
149 this->cornerTwo = hole.cornerTwo;
150 this->foundHole = hole.foundHole;
151 this->phi = hole.phi;
152 this->threshold = hole.threshold;
153 this->x_translation_one = hole.x_translation_one;
154 this->y_translation_one = hole.y_translation_one;
155 this->x_translation_two = hole.x_translation_two;
156 this->y_translation_two = hole.y_translation_two;
157 this->holeSize = hole.holeSize;
158
159 this->points = std::make_unique<std::vector<Pose2D>>();
160 for (uint16_t i = 0; i < hole.points->size(); i++) {
161 this->points->push_back(hole.points->data()[i]);
162 }
163 this->pointHoles = std::make_unique<std::vector<Hole>>();
164 for (uint16_t i = 0; i < hole.pointHoles->size(); i++) {
165 this->pointHoles->push_back(hole.pointHoles->data()[i]);
166 }
167
168}
169
170void Hole::addPoint(const Pose2D& position) {
171 this->points->push_back(position);
172 //General flow:
173 if (this->points->size() > 2) {
174 // should be 3 elements
175 // pick 2 with close headings
176
177 // find index of the pivot
178
179 Pose2D perpendicularPosition;
180 Pose2D parallelOne;
181 Pose2D parallelTwo;
182
183 // positions one and two
184 if (fabs(this->points->at(0).getHeading() - this->points->at(1).getHeading()) < M_PI / 2) {
185 // yay we have our parallel par of one and two
186 perpendicularPosition = this->points->at(2);
187 parallelOne = this->points->at(0);
188 parallelTwo = this->points->at(1);
189 }
190 // check positions two and three
191 else if (fabs(this->points->at(1).getHeading() - this->points->at(2).getHeading()) < M_PI / 2) {
192 // yay we know our parallel pair are two and three
193 perpendicularPosition = this->points->at(0);
194 parallelOne = this->points->at(1);
195 parallelTwo = this->points->at(2);
196 }
197
198 // check positions one and three
199 else if (fabs(this->points->at(0).getHeading() - this->points->at(2).getHeading()) < M_PI / 2) {
200 // we have our parallel pair of 1 and three
201 perpendicularPosition = this->points->at(1);
202 parallelOne = this->points->at(0);
203 parallelTwo = this->points->at(2);
204 }
205
206 if (parallelOne.getX() > parallelTwo.getX()) {
207 const Pose2D temp = parallelOne;
208 parallelOne = parallelTwo;
209 parallelTwo = temp;
210 }
211
212 // none of the angles are similiar so we know that we have three measurmenets from all different edges of the square
213 else {
214 // get the two similiar angles when turned around
215 // pose 1 and 2 are out of phase
216 if (fabs(this->points->at(0).getHeading() + this->points->at(1).getHeading()) < 0.1 || fabs(fabs(this->points->at(0).getHeading()) - fabs(this->points->at(1).getHeading())) < 0.1) {
217 parallelOne = this->points->at(0);
218 parallelOne.translateByMagnitude(holeSize);
219 parallelTwo = this->points->at(1);
220 perpendicularPosition = this->points->at(2);
221 }
222 // pose 2 and three are out of phase
223 else if (fabs(this->points->at(2).getHeading() + this->points->at(1).getHeading()) < 0.1 || fabs(fabs(this->points->at(2).getHeading()) - fabs(this->points->at(1).getHeading())) < 0.1) {
224 parallelOne = this->points->at(2);
225 parallelOne.translateByMagnitude(holeSize);
226 parallelTwo = this->points->at(1);
227 perpendicularPosition = this->points->at(0);
228 }
229 // pose 3 and 1 are out of phase
230 else if (fabs(this->points->at(0).getHeading() + this->points->at(2).getHeading()) < 0.1 || fabs(fabs(this->points->at(0).getHeading()) - fabs(this->points->at(2).getHeading())) < 0.1) {
231 parallelOne = this->points->at(0);
232 parallelOne.translateByMagnitude(holeSize);
233 parallelTwo = this->points->at(2);
234 perpendicularPosition = this->points->at(1);
235 }
236 else {
237 // i'm not sure how we got here and I' m just gonna clear the entire list
238 this->points->clear();
239 }
240
241 }
242
243 Pose2D cornerOne;
244 Pose2D oppositeCorner;
245
246 // now we have to make the cirtical points from the two parallel lines and the perpendicular line
247 double dx = (parallelTwo.getX() - parallelOne.getX());
248 double dy = (parallelTwo.getY() - parallelOne.getY());
249 if (fabs(dx) < 0.01) {
250 // vertical line
251 double xCornerOne = parallelOne.getX();
252 double yCornerOne = perpendicularPosition.getY();
253 cornerOne = Pose2D(xCornerOne, yCornerOne);
254 oppositeCorner = Pose2D(cornerOne);
255 oppositeCorner.setHeading((cornerOne.angleTo(parallelOne) + cornerOne.angleTo(parallelTwo)) / 2);
256 oppositeCorner.translateByMagnitude(holeSize * sqrt(2));
257 }
258 // horizontal line
259 else if (fabs(dy) < 0.01) {
260 double xCornerOne = perpendicularPosition.getX();
261 double yCornerOne = parallelOne.getY();
262 cornerOne = Pose2D(xCornerOne, yCornerOne);
263 oppositeCorner = Pose2D(cornerOne);
264 oppositeCorner.setHeading((parallelOne.getX() + perpendicularPosition.getX()) / 2);
265 oppositeCorner.translateByMagnitude(holeSize * sqrt(2));
266 }
267 else {
268 double m1 = (parallelTwo.getY() - parallelOne.getY()) / dx;
269 double b1 = - m1 * parallelOne.getX() + parallelOne.getY();
270 double m2 = - 1 / m1;
271 double b2 = -m2 * perpendicularPosition.getX() + perpendicularPosition.getY();
272
273 double xIntersection = (1 / m1 + m1) / (b2 - b1);
274 double yIntersection = xIntersection * m1 + b1;
275 cornerOne = Pose2D(xIntersection, yIntersection);
276
277 // favorite very dumb method
278 double angleToOther = (cornerOne.angleTo(parallelOne) + cornerOne.angleTo(perpendicularPosition)) / 2;
279 oppositeCorner = Pose2D(cornerOne);
280 oppositeCorner.setHeading(angleToOther);
281 oppositeCorner.translateByMagnitude(holeSize * sqrt(2));
282 }
283
284 this->cornerOne = cornerOne;
285 this->cornerTwo = oppositeCorner;
286 this->foundHole = true;
287 }
288
289 if (!foundHole) {
290 Pose2D cornerOneNew(position);
291 cornerOneNew.rotateByAngle(M_PI / 4);
292 cornerOneNew.translateByMagnitude(2);
293 Pose2D cornerTwoNew(position);
294 // an astute reader will notice that this is really stupid and that there is a relatively simple
295 // math to accomplish this goal in one operation
296 // however I am stupid
297 cornerTwoNew.rotateByAngle(-M_PI / 4);
298 cornerTwoNew.translateByMagnitude(2);
299 cornerTwoNew.rotateByAngle(M_PI / 2);
300 cornerTwoNew.translateByMagnitude(4);
301 Hole hole(cornerOneNew, cornerTwoNew, 4);
302 this->pointHoles->push_back(hole);
303 }
304}
305
306void Hole::registerPointsToHole(const Pose2D& positionOne, const Pose2D& positionTwo) {
307 // calculate the first translation
308 cornerOne = Pose2D(positionOne);
309 cornerTwo = Pose2D(positionTwo);
310 Pose2D D(positionOne);
311 foundHole = true;
312
313 // wrong should be center x and y
314 Pose2D center(positionOne);
315 center.vecAdd(center.angleTo(positionTwo), center.distanceTo(positionTwo) / 2);
316 x_translation_one = -center.getX();
317 y_translation_one = -center.getY();
318
319 double phi;
320 D.plus(Pose2D(x_translation_one, y_translation_one));
321 switch (D.getQuadrant()) {
322 case 0:
323 if (fabs(D.getX()) < 0.01) {
324 // on y axis
325 if (D.getY() < 0) {
326 phi = - M_PI / 3; // just a nudge
327 }
328 else {
329 phi = M_PI / 4 * 3;
330 }
331 }
332 else {
333 // on x axis
334 if (D.getX() > 0) {
335 phi = -M_PI / 4 * 3;
336 }
337 else {
338 phi = M_PI / 3;
339 }
340 }
341 break;
342 case 1:
343 phi = M_PI;
344 break;
345 case 2:
346 phi = M_PI / 2;
347 break;
348 case 4:
349 phi = -M_PI / 2;
350 break;
351 default:
352 phi = 0;
353 break;
354 }
355
356 D.rotateByAngle(phi);
357
358 double newAngle = M_PI / 4 - atan2(-D.getY(), -D.getX()); // see desmos graph
359 D.rotateByAngle(newAngle);
360 phi = newAngle;
361 this->phi = phi;
362 // calculate position one into
363 x_translation_two = -D.getX();
364 y_translation_two = -D.getY();
365
366 threshold = cornerOne.distanceTo(cornerTwo) / sqrt(2);
367
368 /*std::cout << "x translation: " << x_translation_one << std::endl << "y translation: " << y_translation_one << std::endl
369 << "angleTurn: " << phi << std::endl << "x translation 2: " << x_translation_two << std::endl << "y_translation: " << y_translation_two << std::endl
370 << "threshold: " << threshold << std::endl;*/
371}
372
373std::ostream &operator<<(std::ostream &os, const Hole &hole) {
374 os << "cornerOne: " << hole.cornerOne << " cornerTwo: " << hole.cornerTwo << " threshold: " << hole.threshold << " phi: " << hole.phi
375 << " x_translation_one: " << hole.x_translation_one << " y_translation_one: " << hole.y_translation_one
376 << " x_translation_two: " << hole.x_translation_two << " y_translation_two: " << hole.y_translation_two
377 << " foundHole: " << hole.foundHole << " points: " << hole.points;
378 return os;
379}
380
381void Hole::offset(const Pose2D& offset) {
382 if (foundHole) {
383 this->cornerOne.plus(offset);
384 this->cornerTwo.plus(offset);
385 registerPointsToHole(cornerOne, cornerTwo);
386 }
387 for (uint16_t i = 0; i < this->points->size(); i++) {
388 this->points->at(i).plus(offset);
389 this->pointHoles->at(i).offset(offset);
390 }
391}
392
393bool Hole::lineIntersectsHole(const Pose2D& posOne, const Pose2D& posTwo) const {
394 if (foundHole) {
395 Pose2D positionOne;
396 Pose2D positionTwo;
397 if (posOne.getX() < posTwo.getX()) {
398 positionOne = copyDoOperation(posOne);
399 positionTwo = copyDoOperation(posTwo);
400 } else {
401 positionOne = copyDoOperation(posTwo);
402 positionTwo = copyDoOperation(posOne);
403 }
404
405 // if the line between them, at any point falls between 0 and threshold
406 // annoyingly I think this means that we need to do real math (ew)
407 if (fabs(positionOne.getX() - positionTwo.getX()) < 0.05) {
408 // we have a vertical line
409 // if the vertical line starts below 0 and ends after threshold and X is between 0 and threshold then it intersects
410 return (((positionOne.getX() > 0 && positionOne.getX() < threshold) ||
411 (positionTwo.getX() > 0 && positionTwo.getX() < threshold)) &&
412 fmax(positionOne.getY(), positionTwo.getY()) > threshold &&
413 fmin(positionOne.getY(), positionTwo.getY()) < 0);
414
415 }
416 if (fabs(positionOne.getY() - positionTwo.getY()) < 0.05) {
417 // we have a horizontal line
418 return (((positionOne.getY() > 0 && positionOne.getY() < threshold) ||
419 (positionTwo.getY() > 0 && positionTwo.getY() < threshold)) &&
420 fmax(positionOne.getX(), positionTwo.getX()) > threshold &&
421 fmin(positionOne.getX(), positionTwo.getX()) < 0);
422 }
423
424 // now we gotta make a line, which we can guranteed will exist without a slope of 0
425 double m = (positionTwo.getY() - positionOne.getY()) / (positionTwo.getX() - positionOne.getX());
426 double b = positionOne.getY() - (positionOne.getX() * m);
427
428 // now that we know the equation of the line we can determine if it intersects the x axis, y axis, or y = threshold or x = threshold
429 // yayyyy finding 0's of a function
430 double y2Check = m * positionOne.getX() + b;
431 if ((b < threshold && b > 0) || (y2Check < threshold && y2Check > 0)) {
432 return true; // we intersect with the x axis
433 }
434 double xValueAtYIsZero = (-b / m);
435 double xValueATYIsThreshold = (threshold - b) / m;
436 return (xValueAtYIsZero > 0 && xValueAtYIsZero < threshold) ||
437 (xValueATYIsThreshold > 0 && xValueATYIsThreshold < threshold);
438 }
439 else {
440 for (uint16_t i = 0; i < this->pointHoles->size(); i++) {
441 if (this->pointHoles->at(i).lineIntersectsHole(posOne, posTwo)) {
442 return true;
443 }
444 }
445 }
446 return false;
447}
448
449Hole::Hole(double x1, double y1, double x2, double y2) {
450 this->cornerOne = Pose2D(x1, y1);
451 this->cornerTwo = Pose2D(x2, y2);
452 this->points = std::make_unique<std::vector<Pose2D>>();
453 this->pointHoles = std::make_unique<std::vector<Hole>>();
454 this->holeSize = cornerOne.distanceTo(cornerTwo) / sqrt(2);
455 registerPointsToHole(cornerOne, cornerTwo);
456}
457
458std::vector<Hole> Hole::getSubHolesCopy() const {
459 std::vector<Hole> toReturn;
460 for (uint16_t i = 0; i < this->pointHoles->size(); i++) {
461 toReturn.push_back(this->pointHoles->at(i));
462 }
463 return toReturn;
464}
std::ostream & operator<<(std::ostream &os, const Hole &hole)
Definition Hole.cpp:373
#define HOLE_SIZE
Definition Hole.hpp:14
#define BOT_RADIUS
Definition Pose2D.hpp:17
Definition Hole.hpp:20
Pose2D getOneSquareCorner()
Definition Hole.cpp:35
void addPoint(const Pose2D &position)
Definition Hole.cpp:170
std::vector< Pose2D > getSuggestedNodePlacements()
Definition Hole.cpp:56
void offset(const Pose2D &offset)
Definition Hole.cpp:381
std::vector< Hole > getSubHolesCopy() const
Definition Hole.cpp:458
Hole()
Definition Hole.cpp:121
Pose2D copyDoOperation(const Pose2D &position) const
Definition Hole.cpp:43
void registerPointsToHole(const Pose2D &positionOne, const Pose2D &positionTwo)
Definition Hole.cpp:306
Pose2D getSecondSquareCorner()
Definition Hole.cpp:39
bool lineIntersectsHole(const Pose2D &posOne, const Pose2D &posTwo) const
Definition Hole.cpp:393
bool pointCouldBeMemberOfHole(const Pose2D &measurment)
Definition Hole.cpp:138
bool isInSquare(Pose2D &position) const
Definition Hole.cpp:83
void setHeading(double angle)
Definition Pose2D.cpp:159
void rotateByAngle(double angle)
Definition Pose2D.cpp:116
double angleTo(const Pose2D &other) const
Definition Pose2D.cpp:78
Pose2D clone() const
Definition Pose2D.cpp:106
void plus(const Pose2D &other)
Definition Pose2D.cpp:100
void addAngle(double angle)
Definition Pose2D.cpp:82
void translateByMagnitude(double magnitude)
Definition Pose2D.cpp:137
double distanceTo(const Pose2D &other) const
Definition Pose2D.cpp:86
uint8_t getQuadrant() const
Definition Pose2D.cpp:171
void vecAdd(double angle, double magnitude)
Definition Pose2D.cpp:110
double getY() const
Definition Pose2D.cpp:151
double getX() const
Definition Pose2D.cpp:147
void minus(Pose2D other)
Definition Pose2D.cpp:187