triangulate.hh
Go to the documentation of this file.
1 /* -*- mia-c++ -*-
2  *
3  * This file is part of MIA - a toolbox for medical image analysis
4  * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
5  *
6  * MIA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with MIA; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include <mia/mesh/clist.hh>
22 #include <mia/core/msgstream.hh>
23 #include <iostream>
24 
26 
37 template <class VertexVector, class Polygon>
39 public:
44  TPolyTriangulator(const VertexVector& vv);
45 
55  template <class TriangleList>
56  bool triangulate(TriangleList& output, const Polygon& poly) const;
57 
58 private:
60  typedef typename VertexVector::value_type Vector;
61 
62  Vector eval_orientation(const Polygon& poly) const;
63  bool is_convex(const typename CPoly::const_iterator& i, bool debug = false) const;
64  bool is_ear(const typename CPoly::const_iterator& p, const CPoly& cpoly, bool debug = false) const;
65 
66  bool is_inside(
67  const typename VertexVector::value_type& a,
68  const typename VertexVector::value_type& b,
69  const typename VertexVector::value_type& c,
70  const typename VertexVector::value_type& p,
71  bool debug = false ) const;
72 
73 
74  const VertexVector& m_vv;
75  mutable Vector m_orientation;
76 };
77 
78 template <class VertexVector, class Polygon>
80  m_vv(vv)
81 {
82 }
83 
84 template <class VertexVector, class Polygon>
85 template <class TriangleList>
86 bool
87 TPolyTriangulator<VertexVector,Polygon>::triangulate(TriangleList& output, const Polygon& poly) const
88 {
89  size_t poly_size = poly.size();
90 
91  if ( poly_size < 3) // no triangles at all
92  return false;
93 
95 
96  CPoly cpoly;
97 
98  m_orientation = eval_orientation(poly);
99 
100  typename Polygon::const_iterator pi = poly.begin();
101  typename Polygon::const_iterator pe = poly.end();
102 
103  while (pi != pe)
104  cpoly.push_back(*pi++);
105 
106  typename CPoly::iterator p_i = cpoly.begin();
107  typename CPoly::iterator p_e = cpoly.end();
108 
109  p_i = p_i->succ;
110 
111  while ( (p_i != p_e) && (poly_size > 3)) {
112  if (is_ear(p_i, cpoly, false)) {
113  // we have a valid triangle, store it
114  output.push_back(typename TriangleList::value_type(**p_i->succ, **p_i, **p_i->prev));
115 
116  // set the current middle node
117  typename CPoly::iterator p_r = p_i;
118  p_i = (p_i->prev != cpoly.begin()) ? p_i->prev : p_i->succ;
119 
120  cpoly.remove(p_r);
121  --poly_size;
122  }else
123  p_i = p_i->succ;
124  }
125 
126  if ((p_i == p_e) && (poly_size > 3)) {
127  cvdebug() <<"gotcha\n";
128 
129  p_i = cpoly.begin();
130 
131  p_i = p_i->succ;
132 
133  while ( (p_i != p_e) && (poly_size > 3)) {
134 
135  if (is_ear(p_i, cpoly, true)) {
136  // we have a valid triangle, store it
137  output.push_back(typename TriangleList::value_type(**p_i->succ, **p_i, **p_i->prev));
138 
139  // set the current middle node
140  typename CPoly::iterator p_r = p_i;
141  p_i = (p_i->prev != cpoly.begin()) ? p_i->prev : p_i->succ;
142 
143  cpoly.remove(p_r);
144  --poly_size;
145  }else
146  p_i = p_i->succ;
147  }
148  }
149 
150  output.push_back(typename TriangleList::value_type(**p_i->succ, **p_i, **p_i->prev));
151  return true;
152 
153 
154 }
155 
156 
157 
158 template <class VertexVector, class Polygon>
159 typename TPolyTriangulator<VertexVector,Polygon>::Vector
161 {
162  typename VertexVector::value_type result(0,0,0);
163 
164  typename Polygon::const_iterator pb = poly.begin();
165  typename Polygon::const_iterator be = poly.end();
166 
167  typename Polygon::const_iterator c1 = pb;
168  ++c1;
169 
170  typename Polygon::const_iterator c2 = c1;
171  ++c2;
172 
173  typename VertexVector::value_type a = m_vv[*pb];
174 
175  while (c1 != be && c2 != be) {
176  result += (m_vv[*c1++] - a) ^ (m_vv[*c2++] - a);
177  }
178  return result;
179 
180 }
181 
182 template <class VertexVector, class Polygon>
183 bool TPolyTriangulator<VertexVector,Polygon>::is_convex(const typename CPoly::const_iterator& i, bool /*debug*/) const
184 {
185  typename VertexVector::value_type a = m_vv[**i->prev];
186  typename VertexVector::value_type b = m_vv[**i];
187  typename VertexVector::value_type c = m_vv[**i->succ];
188 
189  typename VertexVector::value_type ab = a - b;
190  typename VertexVector::value_type cb = c - b;
191 
192  typename VertexVector::value_type cross = ab ^ cb;
193 
194  const bool result = dot(cross, m_orientation) > 0;
195 
196  return result;
197 
198 }
199 
200 template <class VertexVector, class Polygon>
201 bool TPolyTriangulator<VertexVector,Polygon>::is_ear(const typename CPoly::const_iterator& p, const CPoly& cpoly, bool debug) const
202 {
203  if (!is_convex(p,debug)) {
204  cvdebug() << "corner is concave\n";
205  return false;
206  }
207 
208  typename VertexVector::value_type a = m_vv[**p->prev];
209  typename VertexVector::value_type b = m_vv[**p];
210  typename VertexVector::value_type c = m_vv[**p->succ];
211 
212  cvdebug() << "check triangle" << a << b << c << " = (" << **p->prev << "," << **p << "," << **p->succ << "\n";
213 
214 
215  typename CPoly::const_iterator i = cpoly.begin();
216  i = i->succ;
217  while (i != cpoly.end()) {
218  if (i != p && i != p->prev && i != p->succ)
219  if (!is_convex(i, debug) && is_inside(a,b,c,m_vv[**i], debug)) {
220  cvdebug() << "point " << **i << ":" << m_vv[**i] << " is concave and inside\n";
221 
222  return false;
223  }
224 
225  i = i->succ;
226  }
227  return true;
228 }
229 
230 template <class VertexVector, class Polygon>
232  const typename VertexVector::value_type& a,
233  const typename VertexVector::value_type& b,
234  const typename VertexVector::value_type& c,
235  const typename VertexVector::value_type& p,
236  bool /*debug*/) const
237 {
238  double abc = ((a-b)^(c-b)).norm() * 0.5;
239  double abp = ((a-p)^(b-p)).norm() * 0.5;
240  double acp = ((a-p)^(c-p)).norm() * 0.5;
241  double bcp = ((b-p)^(c-p)).norm() * 0.5;
242 
243  const bool result = (abc >= abp + acp + bcp);
244 
245  return result;
246 }
247 
TPolyTriangulator(const VertexVector &vv)
Definition: triangulate.hh:79
CDebugSink & cvdebug()
Definition: msgstream.hh:216
#define NS_MIA_BEGIN
conveniance define to start the mia namespace
Definition: defines.hh:33
node * prev
Definition: clist.hh:37
iterator end()
Definition: clist.hh:74
T cross(const T2DVector< T > &a, const T2DVector< T > &b)
Definition: 2d/vector.hh:475
double EXPORT_GSL dot(const gsl_vector *lhs, const gsl_vector *rhs)
class to make a triangle mesh from a closed polygon
Definition: triangulate.hh:38
Definition: clist.hh:29
void remove(node *n)
Definition: clist.hh:87
iterator begin()
Definition: clist.hh:70
bool triangulate(TriangleList &output, const Polygon &poly) const
Definition: triangulate.hh:87
void push_back(T val)
Definition: clist.hh:101
node * succ
Definition: clist.hh:38
#define NS_MIA_END
conveniance define to end the mia namespace
Definition: defines.hh:36