00001
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)
00081 tryClosePolygon();
00082 }
00083
00084 vector<ShapeRoot> PolygonData::formPolygons(const vector<LineData>& lines) {
00085 if (lines.empty()) return vector<ShapeRoot>();
00086
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
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
00115 if (lines.empty()) return vector<ShapeRoot>();
00116
00117 vector<LineData> allEdges = lines;
00118
00119
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
00125 vector<ShapeRoot> newP = formPolygons(allEdges);
00126 vector<Shape<PolygonData> > &newPolygons = *reinterpret_cast<vector<Shape<PolygonData> >*>(&newP);
00127
00128
00129
00130
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();
00169 useEnd2Pt &= ln.end2Pt().isValid();
00170
00171 if (!(useEnd1Pt || useEnd2Pt))
00172 return false;
00173
00174 if (end1Pt().isValid())
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())
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();
00193 useEnd2Pt &= ln.end2Pt().isValid();
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
00254
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))
00261 breakPolygon = true;
00262 edges.erase(it--);
00263 }
00264 }
00265 if (breakPolygon && !edges.empty()) {
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
00288
00289
00290
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
00317
00318
00319
00320 for (; j < edges.size(); j++)
00321 if ( vertices[0] == other.vertices[j] )
00322 break;
00323
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) ) {
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
00367
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;
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
00381 LineData ln(this->getSpace(),pt,(vertices[mostDistIndex]));
00382 unsigned int intersectionCount = 0;
00383
00384
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
00408 intersectionCount++;
00409 }
00410 }
00411
00412 for (unsigned int i = mostDistIndex+1; i < numVertices+mostDistIndex-1; i++) {
00413 LineData cleanEdge(*space,vertices[i%numVertices],vertices[(i+1)%numVertices]);
00414
00415 if (ln.getOrientation() != cleanEdge.getOrientation()
00416 && ln.intersectsLine(cleanEdge)) {
00417
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
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
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
00563
00564
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
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
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
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
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());
00621 return Shape<PolygonData>(new PolygonData(ShS,vertices,true));
00622 }
00623
00624
00625 }