VPTissue Reference Manual
ChainHull.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "ChainHull.h"
21 #include <algorithm>
22 
23 namespace {
25 
34  inline float isLeft(ChainHull::Point P0, ChainHull::Point P1, ChainHull::Point P2)
35  {
36  return (P1.GetX() - P0.GetX())*(P2.GetY() - P0.GetY()) - (P2.GetX() - P0.GetX())*(P1.GetY() - P0.GetY());
37  }
38 }
39 
40 namespace SimPT_Sim {
41 
42 std::vector<std::array<double, 2> > ChainHull::Compute(const std::vector<std::array<double, 2> >& polygon)
43 {
44  // Step 1: Prepare data for 2D hull code - get boundary polygon
45  int pc = 0;
46  Point* p = new Point[polygon.size() + 1];
47  for (auto const& vertex : polygon) {
48  p[pc++] = Point(vertex[0], vertex[1]);
49  }
50 
51  // chainHull algorithm requires sorted points
52  std::sort(p, p + pc);
53 
54  // Step 2: Call 2D hull code
55  int np = polygon.size();
56  Point* hull = new Point[np + 1];
57  int nph = chainHull_2D(p, np, hull);
58 
59  // Step 3: Convert hull array to vector
60  std::vector<std::array<double, 2> > result;
61  for (int i = 0; i < nph - 1; i++) {
62  result.push_back({ {hull[i].GetX(), hull[i].GetY()} });
63  }
64 
65  delete[] p;
66  delete[] hull;
67 
68  return result;
69 }
70 
71 // required to sort points (e.g. Qt's qSort())
72 bool operator<(ChainHull::Point const& p1, ChainHull::Point const& p2)
73 {
74  bool smaller = true;
75  if (p1.GetY() < p2.GetY()) {
76  smaller = true;
77  } else if (p1.GetY() > p2.GetY()) {
78  smaller = false;
79  } else if (p1.GetX() < p2.GetX()) {
80  smaller = true;
81  } else {
82  smaller = false;
83  }
84  return smaller;
85 }
86 
87 int ChainHull::chainHull_2D(Point* P, int n, Point* H)
88 {
89  // the output array H[] will be used as the stack
90  int bot = 0;
91  int top = (-1); // indices for bottom and top of the stack
92  int i; // array scan index
93 
94  // Get the indices of points with min x-coord and min|max y-coord
95  int minmin = 0;
96  int minmax;
97  float xmin = P[0].GetX();
98  for (i = 1; i < n; i++) {
99  if (P[i].GetX() != xmin) {
100  break;
101  }
102  }
103  minmax = i - 1;
104  if (minmax == n - 1) { // degenerate case: all x-coords == xmin
105  H[++top] = P[minmin];
106  if (P[minmax].GetY() != P[minmin].GetY()) { // a nontrivial segment
107  H[++top] = P[minmax];
108  }
109  H[++top] = P[minmin]; // add polygon endpoint
110  return top + 1;
111  }
112 
113  // Get the indices of points with max x-coord and min|max y-coord
114  int maxmin;
115  int maxmax = n - 1;
116  float xmax = P[n - 1].GetX();
117  for (i = n - 2; i >= 0; i--) {
118  if (P[i].GetX() != xmax) {
119  break;
120  }
121  }
122  maxmin = i + 1;
123 
124  // Compute the lower hull on the stack H
125  H[++top] = P[minmin]; // push minmin point onto stack
126  i = minmax;
127  while (++i <= maxmin) {
128  // the lower line joins P[minmin] with P[maxmin]
129  if (isLeft(P[minmin], P[maxmin], P[i]) >= 0 && i < maxmin) {
130  continue; // ignore P[i] above or on the lower line
131  }
132  while (top > 0) // there are at least 2 points on the stack
133  {
134  // test if P[i] is left of the line at the stack top
135  if (isLeft(H[top - 1], H[top], P[i]) > 0)
136  break; // P[i] is a new hull vertex
137  else
138  top--; // pop top point off stack
139  }
140  H[++top] = P[i]; // push P[i] onto stack
141  }
142 
143  // Next, compute upper hull on stack H above bottom hull
144  if (maxmax != maxmin) { // if distinct xmax points
145  H[++top] = P[maxmax]; // push maxmax point onto stack
146  }
147  bot = top; // the bottom point of the upper hull stack
148  i = maxmin;
149  while (--i >= minmax) {
150  // the upper line joins P[maxmax] with P[minmax]
151  if (isLeft(P[maxmax], P[minmax], P[i]) >= 0 && i > minmax) {
152  continue; // ignore P[i] below or on the upper line
153  }
154  while (top > bot) // at least 2 points on the upper stack
155  {
156  // test if P[i] is left of the line at the stack top
157  if (isLeft(H[top - 1], H[top], P[i]) > 0)
158  break; // P[i] is a new hull vertex
159  else
160  top--; // pop top point off stack
161  }
162  H[++top] = P[i]; // push P[i] onto stack
163  }
164  if (minmax != minmin) {
165  H[++top] = P[minmin]; // push joining endpoint onto stack
166  }
167 
168  return top + 1;
169 }
170 
171 } // namespace
Point class needed by 2D convex hull code.
Definition: ChainHull.h:38
Interface for ChainHull.
Compute the convex hull of a set of two-dimensional points.
Definition: ChainHull.h:30
bool operator<(ChainHull::Point const &p1, ChainHull::Point const &p2)
Required to sort points (e.g.
Definition: ChainHull.cpp:72
Namespace for the core simulator.