Homepage Demos Overview Downloads Tutorials Reference
Credits

PolygonData.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #include "ShapeLine.h"
00003 #include "ShapeRoot.h"
00004 #include "ShapeSpace.h"
00005 #include "Sketch.h"
00006 #include "SketchSpace.h"
00007 #include "visops.h"
00008 
00009 #include "PolygonData.h"
00010 #include "ShapePolygon.h"
00011 
00012 namespace DualCoding {
00013 
00014 DATASTUFF_CC(PolygonData);
00015 
00016 PolygonData::PolygonData(const LineData& side) 
00017   : BaseData(*side.space,polygonDataType), edges(), vertices()
00018 { 
00019   edges.push_back(side);
00020   updateVertices();
00021   mobile = POLYGON_DATA_MOBILE;
00022 }
00023 
00024 PolygonData::PolygonData(ShapeSpace& _space, const vector<Point>& pts, 
00025        bool closed, bool end1Valid, bool end2Valid)
00026   : BaseData(_space, polygonDataType), edges(), vertices(pts.size()>1 ? pts : vector<Point>())
00027 {
00028   mobile = POLYGON_DATA_MOBILE;
00029   if (pts.empty()) return;
00030   for(vector<Point>::const_iterator vtx_it = pts.begin();
00031       vtx_it < pts.end()-1; vtx_it++)
00032     edges.push_back(LineData(_space, *vtx_it, *(vtx_it+1)));
00033   edges.front().end1Pt().setValid(end1Valid);
00034   edges.back().end2Pt().setValid(end2Valid);
00035   if (closed) // close polygon
00036     tryClosePolygon();
00037 }
00038 
00039 
00040 vector<Shape<LineData> > PolygonData::extractPolygonEdges(Sketch<bool> const& sketch,
00041                 Sketch<bool> const& occluder) {
00042   vector<Shape<LineData> > lines(LineData::extractLines(sketch, occluder,4));
00043   return lines;
00044 }
00045 
00046 void PolygonData::updateVertices() {
00047   vertices.clear();
00048   if (edges.empty()) return;
00049 
00050   if (isClosed())
00051     vertices.push_back(end1Ln().intersectionWithLine(end2Ln()));
00052   else
00053     vertices.push_back(end1Pt());
00054   if (edges.size() > 1)
00055     for (vector<LineData>::const_iterator it = edges.begin();
00056    it != edges.end()-1; it++)
00057       vertices.push_back(it->intersectionWithLine(*(it+1)));
00058   if (isClosed())
00059     vertices.push_back(vertices.front());
00060   else
00061     vertices.push_back(end2Pt());
00062 }
00063 
00064 vector<ShapeRoot> PolygonData::formPolygons(const vector<LineData>& lines) {
00065   if (lines.empty()) return vector<ShapeRoot>();
00066   // sort lines from longest to shortest
00067   vector<LineData> allEdges = lines;
00068   sort(allEdges.begin(),allEdges.end(), ptr_fun(isFirstLineLonger));
00069   
00070   vector<ShapeRoot> newPolygons;
00071   for (vector<LineData>::iterator line_it = allEdges.begin();
00072       line_it != allEdges.end(); line_it++) {
00073     Shape<PolygonData> temp_polygon(*line_it);
00074     for (vector<LineData>::iterator line_it2 = line_it+1;
00075    line_it2 < allEdges.end(); line_it2++) {
00076       if (line_it2->getColor() == line_it->getColor()
00077     && (temp_polygon->tryUpdateEdge(Shape<LineData>(*line_it2))
00078         || temp_polygon->tryImportNewEndline(*line_it2))) {
00079   allEdges.erase(line_it2);
00080   line_it2 = line_it;
00081       }
00082     }
00083     temp_polygon->setColor(line_it->getColor());
00084     temp_polygon->updateVertices();
00085     temp_polygon->printParams();
00086     newPolygons.push_back(temp_polygon);
00087   }
00088   return newPolygons;
00089 }
00090 
00091 vector<ShapeRoot> PolygonData::formPolygons(const vector<LineData>& lines, 
00092               vector<Shape<PolygonData> >& existingPolygons, 
00093               vector<ShapeRoot>& deletedPolygons) {
00094   if (lines.empty()) return vector<ShapeRoot>();
00095 
00096   vector<LineData> allEdges = lines;
00097   for (vector<Shape<PolygonData> >::const_iterator pol_it = existingPolygons.begin();
00098        pol_it < existingPolygons.end(); pol_it++) {
00099     vector<LineData> existingEdges = (*pol_it)->getEdges();
00100     const int existingParentID = (*pol_it)->getId();
00101     for (vector<LineData>::iterator edge_it = existingEdges.begin();
00102    edge_it != existingEdges.end(); edge_it++)
00103       edge_it->setParentId(existingParentID); // set parent id of all edges to its owner
00104     allEdges.insert(allEdges.end(), existingEdges.begin(),existingEdges.end());
00105   }
00106 
00107   vector<ShapeRoot> newPolygons = formPolygons(allEdges);
00108 
00109   for (vector<Shape<PolygonData> >::iterator existing_it = existingPolygons.begin();
00110        existing_it < existingPolygons.end(); existing_it++) {
00111     vector<ShapeRoot>::iterator new_it = newPolygons.begin();
00112     for (; new_it < newPolygons.end(); new_it++) {
00113       const Shape<PolygonData>& newPolygon = ShapeRootTypeConst(*new_it,PolygonData);
00114       if ((*existing_it)->getEdges().size() == newPolygon->getEdges().size()) {
00115   vector<LineData>::const_iterator edge_it = newPolygon->getEdges().begin();
00116   const int parentPolygonID = (*existing_it)->getId();
00117   for (;edge_it != newPolygon->getEdges().end(); edge_it++)
00118     if (parentPolygonID != edge_it->getParentId())
00119       break;
00120   if (edge_it == newPolygon->getEdges().end()) {// this new_it has the exactly same set of edges as existing_it
00121     (*existing_it)->edges = newPolygon->edges;
00122     (*existing_it)->vertices = newPolygon->vertices;
00123     new_it->deleteShape();
00124     newPolygons.erase(new_it--);
00125     cout << " => match for existing polygon " << parentPolygonID << endl;
00126     break;
00127   }
00128       }
00129     }
00130     if (new_it == newPolygons.end()) {
00131       deletedPolygons.push_back(*existing_it);
00132       existingPolygons.erase(existing_it--);
00133     }
00134   }
00135   return newPolygons;
00136 }
00137 
00138 
00139 BoundingBox PolygonData::getBoundingBox() const {
00140   BoundingBox result(vertices[0].coordX(), vertices[0].coordX(),
00141          vertices[0].coordY(), vertices[0].coordY());
00142   for (vector<Point>::const_iterator it = vertices.begin();
00143        it != vertices.end();
00144        it++) {
00145     if ( (*it).coordX() < result.xmin )
00146       result.xmin = (*it).coordX();
00147     else if ( (*it).coordX() > result.xmax )
00148       result.xmax = (*it).coordX();
00149     if ( (*it).coordY() < result.ymin )
00150       result.ymin = (*it).coordY();
00151     else if ( (*it).coordY() > result.ymax )
00152       result.ymax = (*it).coordY();
00153   }
00154   return result;
00155 }
00156 
00157 bool PolygonData::formsNewEndline(const LineData& ln, bool useEnd1Pt, bool useEnd2Pt) const {
00158   if (edges.empty()) return true;
00159 
00160   useEnd1Pt &= ln.end1Pt().isValid(); // don't use invalid endpoint
00161   useEnd2Pt &= ln.end2Pt().isValid(); // don't use invalid endpoint
00162 
00163   if (!(useEnd1Pt || useEnd2Pt))
00164     return false;
00165 
00166   if (end1Pt().isValid()) //forms vertex with end1Ln?
00167     if((useEnd1Pt && end1Pt().distanceFrom(ln.end1Pt()) < THRESH_DIST_VERTEX)
00168        || (useEnd2Pt && end1Pt().distanceFrom(ln.end2Pt()) < THRESH_DIST_VERTEX))
00169       return true;
00170   if (end2Pt().isValid()) //forms vertex with end2Ln?
00171     if((useEnd1Pt && end2Pt().distanceFrom(ln.end1Pt()) < THRESH_DIST_VERTEX)
00172        || (useEnd2Pt && end2Pt().distanceFrom(ln.end2Pt()) < THRESH_DIST_VERTEX))
00173       return true;
00174 
00175   return false;
00176 }
00177 
00178 bool PolygonData::tryImportNewEndline(const LineData& ln, bool useEnd1Pt, bool useEnd2Pt) {
00179   if (edges.empty()) {
00180     edges.push_back(ln);
00181     return true;
00182   }
00183       
00184   useEnd1Pt &= ln.end1Pt().isValid(); // don't use invalid endpoint
00185   useEnd2Pt &= ln.end2Pt().isValid(); // don't use invalid endpoint
00186   if (!(useEnd1Pt || useEnd2Pt))
00187     return false;
00188   
00189   if (end1Pt().isValid()) {
00190     if (useEnd1Pt && 
00191   end1Pt().distanceFrom(ln.end1Pt()) < THRESH_DIST_VERTEX) {
00192       LineData end1ln = ln;
00193       end1ln.setEndPts(ln.end2Pt(),ln.end1Pt());
00194       edges.insert(edges.begin(), end1ln);
00195       return true;
00196     }
00197     else if (useEnd2Pt && 
00198        end1Pt().distanceFrom(ln.end2Pt()) < THRESH_DIST_VERTEX) {
00199       edges.insert(edges.begin(), ln);
00200       return true;
00201     }
00202   }
00203   
00204   if (end2Pt().isValid()) {
00205     if (useEnd1Pt && 
00206   end2Pt().distanceFrom(ln.end1Pt()) < THRESH_DIST_VERTEX) {
00207       edges.push_back(ln);
00208       return true;
00209     }
00210     else if (useEnd2Pt &&
00211        end2Pt().distanceFrom(ln.end2Pt()) < THRESH_DIST_VERTEX) {
00212       LineData end2ln = ln;
00213       end2ln.setEndPts(ln.end2Pt(),ln.end1Pt());
00214       edges.push_back(end2ln);
00215       return true;
00216     }
00217   }
00218   return false;
00219 }
00220 
00221 bool PolygonData::tryClosePolygon() {
00222   if (vertices.size()<3 || 
00223       !end1Pt().isValid() || !end2Pt().isValid())
00224     return false;
00225   if (end1Ln().isMatchFor(end2Ln())) {
00226     cout << "end1 match for end2\n";
00227     end1Ln().printParams();
00228     end2Ln().printParams();
00229     edges.erase(edges.end());
00230   }
00231   edges.push_back(LineData(*space,end2Pt(),end1Pt()));
00232   edges.front().end1Pt().setValid(true);
00233   updateVertices();
00234   return true;
00235 }
00236 
00237 bool PolygonData::isClosed() const {
00238   return (edges.size() > 2 &&
00239     (end1Ln().isMatchFor(end2Ln()) || 
00240      ((end1Pt().distanceFrom(end2Pt()) < THRESH_DIST_VERTEX)
00241       && end1Pt().isValid() && end2Pt().isValid())));
00242 }
00243 
00244 
00245 bool PolygonData::isMatchForEdge(const LineData& other) const {
00246   for(vector<LineData>::const_iterator this_it = edges.begin();
00247       this_it != edges.end(); this_it++)
00248     if (this_it->isMatchFor(other))
00249       return true;
00250   return false;
00251 }
00252 
00253 // remove edges whose confidence < 0
00254 // break polygon into pieces if inner edge removed
00255 vector<ShapeRoot> PolygonData::updateState() {
00256   bool breakPolygon = false;
00257   for (vector<LineData>::iterator it = edges.begin();
00258        it != edges.end(); it++) {
00259     if (it->getConfidence() < 0) {
00260       if (! (it == edges.begin() || it == edges.end()-1)) //inner edge deleted
00261   breakPolygon = true;
00262       edges.erase(it--);
00263     }
00264   }
00265   if (breakPolygon && !edges.empty()) { //form new polygons from the remaining edges of this polygon
00266     vector<LineData> lines(edges);
00267     edges.clear(); 
00268     return formPolygons(lines);
00269   }
00270   else
00271     return vector<ShapeRoot>();
00272 }
00273 
00274 
00275 bool PolygonData::tryUpdateEdge(const ShapeRoot& ln) {
00276   for(vector<LineData>::iterator it = edges.begin();
00277       it != edges.end(); it++)
00278     if (it->isMatchFor(ln) && it->updateParams(ln)) {
00279       it->increaseConfidence(ln);
00280       if (it->getParentId() == 0 && ln->getParentId() != 0)
00281   it->setParentId(ln->getParentId());
00282       return true;
00283     }
00284   return false;
00285 }
00286 
00287   /*
00288   for(vector<Point>::iterator it = polygon.getVertices.begin();
00289       it != polygon.getVertices.end(); it++)
00290     .....
00291   */
00292 
00293 bool PolygonData::isMatchFor(const ShapeRoot& other) const {
00294   if (other->isType(lineDataType) && isSameColorAs(other)) {
00295     const LineData& other_ln = ShapeRootTypeConst(other,LineData).getData();
00296     return (isMatchForEdge(other_ln));
00297   }
00298   if (other->isType(polygonDataType) && isSameColorAs(other)) {
00299     const PolygonData& other_polygon = ShapeRootTypeConst(other,PolygonData).getData();
00300     if (other_polygon.getEdges().size() == edges.size()) {
00301       vector<LineData>::const_iterator other_it = other_polygon.getEdges().begin();
00302       vector<LineData>::const_iterator this_it = getEdges().begin();
00303       for (; other_it != other_polygon.getEdges().end(); other_it++, this_it++)
00304   if (!this_it->isMatchFor(*other_it)) break;
00305       if (this_it == edges.end())
00306   return true;
00307       vector<LineData>::const_reverse_iterator other_rit = other_polygon.getEdges().rbegin();
00308       this_it = edges.begin();
00309       for (; other_rit != other_polygon.getEdges().rend(); other_it++, this_it++)
00310   if (!this_it->isMatchFor(*other_rit)) break;
00311       return (this_it == edges.end());
00312     }
00313   }
00314   return false;
00315 }
00316 
00317 int PolygonData::getConfidence() const {
00318   switch (edges.size()) {
00319   case 0:
00320     return -1;
00321   case 1:
00322     return edges.front().getConfidence();
00323   default:
00324     vector<LineData>::const_iterator it = edges.begin();
00325     int conf = (it++)->getConfidence();
00326     for (; it != edges.end(); it++)
00327       if (conf > it->getConfidence())
00328   conf = it->getConfidence();
00329     return conf;
00330   };
00331 }
00332 
00333 bool PolygonData::updateParams(const ShapeRoot& other, bool) {
00334   if (other->isType(lineDataType) && tryUpdateEdge(other)) {
00335     updateVertices();
00336     return true;
00337   }
00338   return false;
00339 }
00340 
00341 /*    
00342 bool PolygonData::doUpdateParams(const ShapeRoot& other, bool) {
00343 if (other->isType(lineDataType))
00344 return (tryUpdateEdge(other)); ||
00345 tryImportNewEndline(ShapeRootTypeConst(other,LineData).getData()));
00346 else if (other->isType(polygonDataType)) {
00347 const PolygonData& other_polygon = ShapeRootTypeConst(other, PolygonData).getData();
00348 return tryImportNewEndline(other_polygon.end1Ln(),true,false)
00349 || tryImportNewEndline(other_polygon.end2Ln(),false,true);
00350 }
00351 return false;
00352 }
00353 */
00354 
00355 bool PolygonData::isAdmissible() const {
00356   for (vector<LineData>::const_iterator it = edges.begin();
00357        it != edges.end(); it++) {
00358     if (it->isAdmissible())
00359       return true;
00360   }
00361   return false;
00362 }
00363 
00364 // define a line from pt to most distant vertex from this point.
00365 // count number of intersections with edges (except the ones 
00366 bool PolygonData::isInside(const Point& pt) const {
00367   if (!isClosed()) return false;
00368   float mostDist = -1;
00369   unsigned int mostDistIndex = -1U;
00370   const unsigned int numVertices = vertices.size()-1; // number of unique vertices (first and last are same) 
00371   for (unsigned int i = 0; i < numVertices; i++) {
00372     float dist = pt.distanceFrom(vertices[i]);
00373     if (dist > mostDist) {
00374       mostDist = dist;
00375       mostDistIndex = i;
00376     }
00377   }
00378   //  cout << "Most distant vertex: " << vertices[mostDistIndex] << endl;
00379   LineData ln(this->getSpace(),pt,(vertices[mostDistIndex]));
00380   unsigned int intersectionCount = 0;
00381   // this is a check if this point falls between the two edges surrounding the most distant vertex from this point
00382   // if not, odd number of intersection indicates the point is inside, so increment the count by 1
00383   {
00384     float theta0 = (mostDistIndex == 0) ? 
00385       ((vertices.front() == vertices.back()) ? 
00386        atan2(vertices[vertices.size()-2].coordY()-vertices[mostDistIndex].coordY(),
00387        vertices[vertices.size()-2].coordX()-vertices[mostDistIndex].coordX()) :
00388        atan2(vertices[vertices.size()-1].coordY()-vertices[mostDistIndex].coordY(),
00389        vertices[vertices.size()-1].coordX()-vertices[mostDistIndex].coordX())) :
00390       atan2(vertices[mostDistIndex-1].coordY()-vertices[mostDistIndex].coordY(),
00391       vertices[mostDistIndex-1].coordX()-vertices[mostDistIndex].coordX());
00392     float theta1 = atan2(pt.coordY()-vertices[mostDistIndex].coordY(),pt.coordX()-vertices[mostDistIndex].coordX());
00393     float theta2 = (mostDistIndex == vertices.size()-1) ?
00394       ((vertices.front() == vertices.back()) ? 
00395        atan2(vertices[1].coordY()-vertices[mostDistIndex].coordY(),
00396        vertices[1].coordX()-vertices[mostDistIndex].coordX()) :
00397        atan2(vertices[0].coordY()-vertices[mostDistIndex].coordY(),
00398        vertices[0].coordX()-vertices[mostDistIndex].coordX())) :
00399       atan2(vertices[mostDistIndex+1].coordY()-vertices[mostDistIndex].coordY(),
00400       vertices[mostDistIndex+1].coordX()-vertices[mostDistIndex].coordX());
00401     if ((theta2>theta0 && !((theta2-theta0<M_PI && theta2>theta1 && theta1>theta0) ||
00402          (2*M_PI-theta2+theta0<M_PI && (theta1>theta2 || theta0>theta1)))) 
00403   || (theta0>theta2 && !((theta0-theta2<M_PI && theta0>theta1 && theta1>theta2) ||
00404              (2*M_PI-theta0+theta2<M_PI && (theta1>theta0 || theta2>theta1))))) {
00405       //      cout << "orientataion not b/w edges\n";
00406       intersectionCount++;
00407     }
00408   }
00409     //  cout << "  " << ln.end1Pt() << " <-> " << ln.end2Pt() << endl;
00410   for (unsigned int i = mostDistIndex+1; i < numVertices+mostDistIndex-1; i++) {
00411     LineData cleanEdge(*space,vertices[i%numVertices],vertices[(i+1)%numVertices]);
00412     //    cout << "  " << i << ": " << cleanEdge.end1Pt() << " <-> " << cleanEdge.end2Pt();
00413     if (ln.getOrientation() != cleanEdge.getOrientation()
00414   && ln.intersectsLine(cleanEdge)) {
00415       //      cout << " true\n";
00416       intersectionCount++;
00417     }
00418   }
00419   return (intersectionCount%2) == 0;
00420 }
00421 
00422 
00423 void PolygonData::printParams() const {
00424   cout << edges.size() << " edge(s)\n";
00425   for (vector<LineData>::const_iterator it = edges.begin();
00426        it != edges.end(); it++)
00427     cout << it->end1Pt() << " -> " << it->end2Pt() << endl;
00428 
00429   cout << vertices.size () << " vertice(s):\n";
00430   for (vector<Point>::const_iterator it = vertices.begin();
00431        it != vertices.end(); it++)
00432     cout << (*it) << endl;
00433 }
00434 
00435 void PolygonData::applyTransform(const NEWMAT::Matrix& Tmat) {
00436   for (vector<LineData>::iterator it = edges.begin();
00437        it != edges.end(); it++)
00438     it->applyTransform(Tmat);
00439   for (vector<Point>::iterator it = vertices.begin();
00440        it != vertices.end(); it++)
00441     it->applyTransform(Tmat);
00442 }
00443 
00444 void PolygonData::projectToGround(const NEWMAT::Matrix& camToBase,
00445           const NEWMAT::ColumnVector& groundplane) {
00446   for (vector<LineData>::iterator it = edges.begin();
00447        it != edges.end(); it++)
00448     it->projectToGround(camToBase,groundplane);
00449 }
00450 
00451 Point PolygonData::getCentroid() const {
00452   if (edges.empty())
00453     return Point(0,0,0,getRefFrameType());
00454   vector<LineData>::const_iterator it = edges.begin();
00455   Point centroid = (it++)->getCentroid();
00456   for (; it != edges.end(); it++)
00457     centroid += it->getCentroid();
00458   return centroid/edges.size();
00459 }
00460 
00461 
00462 void PolygonData::setColor(rgb new_color) {
00463   color_rgb = new_color;
00464   for (vector<LineData>::iterator it = edges.begin();
00465        it != edges.end(); it++)
00466     it->setColor(color_rgb);
00467   deleteRendering();
00468 }
00469 
00470 // helper function to sort lines from longest to shortest
00471 bool PolygonData::isFirstLineLonger(const Shape<LineData>& ln1,const Shape<LineData>& ln2) { 
00472   return ln1->isLongerThan(ln2);
00473 }
00474 
00475 Sketch<bool>* PolygonData::render() const {
00476   string const result_name = "render(" + getName() + ")";
00477   Sketch<bool> canvas(space->getDualSpace(), result_name);
00478   canvas = 0;
00479   const int width = space->getDualSpace().getWidth();
00480   const int height = space->getDualSpace().getHeight();
00481   float x1, y1, x2, y2;
00482   for (vector<LineData>::const_iterator it = edges.begin();
00483        it != edges.end(); it++) {
00484     it->setDrawCoords(x1, y1, x2, y2, width, height);
00485     it->drawline2d(canvas, (int)x1, (int)y1, (int)x2, (int)y2);
00486   }
00487   if (!isClosed())
00488     return new Sketch<bool>(canvas);
00489   NEW_SKETCH_N(borders, bool, visops::zeros(canvas));
00490   for (int i = 0; i < width; i++) {
00491     borders(i,0) = ! canvas(i,0);
00492     borders(i,height-1) = ! canvas(i,height-1);
00493   }
00494   for (int j = 1; j < height-1; j++) {
00495     borders(0,j) = ! canvas(0,j);
00496     borders(width-1,j) = ! canvas(width-1,j);
00497   }
00498   usint const not_reached = usint(-1);
00499   NEW_SKETCH_N(bd, usint, visops::bdist(borders, canvas, width*height));
00500   bd->inheritFrom(*this);
00501   bd->setColorMap(jetMap);
00502   NEW_SKETCH(result, bool, bd == not_reached);
00503   result->setName(result_name);
00504   return new Sketch<bool>(result);
00505 }
00506 
00507 //================ Convex Hull ================
00508 
00509 class convexHullPoint {
00510 public:
00511   int x, y;
00512   float angle;
00513 
00514   convexHullPoint() : x(0), y(0), angle(0) {}
00515 
00516   convexHullPoint(int _x, int _y, float _a) : x(_x), y(_y), angle(_a) {}
00517 
00518   static int crossProduct(const convexHullPoint &p1, const convexHullPoint &p2, const convexHullPoint &p3) {
00519     return (p2.x - p1.x)*(p3.y - p1.y) - (p3.x - p1.x)*(p2.y - p1.y);
00520   }
00521 
00522   class pointCompare : public binary_function<convexHullPoint, convexHullPoint, bool> {
00523   private:
00524     const convexHullPoint &pivot;
00525   public:
00526     pointCompare(const convexHullPoint &_pivot) : pivot(_pivot) {}
00527     bool operator() (const convexHullPoint &p1, const convexHullPoint &p2) {
00528       if ( p1.angle < p2.angle )
00529   return true;
00530       else if ( p1.angle > p2.angle )
00531   return false;
00532       else {
00533   int const d1x = pivot.x - p1.x;
00534   int const d1y = pivot.y - p1.y;
00535   int const d2x = pivot.x - p2.x;
00536   int const d2y = pivot.y - p2.y;
00537   return (d1x*d1x+d1y*d1y) < (d2x*d2x+d2y*d2y);
00538       }
00539     }
00540   }
00541 ;
00542 };
00543 
00544 Shape<PolygonData> PolygonData::convexHull(const Sketch<bool> &sketch) {
00545   int const spts = sketch->sum();
00546   int const width = sketch.width;
00547   int const npix = sketch->getNumPixels();
00548   
00549   //  cout << "septs,width,npix= " << spts << ", " << width << ", " << npix << endl;
00550 
00551   // construct a vector of points and find the pivot point
00552   NEW_SKETCH_N(neighbs, uchar, visops::neighborSum(sketch));
00553   std::vector<convexHullPoint> points(spts);
00554   points.clear();
00555   int pivot_x = -1, pivot_y = width+1;
00556   for (int i=0; i<npix; i++) {
00557     //    cout << sketch[i] << " : " << neighbs[i] << endl;
00558     if ( sketch[i] && neighbs[i] < 8 ) {
00559       int const x = i % width;
00560       int const y = i / width;
00561       points.push_back(convexHullPoint(x,y,0));
00562       if ( y < pivot_y || (y == pivot_y && x > pivot_x) ) {
00563   pivot_x = x;
00564   pivot_y = y;
00565       };
00566     }
00567   }
00568   int const npts = points.size();
00569 
00570 
00571   // sort points by angle from the pivot, and if colinear, take closer point first
00572   for (int i=0; i<npts; i++)
00573     points[i].angle  = (float) -atan2((float) (pivot_y - points[i].y), (float) (pivot_x - points[i].x));
00574   std::sort(points.begin(),points.end(),convexHullPoint::pointCompare(convexHullPoint(pivot_x,pivot_y,0)));
00575 
00576   // push points onto a stack to form the convex hull
00577   vector<convexHullPoint> hull(npts);
00578   hull.clear();
00579   hull.push_back(points[0]);
00580   hull.push_back(points[1]);
00581   for ( int i=2; i<npts; i++ ) {
00582     int last = hull.size() - 1;
00583     int o = convexHullPoint::crossProduct(hull[last-1],hull[last],points[i]);
00584     if ( o == 0 )
00585       hull[last] = points[i];
00586     else if ( o < 0 )
00587       hull.push_back(points[i]);
00588     else {
00589       while ( o >= 0 && hull.size() > 2 ) {
00590   hull.pop_back();
00591   last--;
00592   o = convexHullPoint::crossProduct(hull[last-1],hull[last],points[i]);
00593       }
00594       hull.push_back(points[i]);
00595     }
00596   }
00597   int const nhull = hull.size();
00598   // build a polygon to represent the hull
00599   ShapeSpace &ShS = sketch->getDualSpace();
00600   vector<Point> vertices;
00601   for (int i=0; i<nhull; i++)
00602     vertices.push_back(Point(hull[i].x, hull[i].y));
00603   vertices.push_back(Point(hull[0].x, hull[0].y));  // force closed polygon: don't trust tryClose()
00604   return Shape<PolygonData>(new PolygonData(ShS,vertices,true));
00605 }
00606 
00607 
00608 } // namespace

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