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

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