ViSP  2.9.0
vpPolygon.cpp
1 /****************************************************************************
2  *
3  * $Id: vpPolygon.cpp 4632 2014-02-03 17:06:40Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Defines a generic 2D polygon.
36  *
37  * Author:
38  * Amaury Dame
39  * Nicolas Melchior
40  * Romain Tallonneau
41  *
42  *****************************************************************************/
43 
44 
45 
46 #include <visp/vpPolygon.h>
47 #include <visp/vpException.h>
48 #include <visp/vpDisplay.h>
49 #include <visp/vpMeterPixelConversion.h>
50 #include <visp/vpNoise.h>
51 #include <set>
52 #include <limits>
60  : _corners(), _center(), _area(0.), _goodPoly(true), _bbox()
61 {
62  std::vector<vpImagePoint> corners;
63  corners.push_back(vpImagePoint(0,0));
64  corners.push_back(vpImagePoint(1,0));
65  corners.push_back(vpImagePoint(0,1));
66  init(corners);
67 }
68 
76 vpPolygon::vpPolygon(const std::vector<vpImagePoint>& corners)
77  : _corners(), _center(), _area(0.), _goodPoly(true), _bbox()
78 {
79  if(corners.size() < 3){
80  _goodPoly = false;
81  }
82  init(corners);
83 }
84 
91  : _corners(), _center(), _area(0.), _goodPoly(true), _bbox()
92 {
93  _corners = poly._corners;
94  _center = poly._center;
95  _area = poly._area;
96  _goodPoly = poly._goodPoly;
97  _bbox = poly._bbox;
98 }
99 
104 {
105 }
106 
112 vpPolygon &
114 {
115  _corners = poly._corners;
116  _center = poly._center;
117  _area = poly._area;
118  _goodPoly = poly._goodPoly;
119  return *this;
120 };
121 
129 void
130 vpPolygon::buildFrom(const std::vector<vpImagePoint>& corners)
131 {
132  init(corners);
133 }
134 
146 void
147 vpPolygon::buildFrom(const std::vector<vpPoint>& corners, const vpCameraParameters& cam)
148 {
149  std::vector<vpImagePoint> ipCorners(corners.size());
150  for(unsigned int i=0; i<corners.size(); ++i){
151  vpMeterPixelConversion::convertPoint(cam, corners[i].get_x(), corners[i].get_y(), ipCorners[i]);
152  }
153  buildFrom(ipCorners);
154 }
155 
162 void
164 {
166  vpImagePoint ip;
167 
168  std::vector<vpImagePoint> cornersClick;
169 
170  while(button == vpMouseButton::button1){
171  bool ret = vpDisplay::getClick(I, ip, button, true);
172  if(ret && button == vpMouseButton::button1){
174  cornersClick.push_back(ip);
175  vpDisplay::flush(I);
176  }
177  }
178 
179  buildFrom(cornersClick);
180 }
181 
182 
191 void
192 vpPolygon::init(const std::vector<vpImagePoint>& corners)
193 {
194  _corners = corners;
195 
197  updateArea();
198  updateCenter();
199 }
200 
201 
202 
214 bool
215 vpPolygon::testIntersectionSegments(const vpImagePoint& ip1, const vpImagePoint& ip2, const vpImagePoint& ip3, const vpImagePoint& ip4)
216 {
217  double di1 = ip2.get_i() - ip1.get_i();
218  double dj1 = ip2.get_j() - ip1.get_j();
219 
220  double di2 = ip4.get_i() - ip3.get_i();
221  double dj2 = ip4.get_j() - ip3.get_j();
222 
223  double denominator = di1 * dj2 - dj1 * di2;
224 
225  if(fabs(denominator) < std::numeric_limits<double>::epsilon()){
226  throw vpException(vpException::divideByZeroError, "Denominator is null, lines are parallels");
227  }
228 
229  double alpha = - ( ( ip1.get_i() - ip3.get_i() ) * dj2 + di2 * ( ip3.get_j() - ip1.get_j())) / denominator;
230  if(alpha < 0 || alpha >= 1){
231  return false;
232  }
233 
234  double beta = - (di1 * (ip3.get_j() - ip1.get_j() ) + dj1 * (ip1.get_i() - ip3.get_i()) ) / denominator;
235  if(beta < 0 || beta >= 1){
236  return false;
237  }
238 
239  return true;
240 }
241 
249 bool
251 {
252  vpImagePoint infPoint(100000, 100000); // take a point at 'inifinity'
253  vpUniRand generator;
254  infPoint.set_i( infPoint.get_i() + 1000 * generator());
255  infPoint.set_j( infPoint.get_j() + 1000 * generator());// we add random since it appears that sometimes infPoint may cause a degenerated case (so realucnch and hope that result will be different).
256 
257  unsigned int nbinterscetion = 0;
258  for(unsigned int i=0; i<_corners.size(); ++i){
259  vpImagePoint ip1 = _corners[i];
260  vpImagePoint ip2 = _corners[(i+1)%_corners.size()];
261  bool intersection = false;
262 
263  // If the points are the same we continue without trying to found
264  // an intersection
265  if (ip1 == ip2)
266  continue;
267 
268  try{
269  intersection = testIntersectionSegments(ip1, ip2, ip, infPoint );
270  }catch(vpException e){
271  return isInside(ip);
272  }
273 
274  if(intersection){
275  ++nbinterscetion;
276  }
277  }
278 
279  return ((nbinterscetion%2)==1);
280 }
281 
282 
283 
293 void
295 {
296  if(_corners.size() == 0){
297  _area = 0;
298  _goodPoly = false;
299  return;
300  }
301  _area = 0;
302 
303  for(unsigned int i=0; i<_corners.size(); ++i){
304  unsigned int i_p_1 = ( i+1 ) % _corners.size();
305  _area += _corners[i].get_j() * _corners[i_p_1].get_i()
306  - _corners[i_p_1].get_j() * _corners[i].get_i();
307  }
308 
309  _area /= 2;
310  if(_area < 0){
311  _area = - _area;
312  }
313 }
314 
315 
327 void
329 {
330  if(_corners.size() == 0){
331  _center = vpImagePoint(0, 0);
332  _goodPoly = false;
333  return;
334  }
335  double i_tmp = 0;
336  double j_tmp = 0;
337 #if 0
338  for(unsigned int i=0; i<(_corners.size()-1); ++i){
339  i_tmp += (_corners[i].get_i() + _corners[i+1].get_i()) *
340  (_corners[i+1].get_i() * _corners[i].get_j() - _corners[i+1].get_j() * _corners[i].get_i());
341 
342  j_tmp += (_corners[i].get_j() + _corners[i+1].get_j()) *
343  (_corners[i+1].get_i() * _corners[i].get_j() - _corners[i+1].get_j() * _corners[i].get_i());
344  }
345 #else
346  for(unsigned int i=0; i<_corners.size(); ++i){
347  unsigned int i_p_1 = ( i+1 ) % _corners.size();
348  i_tmp += (_corners[i].get_i() + _corners[i_p_1].get_i()) *
349  (_corners[i_p_1].get_i() * _corners[i].get_j()
350  - _corners[i_p_1].get_j() * _corners[i].get_i());
351 
352  j_tmp += (_corners[i].get_j() + _corners[i_p_1].get_j()) *
353  (_corners[i_p_1].get_i() * _corners[i].get_j()
354  - _corners[i_p_1].get_j() * _corners[i].get_i());
355  }
356 #endif
357 
358  if(_area > 0){
359  _center.set_i(fabs(i_tmp / (6 * _area)));
360  _center.set_j(fabs(j_tmp / (6 * _area)));
361  }else{
362  _center = _corners[0];
363  _goodPoly = false;
364  }
365 }
366 
367 void
369 {
370  if(_corners.size() == 0){
373  _goodPoly = false;
374  return;
375  }
376 
377  std::set<double> setI;
378  std::set<double> setJ;
379  for(unsigned int i=0; i<_corners.size(); ++i){
380  setI.insert(_corners[i].get_i());
381  setJ.insert(_corners[i].get_j());
382  }
383  vpImagePoint tl(*(setI.begin()), *(setJ.begin()));
384  std::set<double>::const_iterator iterI = setI.end();
385  std::set<double>::const_iterator iterJ = setJ.end();
386  --iterI;
387  --iterJ;
388  vpImagePoint br(*iterI, *iterJ);
389 
390  if(tl == br){
391  _goodPoly = false;
392  }
393  _bbox.setTopLeft(tl);
394  _bbox.setBottomRight(br);
395 }
396 
405 void
406 vpPolygon::display(const vpImage<unsigned char>& I, const vpColor& color, unsigned int thickness)
407 {
408  const unsigned int N = (unsigned int)_corners.size();
409  for(unsigned int i=0; i<N; ++i){
410  vpDisplay::displayLine(I, _corners[i], _corners[(i+1)%N], color, thickness);
411  }
412 }
virtual ~vpPolygon()
Definition: vpPolygon.cpp:103
double get_i() const
Definition: vpImagePoint.h:194
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Point coordinates conversion from normalized coordinates in meter to pixel coordinates ...
Class to define colors available for display functionnalities.
Definition: vpColor.h:125
void init(const std::vector< vpImagePoint > &corners)
Definition: vpPolygon.cpp:192
error that can be emited by ViSP classes.
Definition: vpException.h:76
vpPolygon & operator=(const vpPolygon &poly)
Definition: vpPolygon.cpp:113
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
Definition: vpPolygon.cpp:406
vpRect _bbox
Boumding box containing the polygon.
Definition: vpPolygon.h:114
vpImagePoint _center
Center of the polygon. It is automatically computed when the corners are set.
Definition: vpPolygon.h:108
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1994
double get_j() const
Definition: vpImagePoint.h:205
static const vpColor red
Definition: vpColor.h:167
void updateArea()
Definition: vpPolygon.cpp:294
bool isInside(const vpImagePoint &iP)
Definition: vpPolygon.cpp:250
Defines a generic 2D polygon.
Definition: vpPolygon.h:102
void set_i(const double ii)
Definition: vpImagePoint.h:158
void updateBoundingBox()
Definition: vpPolygon.cpp:368
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
Generic class defining intrinsic camera parameters.
void setTopLeft(const vpImagePoint &topLeft)
Definition: vpRect.h:279
void set_j(const double jj)
Definition: vpImagePoint.h:169
std::vector< vpImagePoint > _corners
Collection of image points containing the corners.
Definition: vpPolygon.h:106
void initClick(const vpImage< unsigned char > &I)
Definition: vpPolygon.cpp:163
bool _goodPoly
Flag to indicate whether the polygon is a good polygon (ie. it has more than two corners, ...)
Definition: vpPolygon.h:112
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
Class for generating random numbers with uniform probability density.
Definition: vpNoise.h:72
virtual void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
void updateCenter()
Definition: vpPolygon.cpp:328
void setBottomRight(const vpImagePoint &bottomRight)
Definition: vpRect.h:215
void buildFrom(const std::vector< vpImagePoint > &corners)
Definition: vpPolygon.cpp:130
double _area
Area of the polygon.
Definition: vpPolygon.h:110