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

DualCoding 5.1CVS
Generated Mon May 9 04:56:25 2016 by Doxygen 1.6.3