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

DualCoding 5.1CVS
Generated Sat May 4 06:29:28 2013 by Doxygen 1.6.3