Virtual Testbed
Ship dynamics simulator for extreme conditions
polyline.cc
1 #include <algorithm>
2 
3 #include <vtestbed/config/real_type.hh>
4 #include <vtestbed/geometry/inertia_tensor.hh>
5 #include <vtestbed/geometry/line_segment.hh>
6 #include <vtestbed/geometry/math.hh>
7 #include <vtestbed/geometry/polygon.hh>
8 #include <vtestbed/geometry/polyline.hh>
9 
10 namespace {
11 
12  template <class T, int N>
13  inline bool
14  fully_contains(
17  T eps
18  ) {
19  return (lhs.contains(rhs.front(), eps) && lhs.contains(rhs.back(), eps));
20  }
21 
22 }
23 
24 template <class T, int N>
25 void
27  T eps = 0;
28  auto& segments = *this;
29  auto n = segments.size();
30  std::vector<bool> mask(n);
31  for (size_type i=0; i<n; ++i) {
32  for (size_type j=i+1; j<n; ++j) {
33  const auto& s1 = segments[i];
34  const auto& s2 = segments[j];
35  auto s3 = s2;
36  s3.invert();
37  if (near(s1,s2,eps) || near(s1,s3,eps) /*||
38  fully_contains(s1,s2,eps) || fully_contains(s2,s1,eps)*/) {
39  mask[i] = true, mask[j] = true;
40  }
41  }
42  }
43  for (size_type i=n; i>0; --i) {
44  size_type j=i-1;
45  if (mask[j]) {
46  segments.erase(segments.begin()+j);
47  }
48  }
49 }
50 
51 template <class T, int N>
52 void
54  T eps = 1e-3;
55  auto& segments = *this;
56  auto n = segments.size();
57 start:
58  for (size_type i=0; i<n; ++i) {
59  for (size_type j=0; j<n; ++j) {
60  if (i == j) { continue; }
61  auto& s1 = segments[i];
62  const auto& s2 = segments[j];
63  if (near(s1.back(), s2.front(), eps) &&
64  Line_segment<T,N>(s1.front(), s2.back()).contains(s1.back(), eps)) {
65  s1.back() = s2.back();
66  segments.erase(segments.begin()+j);
67  --n;
68  goto start;
69  }
70  }
71  }
72 }
73 
74 template <class T, int N>
75 void
77  T eps = 1e-3;
78  auto& segments = *this;
79  auto n = segments.size();
80  if (n <= 3) { return; }
81  // top right vertex
82  auto p0 = std::max_element(
83  segments.begin(), segments.end(),
84  [] (const_reference lhs, const_reference rhs) {
86  return cmp(lhs.front(), rhs.front());
87  }
88  )->front();
89  Polyline<T,N> convex_hull;
90  for (const auto& s : segments) {
91  std::clog << "near(s.front(), s.back(), eps)=" << near(s.front(), s.back(), eps) << std::endl;
92  }
93  do {
94  bool found = false;
95  value_type candidate, orig;
96  scalar_type diff = 0;
97  size_type idx = 0;
98  std::clog << "convex_hull.size()=" << convex_hull.size() << std::endl;
99  for (size_type i=0; i<n; ++i) {
100  const auto& s = segments[i];
101  if (near(p0, s.front(), eps)) {
102  if (!found) {
103  candidate = s;
104  orig = s;
105  diff = 0;
106  idx = i;
107  found = true;
108  } else {
109  Vertex<T,N> v1 = s.back() - p0;
110  Vertex<T,N> v2 = candidate.back() - p0;
111  //auto cp = cross(v1,v2);
112  //if (all(cp > T{})) {
113  auto x0 = p0(0);
114  auto y0 = p0(1);
115  auto x1 = s.back()(0);
116  auto y1 = s.back()(1);
117  auto x2 = candidate.back()(0);
118  auto y2 = candidate.back()(1);
119  auto x3 = orig.back()(0);
120  auto y3 = orig.back()(1);
121  auto lhs = x2*y0 + x0*y1 + x1*y2;
122  auto rhs = x1*y0 + x2*y1 + x0*y2;
123  auto lhs2 = x3*y0 + x0*y1 + x1*y3;
124  auto rhs2 = x1*y0 + x3*y1 + x0*y3;
125  std::clog << "(lhs-rhs)=" << (lhs-rhs) << std::endl;
126  std::clog << "(lhs2-rhs2)=" << (lhs2-rhs2) << std::endl;
127  if (lhs2-rhs2 > diff) {
128  candidate = s;
129  idx = i;
130  diff = lhs2-rhs2;
131  }
132  }
133  }
134  }
135  std::clog << "candidate=" << candidate << std::endl;
136  convex_hull.emplace_back(candidate);
137  segments.erase(segments.begin()+idx);
138  p0 = candidate.back();
139  } while (!segments.empty() &&
140  !near(convex_hull.front().front(), convex_hull.back().back(), eps));
141  segments = std::move(convex_hull);
142 }
143 
144 template <>
145 void
147  using T = VTB_REAL_TYPE;
148  Vertex<T,2> origin{T{}};
149  for (const auto& segment : *this) {
150  origin += segment[0];
151  origin += segment[1];
152  }
153  origin /= 2*this->size();
154  for (auto& segment : *this) {
155  auto d = det(origin, segment[0], segment[1]);
156  if (d < 0) { segment.flip(); }
157  }
158 }
159 
160 template <class T, int N>
161 void
163  auto& segments = *this;
164  const auto n = segments.size();
165  if (n <= 1) { return; }
166  for (size_t i=0; i<n; ++i) {
167  const auto& back = segments[i].back();
168  for (size_t j=i+1; j<n; ++j) {
169  const auto& front = segments[j].front();
170  if (all(front == back)) {
171  if (j != i+1) { std::swap(segments[i+1], segments[j]); }
172  break;
173  }
174  }
175  }
176 }
177 
178 template <class T, int N>
181  Polygon<T,N> result;
182  for (const auto& segment : *this) {
183  result.emplace_back(segment.front());
184  }
185  return result;
186 }
187 
188 template <class T, int N>
189 void
191  for (const auto& segment : *this) { segment.gnuplot(out); out << "\n\n"; }
192 }
193 
194 template <class T, int N>
196 vtb::geometry::mass_moments(const Polyline<T,N>& polyline) {
197  static const T mult[6] = {
198  T{1}/T{2},
199  T{1}/T{6}, T{1}/T{6},
200  T{1}/T{12}, T{1}/T{12},
201  T{1}/T{24}
202  };
203  T intg[6] = {}; // 1, x, y, x^2, y^2, xy
204  for (const auto& segment : polyline) {
205  const auto& v0 = segment.front();
206  const auto& v1 = segment.back();
207  auto x0 = v0(0), y0 = v0(1), x1 = v1(0), y1 = v1(1);
208  auto x0y1 = x0*y1, y0x1 = y0*x1;
209  auto cp = x0y1 - y0x1;
210  intg[0] += cp;
211  intg[1] += cp*(x0 + x1);
212  intg[2] += cp*(y0 + y1);
213  intg[3] += cp*(y0*y0 + y0*y1 + y1*y1);
214  intg[4] += cp*(x0*x0 + x0*x1 + x1*x1);
215  intg[5] += cp*(x0y1 + 2*x0*y0 + 2*x1*y1 + y0x1);
216  }
217  for (int i=0; i<6; ++i) { intg[i] *= mult[i]; }
218  Mass_moments<T,N> m;
219  m.mass = intg[0];
220  m.centre(0) = intg[1], m.centre(1) = intg[2];
221  if (m.mass != 0) { m.centre /= m.mass; }
222  auto& cm = m.centre;
223  m.inertia.xx = intg[3] - m.mass*cm(0)*cm(0);
224  m.inertia.yy = intg[4] - m.mass*cm(1)*cm(1);
225  m.inertia.xy = intg[5] - m.mass*cm(0)*cm(1);
226  return m;
227 }
228 
231 
233 vtb::geometry::mass_moments(const Polyline<VTB_REAL_TYPE,2>& polygon);
Mass_moments< T, N > mass_moments(const Polyline< T, N > &polyline)
Calculate area, centroid and inertia tensor.
A polygon composed of line segments.
Definition: polyline.hh:20
void gift_wrap()
Convex hull.
Definition: polyline.cc:76