Radium Engine  1.5.0
TopologicalMesh.cpp
1 #include <Core/Geometry/deprecated/TopologicalMesh.hpp>
2 
3 #include <Core/RaCore.hpp>
4 #include <Core/Utils/Log.hpp>
5 
6 #include <Eigen/StdVector>
7 
8 #include <unordered_map>
9 #include <utility>
10 #include <vector>
11 
12 namespace Ra {
13 namespace Core {
14 namespace Geometry {
15 namespace deprecated {
16 
17 using namespace Utils; // log, AttribXXX
18 
20 
21 template <typename P, typename T>
22 void addAttribPairToCore( TriangleMesh& triMesh,
23  const TopologicalMesh* topoMesh,
24  OpenMesh::HPropHandleT<T> oh,
25  std::vector<P>& vprop ) {
26  AttribHandle<T> h = triMesh.addAttrib<T>( topoMesh->property( oh ).name() );
27  vprop.push_back( std::make_pair( h, oh ) );
28 }
29 
30 template <typename T>
31 using HandleAndValueVector = std::vector<std::pair<AttribHandle<T>, T>,
32  Eigen::aligned_allocator<std::pair<AttribHandle<T>, T>>>;
33 
34 template <typename P, typename T>
35 void copyAttribToCoreVertex( HandleAndValueVector<T>& data,
36  const TopologicalMesh* topoMesh,
37  const std::vector<P>& vprop,
38  TopologicalMesh::HalfedgeHandle heh ) {
39  for ( auto pp : vprop ) {
40  data.push_back( std::make_pair( pp.first, topoMesh->property( pp.second, heh ) ) );
41  }
42 }
43 
44 template <typename T>
45 void copyAttribToCore( TriangleMesh& triMesh, const HandleAndValueVector<T>& data ) {
46 
47  for ( auto pp : data ) {
48  auto& attr = triMesh.getAttrib( pp.first );
49  auto& attrData = attr.getDataWithLock();
50  attrData.push_back( pp.second );
51  attr.unlock();
52  }
53 }
54 
58  DefaultNonManifoldFaceCommand( const std::string& details = {} ) : m_details { details } {}
60  inline void initialize( const TriangleMesh& /*triMesh*/ ) {}
62  inline void process( const std::vector<TopologicalMesh::VertexHandle>& /*face_vhandles*/ ) {
63  LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details;
68  }
70  inline void postProcess( TopologicalMesh& /*tm*/ ) {}
72  private:
73  std::string m_details;
74 };
75 
76 TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) :
77  TopologicalMesh( triMesh, DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {}
78 
80  add_property( m_inputTriangleMeshIndexPph );
81 }
82 
84  struct VertexDataInternal {
85  Vector3 _vertex;
86  Vector3 _normal;
87 
88  HandleAndValueVector<Scalar> _float;
89  HandleAndValueVector<Vector2> _vec2;
90  HandleAndValueVector<Vector3> _vec3;
91  HandleAndValueVector<Vector4> _vec4;
92 
93  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
94 
95  bool operator==( const VertexDataInternal& lhs ) const {
96  return _vertex == lhs._vertex && _normal == lhs._normal && _float == lhs._float &&
97  _vec2 == lhs._vec2 && _vec3 == lhs._vec3 && _vec4 == lhs._vec4;
98  }
99  };
100 
101  struct hash_vec {
102  size_t operator()( const VertexDataInternal& lvalue ) const {
103  size_t hx = std::hash<Scalar>()( lvalue._vertex[0] );
104  size_t hy = std::hash<Scalar>()( lvalue._vertex[1] );
105  size_t hz = std::hash<Scalar>()( lvalue._vertex[2] );
106  return ( hx ^ ( hy << 1 ) ) ^ hz;
107  }
108  };
109 
110  TriangleMesh out;
111 
112  using VertexMap = std::unordered_map<VertexDataInternal, int, hash_vec>;
113 
114  VertexMap vertexHandles;
115 
116  if ( !get_property_handle( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" ) ) {
117  add_property( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" );
118  }
119  std::vector<PropPair<Scalar>> vprop_float;
120  std::vector<PropPair<Vector2>> vprop_vec2;
121  std::vector<PropPair<Vector3>> vprop_vec3;
122  std::vector<PropPair<Vector4>> vprop_vec4;
123 
124  // loop over all attribs and build correspondance pair
125  vprop_float.reserve( m_floatPph.size() );
126  for ( auto oh : m_floatPph )
127  addAttribPairToCore( out, this, oh, vprop_float );
128  vprop_vec2.reserve( m_vec2Pph.size() );
129  for ( auto oh : m_vec2Pph )
130  addAttribPairToCore( out, this, oh, vprop_vec2 );
131  vprop_vec3.reserve( m_vec3Pph.size() );
132  for ( auto oh : m_vec3Pph )
133  addAttribPairToCore( out, this, oh, vprop_vec3 );
134  vprop_vec4.reserve( m_vec4Pph.size() );
135  for ( auto oh : m_vec4Pph )
136  addAttribPairToCore( out, this, oh, vprop_vec4 );
137 
138  // iterator over all faces
139  unsigned int vertexIndex = 0;
140 
141  // out will have at least n_vertices vertices and normals.
142  TriangleMesh::PointAttribHandle::Container vertices;
143  TriangleMesh::NormalAttribHandle::Container normals;
145 
146  vertices.reserve( n_vertices() );
147  normals.reserve( n_vertices() );
148  indices.reserve( n_faces() );
149 
150  for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) {
151  int tindices[3];
152  int i = 0;
153 
154  // iterator over vertex (through halfedge to get access to halfedge normals)
155  for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid();
156  ++fh_it ) {
157  VertexDataInternal v;
158  CORE_ASSERT( i < 3, "Non-triangular face found." );
159  v._vertex = point( to_vertex_handle( *fh_it ) );
160 
161  if ( has_halfedge_normals() ) {
162  v._normal = normal( to_vertex_handle( *fh_it ), *f_it );
163  }
164  copyAttribToCoreVertex( v._float, this, vprop_float, *fh_it );
165  copyAttribToCoreVertex( v._vec2, this, vprop_vec2, *fh_it );
166  copyAttribToCoreVertex( v._vec3, this, vprop_vec3, *fh_it );
167  copyAttribToCoreVertex( v._vec4, this, vprop_vec4, *fh_it );
168 
169  int vi;
170  VertexMap::iterator vtr = vertexHandles.find( v );
171  if ( vtr == vertexHandles.end() ) {
172  vi = int( vertexIndex++ );
173  vertexHandles.insert( vtr, VertexMap::value_type( v, vi ) );
174  vertices.push_back( v._vertex );
175  if ( has_halfedge_normals() ) { normals.push_back( v._normal ); }
176  copyAttribToCore( out, v._float );
177  copyAttribToCore( out, v._vec2 );
178  copyAttribToCore( out, v._vec3 );
179  copyAttribToCore( out, v._vec4 );
180  }
181  else { vi = vtr->second; }
182  tindices[i] = vi;
183  property( m_outputTriangleMeshIndexPph, *fh_it ) = vi;
184  i++;
185  }
186  indices.emplace_back( tindices[0], tindices[1], tindices[2] );
187  }
188  out.setVertices( std::move( vertices ) );
189  if ( has_halfedge_normals() ) { out.setNormals( std::move( normals ) ); }
190  out.setIndices( std::move( indices ) );
191  CORE_ASSERT( vertexIndex == vertices.size(),
192  "Inconsistent number of faces in generated TriangleMesh." );
193 
194  return out;
195 }
196 
197 bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) {
198  // Global schema of operation
199  /*
200  TRIANGLES ONLY
201  before after
202  A A
203  / F0 \ / F2 | F0 \
204  / \ / | \
205  /h1 h0\ /h1 e2|e0 h0\
206  / he0 \ / he2 | he0 \
207  V1 -------- V0 V1 ------ V ------ V0
208  \ he1 / \ he3 | he1 /
209  \o1 o0/ \o1 e3|e1 o0/
210  \ / \ | /
211  \ F1 / \ F3 | F1 /
212  B B
213 
214  */
215 
216  // incorrect factor
217  if ( f < 0 || f > 1 ) { return false; }
218 
219  // get existing topology data
220  HalfedgeHandle he0 = halfedge_handle( eh, 0 );
221  HalfedgeHandle he1 = halfedge_handle( eh, 1 );
222  VertexHandle v0 = to_vertex_handle( he0 );
223  VertexHandle v1 = to_vertex_handle( he1 );
224  FaceHandle F0 = face_handle( he0 );
225  FaceHandle F1 = face_handle( he1 );
226 
227  // not triangles or holes
228  if ( ( !is_boundary( he0 ) && valence( F0 ) != 3 ) ||
229  ( !is_boundary( he1 ) && valence( F1 ) != 3 ) ) {
230  return false;
231  }
232 
233  // add the new vertex
234  const Point p = Point( f * point( v0 ) + ( Scalar( 1. ) - f ) * point( v1 ) );
235  VertexHandle v = add_vertex( p );
236 
237  // create the new faces and reconnect the topology
238  HalfedgeHandle he3 = new_edge( v, v1 );
239  HalfedgeHandle he2 = opposite_halfedge_handle( he3 );
240  set_halfedge_handle( v, he0 );
241  set_vertex_handle( he1, v );
242 
243  // does F0 exist
244  if ( !is_boundary( he0 ) ) {
245  HalfedgeHandle h0 = next_halfedge_handle( he0 );
246  HalfedgeHandle h1 = next_halfedge_handle( h0 );
247  // create new edge
248  VertexHandle A = to_vertex_handle( h0 );
249  HalfedgeHandle e2 = new_edge( v, A );
250  HalfedgeHandle e0 = opposite_halfedge_handle( e2 );
251  // split F0
252  FaceHandle F2 = new_face();
253  set_halfedge_handle( F0, he0 );
254  set_halfedge_handle( F2, h1 );
255  // update F0
256  set_face_handle( h0, F0 );
257  set_face_handle( e0, F0 );
258  set_face_handle( he0, F0 );
259  set_next_halfedge_handle( he0, h0 );
260  set_next_halfedge_handle( h0, e0 );
261  set_next_halfedge_handle( e0, he0 );
262  // update F2
263  set_face_handle( h1, F2 );
264  set_face_handle( he2, F2 );
265  set_face_handle( e2, F2 );
266  set_next_halfedge_handle( e2, h1 );
267  set_next_halfedge_handle( h1, he2 );
268  set_next_halfedge_handle( he2, e2 );
269  // deal with custom properties
270  // interpolate at he2
271  interpolateAllProps( h1, he0, he2, 0.5 );
272  // copy at e0, and e2
273  copyAllProps( he2, e0 );
274  }
275  else {
276  HalfedgeHandle h1 = prev_halfedge_handle( he0 );
277  set_next_halfedge_handle( h1, he2 );
278  set_next_halfedge_handle( he2, he0 );
279  // next halfedge handle of he0 already is h0
280  // halfedge handle of V already is he0
281  }
282 
283  // does F1 exist
284  if ( !is_boundary( he1 ) ) {
285  HalfedgeHandle o1 = next_halfedge_handle( he1 );
286  HalfedgeHandle o0 = next_halfedge_handle( o1 );
287  // create new edge
288  VertexHandle B = to_vertex_handle( o1 );
289  HalfedgeHandle e1 = new_edge( v, B );
290  HalfedgeHandle e3 = opposite_halfedge_handle( e1 );
291  // split F1
292  FaceHandle F3 = new_face();
293  set_halfedge_handle( F3, o1 );
294  set_halfedge_handle( F1, he1 );
295  // update F1
296  set_face_handle( o1, F3 );
297  set_face_handle( e3, F3 );
298  set_face_handle( he3, F3 );
299  set_next_halfedge_handle( he3, o1 );
300  set_next_halfedge_handle( o1, e3 );
301  set_next_halfedge_handle( e3, he3 );
302  // update F3
303  set_face_handle( o0, F1 );
304  set_face_handle( he1, F1 );
305  set_face_handle( e1, F1 );
306  set_next_halfedge_handle( he1, e1 );
307  set_next_halfedge_handle( e1, o0 );
308  set_next_halfedge_handle( o0, he1 );
309  // deal with custom properties
310  // first copy at he3
311  copyAllProps( he1, he3 );
312  // interpolate at he1
313  interpolateAllProps( o0, he3, he1, 0.5 );
314  // copy at e1, and e3
315  copyAllProps( he1, e3 );
316  copyAllProps( o1, e1 );
317  }
318  else {
319  HalfedgeHandle o1 = next_halfedge_handle( he1 );
320  // next halfedge handle of o0 already is he1
321  set_next_halfedge_handle( he1, he3 );
322  set_next_halfedge_handle( he3, o1 );
323  // halfedge handle of V already is he0
324  }
325 
326  // ensure consistency at v1
327  if ( halfedge_handle( v1 ) == he0 ) { set_halfedge_handle( v1, he2 ); }
328 
329  return true;
330 }
331 
332 //-----------------------------------------------------------------------------
333 // from /OpenMesh/Core/Mesh/TriConnectivity.cc
334 void TopologicalMesh::split( EdgeHandle _eh, VertexHandle _vh ) {
335  HalfedgeHandle h0 = halfedge_handle( _eh, 0 );
336  HalfedgeHandle o0 = halfedge_handle( _eh, 1 );
337 
338  VertexHandle v2 = to_vertex_handle( o0 );
339 
340  HalfedgeHandle e1 = new_edge( _vh, v2 );
341  HalfedgeHandle t1 = opposite_halfedge_handle( e1 );
342 
343  FaceHandle f0 = face_handle( h0 );
344  FaceHandle f3 = face_handle( o0 );
345 
346  set_halfedge_handle( _vh, h0 );
347  set_vertex_handle( o0, _vh );
348 
349  if ( !is_boundary( h0 ) ) {
350  HalfedgeHandle h1 = next_halfedge_handle( h0 );
351  HalfedgeHandle h2 = next_halfedge_handle( h1 );
352 
353  VertexHandle v1 = to_vertex_handle( h1 );
354 
355  HalfedgeHandle e0 = new_edge( _vh, v1 );
356  HalfedgeHandle t0 = opposite_halfedge_handle( e0 );
357 
358  FaceHandle f1 = new_face();
359  set_halfedge_handle( f0, h0 );
360  set_halfedge_handle( f1, h2 );
361 
362  set_face_handle( h1, f0 );
363  set_face_handle( t0, f0 );
364  set_face_handle( h0, f0 );
365 
366  set_face_handle( h2, f1 );
367  set_face_handle( t1, f1 );
368  set_face_handle( e0, f1 );
369 
370  set_next_halfedge_handle( h0, h1 );
371  set_next_halfedge_handle( h1, t0 );
372  set_next_halfedge_handle( t0, h0 );
373 
374  set_next_halfedge_handle( e0, h2 );
375  set_next_halfedge_handle( h2, t1 );
376  set_next_halfedge_handle( t1, e0 );
377  }
378  else {
379  set_next_halfedge_handle( prev_halfedge_handle( h0 ), t1 );
380  set_next_halfedge_handle( t1, h0 );
381  // halfedge handle of _vh already is h0
382  }
383 
384  if ( !is_boundary( o0 ) ) {
385  HalfedgeHandle o1 = next_halfedge_handle( o0 );
386  HalfedgeHandle o2 = next_halfedge_handle( o1 );
387 
388  VertexHandle v3 = to_vertex_handle( o1 );
389 
390  HalfedgeHandle e2 = new_edge( _vh, v3 );
391  HalfedgeHandle t2 = opposite_halfedge_handle( e2 );
392 
393  FaceHandle f2 = new_face();
394  set_halfedge_handle( f2, o1 );
395  set_halfedge_handle( f3, o0 );
396 
397  set_face_handle( o1, f2 );
398  set_face_handle( t2, f2 );
399  set_face_handle( e1, f2 );
400 
401  set_face_handle( o2, f3 );
402  set_face_handle( o0, f3 );
403  set_face_handle( e2, f3 );
404 
405  set_next_halfedge_handle( e1, o1 );
406  set_next_halfedge_handle( o1, t2 );
407  set_next_halfedge_handle( t2, e1 );
408 
409  set_next_halfedge_handle( o0, e2 );
410  set_next_halfedge_handle( e2, o2 );
411  set_next_halfedge_handle( o2, o0 );
412  }
413  else {
414  set_next_halfedge_handle( e1, next_halfedge_handle( o0 ) );
415  set_next_halfedge_handle( o0, e1 );
416  set_halfedge_handle( _vh, e1 );
417  }
418 
419  if ( halfedge_handle( v2 ) == h0 ) set_halfedge_handle( v2, t1 );
420 }
421 
422 //-----------------------------------------------------------------------------
423 
424 void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) {
425  const VertexHandle v0 = to_vertex_handle( halfedge_handle( _eh, 0 ) );
426  const VertexHandle v1 = to_vertex_handle( halfedge_handle( _eh, 1 ) );
427 
428  const int nf = n_faces();
429 
430  // Split the halfedge ( handle will be preserved)
431  split( _eh, _vh );
432 
433  // Copy the properties of the original edge to all neighbor edges that
434  // have been created
435  for ( VEIter ve_it = ve_iter( _vh ); ve_it.is_valid(); ++ve_it )
436  copy_all_properties( _eh, *ve_it, true );
437 
438  for ( auto vh : { v0, v1 } ) {
439  // get the halfedge pointing from new vertex to old vertex
440  const HalfedgeHandle h = find_halfedge( _vh, vh );
441  // for boundaries there are no faces whose properties need to be copied
442  if ( !is_boundary( h ) ) {
443  FaceHandle fh0 = face_handle( h );
444  FaceHandle fh1 = face_handle( opposite_halfedge_handle( prev_halfedge_handle( h ) ) );
445  // is fh0 the new face?
446  if ( fh0.idx() >= nf ) std::swap( fh0, fh1 );
447 
448  // copy properties from old face to new face
449  copy_all_properties( fh0, fh1, true );
450  }
451  }
452 }
453 
454 } // namespace deprecated
455 } // namespace Geometry
456 } // namespace Core
457 } // namespace Ra
const Normal & normal(VertexHandle vh, FaceHandle fh) const
void copyAllProps(HalfedgeHandle input_heh, HalfedgeHandle copy_heh)
void interpolateAllProps(HalfedgeHandle in_a, HalfedgeHandle in_b, HalfedgeHandle out, Scalar f)
bool splitEdge(TopologicalMesh::EdgeHandle eh, Scalar f)
HalfedgeHandle halfedge_handle(VertexHandle vh, FaceHandle fh) const
Definition: Cage.cpp:3
void initialize(const TriangleMesh &)
Initalize with input Ra::Core::Geometry::TriangleMesh.
DefaultNonManifoldFaceCommand(const std::string &details={})
details string is printed along with the message
void postProcess(TopologicalMesh &)
If needed, apply post-processing on the TopologicalMesh.
void process(const std::vector< TopologicalMesh::VertexHandle > &)
Process non-manifold face.