Polygon.cpp
Go to the documentation of this file.
1 /*
2  * Polygon.cpp
3  *
4  * Created on: Nov 7, 2014
5  * Author: Péter Fankhauser
6  * Institute: ETH Zurich, ANYbotics
7  */
8 
10 
11 #include <Eigen/Core>
12 #include <Eigen/Geometry>
13 
14 #include <limits>
15 #include <algorithm>
16 
17 namespace grid_map {
18 
20  : timestamp_(0)
21 {
22 }
23 
24 Polygon::Polygon(std::vector<Position> vertices)
25  : Polygon()
26 {
27  vertices_ = vertices;
28 }
29 
30 bool Polygon::isInside(const Position& point) const
31 {
32  int cross = 0;
33  for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
34  if ( ((vertices_[i].y() > point.y()) != (vertices_[j].y() > point.y()))
35  && (point.x() < (vertices_[j].x() - vertices_[i].x()) * (point.y() - vertices_[i].y()) /
36  (vertices_[j].y() - vertices_[i].y()) + vertices_[i].x()) )
37  {
38  cross++;
39  }
40  }
41  return bool(cross % 2);
42 }
43 
44 void Polygon::addVertex(const Position& vertex)
45 {
46  vertices_.push_back(vertex);
47 }
48 
49 const Position& Polygon::getVertex(const size_t index) const
50 {
51  return vertices_.at(index);
52 }
53 
55 {
56  vertices_.clear();
57 }
58 
59 const Position& Polygon::operator [](const size_t index) const
60 {
61  return getVertex(index);
62 }
63 
64 const std::vector<Position>& Polygon::getVertices() const
65 {
66  return vertices_;
67 }
68 
69 size_t Polygon::nVertices() const
70 {
71  return vertices_.size();
72 }
73 
74 const std::string& Polygon::getFrameId() const
75 {
76  return frameId_;
77 }
78 
79 void Polygon::setFrameId(const std::string& frameId)
80 {
81  frameId_ = frameId;
82 }
83 
84 uint64_t Polygon::getTimestamp() const
85 {
86  return timestamp_;
87 }
88 
89 void Polygon::setTimestamp(const uint64_t timestamp)
90 {
91  timestamp_ = timestamp;
92 }
93 
95 {
96  timestamp_ = 0.0;
97 }
98 
99 double Polygon::getArea() const
100 {
101  double area = 0.0;
102  int j = vertices_.size() - 1;
103  for (size_t i = 0; i < vertices_.size(); i++) {
104  area += (vertices_.at(j).x() + vertices_.at(i).x())
105  * (vertices_.at(j).y() - vertices_.at(i).y());
106  j = i;
107  }
108  return std::abs(area / 2.0);
109 }
110 
112 {
113  Position centroid = Position::Zero();
114  std::vector<Position> vertices = getVertices();
115  vertices.push_back(vertices.at(0));
116  double area = 0.0;
117  for (size_t i = 0; i < vertices.size() - 1; i++) {
118  const double a = vertices[i].x() * vertices[i+1].y() - vertices[i+1].x() * vertices[i].y();
119  area += a;
120  centroid.x() += a * (vertices[i].x() + vertices[i+1].x());
121  centroid.y() += a * (vertices[i].y() + vertices[i+1].y());
122  }
123  area *= 0.5;
124  centroid /= (6.0 * area);
125  return centroid;
126 }
127 
128 void Polygon::getBoundingBox(Position& center, Length& length) const
129 {
130  double minX = std::numeric_limits<double>::infinity();
131  double maxX = -std::numeric_limits<double>::infinity();
132  double minY = std::numeric_limits<double>::infinity();
133  double maxY = -std::numeric_limits<double>::infinity();
134  for (const auto& vertex : vertices_) {
135  if (vertex.x() > maxX) maxX = vertex.x();
136  if (vertex.y() > maxY) maxY = vertex.y();
137  if (vertex.x() < minX) minX = vertex.x();
138  if (vertex.y() < minY) minY = vertex.y();
139  }
140  center.x() = (minX + maxX) / 2.0;
141  center.y() = (minY + maxY) / 2.0;
142  length.x() = (maxX - minX);
143  length.y() = (maxY - minY);
144 }
145 
146 bool Polygon::convertToInequalityConstraints(Eigen::MatrixXd& A, Eigen::VectorXd& b) const
147 {
148  Eigen::MatrixXd V(nVertices(), 2);
149  for (unsigned int i = 0; i < nVertices(); ++i)
150  V.row(i) = vertices_[i];
151 
152  // Create k, a list of indices from V forming the convex hull.
153  // TODO: Assuming counter-clockwise ordered convex polygon.
154  // MATLAB: k = convhulln(V);
155  Eigen::MatrixXi k;
156  k.resizeLike(V);
157  for (unsigned int i = 0; i < V.rows(); ++i)
158  k.row(i) << i, (i+1) % V.rows();
159  Eigen::RowVectorXd c = V.colwise().mean();
160  V.rowwise() -= c;
161  A = Eigen::MatrixXd::Constant(k.rows(), V.cols(), NAN);
162 
163  unsigned int rc = 0;
164  for (unsigned int ix = 0; ix < k.rows(); ++ix) {
165  Eigen::MatrixXd F(2, V.cols());
166  F.row(0) << V.row(k(ix, 0));
167  F.row(1) << V.row(k(ix, 1));
168  Eigen::FullPivLU<Eigen::MatrixXd> luDecomp(F);
169  if (luDecomp.rank() == F.rows()) {
170  A.row(rc) = F.colPivHouseholderQr().solve(Eigen::VectorXd::Ones(F.rows()));
171  ++rc;
172  }
173  }
174 
175  A = A.topRows(rc);
176  b = Eigen::VectorXd::Ones(A.rows());
177  b = b + A * c.transpose();
178 
179  return true;
180 }
181 
182 bool Polygon::thickenLine(const double thickness)
183 {
184  if (vertices_.size() != 2) return false;
185  const Vector connection(vertices_[1] - vertices_[0]);
186  const Vector orthogonal = thickness * Vector(connection.y(), -connection.x()).normalized();
187  std::vector<Position> newVertices;
188  newVertices.reserve(4);
189  newVertices.push_back(vertices_[0] + orthogonal);
190  newVertices.push_back(vertices_[0] - orthogonal);
191  newVertices.push_back(vertices_[1] - orthogonal);
192  newVertices.push_back(vertices_[1] + orthogonal);
193  vertices_ = newVertices;
194  return true;
195 }
196 
197 bool Polygon::offsetInward(const double margin)
198 {
199  // Create a list of indices of the neighbours of each vertex.
200  // TODO: Assuming counter-clockwise ordered convex polygon.
201  std::vector<Eigen::Array2i> neighbourIndices;
202  const unsigned int n = nVertices();
203  neighbourIndices.resize(n);
204  for (unsigned int i = 0; i < n; ++i) {
205  neighbourIndices[i] << (i > 0 ? (i-1)%n : n-1), (i + 1) % n;
206  }
207 
208  std::vector<Position> copy(vertices_);
209  for (unsigned int i = 0; i < neighbourIndices.size(); ++i) {
210  Eigen::Vector2d v1 = vertices_[neighbourIndices[i](0)] - vertices_[i];
211  Eigen::Vector2d v2 = vertices_[neighbourIndices[i](1)] - vertices_[i];
212  v1.normalize();
213  v2.normalize();
214  const double angle = acos(v1.dot(v2));
215  copy[i] += margin / sin(angle) * (v1 + v2);
216  }
217  vertices_ = copy;
218  return true;
219 }
220 
221 std::vector<Polygon> Polygon::triangulate(const TriangulationMethods& /*method*/) const
222 {
223  // TODO Add more triangulation methods.
224  // https://en.wikipedia.org/wiki/Polygon_triangulation
225  std::vector<Polygon> polygons;
226  if (vertices_.size() < 3)
227  return polygons;
228 
229  size_t nPolygons = vertices_.size() - 2;
230  polygons.reserve(nPolygons);
231 
232  if (nPolygons < 1) {
233  // Special case.
234  polygons.push_back(*this);
235  } else {
236  // General case.
237  for (size_t i = 0; i < nPolygons; ++i) {
238  Polygon polygon({vertices_[0], vertices_[i + 1], vertices_[i + 2]});
239  polygons.push_back((polygon));
240  }
241  }
242 
243  return polygons;
244 }
245 
246 Polygon Polygon::fromCircle(const Position center, const double radius,
247  const int nVertices)
248 {
249  Eigen::Vector2d centerToVertex(radius, 0.0), centerToVertexTemp;
250 
251  Polygon polygon;
252  for (int j = 0; j < nVertices; j++) {
253  double theta = j * 2 * M_PI / (nVertices - 1);
254  Eigen::Rotation2D<double> rot2d(theta);
255  centerToVertexTemp = rot2d.toRotationMatrix() * centerToVertex;
256  polygon.addVertex(center + centerToVertexTemp);
257  }
258  return polygon;
259 }
260 
262  const Position center2, const double radius,
263  const int nVertices)
264 {
265  if (center1 == center2) return fromCircle(center1, radius, nVertices);
266  Eigen::Vector2d centerToVertex, centerToVertexTemp;
267  centerToVertex = center2 - center1;
268  centerToVertex.normalize();
269  centerToVertex *= radius;
270 
271  grid_map::Polygon polygon;
272  for (int j = 0; j < ceil(nVertices / 2.0); j++) {
273  double theta = M_PI_2 + j * M_PI / (ceil(nVertices / 2.0) - 1);
274  Eigen::Rotation2D<double> rot2d(theta);
275  centerToVertexTemp = rot2d.toRotationMatrix() * centerToVertex;
276  polygon.addVertex(center1 + centerToVertexTemp);
277  }
278  for (int j = 0; j < ceil(nVertices / 2.0); j++) {
279  double theta = 3 * M_PI_2 + j * M_PI / (ceil(nVertices / 2.0) - 1);
280  Eigen::Rotation2D<double> rot2d(theta);
281  centerToVertexTemp = rot2d.toRotationMatrix() * centerToVertex;
282  polygon.addVertex(center2 + centerToVertexTemp);
283  }
284  return polygon;
285 }
286 
288 {
289  std::vector<Position> vertices;
290  vertices.reserve(polygon1.nVertices() + polygon2.nVertices());
291  vertices.insert(vertices.end(), polygon1.getVertices().begin(), polygon1.getVertices().end());
292  vertices.insert(vertices.end(), polygon2.getVertices().begin(), polygon2.getVertices().end());
293 
294  return monotoneChainConvexHullOfPoints(vertices);
295 }
296 
297 Polygon Polygon::monotoneChainConvexHullOfPoints(const std::vector<Position>& points)
298 {
299  // Adapted from https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
300  if (points.size() <= 3) {
301  return Polygon(points);
302  }
303  std::vector<Position> pointsConvexHull(2 * points.size());
304 
305  // Sort points lexicographically.
306  auto sortedPoints(points);
307  std::sort(sortedPoints.begin(), sortedPoints.end(), sortVertices);
308 
309 
310  int k = 0;
311  // Build lower hull
312  for (size_t i = 0; i < sortedPoints.size(); ++i) {
313  while (k >= 2 && vectorsMakeClockwiseTurn(pointsConvexHull.at(k - 2), pointsConvexHull.at(k - 1), sortedPoints.at(i))) {
314  k--;
315  }
316  pointsConvexHull.at(k++) = sortedPoints.at(i);
317  }
318 
319  // Build upper hull.
320  for (int i = sortedPoints.size() - 2, t = k + 1; i >= 0; i--) {
321  while (k >= t && vectorsMakeClockwiseTurn(pointsConvexHull.at(k - 2), pointsConvexHull.at(k - 1), sortedPoints.at(i))) {
322  k--;
323  }
324  pointsConvexHull.at(k++) = sortedPoints.at(i);
325  }
326  pointsConvexHull.resize(k - 1);
327 
328  Polygon polygon(pointsConvexHull);
329  return polygon;
330 }
331 
332 bool Polygon::sortVertices(const Eigen::Vector2d& vector1,
333  const Eigen::Vector2d& vector2)
334 {
335  return (vector1.x() < vector2.x()
336  || (vector1.x() == vector2.x() && vector1.y() < vector2.y()));
337 }
338 
339 double Polygon::computeCrossProduct2D(const Eigen::Vector2d& vector1,
340  const Eigen::Vector2d& vector2)
341 {
342  return (vector1.x() * vector2.y() - vector1.y() * vector2.x());
343 }
344 
345 double Polygon::vectorsMakeClockwiseTurn(const Eigen::Vector2d &pointOrigin,
346  const Eigen::Vector2d &pointA,
347  const Eigen::Vector2d &pointB)
348 {
349  return computeCrossProduct2D(pointA - pointOrigin, pointB - pointOrigin) <= 0;
350 }
351 
352 } /* namespace grid_map */
const std::string & getFrameId() const
Definition: Polygon.cpp:74
static Polygon convexHullOfTwoCircles(Position center1, Position center2, double radius, int nVertices=20)
Definition: Polygon.cpp:261
const Position & operator[](size_t index) const
Definition: Polygon.cpp:59
size_t nVertices() const
Definition: Polygon.cpp:69
static double computeCrossProduct2D(const Eigen::Vector2d &vector1, const Eigen::Vector2d &vector2)
Definition: Polygon.cpp:339
Position getCentroid() const
Definition: Polygon.cpp:111
static Polygon monotoneChainConvexHullOfPoints(const std::vector< Position > &points)
Definition: Polygon.cpp:297
void setTimestamp(uint64_t timestamp)
Definition: Polygon.cpp:89
uint64_t timestamp_
Timestamp of the polygon (nanoseconds).
Definition: Polygon.hpp:240
void resetTimestamp()
Definition: Polygon.cpp:94
Eigen::Vector2d Position
Definition: TypeDefs.hpp:18
void removeVertices()
Definition: Polygon.cpp:54
const Position & getVertex(size_t index) const
Definition: Polygon.cpp:49
std::string frameId_
Frame id of the polygon.
Definition: Polygon.hpp:237
void addVertex(const Position &vertex)
Definition: Polygon.cpp:44
Eigen::Array2d Length
Definition: TypeDefs.hpp:24
static Polygon fromCircle(Position center, double radius, int nVertices=20)
Definition: Polygon.cpp:246
bool offsetInward(double margin)
Definition: Polygon.cpp:197
bool isInside(const Position &point) const
Definition: Polygon.cpp:30
std::vector< Position > vertices_
Vertices of the polygon.
Definition: Polygon.hpp:243
std::vector< Polygon > triangulate(const TriangulationMethods &method=TriangulationMethods::FAN) const
Definition: Polygon.cpp:221
static Polygon convexHull(Polygon &polygon1, Polygon &polygon2)
Definition: Polygon.cpp:287
static bool sortVertices(const Eigen::Vector2d &vector1, const Eigen::Vector2d &vector2)
Definition: Polygon.cpp:332
static double vectorsMakeClockwiseTurn(const Eigen::Vector2d &pointO, const Eigen::Vector2d &pointA, const Eigen::Vector2d &pointB)
Definition: Polygon.cpp:345
void setFrameId(const std::string &frameId)
Definition: Polygon.cpp:79
bool thickenLine(double thickness)
Definition: Polygon.cpp:182
uint64_t getTimestamp() const
Definition: Polygon.cpp:84
bool convertToInequalityConstraints(Eigen::MatrixXd &A, Eigen::VectorXd &b) const
Definition: Polygon.cpp:146
const std::vector< Position > & getVertices() const
Definition: Polygon.cpp:64
void getBoundingBox(Position &center, Length &length) const
Definition: Polygon.cpp:128
Eigen::Vector2d Vector
Definition: TypeDefs.hpp:19
double getArea() const
Definition: Polygon.cpp:99


grid_map_core
Author(s): Péter Fankhauser
autogenerated on Wed Jul 5 2023 02:23:35