00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "ArExport.h"
00028
00029 #include "ariaOSDef.h"
00030 #include "ArLineFinder.h"
00031
00032 ArLineFinder::ArLineFinder(ArRangeDevice *rangeDevice)
00033 {
00034 myRangeDevice = rangeDevice;
00035 myPrinting = false;
00036 myPoints = NULL;
00037 myLines = NULL;
00038 myFlippedFound = false;
00039
00040 setLineCreationParams();
00041 setLineCombiningParams();
00042 setLineFilteringParams();
00043 setLineValidParams();
00044 }
00045
00046 ArLineFinder::~ArLineFinder()
00047 {
00048
00049 }
00050
00051 std::map<int, ArLineFinderSegment *> *ArLineFinder::getLines(void)
00052 {
00053
00054 fillPointsFromLaser();
00055
00056 findLines();
00057
00058
00059 combineLines();
00060
00061 filterLines();
00062
00063 combineLines();
00064 return myLines;
00065 }
00066
00067
00068 void ArLineFinder::fillPointsFromLaser(void)
00069 {
00070 const std::list<ArSensorReading *> *readings;
00071 std::list<ArSensorReading *>::const_iterator it;
00072 std::list<ArSensorReading *>::const_reverse_iterator rit;
00073 ArSensorReading *reading;
00074 int pointCount = 0;
00075
00076 if (myPoints != NULL)
00077 delete myPoints;
00078
00079 myPoints = new std::map<int, ArPose>;
00080
00081 myRangeDevice->lockDevice();
00082 readings = myRangeDevice->getRawReadings();
00083
00084 if (!myFlippedFound)
00085 {
00086 if (readings->begin() != readings->end())
00087 {
00088 int size;
00089 size = readings->size();
00090 it = readings->begin();
00091
00092 for (int i = 0; i < 10 && i < size / 2; i++)
00093 it++;
00094
00095 if (ArMath::subAngle((*(readings->begin()))->getSensorTh(),
00096 (*it)->getSensorTh()) > 0)
00097 myFlipped = true;
00098 else
00099 myFlipped = false;
00100 myFlippedFound = true;
00101
00102
00103
00104 }
00105 }
00106
00107
00108
00109
00110 if (readings->begin() == readings->end())
00111 {
00112 myRangeDevice->unlockDevice();
00113 return;
00114 }
00115 myPoseTaken = (*readings->begin())->getPoseTaken();
00116
00117 if (myFlipped)
00118 {
00119 for (rit = readings->rbegin(); rit != readings->rend(); rit++)
00120 {
00121 reading = (*rit);
00122 if (reading->getRange() > 5000)
00123 continue;
00124 (*myPoints)[pointCount] = reading->getPose();
00125 pointCount++;
00126 }
00127 }
00128 else
00129 {
00130 for (it = readings->begin(); it != readings->end(); it++)
00131 {
00132 reading = (*it);
00133 if (reading->getRange() > 5000)
00134 continue;
00135 (*myPoints)[pointCount] = reading->getPose();
00136 pointCount++;
00137 }
00138 }
00139 myRangeDevice->unlockDevice();
00140 }
00141
00142 void ArLineFinder::findLines(void)
00143 {
00144 int start = 0;
00145 int pointsLen = myPoints->size();
00146 int end;
00147
00148 if (myLines != NULL)
00149 {
00150 ArUtil::deleteSetPairs(myLines->begin(), myLines->end());
00151 delete myLines;
00152 myLines = NULL;
00153 }
00154 myLines = new std::map<int, ArLineFinderSegment *>;
00155 int numLines = 0;
00156
00157 FILE *lineFile = NULL;
00158
00159
00160
00161
00162
00163
00164
00165 ArLineFinderSegment *newLine;
00166 double totalDistFromLine = 0;
00167 double dist;
00168 int i;
00169
00170 while (1)
00171 {
00172
00173
00174 for (end = start; ; end++)
00175 {
00176
00177 if (end >= pointsLen)
00178 break;
00179
00180 if (end - start >= myMakingMinPoints &&
00181 (*myPoints)[start].findDistanceTo((*myPoints)[end]) > myMakingMinLen)
00182 break;
00183 }
00184 if (end < pointsLen)
00185 {
00186
00187 if ((*myPoints)[start].findDistanceTo((*myPoints)[end]) <
00188 ((*myPoints)[start].findDistanceTo(myPoseTaken) *
00189 ArMath::sin(1) / ArMath::sin(5)))
00190 {
00191 if (lineFile != NULL)
00192 fprintf(lineFile, "%.0f %.0f %.0f %.0f\n",
00193 (*myPoints)[start].getX(), (*myPoints)[start].getY(),
00194 (*myPoints)[end].getX() - (*myPoints)[start].getX(),
00195 (*myPoints)[end].getY() - (*myPoints)[start].getY());
00196
00197 newLine = new ArLineFinderSegment(
00198 (*myPoints)[start].getX(),
00199 (*myPoints)[start].getY(),
00200 (*myPoints)[end].getX(),
00201 (*myPoints)[end].getY(),
00202 1, start, end);
00203
00204 totalDistFromLine = 0;
00205
00206 for (i = newLine->getStartPoint(); i <= newLine->getEndPoint(); i++)
00207 {
00208 dist = newLine->getDistToLine((*myPoints)[i]);
00209 totalDistFromLine += dist;
00210 }
00211 newLine->setAveDistFromLine(totalDistFromLine / (end - start));
00212
00213 (*myLines)[numLines] = newLine;
00214 numLines++;
00215 }
00216 else
00217 {
00218 if (myPrinting)
00219 ArLog::log(ArLog::Normal, "too great a distance between the two line points %d %d", start, end);
00220 }
00221 }
00222
00223 start += 1;
00224 if (start >= pointsLen)
00225 break;
00226 }
00227
00228 if (lineFile != NULL)
00229 fclose(lineFile);
00230 }
00231
00232 bool ArLineFinder::combineLines(void)
00233 {
00234 int start = 0;
00235 int len = myLines->size();
00236
00237 std::map<int, ArLineFinderSegment *> *newLines;
00238 int numNewLines = 0;
00239 int numNewMerges = 0;
00240 ArLineFinderSegment *newLine;
00241
00242 newLines = new std::map<int, ArLineFinderSegment *>;
00243
00244 if (myPrinting)
00245 ArLog::log(ArLog::Normal, "new iteration\n");
00246
00247 bool nextMerged = false;
00248 for (start = 0; start < len; start++)
00249 {
00250 if (nextMerged)
00251 {
00252 nextMerged = false;
00253 continue;
00254 }
00255
00256 if (start + 1 == len)
00257 {
00258 if (myPrinting)
00259 ArLog::log(ArLog::Normal, "inserted last one %g",
00260 ArPose((*myLines)[start]->getX1(),
00261 (*myLines)[start]->getY1()).findDistanceTo(
00262 ArPose((*myLines)[start]->getX2(), (*myLines)[start]->getY2())));
00263 (*newLines)[numNewLines] = new ArLineFinderSegment(*((*myLines)[start]));
00264 numNewLines++;
00265 continue;
00266 }
00267
00268 newLine = averageSegments((*myLines)[start], (*myLines)[start+1]);
00269 if (newLine != NULL)
00270 {
00271
00272 if (myPrinting)
00273 ArLog::log(ArLog::Normal, "merged %g %g to %g",
00274 (*myLines)[start]->getLength(),
00275 (*myLines)[start+1]->getLength(),
00276 newLine->getLength());
00277 (*newLines)[numNewLines] = newLine;
00278 numNewLines++;
00279 numNewMerges++;
00280 nextMerged = true;
00281 }
00282 else
00283 {
00284 if (myPrinting)
00285 ArLog::log(ArLog::Normal, "inserted anyways %g",
00286 (*myLines)[start]->getLength());
00287 (*newLines)[numNewLines] = new ArLineFinderSegment(*((*myLines)[start]));
00288 numNewLines++;
00289 }
00290
00291 }
00292
00293
00294 if (myLines != NULL && myLines->begin() != myLines->end())
00295 {
00296 ArUtil::deleteSetPairs(myLines->begin(), myLines->end());
00297 delete myLines;
00298 myLines = NULL;
00299 }
00300 else if (myLines != NULL)
00301 {
00302 delete myLines;
00303 myLines = NULL;
00304 }
00305 myLines = newLines;
00306
00307 if (numNewMerges == 0)
00308 return true;
00309
00310
00311 return combineLines();
00312 }
00313
00314 ArLineFinderSegment *ArLineFinder::averageSegments(
00315 ArLineFinderSegment *line1,
00316 ArLineFinderSegment *line2)
00317 {
00318
00319
00320
00321 if (myPrinting)
00322 ArLog::log(ArLog::Normal,
00323 "%3.0f %5.0f %3.0f %3.0f (%5.0f %5.0f) <%d %d> (%5.0f %5.0f) <%d %d>",
00324 ArMath::subAngle(line1->getLineAngle(),
00325 line2->getLineAngle()),
00326 line1->getEndPoint2().findDistanceTo(line2->getEndPoint1()),
00327 line1->getLineAngle(), line2->getLineAngle(),
00328 line1->getX2(), line1->getY2(),
00329 line1->getStartPoint(), line1->getEndPoint(),
00330 line2->getX1(), line2->getY1(),
00331 line2->getStartPoint(), line2->getEndPoint());
00332
00333
00334 if (line1->getEndPoint2().findDistanceTo(line2->getEndPoint1()) >
00335 line1->getEndPoint2().findDistanceTo(myPoseTaken) *
00336 ArMath::sin(1) / ArMath::sin(5))
00337 {
00338 if (myPrinting)
00339 ArLog::log(ArLog::Normal,
00340 "too great a distance between the two line points");
00341 return NULL;
00342 }
00343
00344 double angleOff;
00345 if ((angleOff = ArMath::fabs(
00346 ArMath::subAngle(line1->getLineAngle(),
00347 line2->getLineAngle()))) > myCombiningAngleTol)
00348 {
00349 if (myPrinting)
00350 ArLog::log(ArLog::Normal, "greater than angle tolerance");
00351 return NULL;
00352 }
00353
00354 ArPose endPose2(line2->getX2(), line2->getY2());
00355 ArPose intersection1;
00356 ArLine line1Line(*(line1->getLine()));
00357 ArLine perpLine1;
00358
00359
00360 line1Line.makeLinePerp(&endPose2, &perpLine1);
00361 if (!line1Line.intersects(&perpLine1, &intersection1) ||
00362 intersection1.findDistanceTo(endPose2) > myCombiningLinesCloseEnough)
00363 {
00364
00365
00366 if (myPrinting)
00367 ArLog::log(ArLog::Normal, "endPose2 too far from line1");
00368 return NULL;
00369 }
00370
00371 ArPose endPose1(line1->getX1(), line1->getY1());
00372 ArPose intersection2;
00373 ArLine line2Line(*(line2->getLine()));
00374 ArLine perpLine2;
00375
00376
00377
00378 line2Line.makeLinePerp(&endPose1, &perpLine2);
00379 if (!line2Line.intersects(&perpLine2, &intersection2) ||
00380 intersection2.findDistanceTo(endPose1) > myCombiningLinesCloseEnough)
00381 {
00382
00383 if (myPrinting)
00384 ArLog::log(ArLog::Normal, "endPose1 too far from line2");
00385 return NULL;
00386 }
00387
00388
00389
00390 ArLineFinderSegment *newLine;
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 int l1C = line1->getNumPoints();
00401 int l2C = line2->getNumPoints();
00402 newLine = new ArLineFinderSegment((endPose1.getX() * l1C +
00403 intersection2.getX() * l2C) / (l1C + l2C),
00404 (endPose1.getY() * l1C +
00405 intersection2.getY() * l2C) / (l1C + l2C),
00406 (endPose2.getX() * l2C +
00407 intersection1.getX() * l1C) / (l1C + l2C),
00408 (endPose2.getY() * l2C +
00409 intersection1.getY() * l1C) / (l1C + l2C),
00410 (line1->getNumPoints() +
00411 line2->getNumPoints()),
00412 line1->getStartPoint(),
00413 line2->getEndPoint());
00414
00415
00416 double totalDistFromLine = 0;
00417 double dist;
00418 int i;
00419
00420 for (i = newLine->getStartPoint(); i <= newLine->getEndPoint(); i++)
00421 {
00422 if ((dist = newLine->getDistToLine((*myPoints)[i])) >
00423 myValidMaxDistFromLine &&
00424 i != newLine->getStartPoint() &&
00425 i != newLine->getEndPoint())
00426 {
00427 if (myPrinting)
00428 ArLog::log(ArLog::Normal,
00429 "Had a point %d that was to far from our line at %.0f (max %d)",
00430 i, dist, myValidMaxDistFromLine);
00431
00432 delete newLine;
00433 return NULL;
00434 }
00435
00436 totalDistFromLine += dist;
00437 }
00438 newLine->setAveDistFromLine(totalDistFromLine / (newLine->getEndPoint() - newLine->getStartPoint()));
00439
00440
00441 if (newLine->getAveDistFromLine() > myValidMaxAveFromLine)
00442 {
00443 if (myPrinting)
00444 ArLog::log(ArLog::Normal,
00445 "Ave dist from line was too great at %.0f (max %d)",
00446 newLine->getAveDistFromLine(), myValidMaxDistFromLine);
00447
00448 delete newLine;
00449 return NULL;
00450 }
00451 if (newLine->getAveDistFromLine() > (line1->getAveDistFromLine() +
00452 line2->getAveDistFromLine()) * 1.25)
00453 {
00454 if (myPrinting)
00455 ArLog::log(ArLog::Normal,
00456 "Ave dist from line greater than component lines at %.0f (component lines %.0f %.0f)",
00457 newLine->getAveDistFromLine(),
00458 line1->getAveDistFromLine(),
00459 line2->getAveDistFromLine());
00460
00461 delete newLine;
00462 return NULL;
00463
00464 }
00465
00466 if (angleOff < myCombiningAngleTol / 2)
00467 return newLine;
00468
00469
00470 if ((ArMath::subAngle(newLine->getLineAngle(), line2->getLineAngle()) > 0 &&
00471 ArMath::subAngle(line1->getLineAngle(), newLine->getLineAngle()) > 0) ||
00472 (ArMath::subAngle(newLine->getLineAngle(), line1->getLineAngle()) > 0 &&
00473 ArMath::subAngle(line2->getLineAngle(), newLine->getLineAngle()) > 0))
00474 return newLine;
00475
00476
00477 if (myPrinting)
00478 ArLog::log(ArLog::Normal, "angles wonky");
00479
00480 delete newLine;
00481 return NULL;
00482 }
00483
00484 void ArLineFinder::filterLines(void)
00485 {
00486 int start = 0;
00487 int len = myLines->size();
00488
00489
00490 std::map<int, ArLineFinderSegment *> *newLines;
00491 int numNewLines = 0;
00492
00493 newLines = new std::map<int, ArLineFinderSegment *>;
00494
00495 if (myPrinting)
00496 ArLog::log(ArLog::Normal, "filtering lines\n");
00497
00498 for (start = 0; start < len; start++)
00499 {
00500 if ((*myLines)[start]->getNumPoints() >= myFilteringMinPointsInLine &&
00501 (*myLines)[start]->getEndPoint1().findDistanceTo(
00502 (*myLines)[start]->getEndPoint2()) > myFilteringMinLineLength)
00503 {
00504 if (myPrinting)
00505 ArLog::log(ArLog::Normal, "kept %g (%d points)",
00506 (*myLines)[start]->getLength(),
00507 (*myLines)[start]->getNumPoints());
00508 (*newLines)[numNewLines] = new ArLineFinderSegment(*((*myLines)[start]));
00509 numNewLines++;
00510 }
00511 else
00512 {
00513 if (myPrinting)
00514 ArLog::log(ArLog::Normal, "Clipped %g (%d points)",
00515 (*myLines)[start]->getLength(),
00516 (*myLines)[start]->getNumPoints());
00517 }
00518
00519 }
00520
00521
00522 if (myLines != NULL && myLines->begin() != myLines->end())
00523 {
00524 ArUtil::deleteSetPairs(myLines->begin(), myLines->end());
00525 delete myLines;
00526 myLines = NULL;
00527 }
00528 else if (myLines != NULL)
00529 {
00530 delete myLines;
00531 myLines = NULL;
00532 }
00533 myLines = newLines;
00534
00535 }
00536
00537
00538
00544 void ArLineFinder::saveLast(void)
00545 {
00546 int len = myPoints->size();
00547 int i;
00548
00549 FILE *points;
00550 if ((points = fopen("points", "w+")) == NULL)
00551 {
00552 ArLog::log(ArLog::Terse, "ArLineFinder::log: Could not open 'points' file for output");
00553 return;
00554 }
00555 for (i = 0; i < len; i++)
00556 {
00557 fprintf(points, "%.0f %.0f\n",
00558 (*myPoints)[i].getX(), (*myPoints)[i].getY());
00559 }
00560 fclose(points);
00561
00562
00563 len = myLines->size();
00564
00565 FILE *lines;
00566 if ((lines = fopen("lines", "w+")) == NULL)
00567 {
00568 ArLog::log(ArLog::Terse, "ArLineFinder::log: Could not open 'lines' file for output");
00569 return;
00570 }
00571 for (i = 0; i < len; i++)
00572 {
00573 fprintf(lines, "%.0f %.0f %.0f %.0f\n",
00574 (*myLines)[i]->getX1(), (*myLines)[i]->getY1(),
00575 (*myLines)[i]->getX2() - (*myLines)[i]->getX1(),
00576 (*myLines)[i]->getY2() - (*myLines)[i]->getY1());
00577 }
00578 fclose(lines);
00579
00580 ArLog::log(ArLog::Normal, "Saved points and lines");
00581 }
00582
00583 void ArLineFinder::getLinesAndSaveThem(void)
00584 {
00585 getLines();
00586 saveLast();
00587 }
00588