Homepage Demos Overview Downloads Tutorials Reference
Credits

BrickData.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 
00003 #include <iostream>
00004 #include <vector>
00005 
00006 #include "BaseData.h"    // superclass
00007 #include "Point.h"       // Point data member
00008 #include "ShapeTypes.h"  // brickDataType
00009 
00010 #include "SketchSpace.h"
00011 #include "Sketch.h"
00012 #include "visops.h"
00013 
00014 #include "ShapeSpace.h"  // required by DATASTUFF_CC
00015 #include "ShapeRoot.h"   // required by DATASTUFF_CC
00016 
00017 #include "BrickData.h"
00018 #include "ShapeBrick.h"
00019 #include "ShapePoint.h"
00020 #include "Region.h"
00021 
00022 
00023 namespace DualCoding {
00024 
00025 BrickData::BrickData(ShapeSpace& _space,
00026          const EndPoint &_GFL, const EndPoint &_GFR, 
00027          const EndPoint &_GBL, const EndPoint &_GBR, 
00028          const EndPoint &_TFL, const EndPoint &_TFR, 
00029          const EndPoint &_TBL, const EndPoint &_TBR) 
00030   : BaseData(_space,brickDataType), 
00031     GFL(_GFL), GFR(_GFR), GBL(_GBL), GBR(_GBR),
00032     TFL(_TFL), TFR(_TFR), TBL(_TBL), TBR(_TBR),
00033     centroid((GFL + GFR + GBL + GBR + TFL + TFR + TBL + TBR) / 8)
00034 {
00035 }
00036 
00037   
00038 DATASTUFF_CC(BrickData);
00039 
00040 bool BrickData::isMatchFor(const ShapeRoot& other) const {
00041   if (!(isSameTypeAs(other) && isSameColorAs(other)))
00042     return false;
00043   // const Shape<BrickData>& other_point = ShapeRootTypeConst(other,BrickData);
00044   // float dist = the_point.distanceFrom(other_point->getCentroid());
00045   float dist = 0;
00046   return dist < 20; // *** DST hack
00047 }
00048 
00049 void BrickData::mergeWith(const ShapeRoot& other) {
00050   const Shape<BrickData>& other_brick = ShapeRootTypeConst(other,BrickData);
00051   if (other_brick->confidence <= 0)
00052     return;
00053   /*
00054   const int other_conf = other_point->confidence;
00055   confidence += other_conf;
00056   the_point = (the_point*confidence + other_point->getCentroid()*other_conf) / (confidence+other_conf);*/
00057 }
00058 
00059 bool BrickData::updateParams(const ShapeRoot& other, bool) {
00060   const Shape<BrickData>& other_brick = *static_cast<const Shape<BrickData>*>(&other);
00061   //  ++confidence;
00062   GFL = (GFL*(confidence-1) + other_brick->getGFL())/confidence;
00063   GFR = (GFR*(confidence-1) + other_brick->getGFR())/confidence;
00064   GBL = (GBL*(confidence-1) + other_brick->getGBL())/confidence;
00065   GBR = (GBR*(confidence-1) + other_brick->getGBR())/confidence;
00066   TFL = (TFL*(confidence-1) + other_brick->getTFL())/confidence;
00067   TFR = (TFR*(confidence-1) + other_brick->getTFR())/confidence;
00068   TBL = (TBL*(confidence-1) + other_brick->getTBL())/confidence;
00069   TBR = (TBR*(confidence-1) + other_brick->getTBR())/confidence;
00070   deleteRendering();
00071   return true;
00072 }
00073 
00074 //! Print information about this shape. (Virtual in BaseData.)
00075 void
00076 BrickData::printParams() const {
00077   cout << "Type = " << getTypeName();
00078   cout << "Shape ID = " << getId() << endl;
00079   cout << "Parent ID = " << getParentId() << endl;
00080   
00081   // Print critical points.
00082   cout << endl;
00083   //cout << "center{" << getCentroid().coordX() << ", " << getCentroid().coordY() << "}" << endl;
00084   /* Didn't work initially... not sure why, didn't try too hard.
00085     cout<<"GFL: "; GFL.printData(); cout<<endl;
00086   cout<<"GFR: "; GFR.printData(); cout<<endl;
00087   cout<<"GBL: "; GBL.printData(); cout<<endl;
00088   cout<<"GBR: "; GBR.printData(); cout<<endl;
00089   cout<<"TFL: "; TFL.printData(); cout<<endl;
00090   cout<<"TFR: "; TFR.printData(); cout<<endl;
00091   cout<<"TBL: "; TBL.printData(); cout<<endl;
00092   cout<<"TBR: "; TBR.printData(); cout<<endl;*/
00093   printf("color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00094   cout << "viewable = " << isViewable() << endl;
00095 }
00096 
00097 
00098 //! Transformations. (Virtual in BaseData.)
00099 void BrickData::applyTransform(const NEWMAT::Matrix& Tmat) {
00100   GFL.applyTransform(Tmat);
00101   GFR.applyTransform(Tmat);
00102   GBL.applyTransform(Tmat);
00103   GBR.applyTransform(Tmat);
00104   TFL.applyTransform(Tmat);
00105   TFR.applyTransform(Tmat);
00106   TBL.applyTransform(Tmat);
00107   TBR.applyTransform(Tmat);
00108 }
00109 
00110 void BrickData::projectToGround(const NEWMAT::Matrix& camToBase,
00111         const NEWMAT::ColumnVector& groundplane) {
00112   GFL.projectToGround(camToBase,groundplane);
00113   GFR.projectToGround(camToBase,groundplane);
00114   GBL.projectToGround(camToBase,groundplane);
00115   GBR.projectToGround(camToBase,groundplane);
00116 
00117   // Compute height at every corner except BL (because we didn't actually observe that corner)
00118   float FLHeight, FRHeight, BRHeight;
00119   TFL.projectToGround(camToBase,groundplane);
00120   TFR.projectToGround(camToBase,groundplane);
00121   TBR.projectToGround(camToBase,groundplane);
00122   FLHeight = TFL.getHeightAbovePoint(GFL, groundplane);
00123   FRHeight = TFR.getHeightAbovePoint(GFR, groundplane);
00124   BRHeight = TBR.getHeightAbovePoint(GBR, groundplane);
00125   float brickHeight = (FLHeight + FRHeight+ BRHeight) / 3.0;
00126   TFL.setCoords(GFL.coordX(), GFL.coordY(), GFL.coordZ() + FLHeight);
00127   TFR.setCoords(GFR.coordX(), GFR.coordY(), GFR.coordZ() + FRHeight);
00128   TBL.setCoords(GBL.coordX(), GBL.coordY(), GBL.coordZ() + brickHeight);
00129   TBR.setCoords(GBR.coordX(), GBR.coordY(), GBR.coordZ() + BRHeight);
00130   centroid = (GFL + GFR + GBL + GBR)/4;
00131   centroid.setCoords(centroid.coordX(), centroid.coordY(), brickHeight/2);
00132   std::cout<<"New centroid: ("<<centroid.coordX()<<","<<centroid.coordY()<<","<<centroid.coordZ()<<")\n";
00133 
00134 }
00135 
00136 // ==================================================
00137 // BEGIN SKETCH MANIPULATION AND BRICK EXTRACTION CODE
00138 // ==================================================
00139 
00140 
00141 //! Brick extraction.
00142 
00143 
00144 //! Render into a sketch space and return reference. (Private.)
00145 Sketch<bool>* BrickData::render() const {
00146   SketchSpace &renderspace = space->getDualSpace();
00147   //int const width = renderspace.getWidth();
00148   //int const height = renderspace.getHeight();
00149   //float x1,y1,x2,y2;
00150   Sketch<bool>* draw_result = 
00151     new Sketch<bool>(renderspace, "render("+getName()+")");
00152   (*draw_result)->setParentId(getViewableId());
00153   (*draw_result)->setColor(getColor());
00154   *draw_result = 0;
00155   LineData GF(*space, GFL, GFR);
00156   *draw_result = *draw_result & GF.getRendering();
00157   LineData GL(*space, GFL, GBL);
00158   *draw_result = *draw_result & GL.getRendering();
00159   LineData GB(*space, GBL, GBR);
00160   *draw_result = *draw_result & GB.getRendering();
00161   LineData GR(*space, GBR, GFR);
00162   *draw_result = *draw_result & GR.getRendering();
00163   
00164   return draw_result;
00165 }
00166 
00167 
00168 
00169 
00170   // Old version of brick extraction
00171   // Final version resides in extractBrick
00172 std::vector<Shape<BrickData> > BrickData::findBricks(ShapeSpace& ShS, std::vector<Shape<LineData> > lines)
00173 {
00174   const float lengthConst = .3;
00175   std::vector<Shape<LineData> > resultLines;
00176   std::vector<Shape<BrickData> > resultBricks;
00177   float longLength, shortLength;
00178 
00179   if (lines.size() < 3)
00180     {
00181       return resultBricks;
00182     }
00183 
00184   lines = stable_sort(lines, not2(LineData::LengthLessThan()));
00185 
00186   DO_SHAPEVEC(lines, LineData, l1, {
00187     DO_SHAPENEXT(lines, LineData, l1, l2, {
00188     if (l1->getLength() > l2->getLength()){
00189       longLength = l1->getLength();
00190       shortLength = l2->getLength();
00191     }
00192     else {
00193       longLength = l2->getLength();
00194       shortLength = l1->getLength();
00195     }
00196     if (LineData::ParallelTest()(l1,l2) && !LineData::ColinearTest()(l1,l2) && 
00197   (shortLength / longLength > lengthConst)) {
00198       DO_SHAPENEXT(lines, LineData, l2, l3, {
00199   if (LineData::ParallelTest()(l1,l3) && 
00200       !LineData::ColinearTest()(l1,l3) &&
00201       LineData::ParallelTest()(l2,l3) && 
00202       !LineData::ColinearTest()(l2,l3) &&
00203       (l3->getLength() / longLength > lengthConst) && 
00204       (shortLength / l3->getLength() > lengthConst)) {
00205     NEW_SHAPE_N(l1_2, LineData,  new LineData(ShS, l1->leftPt(), l1->rightPt()));
00206     NEW_SHAPE_N(l2_2, LineData, new LineData(ShS, l2->leftPt(), l2->rightPt()));
00207     NEW_SHAPE_N(l3_2, LineData, new LineData(ShS, l3->leftPt(), l3->rightPt()));
00208     l1_2->setParentId(l1->getViewableId());
00209     l2_2->setParentId(l1->getViewableId());
00210     l3_2->setParentId(l1->getViewableId());
00211     resultLines.push_back(l1_2);
00212     resultLines.push_back(l2_2);
00213     resultLines.push_back(l3_2);
00214   }
00215       });
00216     }
00217     });
00218   });
00219         
00220   if (resultLines.size() < 3) {
00221       return resultBricks;
00222   }
00223   
00224   for (unsigned int i=0; i<resultLines.size(); i+=3)
00225     {
00226       const Shape<LineData>& final1 = ShapeRootTypeConst(resultLines[i+0],LineData);
00227       const Shape<LineData>& final2 = ShapeRootTypeConst(resultLines[i+1],LineData);
00228       const Shape<LineData>& final3 = ShapeRootTypeConst(resultLines[i+2],LineData);
00229       /*cout<<"3 lines:"<<endl;
00230   final1->printEnds();
00231   final2->printEnds();
00232   final3->printEnds();*/
00233       
00234       std::vector<Shape<LineData> > threeLines;
00235       
00236       if (final1->bottomPt().isBelow(final2->bottomPt(),camcentric))
00237   {
00238     if (final1->bottomPt().isBelow(final3->bottomPt(),camcentric))
00239       {
00240         threeLines.push_back(final1);
00241         if (final2->bottomPt().isBelow(final3->bottomPt(),camcentric))
00242     {
00243       threeLines.push_back(final2);
00244       threeLines.push_back(final3);
00245     }
00246         else
00247     {
00248       threeLines.push_back(final3);
00249       threeLines.push_back(final3);
00250     }
00251       }
00252     else
00253       {
00254         threeLines.push_back(final3);
00255         threeLines.push_back(final1);
00256         threeLines.push_back(final2);
00257       }
00258   }
00259       else
00260   {
00261     if (final2->bottomPt().isBelow(final3->bottomPt(),camcentric))
00262       {
00263         threeLines.push_back(final2);
00264         if (final1->bottomPt().isBelow(final3->bottomPt(),camcentric))
00265     {
00266       threeLines.push_back(final1);
00267       threeLines.push_back(final3);
00268     }
00269         else
00270     {
00271       threeLines.push_back(final3);
00272       threeLines.push_back(final1);
00273     }
00274       }
00275     else
00276       {
00277         threeLines.push_back(final3);
00278         threeLines.push_back(final2);
00279         threeLines.push_back(final1);
00280       }
00281   }
00282       const Shape<LineData> &bottom = ShapeRootTypeConst(threeLines[0], LineData);
00283       const Shape<LineData> &mid = ShapeRootTypeConst(threeLines[1], LineData);
00284       const Shape<LineData> &top = ShapeRootTypeConst(threeLines[2], LineData);
00285       
00286       /*cout<<"Sorted Lines: "<<endl;
00287   bottom->printEnds();
00288   mid->printEnds();
00289   top->printEnds();*/
00290       
00291       Point gbl(top->leftPt()+(bottom->leftPt() - mid->leftPt()));
00292       Point gbr(top->rightPt()+(bottom->rightPt() - mid->rightPt()));
00293       Shape<BrickData> newBrick (ShS, (Point&)(bottom->leftPt()), (Point&)bottom->rightPt(), 
00294          gbl, gbr, 
00295          (Point&)mid->leftPt(), (Point&)mid->rightPt(), 
00296          (Point&)top->leftPt(), (Point&)top->rightPt());
00297       
00298       newBrick->setParentId(final1->getViewableId());
00299 
00300       NEW_SHAPE(brickl1, LineData, Shape<LineData>(bottom.getData()));
00301       NEW_SHAPE(brickl2, LineData, Shape<LineData>(mid.getData()));
00302       NEW_SHAPE(brickl3, LineData, Shape<LineData>(top.getData()));
00303 
00304       brickl1->setParentId(newBrick->getViewableId());
00305       brickl2->setParentId(newBrick->getViewableId());
00306       brickl3->setParentId(newBrick->getViewableId());
00307       
00308       resultBricks.push_back(newBrick);
00309     }
00310   
00311   return resultBricks;
00312 }
00313 
00314 
00315 // Find bricks from 3 vectors of candidate blobs
00316 // Each vector is blobs of a different face color
00317 //
00318 // Also an old version. Final version is in extractBrick
00319 std::vector<Shape<BrickData> > BrickData::findBricksFromBlobs(ShapeSpace& ShS, 
00320                     std::vector<Shape<BlobData> > blobs1,
00321                     std::vector<Shape<BlobData> > blobs2,
00322                     std::vector<Shape<BlobData> > blobs3) 
00323 {
00324 
00325   const float distanceThresh = 10;
00326 
00327   unsigned int i, i1, i2;
00328   Shape<BlobData> blob1, blob2, blob3;
00329 
00330   std::vector<Shape<BrickData> > resultBricks;
00331 
00332   Point GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR;
00333   Point c12,c13,c23;
00334 
00335   std::vector<std::vector<Point> > corners1;
00336   std::vector<std::vector<Point> > corners2;
00337   std::vector<std::vector<Point> > corners3;
00338   std::vector<bool> used1;
00339   std::vector<bool> used2;
00340   std::vector<bool> used3;
00341   for (i=0; i<blobs1.size(); i++) { 
00342     used1.push_back(false); 
00343     corners1.push_back(blobs1[i]->findCornersDiagonal()); 
00344   }
00345   for (i=0; i<blobs2.size(); i++) { 
00346     used2.push_back(false); 
00347     corners2.push_back(blobs2[i]->findCornersDiagonal()); 
00348   }
00349   for (i=0; i<blobs3.size(); i++) { 
00350     used3.push_back(false); 
00351     corners3.push_back(blobs3[i]->findCornersDiagonal()); 
00352   }
00353 
00354   // Look for bricks with a good common edge between each pair of viable brick face colors
00355   int used;
00356   for (i1=0; i1<blobs1.size(); i1++){
00357     for (i2=0; i2<blobs2.size();i2++){
00358       if (!used1[i1] && !used2[i2]) {
00359   used = addBrickWithTwoSides(ShS, corners1[i1], corners2[i2], corners3, 
00360             resultBricks, distanceThresh);
00361   if (used>=0) {
00362     used1[i1] = true;
00363     used2[i2] = true;
00364     used3[used] = true;
00365     resultBricks[resultBricks.size()-1]->setParentId(blobs1[i1]->getViewableId());
00366   }
00367       }
00368     }
00369   }
00370 
00371   for (i1=0; i1<blobs1.size(); i1++){
00372     for (i2=0; i2<blobs3.size();i2++){
00373       if (!used1[i1] && !used3[i2]) {
00374   used = addBrickWithTwoSides(ShS, corners1[i1], corners3[i2], corners2, 
00375             resultBricks, distanceThresh);
00376   if (used>=0) {
00377     used1[i1] = true;
00378     used3[i2] = true;
00379     used2[used] = true;
00380     resultBricks[resultBricks.size()-1]->setParentId(blobs1[i1]->getViewableId());
00381   }
00382       }
00383     }
00384   }
00385 
00386   for (i1=0; i1<blobs3.size(); i1++){
00387     for (i2=0; i2<blobs2.size();i2++){
00388       if (!used3[i1] && !used2[i2]) {
00389   used = addBrickWithTwoSides(ShS, corners3[i1], corners2[i2], corners1, 
00390             resultBricks, distanceThresh);
00391   if (used>=0) {
00392     used3[i1] = true;
00393     used2[i2] = true;
00394     used1[used] = true;
00395     resultBricks[resultBricks.size()-1]->setParentId(blobs3[i1]->getViewableId());
00396   }
00397       }
00398     }
00399   }
00400 
00401 
00402   return resultBricks;
00403 }
00404 
00405 
00406 // Subroutine for blob brick detection
00407 // If the two sides match, finds the third side that matches
00408 // Extrapolates all the points and adds the brick to the vector
00409 // returns the index of the third face, or -1 if no match is found
00410 //
00411 // subroutine for an old version
00412 int BrickData::addBrickWithTwoSides(ShapeSpace &ShS,
00413             std::vector<Point>& corners1, 
00414             std::vector<Point>& corners2, 
00415             std::vector<std::vector<Point> >& blobs3, 
00416             std::vector<Shape<BrickData> >& result, 
00417             float distanceThresh)
00418 {
00419   unsigned int blobi;
00420   int i1=-1,j1=-1, i2=-1, j2=-1;
00421   for (int i=0; i<4 && i2<0; i++) {
00422     for (int j=0; j<4 && j2<0; j++) {
00423       if (corners1[i].distanceFrom(corners2[j]) < distanceThresh) {
00424   if (corners1[(i+1)%4].distanceFrom(corners2[(j+3)%4]) < distanceThresh) {
00425     i1 = i;
00426     i2 = (i+1)%4;
00427     j1 = (j+3)%4;
00428     j2 = j;
00429   }
00430   else if (corners1[(i+3)%4].distanceFrom(corners2[(j+1)%4]) < distanceThresh) {
00431     i1 = (i+3)%4;
00432     i2 = i;
00433     j1 = j;
00434     j2 = (j+1)%4;
00435   }
00436   if (i2>=0) {
00437     // Two matching corners have been found: (i1,j2), (i2, j1)
00438     // Look for the third side
00439     bool found = false;
00440     Point center, mid1, mid2, mid3, c1, c2, c3;
00441     for (blobi=0; blobi<blobs3.size() && !found; blobi++) {
00442       for(int k=0; k<4 && !found; k++) {
00443         if (((blobs3[blobi][k].distanceFrom(corners1[i1]) < distanceThresh) +
00444        (blobs3[blobi][(k+1)%4].distanceFrom(corners1[(i1+3)%4]) < distanceThresh) +
00445        (blobs3[blobi][(k+3)%4].distanceFrom(corners2[(j2+1)%4]) < distanceThresh)) > 1) {
00446     // (i1,j2, k) is the center
00447     found = true;
00448     mid1 = (corners1[i2]+corners2[j1])/2;
00449     if (blobs3[blobi][k].distanceFrom(corners1[i1]) < distanceThresh) 
00450       center = (corners1[i1]+corners2[j2]+blobs3[blobi][k])/3;
00451     else
00452       center = (corners1[i1]+corners2[j2])/2;
00453     if (blobs3[blobi][(k+1)%4].distanceFrom(corners1[(i1+3)%4]) < distanceThresh)
00454       mid2 = (blobs3[blobi][(k+1)%4] + corners1[(i1+3)%4])/2;
00455     else
00456       mid2 = corners1[(i1+3)%4];
00457     if (blobs3[blobi][(k+3)%4].distanceFrom(corners2[(j2+1)%4]) < distanceThresh)
00458       mid3 = (blobs3[blobi][(k+3)%4] + corners2[(j2+1)%4])/2;
00459     else
00460       mid3 = corners2[(j2+1)%4];
00461     c1 = corners1[(i1+2)%4];
00462     c2 = blobs3[blobi][(k+2)%4];
00463     c3 = corners2[(j2+2)%4];
00464         }
00465         else if (((blobs3[blobi][k].distanceFrom(corners1[i2]) < distanceThresh) +
00466        (blobs3[blobi][(k+1)%4].distanceFrom(corners2[(j1+3)%4]) < distanceThresh) +
00467        (blobs3[blobi][(k+3)%4].distanceFrom(corners1[(i2+1)%4]) < distanceThresh)) > 1) {
00468     // (i2, j1, k) is the center
00469     found = true;
00470     mid1 = (corners1[i1]+corners2[j2])/2;
00471     if (blobs3[blobi][k].distanceFrom(corners1[i2]) < distanceThresh) 
00472       center = (corners1[i2]+corners2[j1]+blobs3[blobi][k])/3;
00473     else
00474       center = (corners1[i2]+corners2[j1])/2;
00475     if (blobs3[blobi][(k+1)%4].distanceFrom(corners2[(j1+3)%4]) < distanceThresh)
00476       mid2 = (blobs3[blobi][(k+1)%4] + corners2[(j1+3)%4])/2;
00477     else
00478       mid2 = corners2[(j1+3)%4];
00479     if (blobs3[blobi][(k+3)%4].distanceFrom(corners1[(i2+1)%4]) < distanceThresh)
00480       mid3 = (blobs3[blobi][(k+3)%4] + corners1[(i2+1)%4])/2;
00481     else
00482       mid3 = corners1[(i2+1)%4];
00483     c1 = corners2[(j1+2)%4];
00484     c2 = blobs3[blobi][(k+2)%4];
00485     c3 = corners1[(i2+2)%4];
00486         }
00487       }
00488 
00489     }
00490 
00491     if (found) {
00492       // Found a brick, figure out where the top / left / etc sides are
00493 
00494       // Debug shapes
00495       NEW_SHAPE(centerp, PointData, new PointData(ShS, center));
00496       NEW_SHAPE(mid1p, PointData, new PointData(ShS, mid1));
00497       NEW_SHAPE(mid2p, PointData, new PointData(ShS, mid2));
00498       NEW_SHAPE(mid3p, PointData, new PointData(ShS, mid3));
00499       NEW_SHAPE(c1p, PointData, new PointData(ShS, c1));
00500       NEW_SHAPE(c2p, PointData, new PointData(ShS, c2));
00501       NEW_SHAPE(c3p, PointData, new PointData(ShS, c3));
00502       centerp->setColor(rgb(150,0,255));
00503       mid1p->setColor(rgb(150,0,255));
00504       mid2p->setColor(rgb(150,0,255));
00505       mid3p->setColor(rgb(150,0,255));
00506       c1p->setColor(rgb(150,0,255));
00507       c2p->setColor(rgb(150,0,255));
00508       c3p->setColor(rgb(150,0,255));
00509       
00510       Point GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR;
00511       
00512       TFR = center;
00513       if (mid1.isBelow(center, camcentric) && mid1.isBelow(mid2, camcentric) && mid1.isBelow(mid3, camcentric)) {
00514         GFR = mid1;
00515         GBR = c1;
00516         if (mid2.isRightOf(mid3, camcentric)) {
00517     TBR = mid2;
00518     TBL = c2;
00519     TFL = mid3;
00520     GFL = c3;
00521         }
00522         else {
00523     TBR = mid3;
00524     TBL = c3;
00525     TFL = mid2;
00526     GFL = c2;
00527         }
00528       }
00529       else if (mid2.isBelow(center, camcentric) && mid2.isBelow(mid1, camcentric) && mid2.isBelow(mid3, camcentric)) {
00530         GFR = mid2;
00531         GBR = c2;
00532         if (mid1.isRightOf(mid3, camcentric)) {
00533     TBR = mid1;
00534     TBL = c1;
00535     TFL = mid3;
00536     GFL = c3;
00537         }
00538         else {
00539     TBR = mid3;
00540     TBL = c3;
00541     TFL = mid1;
00542     GFL = c1;
00543         }
00544       }
00545       else {
00546         GFR = mid3;
00547         GBR = c3;
00548         if (mid2.isRightOf(mid1, camcentric)) {
00549     TBR = mid2;
00550     TBL = c2;
00551     TFL = mid1;
00552     GFL = c1;
00553         }
00554         else {
00555     TBR = mid1;
00556     TBL = c1;
00557     TFL = mid2;
00558     GFL = c2;
00559         }
00560       }
00561       
00562       GBL = GFL + (TBL - TFL);
00563 
00564       Shape<BrickData> newBrick(ShS, GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR);
00565       result.push_back(newBrick);
00566       centerp->setParentId(newBrick->getViewableId());
00567       mid1p->setParentId(newBrick->getViewableId());
00568       mid2p->setParentId(newBrick->getViewableId());
00569       mid3p->setParentId(newBrick->getViewableId());
00570       c1p->setParentId(newBrick->getViewableId());
00571       c2p->setParentId(newBrick->getViewableId());
00572       c3p->setParentId(newBrick->getViewableId());
00573       return blobi;
00574     }
00575     else {
00576       // What do we do if we get two good faces and no third?
00577     }
00578     
00579   }
00580       }
00581     }
00582   }
00583 
00584   return -1;
00585 
00586 }
00587 
00588 
00589 
00590 
00591 
00592 /* Unified brick extraction starting from 2 or 3 blobs, each of a different color 
00593  *
00594  *************    Final Version   ***************
00595  *
00596  * Checks the relative locations of the blobs (to ensure they are adjacent enough to 
00597  * be part of the same brick)
00598  *
00599  * Computes the interior edge lines from the regions close to two faces.
00600  *
00601  * Computes the corners of each face individually. 
00602  * This step is handled in blobData::findCorners
00603  *
00604  * Combine all the corner guesses together and extrapolate missing corners.
00605  *
00606  *
00607  * Some helper functions can be found in BrickOps.h 
00608  */
00609 Shape<BrickData> BrickData::extractBrick(ShapeSpace& space, vector<Shape<BlobData> > &blobs)
00610 {
00611   unsigned int nblobs = blobs.size();
00612   std::vector<Point> centroids;
00613 
00614   ShapeRoot invalid;
00615   if (nblobs > 3 || nblobs < 2) {
00616     return ShapeRootType(invalid,BrickData);
00617   }
00618 
00619   for (unsigned int i=0; i<nblobs; i++) {
00620     centroids.push_back(blobs[i]->getCentroid());
00621   }
00622 
00623   // Check inter-blob distance
00624   // If any pair of blobs are too far apart, this set is invalid
00625   for (unsigned int i=0; i<nblobs; i++) {
00626     for (unsigned int j=i+1; j<nblobs; j++) {
00627       if (centroids[i].distanceFrom(centroids[j]) >= 
00628     blobs[i]->topLeft.distanceFrom(centroids[i]) + 
00629     blobs[j]->topLeft.distanceFrom(centroids[j])){
00630   return ShapeRootType(invalid,BrickData);  
00631       }
00632     }
00633   }
00634 
00635 
00636   // arbitrary face assignment, aligned as the brick is in camera space
00637   // this will probably break down if the dog tilts its head
00638   // 
00639   // if we only have two faces, we're assuming only the top and "left" faces are visible
00640   // always assume a top face is visible, becuase any shape without a top face is much more likely
00641   // to be a pyramid than a tall brick
00642   int top=-1, left=-1, right=-1;
00643   
00644   if (centroids[0].isAbove(centroids[1], camcentric)) {
00645     top = 0;
00646   }
00647   else {
00648     top = 1;
00649   }
00650   if (nblobs > 2 && centroids[2].isAbove(centroids[top], camcentric)) {
00651     top = 2;
00652   }
00653 
00654   if ((top != 0 && centroids[0].isLeftOf(centroids[1], camcentric)) || top == 1) {
00655     left = 0;
00656   }
00657   else {
00658     left = 1;
00659   }
00660   if (nblobs>2 && top != 2 && centroids[2].isLeftOf(centroids[left], camcentric)) {
00661     left = 2;
00662   }
00663 
00664   if (nblobs > 2) {
00665     if (top != 0 && left != 0) {
00666       right = 0;
00667     }
00668     else if (top != 1 && left != 1) {
00669       right = 1;
00670     }
00671     else {
00672       right = 2;
00673     }
00674   }
00675 
00676   if (top == left || top == right || left == right){
00677     std::cout<<"ERROR: Brick side misclassification!"<<std::endl;
00678     return ShapeRootType(invalid,BrickData);  
00679   }
00680 
00681 
00682   // Compute two-blob boundary regions
00683   // This is used to find the interior edges of the brick
00684   // It is also used as a second check for inter-brick distance
00685   const int INTERSECT_DIST = 5, MIN_REQUIRED_DIST = 2;
00686   std::vector<Sketch<bool> > boundaries;
00687   NEW_SKETCH_N(topEdist, uchar, visops::edist(blobs[top]->getRendering()));
00688   NEW_SKETCH_N(leftEdist, uchar, visops::edist(blobs[left]->getRendering()));
00689   NEW_SKETCH(tlsmall, bool, topEdist<MIN_REQUIRED_DIST & leftEdist<MIN_REQUIRED_DIST);
00690   if (!tlsmall->max()){
00691     return ShapeRootType(invalid,BrickData);  
00692   }
00693   NEW_SKETCH(tl, bool, topEdist<INTERSECT_DIST & leftEdist<INTERSECT_DIST);
00694   rgb green_rgb(0,0,255);
00695   tl->setColor(green_rgb);
00696   boundaries.push_back(tl);
00697 
00698   if (nblobs>2) {
00699     NEW_SKETCH_N(rightEdist, uchar, visops::edist(blobs[right]->getRendering()));
00700     NEW_SKETCH(trsmall, bool, topEdist<MIN_REQUIRED_DIST & rightEdist<MIN_REQUIRED_DIST);
00701     if (!trsmall->max()){
00702       return ShapeRootType(invalid,BrickData);
00703     } 
00704     NEW_SKETCH(tr, bool, topEdist<INTERSECT_DIST & rightEdist<INTERSECT_DIST);
00705     tr->setColor(green_rgb);
00706     boundaries.push_back(tr);
00707 
00708     NEW_SKETCH(lrsmall, bool, leftEdist<MIN_REQUIRED_DIST & rightEdist<MIN_REQUIRED_DIST);
00709     if (!lrsmall->max()){
00710       return ShapeRootType(invalid,BrickData);
00711     } 
00712     NEW_SKETCH(lr, bool, leftEdist<INTERSECT_DIST & rightEdist<INTERSECT_DIST);
00713     lr->setColor(green_rgb);
00714     boundaries.push_back(lr);
00715   }
00716 
00717 
00718 
00719   // Begin gathering evidence for each point
00720   // This should probably be augmented by an extra vector of confidences
00721   std::vector<std::vector<Point> > points(8);
00722 
00723   // Arbitrary corner / face assignemt (in cam space)
00724   //
00725   //      5------6
00726   //     /   T  /|
00727   //    /(4)   / 7
00728   //   1------2 / <-- R
00729   //   |  L   |/
00730   //   0------3
00731   //    
00732 
00733 
00734   // Construct the interior lines
00735   // Add their guesses to the appropriate points on the brick
00736   NEW_SHAPE(tlline, LineData, LineData::extractLine(boundaries[0]));
00737   Shape<LineData> trline, lrline;
00738 
00739   if (right!=-1) {
00740     trline = LineData::extractLine(boundaries[1]);
00741     lrline = LineData::extractLine(boundaries[2]);
00742 
00743     // shorten interior lines based on their intersections
00744     bool on1=false, on2=false;
00745     if (tlline.isValid() && trline.isValid()) {
00746       Point isectPt = tlline->intersectionWithLine(trline, on1, on2);
00747       if (on1) {
00748   tlline->rightPt().setCoords(isectPt);
00749       }
00750       if (on2) {
00751   trline->leftPt().setCoords(isectPt);
00752       }
00753     }
00754 
00755     if (tlline.isValid() && lrline.isValid()) {
00756       Point isectPt = tlline->intersectionWithLine(lrline, on1, on2);
00757       if (on1) {
00758   tlline->rightPt().setCoords(isectPt);
00759       }
00760       if (on2) {
00761   lrline->topPt().setCoords(isectPt);
00762       }
00763     }
00764 
00765     if (trline.isValid() && lrline.isValid()) {
00766       Point isectPt = trline->intersectionWithLine(lrline, on1, on2);
00767       if (on1) {
00768   trline->leftPt().setCoords(isectPt);
00769       }
00770       if (on2) {
00771   lrline->topPt().setCoords(isectPt);
00772       }
00773     }
00774 
00775 
00776     if (trline.isValid()) {
00777       points[2].push_back(trline->leftPt());
00778       points[6].push_back(trline->rightPt());
00779     }
00780 
00781     if (lrline.isValid()) {
00782       points[2].push_back(lrline->topPt());
00783       points[3].push_back(lrline->bottomPt());
00784     }
00785   }
00786 
00787   if (tlline.isValid()) {
00788     points[1].push_back(tlline->leftPt());
00789     points[2].push_back(tlline->rightPt());
00790   }
00791 
00792 
00793 
00794   // Extract the corners of the blob using the derivative approach
00795   //
00796   // corners are coming out of findCorners() in counter-clock-wise order around the blob
00797   //  with unknown starting position
00798   //
00799   // the findCorners function in BlobData is the other important part of the algorithm
00800   // Several different methods of corner extraction can be connected there. 
00801   std::vector<Point> candidates;
00802 
00803   // top face
00804 
00805   // Compute an orthogonal bounding box from the top-left line
00806   if (tlline.isValid()) {
00807     if (trline.isValid() && trline->getLength() > tlline->getLength()) {
00808       candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], trline);
00809     }
00810     else {
00811       candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], tlline);      
00812     }
00813   }
00814   else if (trline.isValid()) {
00815     candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], trline);
00816   }
00817   
00818   float cornerValue; 
00819 
00820   std::vector<Point> tcorners = blobs[top]->findCorners(4, candidates, cornerValue);
00821 
00822   if (tcorners.size() == 4) {
00823     
00824     // Sort out which corner is which
00825     // if there's a clear left-most corner, its corner 1
00826     // if two corners are close in left-ness, then they should be 1 and 5
00827     unsigned int leftCorner = 0;
00828     for (unsigned int i=1; i<4; i++){
00829       if (tcorners[i].isLeftOf(tcorners[leftCorner], camcentric)) {
00830   leftCorner = i;
00831       }
00832     }
00833     int closeCorner = -1;
00834     float mostLeft = tcorners[leftCorner].coordX();
00835     const int MAX_CLOSE_DIST = 5;
00836     for (unsigned int i=0; i<4; i++) {
00837       if (i != leftCorner && tcorners[i].coordX() - mostLeft < MAX_CLOSE_DIST) {
00838   closeCorner = i;
00839       }
00840     }
00841     
00842     if (closeCorner != -1) {
00843       // If 5 was actually left-most, switch leftCorner to 1
00844       if ((unsigned int)closeCorner == (leftCorner+1)%4) {
00845   leftCorner = closeCorner;
00846       }
00847       else if ((unsigned int)closeCorner != (leftCorner+3)%4) {
00848   std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
00849       }
00850     }
00851     NEW_SHAPE(top1, PointData, PointData(space, tcorners[leftCorner]));
00852     points[1].push_back(tcorners[leftCorner]);
00853     points[2].push_back(tcorners[(leftCorner+1)%4]);
00854     points[6].push_back(tcorners[(leftCorner+2)%4]);
00855     points[5].push_back(tcorners[(leftCorner+3)%4]);
00856 
00857   }
00858   else {
00859     // Some versions of findCorners don't always return 4 corners. 
00860     // How to handle these cases is ambiguous at best. 
00861   }
00862 
00863   // repeat with other faces
00864 
00865   // left face
00866   candidates.clear();
00867   if (tlline.isValid()) {
00868     if (lrline.isValid() && lrline->getLength() > tlline->getLength()) {
00869       candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], lrline);
00870     }
00871     else {
00872       candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], tlline);      
00873     }
00874   }
00875   else if (trline.isValid()) {
00876     candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], lrline);
00877   }
00878 
00879   for (unsigned int i=0; i<candidates.size(); i++) {
00880     NEW_SHAPE(candidate, PointData, PointData(space, candidates[i]));
00881     candidate->setParentId(blobs[left]->getViewableId());
00882   }
00883   std::vector<Point> lcorners = blobs[left]->findCorners(4, candidates, cornerValue);
00884   if (lcorners.size() == 4) {
00885     
00886     // if there's a clear right-most corner, its corner 3
00887     // if two corners are close in right-ness, then they should 3 and 2
00888     unsigned int rightCorner = 0;
00889     for (unsigned int i=1; i<4; i++){
00890       if (lcorners[i].isRightOf(lcorners[rightCorner], camcentric)) {
00891   rightCorner = i;
00892       }
00893     }
00894     int closeCorner = -1;
00895     float mostRight = lcorners[rightCorner].coordX();
00896     const int MAX_CLOSE_DIST = 5;
00897     for (unsigned int i=0; i<4; i++) {
00898       if (i != rightCorner && mostRight - lcorners[i].coordX() < MAX_CLOSE_DIST) {
00899   closeCorner = i;
00900       }
00901     }
00902     
00903     if (closeCorner != -1) {
00904       // If 2 was actually right-most, switch rightCorner to 3
00905       if ((unsigned int)closeCorner == (rightCorner+3)%4) {
00906   rightCorner = closeCorner;
00907       }
00908       else if ((unsigned int)closeCorner != (rightCorner+1)%4) {
00909   std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
00910       }
00911     }
00912     NEW_SHAPE(left2, PointData, PointData(space, lcorners[rightCorner]));
00913     points[3].push_back(lcorners[rightCorner]);
00914     points[2].push_back(lcorners[(rightCorner+1)%4]);
00915     points[1].push_back(lcorners[(rightCorner+2)%4]);
00916     points[0].push_back(lcorners[(rightCorner+3)%4]);
00917 
00918   }
00919   else {
00920 
00921   }
00922 
00923   // right face
00924   if (right != -1) {
00925 
00926     candidates.clear();
00927     if (trline.isValid()) {
00928       if (lrline.isValid() && lrline->getLength() > trline->getLength()) {
00929   candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], lrline);
00930       }
00931       else {
00932   candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], trline);      
00933       }
00934     }
00935     else if (lrline.isValid()) {
00936       candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], lrline);
00937     }
00938 
00939     std::vector<Point> rcorners = blobs[right]->findCorners(4, candidates, cornerValue);
00940     if (rcorners.size() == 4) {
00941     
00942       // if there's a clear bottom-most corner, its corner 3
00943       // if two corners are close in bottom-ness, then they should 3 and 7
00944       unsigned int bottomCorner = 0;
00945       for (unsigned int i=1; i<4; i++){
00946   if (rcorners[i].isBelow(rcorners[bottomCorner], camcentric)) {
00947     bottomCorner = i;
00948   }
00949       }
00950       int closeCorner = -1;
00951       float mostBottom = rcorners[bottomCorner].coordY();
00952       const int MAX_CLOSE_DIST = 5;
00953       for (unsigned int i=0; i<4; i++) {
00954   if (i != bottomCorner && mostBottom - rcorners[i].coordY() < MAX_CLOSE_DIST) {
00955     closeCorner = i;
00956   }
00957       }
00958     
00959       if (closeCorner != -1) {
00960   // If 7 was actually bottom-most, switch bottomCorner to 3
00961   if ((unsigned int)closeCorner == (bottomCorner+3)%4) {
00962     bottomCorner = closeCorner;
00963   }
00964   else if ((unsigned int)closeCorner != (bottomCorner+1)%4) {
00965     std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
00966   }
00967       }
00968       NEW_SHAPE(right3, PointData, PointData(space,rcorners[bottomCorner]));
00969       points[3].push_back(rcorners[bottomCorner]);
00970       points[7].push_back(rcorners[(bottomCorner+1)%4]);
00971       points[6].push_back(rcorners[(bottomCorner+2)%4]);
00972       points[2].push_back(rcorners[(bottomCorner+3)%4]);
00973 
00974     }
00975   }
00976 
00977 
00978   // If we have additional ways of extracting candidate corners, 
00979   // add the corners they find to the vector of corners now.
00980 
00981 
00982   // debug output
00983   /*for (unsigned int i=0; i<8; i++){
00984     for (unsigned int j=0; j<points[i].size(); j++) {
00985       NEW_SHAPE(corner, PointData, PointData(space, points[i][j]));
00986       char name[10];
00987       sprintf(name, "corner%d%d",i,j);
00988       corner->setName(name);
00989     }
00990     }*/
00991 
00992 
00993   // Now merge all our candidate points to get the final brick
00994 
00995   vector<Point> finalCorners(8);
00996 
00997   // for now just average corners together to get the last corners
00998   // should at least weight the average based on confidence
00999   // could also do statistics
01000   // produce a final confidence based on the std. deviation
01001 
01002   // if we didn't get the center point of the brick then we don't have a shot
01003   // top-left line also is pretty critical, 
01004   // though I probably should re-work below to work in the case where top and right only work well
01005   if (points[2].size()==0 || points[1].size()==0){
01006     return ShapeRootType(invalid,BrickData);    
01007   }
01008 
01009   Point empty(0,0);
01010 
01011 
01012   // Lots of cases for which corners are visible and extrapolating the others
01013 
01014   for (unsigned int i=0; i<8; i++) {
01015     finalCorners[i] = empty;
01016     for (unsigned int j=0; j<points[i].size(); j++) {
01017       finalCorners[i]+=points[i][j];
01018     }
01019     if (points[i].size() > 0) {
01020       finalCorners[i]/=points[i].size();
01021     }
01022   }
01023 
01024   if (points[3].size()==0){
01025     // These should be easier cases
01026     return ShapeRootType(invalid,BrickData);        
01027   }
01028 
01029   if (points[6].size() == 0) {
01030     // If we have the top left line but not corner 6, infer corner 6 from the thickness of the top side
01031     if (tlline.isValid()) {
01032       NEW_SKETCH_N(topRendering, bool, blobs[top]->getRendering());
01033       Point topPt = (Region::extractRegion(topRendering)).mostDistantPtFrom(tlline.getData());
01034       NEW_SHAPE(intersectLine, LineData, LineData(space, topPt, tlline->getThetaNorm()));
01035       Point intersectPoint = intersectLine->intersectionWithLine(tlline);
01036       // lower confidence result
01037       finalCorners[6] = topPt+finalCorners[2]-intersectPoint;
01038     }
01039     // can also use right left line and the right side, but the top side is more likely to be good
01040     else {
01041       return ShapeRootType(invalid,BrickData);        
01042     }
01043  }
01044 
01045   if (points[0].size() == 0) {
01046     finalCorners[0] = finalCorners[3] + finalCorners[1]-finalCorners[2];
01047   }
01048 
01049   if (points[5].size() == 0) {
01050     finalCorners[5] = finalCorners[6] + finalCorners[1]-finalCorners[2];
01051   }
01052 
01053   if (points[7].size() == 0) {
01054     finalCorners[7] = finalCorners[3] + finalCorners[6]-finalCorners[2];
01055   }
01056 
01057   finalCorners[4] = finalCorners[5] + finalCorners[7] - finalCorners[6] +
01058     finalCorners[5] + finalCorners[0] - finalCorners[1] +
01059     finalCorners[0] + finalCorners[7] - finalCorners[3];
01060   finalCorners[4]/=3.0;
01061 
01062   // left == front for generalized brick
01063   NEW_SHAPE(returnbrick, BrickData, new BrickData(space, 
01064               finalCorners[0], finalCorners[3],
01065               finalCorners[4], finalCorners[7],
01066               finalCorners[1], finalCorners[2],
01067               finalCorners[5], finalCorners[6]));
01068   return returnbrick;
01069     
01070 }
01071 
01072 
01073 
01074   // Generates a wide bounding box around the blob from a parallel line along one edge
01075   // This bounding box will be used as a starting point for the quadrilateral-fitting algorithm
01076   // 
01077   // Generates 4 points based on the line, centroid of the blob, and parameters for extending the bounds
01078   // Then sorts the points into counter-clockwise order to satisfy the ordering constraints to make other 
01079   // extrapolations possible. 
01080 vector<Point> BrickData::findOrthogonalBoundingBox(ShapeSpace& space, Shape<BlobData> blob, Point centroid, Shape<LineData> parallel)
01081 {
01082   const float PARALLEL_EXTEND_FACTOR = .6, ORTHO_EXTEND_FACTOR = .6;
01083 
01084   vector<Point> candidates;
01085   LineData candidate1(space, parallel->end1Pt(), parallel->end2Pt());
01086 
01087   //candidate1.setEndPts(parallel->end1Pt(), parallel->end2Pt());
01088   Point parallelExtend(candidate1.end2Pt() - candidate1.end1Pt());
01089   parallelExtend *= PARALLEL_EXTEND_FACTOR;
01090   LineData ortho(space, centroid, candidate1.getThetaNorm());
01091   Point orthoIsect = candidate1.intersectionWithLine(ortho);
01092   Point candidate2Offset = (centroid - orthoIsect) * 2.0;
01093   Point orthoExtend = candidate2Offset * ORTHO_EXTEND_FACTOR;
01094 
01095   LineData candidate2(space, candidate1.end1Pt() + candidate2Offset + orthoExtend - parallelExtend,
01096           candidate1.end2Pt() + candidate2Offset + orthoExtend + parallelExtend);
01097   candidate1.setEndPts(candidate1.end1Pt() - orthoExtend - parallelExtend,
01098            candidate1.end2Pt() - orthoExtend + parallelExtend);
01099   candidates.push_back(candidate1.leftPt());
01100   candidates.push_back(candidate1.rightPt());
01101   candidates.push_back(candidate2.rightPt());
01102   candidates.push_back(candidate2.leftPt());
01103 
01104   // debug output
01105   for (unsigned int i=0; i<candidates.size(); i++) {
01106     NEW_SHAPE_N(candidate, PointData, PointData(space, candidates[i]));
01107     candidate->setParentId(blob->getViewableId());
01108   }
01109 
01110   // order counter-clockwise around the blob before returning
01111   Point centerPoint = (candidates[0] + candidates[1] + candidates[2] + candidates[3]) / 4.0;
01112   vector<float> centerAngles;
01113   for (unsigned int i=0; i<candidates.size(); i++) {
01114     NEW_SHAPE_N(centerLine, LineData, LineData(space, centerPoint, candidates[i]));
01115     centerLine->setParentId(blob->getViewableId());
01116     centerAngles.push_back(atan2(centerLine->end2Pt().coordY() - centerLine->end1Pt().coordY(),
01117          centerLine->end2Pt().coordX() - centerLine->end1Pt().coordX()));
01118   }
01119 
01120 
01121   vector<Point> orderedPoints;
01122   
01123   int maxi = 0, mini = 0;
01124   float maxAng = centerAngles[0];
01125   float minAng = maxAng;
01126   
01127   for (unsigned int i=1; i<candidates.size(); i++) {
01128     if (centerAngles[i] > maxAng) {
01129       maxAng = centerAngles[i];
01130       maxi = i;
01131     }
01132     if (centerAngles[i] < minAng) {
01133       minAng = centerAngles[i];
01134       mini = i;
01135     }
01136        
01137   }
01138 
01139   orderedPoints.push_back(candidates[maxi]);
01140   
01141   float lastMax = maxAng;
01142   for (unsigned int i=1; i<candidates.size(); i++) {
01143     maxi = mini;
01144     maxAng = minAng;
01145     for (unsigned int j=0; j<candidates.size(); j++) {
01146       float curAng = centerAngles[j];
01147       if (curAng > maxAng && curAng < lastMax) {
01148   maxi = j;
01149   maxAng = curAng;
01150       }
01151     }
01152     orderedPoints.push_back(candidates[maxi]);
01153     lastMax = maxAng;
01154   }
01155   
01156   // debug output
01157   for (unsigned int i=0; i<candidates.size(); i++) {
01158     NEW_SHAPE(orderedcandidate, PointData, PointData(space, orderedPoints[i]));
01159     orderedcandidate->setParentId(blob->getViewableId());
01160   }
01161 
01162   return orderedPoints;
01163 }
01164 
01165 
01166 
01167 } // namespace

DualCoding 3.0beta
Generated Wed Oct 4 00:01:53 2006 by Doxygen 1.4.7