ViSP  2.8.0
vpPolygon.cpp
1 /****************************************************************************
2  *
3  * $Id: vpPolygon.cpp 4303 2013-07-04 14:14:00Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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 {
61  _goodPoly = true;
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 {
78  if(corners.size() < 3){
79  _goodPoly = false;
80  }
81  init(corners);
82 }
83 
90 {
91  _corners = poly._corners;
92  _center = poly._center;
93  _area = poly._area;
94  _goodPoly = poly._goodPoly;
95 }
96 
101 {
102 }
103 
109 vpPolygon &
111 {
112  _corners = poly._corners;
113  _center = poly._center;
114  _area = poly._area;
115  _goodPoly = poly._goodPoly;
116  return *this;
117 };
118 
126 void
127 vpPolygon::buildFrom(const std::vector<vpImagePoint>& corners)
128 {
129  init(corners);
130 }
131 
143 void
144 vpPolygon::buildFrom(const std::vector<vpPoint>& corners, const vpCameraParameters& cam)
145 {
146  std::vector<vpImagePoint> ipCorners(corners.size());
147  for(unsigned int i=0; i<corners.size(); ++i){
148  vpMeterPixelConversion::convertPoint(cam, corners[i].get_x(), corners[i].get_y(), ipCorners[i]);
149  }
150  buildFrom(ipCorners);
151 }
152 
159 void
161 {
163  vpImagePoint ip;
164 
165  std::vector<vpImagePoint> cornersClick;
166 
167  while(button == vpMouseButton::button1){
168  vpDisplay::getClick(I, ip, button, true);
169  if(button == vpMouseButton::button1){
171  cornersClick.push_back(ip);
172  vpDisplay::flush(I);
173  }
174  }
175 
176  buildFrom(cornersClick);
177 }
178 
179 
188 void
189 vpPolygon::init(const std::vector<vpImagePoint>& corners)
190 {
191  _corners = corners;
192 
194  updateArea();
195  updateCenter();
196 }
197 
198 
199 
211 bool
212 vpPolygon::testIntersectionSegments(const vpImagePoint& ip1, const vpImagePoint& ip2, const vpImagePoint& ip3, const vpImagePoint& ip4)
213 {
214  double di1 = ip2.get_i() - ip1.get_i();
215  double dj1 = ip2.get_j() - ip1.get_j();
216 
217  double di2 = ip4.get_i() - ip3.get_i();
218  double dj2 = ip4.get_j() - ip3.get_j();
219 
220  double denominator = di1 * dj2 - dj1 * di2;
221 
222  if(fabs(denominator) < std::numeric_limits<double>::epsilon()){
223  throw vpException(vpException::divideByZeroError, "Denominator is null, lines are parallels");
224  }
225 
226  double alpha = - ( ( ip1.get_i() - ip3.get_i() ) * dj2 + di2 * ( ip3.get_j() - ip1.get_j())) / denominator;
227  if(alpha < 0 || alpha >= 1){
228  return false;
229  }
230 
231  double beta = - (di1 * (ip3.get_j() - ip1.get_j() ) + dj1 * (ip1.get_i() - ip3.get_i()) ) / denominator;
232  if(beta < 0 || beta >= 1){
233  return false;
234  }
235 
236  return true;
237 }
238 
246 bool
248 {
249  vpImagePoint infPoint(100000, 100000); // take a point at 'inifinity'
250  vpUniRand generator;
251  infPoint.set_i( infPoint.get_i() + 1000 * generator());
252  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).
253 
254  unsigned int nbinterscetion = 0;
255  for(unsigned int i=0; i<_corners.size(); ++i){
256  vpImagePoint ip1 = _corners[i];
257  vpImagePoint ip2 = _corners[(i+1)%_corners.size()];
258  bool intersection = false;
259 
260  // If the points are the same we continue without trying to found
261  // an intersection
262  if (ip1 == ip2)
263  continue;
264 
265  try{
266  intersection = testIntersectionSegments(ip1, ip2, ip, infPoint );
267  }catch(vpException e){
268  return isInside(ip);
269  }
270 
271  if(intersection){
272  ++nbinterscetion;
273  }
274  }
275 
276  return ((nbinterscetion%2)==1);
277 }
278 
279 
280 
290 void
292 {
293  if(_corners.size() == 0){
294  _area = 0;
295  _goodPoly = false;
296  return;
297  }
298  _area = 0;
299 
300  for(unsigned int i=0; i<_corners.size(); ++i){
301  unsigned int i_p_1 = ( i+1 ) % _corners.size();
302  _area += _corners[i].get_j() * _corners[i_p_1].get_i()
303  - _corners[i_p_1].get_j() * _corners[i].get_i();
304  }
305 
306  _area /= 2;
307  if(_area < 0){
308  _area = - _area;
309  }
310 }
311 
312 
324 void
326 {
327  if(_corners.size() == 0){
328  _center = vpImagePoint(0, 0);
329  _goodPoly = false;
330  return;
331  }
332  double i_tmp = 0;
333  double j_tmp = 0;
334 #if 0
335  for(unsigned int i=0; i<(_corners.size()-1); ++i){
336  i_tmp += (_corners[i].get_i() + _corners[i+1].get_i()) *
337  (_corners[i+1].get_i() * _corners[i].get_j() - _corners[i+1].get_j() * _corners[i].get_i());
338 
339  j_tmp += (_corners[i].get_j() + _corners[i+1].get_j()) *
340  (_corners[i+1].get_i() * _corners[i].get_j() - _corners[i+1].get_j() * _corners[i].get_i());
341  }
342 #else
343  for(unsigned int i=0; i<_corners.size(); ++i){
344  unsigned int i_p_1 = ( i+1 ) % _corners.size();
345  i_tmp += (_corners[i].get_i() + _corners[i_p_1].get_i()) *
346  (_corners[i_p_1].get_i() * _corners[i].get_j()
347  - _corners[i_p_1].get_j() * _corners[i].get_i());
348 
349  j_tmp += (_corners[i].get_j() + _corners[i_p_1].get_j()) *
350  (_corners[i_p_1].get_i() * _corners[i].get_j()
351  - _corners[i_p_1].get_j() * _corners[i].get_i());
352  }
353 #endif
354 
355  if(_area > 0){
356  _center.set_i(fabs(i_tmp / (6 * _area)));
357  _center.set_j(fabs(j_tmp / (6 * _area)));
358  }else{
359  _center = _corners[0];
360  _goodPoly = false;
361  }
362 }
363 
364 void
366 {
367  if(_corners.size() == 0){
370  _goodPoly = false;
371  return;
372  }
373 
374  std::set<double> setI;
375  std::set<double> setJ;
376  for(unsigned int i=0; i<_corners.size(); ++i){
377  setI.insert(_corners[i].get_i());
378  setJ.insert(_corners[i].get_j());
379  }
380  vpImagePoint tl(*(setI.begin()), *(setJ.begin()));
381  std::set<double>::const_iterator iterI = setI.end();
382  std::set<double>::const_iterator iterJ = setJ.end();
383  --iterI;
384  --iterJ;
385  vpImagePoint br(*iterI, *iterJ);
386 
387  if(tl == br){
388  _goodPoly = false;
389  }
390  _bbox.setTopLeft(tl);
391  _bbox.setBottomRight(br);
392 }
393 
402 void
403 vpPolygon::display(const vpImage<unsigned char>& I, const vpColor& color, unsigned int thickness)
404 {
405  const unsigned int N = (unsigned int)_corners.size();
406  for(unsigned int i=0; i<N; ++i){
407  vpDisplay::displayLine(I, _corners[i], _corners[(i+1)%N], color, thickness);
408  }
409 }
void set_j(const double j)
Definition: vpImagePoint.h:156
virtual ~vpPolygon()
Definition: vpPolygon.cpp:100
double get_i() const
Definition: vpImagePoint.h:181
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:189
void set_i(const double i)
Definition: vpImagePoint.h:145
error that can be emited by ViSP classes.
Definition: vpException.h:75
vpPolygon & operator=(const vpPolygon &poly)
Definition: vpPolygon.cpp:110
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
Definition: vpPolygon.cpp:403
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:1991
double get_j() const
Definition: vpImagePoint.h:192
static const vpColor red
Definition: vpColor.h:167
void updateArea()
Definition: vpPolygon.cpp:291
bool isInside(const vpImagePoint &iP)
Definition: vpPolygon.cpp:247
Defines a generic 2D polygon.
Definition: vpPolygon.h:102
void updateBoundingBox()
Definition: vpPolygon.cpp:365
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:267
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:160
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:325
void setBottomRight(const vpImagePoint &bottomRight)
Definition: vpRect.h:206
void buildFrom(const std::vector< vpImagePoint > &corners)
Definition: vpPolygon.cpp:127
double _area
Area of the polygon.
Definition: vpPolygon.h:110