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