GRALE
polygon2d.h
Go to the documentation of this file.
1 /*
2 
3  This file is a part of GRALE, a library to facilitate the simulation
4  and inversion of gravitational lenses.
5 
6  Copyright (C) 2008-2012 Jori Liesenborgs
7 
8  Contact: jori.liesenborgs@gmail.com
9 
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 
24 */
25 
30 #ifndef GRALE_POLYGON2D_H
31 
32 #define GRALE_POLYGON2D_H
33 
34 #include "graleconfig.h"
35 #include "vector2d.h"
36 #include "polygon2d.h"
37 #include "rectangle2d.h"
38 #include "line2d.h"
39 #include "constants.h"
40 #include "Wm5ConvexHull2.h"
41 #include "Wm5ContMinBox2.h"
42 #include <iterator>
43 #include <vector>
44 #include <list>
45 
46 namespace grale
47 {
48 
50 template<class T>
51 class Polygon2D
52 {
53 public:
54  Polygon2D() { m_numCoords = 0; m_isConvexHull = false; }
55  Polygon2D(const Polygon2D<T> &p) { m_numCoords = 0; m_isConvexHull = false; copyFieldsFrom(p); }
56  ~Polygon2D() { }
57 
58  void init(const Vector2D<T> *pPoints, int numPoints, bool calcConvexHull);
59  void init(const std::list<Vector2D<T> > &points, bool calcConvexHull);
60  bool init(Polygon2D<T> &hull, int numPoints);
61  bool isInside(Vector2D<T> p) const;
62  T getDistanceSquared(Vector2D<T> p) const;
63  T getArea() const;
64  bool isConvexHull() const { return m_isConvexHull; }
65  const Vector2D<T> *getPoints() const { return &(m_xyCoords[0]); }
66  int getNumberOfPoints() const { return m_numCoords; }
67  void scale(T scaleFactor);
68 
69  bool getMinimalAreaRectangle(Rectangle2D<T> &r) const;
70 
71  void operator=(const Polygon2D<T> &p) { copyFieldsFrom(p); }
72 private:
73  void copyFieldsFrom(const Polygon2D<T> &p);
74 
75  template<class Iterator> void calculateHull(Iterator startIt, int numPoints);
76  static void calcRectangle(const Line2D<T> supportLines[4], Rectangle2D<T> &rect);
77  inline T calcDist2(Vector2D<T> p1, Vector2D<T> p2, Vector2D<T> P) const;
78 
79  std::vector<Vector2D<T> > m_xyCoords;
80  int m_numCoords;
81  bool m_isConvexHull;
82 };
83 
84 template<class T>
85 inline bool Polygon2D<T>::isInside(Vector2D<T> p) const
86 {
87  T x = p.getX();
88  T y = p.getY();
89  int intersections = 0;
90 
91  for (int i = 0 ; i < m_numCoords ; i++)
92  {
93  T y1 = m_xyCoords[i].getY();
94  T y2 = m_xyCoords[i+1].getY();
95  T Y1 = MIN(m_xyCoords[i].getY(), m_xyCoords[i+1].getY());
96  T Y2 = MAX(m_xyCoords[i].getY(), m_xyCoords[i+1].getY());
97 
98  if (Y1 < y && y <= Y2)
99  {
100  T x1 = m_xyCoords[i].getX();
101  T x2 = m_xyCoords[i+1].getX();
102 
103  if (x <= MAX(x1, x2))
104  {
105  if (x1 == x2)
106  intersections++;
107  else
108  {
109  T x0 = ((y - y1)*(x2 - x1))/(y2 - y1) + x1;
110 
111  if (x <= x0)
112  intersections++;
113  }
114  }
115  }
116  }
117  return (intersections&1)?true:false;
118 }
119 
120 template<class T>
121 inline T Polygon2D<T>::getDistanceSquared(Vector2D<T> p) const
122 {
123  if (m_numCoords == 0)
124  return 0;
125  if (m_numCoords == 1)
126  {
127  Vector2D<T> p2 = m_xyCoords[0];
128  p2 -= p;
129  return p2.getLengthSquared();
130  }
131 
132  T minDist2 = calcDist2(m_xyCoords[0], m_xyCoords[1], p);
133 
134  for (int i = 1 ; i < m_numCoords ; i++)
135  {
136  T d2 = calcDist2(m_xyCoords[i], m_xyCoords[i+1], p);
137 
138  if (d2 < minDist2)
139  minDist2 = d2;
140  }
141  return minDist2;
142 }
143 
144 template<class T>
145 inline T Polygon2D<T>::calcDist2(Vector2D<T> p1, Vector2D<T> p2, Vector2D<T> P) const
146 {
147  Vector2D<T> Q;
148  T dx = p2.getX() - p1.getX();
149  T dy = p2.getY() - p1.getY();
150  T denom = dx*dx + dy*dy;
151 
152  if (denom == 0)
153  Q = p1;
154  else
155  {
156  T l = ((P.getX() - p1.getX())*dx + (P.getY() - p1.getY())*dy)/denom;
157 
158  if (l <= 0)
159  Q = p1;
160  else if (l >= 1)
161  Q = p2;
162  else
163  Q = Vector2D<T>(p1.getX() + l*dx, p1.getY() + l*dy);
164  }
165 
166  Q -= P;
167  return Q.getLengthSquared();
168 }
169 
170 template<class T>
171 inline void Polygon2D<T>::copyFieldsFrom(const Polygon2D<T> &p)
172 {
173  m_numCoords = p.m_numCoords;
174  m_isConvexHull = p.m_isConvexHull;
175  m_xyCoords = p.m_xyCoords;
176 }
177 
178 template<class T>
179 inline T Polygon2D<T>::getArea() const
180 {
181  T area = 0;
182 
183  for (int i = 0 ; i < m_numCoords ; i++)
184  {
185  T areaPart = m_xyCoords[i].getX()*m_xyCoords[i+1].getY() - m_xyCoords[i+1].getX()*m_xyCoords[i].getY();
186 
187  area += areaPart;
188  }
189 
190  area /= (T)2;
191 
192  return area;
193 }
194 
195 template<class T>
196 inline void Polygon2D<T>::scale(T scaleFactor)
197 {
198 #if 0
199  Vector2D<T> center(0, 0);
200  for (int i = 0 ; i < m_numCoords ; i++)
201  center += m_pXYCoords[i];
202  center /= (T)m_numCoords;
203 #else
204 
205  T area = 0;
206  T cx = 0;
207  T cy = 0;
208 
209  for (int i = 0 ; i < m_numCoords ; i++)
210  {
211  T areaPart = m_xyCoords[i].getX()*m_xyCoords[i+1].getY() - m_xyCoords[i+1].getX()*m_xyCoords[i].getY();
212 
213  area += areaPart;
214  cx += (m_xyCoords[i].getX() + m_xyCoords[i+1].getX())*areaPart;
215  cy += (m_xyCoords[i].getY() + m_xyCoords[i+1].getY())*areaPart;
216 
217  }
218 
219  area /= (T)2;
220  cx /= area*(T)6;
221  cy /= area*(T)6;
222 
223  Vector2D<T> center(cx, cy);
224 
225  for (int i = 0 ; i < m_numCoords ; i++)
226  {
227  Vector2D<T> diff = m_xyCoords[i] - center;
228  diff *= scaleFactor;
229  m_xyCoords[i] = center + diff;
230  }
231 #endif
232 }
233 
234 template<class T>
235 void Polygon2D<T>::init(const Vector2D<T> *pPoints, int numPoints, bool calcConvexHull)
236 {
237  if (numPoints == 0)
238  {
239  m_numCoords = 0;
240  m_isConvexHull = false;
241  m_xyCoords.resize(0);
242  return;
243  }
244 
245  if (calcConvexHull)
246  {
247  if (numPoints <= 3)
248  init(pPoints, numPoints, false);
249  else
250  calculateHull(pPoints, numPoints);
251  m_isConvexHull = true;
252  return;
253  }
254 
255  m_isConvexHull = false;
256 
257  m_xyCoords.resize(numPoints+1);
258  m_numCoords = numPoints;
259 
260  const Vector2D<T> *pPtr;
261  int i;
262 
263  pPtr = pPoints;
264 
265  m_xyCoords[m_numCoords] = *pPtr;
266  for (i = 0 ; i < m_numCoords ; pPtr++, i++)
267  m_xyCoords[i] = *pPtr;
268 }
269 
270 template<class T>
271 void Polygon2D<T>::init(const std::list<Vector2D<T> > &points, bool calcConvexHull)
272 {
273  if (points.size() == 0)
274  {
275  m_numCoords = 0;
276  m_isConvexHull = false;
277  m_xyCoords.resize(0);
278  return;
279  }
280 
281  if (calcConvexHull)
282  {
283  if (points.size() <= 3)
284  init(points, false);
285  else
286  calculateHull(points.begin(), points.size());
287  m_isConvexHull = true;
288  return;
289  }
290 
291  m_isConvexHull = false;
292 
293  m_xyCoords.resize(points.size() + 1);
294  m_numCoords = points.size();
295 
296  typename std::list< Vector2D<T> >::const_iterator it;
297  int i;
298 
299  it = points.begin();
300 
301  m_xyCoords[m_numCoords] = (*it);
302  for (i = 0 ; i < m_numCoords ; it++, i++)
303  m_xyCoords[i] = (*it);
304 }
305 
306 template<class T>
307 template<class Iterator>
308 void Polygon2D<T>::calculateHull(Iterator startIt, int numPoints)
309 {
310  std::vector<Wm5::Vector2<T> > points(numPoints);
311 
312  Iterator it = startIt;
313 
314  for (int i = 0 ; i < numPoints ; i++, it++)
315  points[i] = Wm5::Vector2<T>((*it).getX(), (*it).getY());
316 
317  m_xyCoords.resize(0);
318 
319  Wm5::ConvexHull2<T> hull(numPoints, &(points[0]), 0, false, Wm5::Query::QT_INTEGER);
320 
321  int numIndices = hull.GetNumSimplices();
322  const int *pIndices = hull.GetIndices();
323 
324  m_numCoords = numIndices;
325  m_xyCoords.resize(m_numCoords+1);
326 
327  m_xyCoords[m_numCoords] = Vector2D<T>(points[pIndices[0]].X(), points[pIndices[0]].Y());
328  for (int i = 0 ; i < m_numCoords ; i++)
329  m_xyCoords[i] = Vector2D<T>(points[pIndices[i]].X(), points[pIndices[i]].Y());
330 }
331 
332 template<class T>
333 bool Polygon2D<T>::getMinimalAreaRectangle(Rectangle2D<T> &r) const
334 {
335  if (!m_isConvexHull || m_numCoords < 3)
336  return false;
337 
338  std::vector<Wm5::Vector2<T> > points(m_numCoords);
339 
340  for (int i = 0 ; i < m_numCoords ; i++)
341  points[i] = Wm5::Vector2<T>(m_xyCoords[i].getX(), m_xyCoords[i].getY());
342 
343  Wm5::MinBox2<T> box(m_numCoords, &(points[0]), 0, Wm5::Query::QT_INTEGER, true);
344  Wm5::Vector2<T> rectPoints[4];
345 
346  Wm5::Box2<T> rectBox = box;
347  rectBox.ComputeVertices(rectPoints);
348 
349  Vector2D<T> graleRectPoints[4];
350 
351  graleRectPoints[0] = Vector2D<T>(rectPoints[0].X(), rectPoints[0].Y());
352  graleRectPoints[1] = Vector2D<T>(rectPoints[1].X(), rectPoints[1].Y());
353  graleRectPoints[2] = Vector2D<T>(rectPoints[2].X(), rectPoints[2].Y());
354  graleRectPoints[3] = Vector2D<T>(rectPoints[3].X(), rectPoints[3].Y());
355  r.init(graleRectPoints);
356  return true;
357 }
358 
359 } // end namespace
360 
361 #endif // GRALE_POLYGON2D_H
362