Radium Engine  1.5.0
TopologicalMesh.cpp
1 #include <Core/Geometry/TopologicalMesh.hpp>
2 
3 #include <Core/RaCore.hpp>
4 #include <Core/Utils/Log.hpp>
5 
6 #include <Eigen/StdVector>
7 
8 #include <utility>
9 #include <vector>
10 
11 namespace Ra {
12 namespace Core {
13 namespace Geometry {
14 
15 using namespace Utils; // log, AttribXXX
16 
18 
19 std::string wedgeInfo( const Ra::Core::Geometry::TopologicalMesh& topo,
20  const Ra::Core::Geometry::TopologicalMesh::WedgeIndex& idx ) {
21 
22  std::stringstream buffer;
23  if ( !idx.isValid() ) {
24  buffer << "wedge (invalid) ";
25  return buffer.str();
26  }
27 
29 
30  buffer << "wedge (" << idx << "," << topo.getWedgeRefCount( idx ) << "), ";
31  auto& floatAttrNames = topo.getFloatAttribNames();
32  for ( size_t i = 0; i < floatAttrNames.size(); ++i ) {
33  buffer << floatAttrNames[i];
34  buffer << "[";
35  buffer << wd.m_floatAttrib[i];
36  buffer << "], ";
37  }
38  auto vec2AttrNames = topo.getVec2AttribNames();
39  for ( size_t i = 0; i < vec2AttrNames.size(); ++i ) {
40  buffer << vec2AttrNames[i];
41  buffer << "[";
42  buffer << wd.m_vector2Attrib[i].transpose();
43  buffer << "], ";
44  }
45  auto vec3AttrNames = topo.getVec3AttribNames();
46  for ( size_t i = 0; i < vec3AttrNames.size(); ++i ) {
47  buffer << vec3AttrNames[i];
48  buffer << "[";
49  buffer << wd.m_vector3Attrib[i].transpose();
50  buffer << "], ";
51  }
52 
53  auto vec4AttrNames = topo.getVec4AttribNames();
54  for ( size_t i = 0; i < vec4AttrNames.size(); ++i ) {
55  buffer << vec4AttrNames[i];
56  buffer << "[";
57  buffer << wd.m_vector4Attrib[i].transpose();
58  buffer << "], ";
59  }
60 
61  return buffer.str();
62 }
63 
64 bool TopologicalMesh::isManifold( VertexHandle vh ) const {
65  return is_manifold( vh );
66 }
67 
69  std::vector<unsigned int> count( m_wedges.size(), 0 );
70  bool ret = true;
71  for ( auto he_itr { halfedges_begin() }; he_itr != halfedges_end(); ++he_itr ) {
72  auto widx = property( m_wedgeIndexPph, *he_itr );
73 
74  if ( status( *he_itr ).deleted() ) { continue; }
75 
76  if ( is_boundary( *he_itr ) != widx.isInvalid() ) {
77  LOG( logWARNING ) << "topological mesh wedge inconsistency, boundary he ("
78  << ( is_boundary( *he_itr ) ? "true," : "false," ) << he_itr->idx()
79  << ") != invalid Wedge (" << ( widx.isInvalid() ? "true," : "false," )
80  << widx << ") ref "
81  << ( widx.isValid() ? m_wedges.getWedge( widx ).getRefCount() : 0 );
82  ret = false;
83  }
84 
85  if ( widx.isValid() ) // i.e. non boudnary
86  {
87  count[widx]++;
88 
89  if ( m_wedges.getWedgeData( widx ).m_position !=
90  point( to_vertex_handle( *he_itr ) ) ) {
91  LOG( logWARNING ) << "topological mesh wedge inconsistency, wedge and to position "
92  "differ for widx "
93  << widx << ", have ("
94  << m_wedges.getWedgeData( widx ).m_position.transpose()
95  << ") instead of ("
96  << point( to_vertex_handle( *he_itr ) ).transpose() << ")";
97  ret = false;
98  }
99  }
100  }
101 
102  for ( int widx = 0; widx < int( m_wedges.size() ); ++widx ) {
103  if ( m_wedges.getWedge( WedgeIndex { widx } ).getRefCount() != count[widx] ) {
104  LOG( logWARNING ) << "topological mesh wedge count inconsistency, topo count [ "
105  << count[widx] << " ] != wedge count [ "
106  << m_wedges.getWedge( WedgeIndex { widx } ).getRefCount()
107  << " ] for id " << widx;
108  ret = false;
109  }
110  }
111  return ret;
112 }
113 
114 void TopologicalMesh::triangulate() {
115 
116  auto fix = [this]( HalfedgeHandle next_he, const std::vector<HalfedgeHandle>& old_heh ) {
117  // tagged if already fixed
118  auto to_vh = to_vertex_handle( next_he );
119  // find ref in old_he to copy wedge idx
120 
121  auto ref = std::find_if(
122  old_heh.begin(), old_heh.end(), [this, to_vh]( const HalfedgeHandle& he ) {
123  return to_vertex_handle( he ) == to_vh;
124  } );
125  if ( ref != old_heh.end() ) {
126  property( m_wedgeIndexPph, next_he ) =
127  m_wedges.newReference( property( m_wedgeIndexPph, *ref ) );
128  }
129  else { LOG( logERROR ) << "triangulate::fix reference halfedge not found"; }
130  status( next_he ).set_tagged( true );
131  };
132 
133  FaceIter f_it( faces_begin() ), f_end( faces_end() );
134  for ( ; f_it != f_end; ++f_it ) {
135  // save original halfedge of the face
136  std::vector<HalfedgeHandle> old_heh;
137  ConstFaceHalfedgeIter fh_itr = cfh_iter( *f_it );
138  for ( ; fh_itr.is_valid(); ++fh_itr ) {
139  old_heh.push_back( *fh_itr );
140  }
141  auto size = old_heh.size();
142  // if ( size <= 3 ) continue;
143 
144  // base openmesh triangulate
145  base::triangulate( *f_it );
146 
147  // fix newly created he
148  for ( size_t i = 0; i < size; ++i ) {
149  auto next_he = next_halfedge_handle( old_heh[i] );
150  // if next_he is not the same as next in old_heh, then it's a new one.
151  // fix tag halfedge so that it is not fixed two times (in case opposite halfedge is also
152  // parsed in this loop.
153  if ( !status( next_he ).tagged() && next_he != old_heh[( i + 1 ) % size] ) {
154  fix( next_he, old_heh );
155  fix( opposite_halfedge_handle( next_he ), old_heh );
156  }
157  }
158  }
159  // untag everything
160  for ( auto& he : halfedges() ) {
161  status( he ).set_tagged( false );
162  }
163 }
164 
165 void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) {
166  using namespace Ra::Core;
167 
168  for ( auto itr = topo.vertices_sbegin(); itr != topo.vertices_end(); ++itr ) {
169  LOG( Utils::logINFO ) << "vertex " << *itr;
170  auto wedges = topo.getVertexWedges( *itr );
171  for ( auto wedgeIndex : wedges ) {
172  LOG( Utils::logINFO ) << wedgeInfo( topo, wedgeIndex );
173  }
174  }
175 
176  for ( auto itr = topo.halfedges_sbegin(); itr != topo.halfedges_end(); ++itr ) {
177  LOG( Utils::logINFO ) << "he " << *itr
178  << ( topo.is_boundary( *itr ) ? " boundary " : " inner " );
179  LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) );
180  }
181 }
182 
184  add_property( m_inputTriangleMeshIndexPph );
185  add_property( m_wedgeIndexPph );
186 }
187 
188 template <typename T>
189 void copyWedgeDataToAttribContainer( AlignedStdVector<typename Attrib<T>::Container>& c,
190  const VectorArray<T>& wd ) {
191  for ( size_t i = 0; i < wd.size(); ++i ) {
192  c[i].push_back( wd[i] );
193  }
194 }
195 
196 template <typename T>
197 void moveContainerToMesh( Ra::Core::Geometry::MultiIndexedGeometry& out,
198  const std::vector<std::string>& names,
199  AlignedStdVector<typename Attrib<T>::Container>& wedgeAttribData ) {
200  for ( size_t i = 0; i < wedgeAttribData.size(); ++i ) {
201  auto attrHandle = out.template addAttrib<T>( names[i] );
202  out.getAttrib( attrHandle ).setData( std::move( wedgeAttribData[i] ) );
203  }
204 }
205 
207  // first cleanup deleted element
208  garbage_collection();
209 
210  TriangleMesh out;
212 
214  TriangleMesh::PointAttribHandle::Container wedgePosition;
215  AlignedStdVector<Attrib<Scalar>::Container> wedgeFloatAttribData(
216  m_wedges.m_floatAttribNames.size() );
217  AlignedStdVector<Attrib<Vector2>::Container> wedgeVector2AttribData(
218  m_wedges.m_vector2AttribNames.size() );
219  AlignedStdVector<Attrib<Vector3>::Container> wedgeVector3AttribData(
220  m_wedges.m_vector3AttribNames.size() );
221  AlignedStdVector<Attrib<Vector4>::Container> wedgeVector4AttribData(
222  m_wedges.m_vector4AttribNames.size() );
223 
225  for ( WedgeIndex widx { 0 }; widx < WedgeIndex { m_wedges.size() }; ++widx ) {
226  const auto& wd = m_wedges.getWedgeData( widx );
227  wedgePosition.push_back( wd.m_position );
228  copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
229  copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
230  copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
231  copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
232  }
233 
234  out.setVertices( std::move( wedgePosition ) );
235  moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
236  moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
237  moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
238  moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
239 
240  for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) {
241  int tindices[3];
242  int i = 0;
243 
244  for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid();
245  ++fh_it ) {
246  CORE_ASSERT( i < 3, "Non-triangular face found." );
247  tindices[i] = property( m_wedgeIndexPph, *fh_it );
248  i++;
249  }
250  indices.emplace_back( tindices[0], tindices[1], tindices[2] );
251  }
252 
253  out.setIndices( std::move( indices ) );
254 
255  return out;
256 }
257 
259  // first cleanup deleted element
260  garbage_collection();
261 
262  LineMesh out;
264 
265  TriangleMesh::PointAttribHandle::Container wedgePosition;
266  AlignedStdVector<Attrib<Scalar>::Container> wedgeFloatAttribData(
267  m_wedges.m_floatAttribNames.size() );
268  AlignedStdVector<Attrib<Vector2>::Container> wedgeVector2AttribData(
269  m_wedges.m_vector2AttribNames.size() );
270  AlignedStdVector<Attrib<Vector3>::Container> wedgeVector3AttribData(
271  m_wedges.m_vector3AttribNames.size() );
272  AlignedStdVector<Attrib<Vector4>::Container> wedgeVector4AttribData(
273  m_wedges.m_vector4AttribNames.size() );
274 
276  for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
277  const auto& wd = m_wedges.getWedgeData( widx );
278  wedgePosition.push_back( wd.m_position );
279  copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
280  copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
281  copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
282  copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
283  }
284 
285  out.setVertices( std::move( wedgePosition ) );
286  moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
287  moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
288  moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
289  moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
290 
291  for ( TopologicalMesh::EdgeIter e_it = edges_sbegin(); e_it != edges_end(); ++e_it ) {
292  int tindices[2];
293 
294  // take care of boundaries
295  auto he0 = halfedge_handle( *e_it, 0 );
296  if ( OpenMesh::ArrayKernel::is_boundary( he0 ) ) {
297  he0 = prev_halfedge_handle( opposite_halfedge_handle( he0 ) );
298  }
299  if ( OpenMesh::ArrayKernel::is_boundary( he0 ) ) continue;
300  auto he1 = halfedge_handle( *e_it, 1 );
301  if ( OpenMesh::ArrayKernel::is_boundary( he1 ) ) {
302  he1 = prev_halfedge_handle( opposite_halfedge_handle( he1 ) );
303  }
304  if ( OpenMesh::ArrayKernel::is_boundary( he1 ) ) continue;
305 
306  tindices[0] = property( m_wedgeIndexPph, he0 );
307  tindices[1] = property( m_wedgeIndexPph, he1 );
308 
309  indices.emplace_back( tindices[0], tindices[1] );
310  }
311 
312  out.setIndices( std::move( indices ) );
313 
314  return out;
315 }
317  // first cleanup deleted element
318  garbage_collection();
319 
320  PolyMesh out;
322 
324  std::vector<AttribHandle<Scalar>> wedgeFloatAttribHandles;
325  std::vector<AttribHandle<Vector2>> wedgeVector2AttribHandles;
326  std::vector<AttribHandle<Vector3>> wedgeVector3AttribHandles;
327  std::vector<AttribHandle<Vector4>> wedgeVector4AttribHandles;
328 
329  TriangleMesh::PointAttribHandle::Container wedgePosition;
330  AlignedStdVector<Attrib<Scalar>::Container> wedgeFloatAttribData(
331  m_wedges.m_floatAttribNames.size() );
332  AlignedStdVector<Attrib<Vector2>::Container> wedgeVector2AttribData(
333  m_wedges.m_vector2AttribNames.size() );
334  AlignedStdVector<Attrib<Vector3>::Container> wedgeVector3AttribData(
335  m_wedges.m_vector3AttribNames.size() );
336  AlignedStdVector<Attrib<Vector4>::Container> wedgeVector4AttribData(
337  m_wedges.m_vector4AttribNames.size() );
338 
340  for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
341  const auto& wd = m_wedges.getWedgeData( widx );
342  wedgePosition.push_back( wd.m_position );
343  copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
344  copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
345  copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
346  copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
347  }
348 
349  out.setVertices( std::move( wedgePosition ) );
350  moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
351  moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
352  moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
353  moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
354 
355  for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) {
356  int i = 0;
357  PolyMesh::IndexType faceIndices( valence( *f_it ) );
358  // iterator over vertex (through halfedge to get access to halfedge normals)
359  for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid();
360  ++fh_it ) {
361  faceIndices( i ) = property( m_wedgeIndexPph, *fh_it );
362  i++;
363  }
364  // LOG( logDEBUG ) << "add polymesh face " << faceIndices.transpose();
365  indices.push_back( faceIndices );
366  }
367 
368  out.setIndices( std::move( indices ) );
369 
370  return out;
371 }
372 
374  TriangleMesh::PointAttribHandle::Container wedgePosition;
375  AlignedStdVector<Attrib<Scalar>::Container> wedgeFloatAttribData(
376  m_wedges.m_floatAttribNames.size() );
377  AlignedStdVector<Attrib<Vector2>::Container> wedgeVector2AttribData(
378  m_wedges.m_vector2AttribNames.size() );
379  AlignedStdVector<Attrib<Vector3>::Container> wedgeVector3AttribData(
380  m_wedges.m_vector3AttribNames.size() );
381  AlignedStdVector<Attrib<Vector4>::Container> wedgeVector4AttribData(
382  m_wedges.m_vector4AttribNames.size() );
383 
385  for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
386  const auto& wd = m_wedges.getWedgeData( widx );
387  wedgePosition.push_back( wd.m_position );
388  copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
389  copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
390  copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
391  copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
392  }
393 
394  out.setVertices( std::move( wedgePosition ) );
395  moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
396  moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
397  moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
398  moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
399 }
400 
401 void TopologicalMesh::updateTriangleMeshNormals(
402  AttribArrayGeometry::NormalAttribHandle::Container& normals ) {
403  if ( !has_halfedge_normals() ) {
404  LOG( logERROR ) << "TopologicalMesh has no normals, nothing set";
405  return;
406  }
407 
408  for ( unsigned int widx = 0; widx < m_wedges.size(); ++widx ) {
409  normals[widx] = m_wedges.getWedgeData<Normal>( widx, m_normalsIndex );
410  }
411 }
412 
413 void TopologicalMesh::updateTriangleMeshNormals( Ra::Core::Geometry::MultiIndexedGeometry& out ) {
414  auto& normals = out.normalsWithLock();
415  updateTriangleMeshNormals( normals );
416  out.normalsUnlock();
417 }
418 
419 void TopologicalMesh::update( const Ra::Core::Geometry::MultiIndexedGeometry& triMesh ) {
420  for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) {
421  WedgeData wd;
422  wd.m_position = triMesh.vertices()[i];
423  copyMeshToWedgeData( triMesh,
424  i,
425  m_wedges.m_wedgeFloatAttribHandles,
426  m_wedges.m_wedgeVector2AttribHandles,
427  m_wedges.m_wedgeVector3AttribHandles,
428  m_wedges.m_wedgeVector4AttribHandles,
429  &wd );
430  m_wedges.setWedgeData( i, wd );
431  }
432  // update positions
433  for ( auto itr = halfedges_begin(), stop = halfedges_end(); itr != stop; ++itr ) {
434  point( to_vertex_handle( *itr ) ) =
435  m_wedges.getWedgeData( getWedgeIndex( *itr ) ).m_position;
436  }
437 }
438 
439 void TopologicalMesh::updatePositions( const Ra::Core::Geometry::MultiIndexedGeometry& triMesh ) {
440  updatePositions( triMesh.vertices() );
441 }
442 
443 void TopologicalMesh::updatePositions(
444  const AttribArrayGeometry::PointAttribHandle::Container& vertices ) {
445 
446  for ( size_t i = 0; i < vertices.size(); ++i ) {
447  m_wedges.m_data[i].getWedgeData().m_position = vertices[i];
448  point( m_wedges.m_data[i].getWedgeData().m_vertexHandle ) = vertices[i];
449  }
450 }
451 
452 void TopologicalMesh::updateNormals( const Ra::Core::Geometry::MultiIndexedGeometry& triMesh ) {
453  auto& normals = triMesh.normals();
454 
455  for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) {
456  m_wedges.setWedgeAttrib<Normal>( i, m_normalsIndex, normals[i] );
457  }
458 }
459 
460 void TopologicalMesh::updateWedgeNormals() {
461  if ( !has_halfedge_normals() ) {
462  LOG( logERROR ) << "TopologicalMesh has no normals, nothing set";
463  return;
464  }
465  // update_face_normals();
466  FaceIter f_it( faces_sbegin() ), f_end( faces_end() );
467  for ( ; f_it != f_end; ++f_it ) {
468  auto fv_it = this->cfv_iter( *f_it );
469  const auto& p0 = point( *fv_it );
470  ++fv_it;
471  const auto& p1 = point( *fv_it );
472  ++fv_it;
473  const auto& p2 = point( *fv_it );
474  ++fv_it;
475  set_normal( *f_it, ( p1 - p0 ).cross( p2 - p0 ).normalized() );
476  }
477 
478  for ( auto& w : m_wedges.m_data ) {
479  w.getWedgeData().m_vector3Attrib[m_normalsIndex] = Normal { 0_ra, 0_ra, 0_ra };
480  }
481 
482  for ( auto v_itr = vertices_begin(), stop = vertices_end(); v_itr != stop; ++v_itr ) {
483  for ( ConstVertexFaceIter f_itr = cvf_iter( *v_itr ); f_itr.is_valid(); ++f_itr ) {
484  for ( const auto& widx :
485  m_vertexFaceWedgesWithSameNormals[v_itr->idx()][f_itr->idx()] ) {
486  m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] +=
487  normal( *f_itr );
488  }
489  }
490  }
491 
492  for ( auto& w : m_wedges.m_data ) {
493  w.getWedgeData().m_vector3Attrib[m_normalsIndex].normalize();
494  }
495 }
496 
498  for ( auto& w : m_wedges.m_data ) {
499  w.m_wedgeData.m_position = point( w.m_wedgeData.m_vertexHandle );
500  }
501 }
502 
503 template <typename T>
504 void interpolate( const VectorArray<T>& in1,
505  const VectorArray<T>& in2,
506  VectorArray<T>& out,
507  const Scalar alpha ) {
508  for ( size_t i = 0; i < in1.size(); ++i ) {
509  out.push_back( ( 1_ra - alpha ) * in1[i] + alpha * in2[i] );
510  }
511 }
512 
514 TopologicalMesh::interpolateWedgeAttributes( const TopologicalMesh::WedgeData& w1,
515  const TopologicalMesh::WedgeData& w2,
516  Scalar alpha ) {
517  WedgeData ret;
518  interpolate( w1.m_floatAttrib, w2.m_floatAttrib, ret.m_floatAttrib, alpha );
519  interpolate( w1.m_vector2Attrib, w2.m_vector2Attrib, ret.m_vector2Attrib, alpha );
520  interpolate( w1.m_vector3Attrib, w2.m_vector3Attrib, ret.m_vector3Attrib, alpha );
521  interpolate( w1.m_vector4Attrib, w2.m_vector4Attrib, ret.m_vector4Attrib, alpha );
522  return ret;
523 }
524 
525 //-----------------------------------------------------------------------------
526 // from /OpenMesh/Core/Mesh/TriConnectivity.cc
527 void TopologicalMesh::split( EdgeHandle _eh, VertexHandle _vh ) {
528  HalfedgeHandle h0 = halfedge_handle( _eh, 0 );
529  HalfedgeHandle o0 = halfedge_handle( _eh, 1 );
530 
531  VertexHandle v2 = to_vertex_handle( o0 );
532 
533  HalfedgeHandle e1 = new_edge( _vh, v2 );
534  HalfedgeHandle t1 = opposite_halfedge_handle( e1 );
535 
536  FaceHandle f0 = face_handle( h0 );
537  FaceHandle f3 = face_handle( o0 );
538 
539  set_halfedge_handle( _vh, h0 );
540  set_vertex_handle( o0, _vh );
541 
542  if ( !is_boundary( h0 ) ) {
543  HalfedgeHandle h1 = next_halfedge_handle( h0 );
544  HalfedgeHandle h2 = next_halfedge_handle( h1 );
545 
546  VertexHandle v1 = to_vertex_handle( h1 );
547 
548  HalfedgeHandle e0 = new_edge( _vh, v1 );
549  HalfedgeHandle t0 = opposite_halfedge_handle( e0 );
550 
551  FaceHandle f1 = new_face();
552  set_halfedge_handle( f0, h0 );
553  set_halfedge_handle( f1, h2 );
554 
555  set_face_handle( h1, f0 );
556  set_face_handle( t0, f0 );
557  set_face_handle( h0, f0 );
558 
559  set_face_handle( h2, f1 );
560  set_face_handle( t1, f1 );
561  set_face_handle( e0, f1 );
562 
563  set_next_halfedge_handle( h0, h1 );
564  set_next_halfedge_handle( h1, t0 );
565  set_next_halfedge_handle( t0, h0 );
566 
567  set_next_halfedge_handle( e0, h2 );
568  set_next_halfedge_handle( h2, t1 );
569  set_next_halfedge_handle( t1, e0 );
570  }
571  else {
572  set_next_halfedge_handle( prev_halfedge_handle( h0 ), t1 );
573  set_next_halfedge_handle( t1, h0 );
574  // halfedge handle of _vh already is h0
575  }
576 
577  if ( !is_boundary( o0 ) ) {
578  HalfedgeHandle o1 = next_halfedge_handle( o0 );
579  HalfedgeHandle o2 = next_halfedge_handle( o1 );
580 
581  VertexHandle v3 = to_vertex_handle( o1 );
582 
583  HalfedgeHandle e2 = new_edge( _vh, v3 );
584  HalfedgeHandle t2 = opposite_halfedge_handle( e2 );
585 
586  FaceHandle f2 = new_face();
587  set_halfedge_handle( f2, o1 );
588  set_halfedge_handle( f3, o0 );
589 
590  set_face_handle( o1, f2 );
591  set_face_handle( t2, f2 );
592  set_face_handle( e1, f2 );
593 
594  set_face_handle( o2, f3 );
595  set_face_handle( o0, f3 );
596  set_face_handle( e2, f3 );
597 
598  set_next_halfedge_handle( e1, o1 );
599  set_next_halfedge_handle( o1, t2 );
600  set_next_halfedge_handle( t2, e1 );
601 
602  set_next_halfedge_handle( o0, e2 );
603  set_next_halfedge_handle( e2, o2 );
604  set_next_halfedge_handle( o2, o0 );
605  }
606  else {
607  set_next_halfedge_handle( e1, next_halfedge_handle( o0 ) );
608  set_next_halfedge_handle( o0, e1 );
609  set_halfedge_handle( _vh, e1 );
610  }
611 
612  if ( halfedge_handle( v2 ) == h0 ) set_halfedge_handle( v2, t1 );
613 }
614 
615 //-----------------------------------------------------------------------------
616 
617 void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) {
618  const VertexHandle v0 = to_vertex_handle( halfedge_handle( _eh, 0 ) );
619  const VertexHandle v1 = to_vertex_handle( halfedge_handle( _eh, 1 ) );
620 
621  const int nf = n_faces();
622 
623  // Split the halfedge ( handle will be preserved)
624  split( _eh, _vh );
625 
626  // Copy the properties of the original edge to all neighbor edges that
627  // have been created
628  for ( VEIter ve_it = ve_iter( _vh ); ve_it.is_valid(); ++ve_it )
629  copy_all_properties( _eh, *ve_it, true );
630 
631  for ( auto vh : { v0, v1 } ) {
632  // get the halfedge pointing from new vertex to old vertex
633  const HalfedgeHandle h = find_halfedge( _vh, vh );
634  // for boundaries there are no faces whose properties need to be copied
635  if ( !is_boundary( h ) ) {
636  FaceHandle fh0 = face_handle( h );
637  FaceHandle fh1 = face_handle( opposite_halfedge_handle( prev_halfedge_handle( h ) ) );
638  // is fh0 the new face?
639  if ( fh0.idx() >= nf ) std::swap( fh0, fh1 );
640 
641  // copy properties from old face to new face
642  copy_all_properties( fh0, fh1, true );
643  }
644  }
645 }
646 
647 bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) {
648  // Global schema of operation
649  /*
650  TRIANGLES ONLY
651  before after
652 
653  / \ / | \
654  / \ / | \
655  /h2 h1\ /r2 r1|s2 s1\
656  / h0 -->\ / r0 | s0=h0 \
657  V0 -------- V1 V0-(1-f)-V---f---V1
658  <-- o0 / \ u0 | t0=o0 /
659  \o1 o2/ \u1 u2|t1 t2/
660  \ / \ | /
661  \ / \ | /
662 
663 
664  */
665 
666  // incorrect factor
667  if ( f < 0 || f > 1 ) { return false; }
668 
669  const auto h0 = halfedge_handle( eh, 0 );
670  const auto o0 = halfedge_handle( eh, 1 );
671 
672  const auto v0 = to_vertex_handle( o0 );
673  const auto v1 = to_vertex_handle( h0 );
674 
675  const auto h1 = next_halfedge_handle( h0 );
676  const auto h2 = next_halfedge_handle( h1 );
677  const auto o1 = next_halfedge_handle( o0 );
678  const auto o2 = next_halfedge_handle( o1 );
679 
680  // add the new point
681  const Point p = Point( f * point( v1 ) + ( 1_ra - f ) * point( v0 ) );
682  VertexHandle vh = add_vertex( p );
683 
684  // compute interpolated wedge, or the two wedges if not the same wedges
685  // around the two vertices of the edge (we always compute for two wedges,
686  // even if add will return the same wedge.
687  WedgeIndex ovwidx;
688  WedgeIndex hvwidx;
689  if ( !is_boundary( h0 ) ) {
690 
691  const auto hw0idx = property( m_wedgeIndexPph, h2 );
692  const auto hw1idx = property( m_wedgeIndexPph, h0 );
693  const auto hw0 = m_wedges.getWedgeData( hw0idx );
694  const auto hw1 = m_wedges.getWedgeData( hw1idx );
695  auto hvw = interpolateWedgeAttributes( hw0, hw1, f );
696  hvw.m_position = p;
697  hvwidx = m_wedges.add( hvw );
698  }
699  if ( !is_boundary( o0 ) ) {
700 
701  const auto ow0idx = property( m_wedgeIndexPph, o2 );
702  const auto ow1idx = property( m_wedgeIndexPph, o0 );
703  const auto ow0 = m_wedges.getWedgeData( ow0idx );
704  const auto ow1 = m_wedges.getWedgeData( ow1idx );
705  auto ovw = interpolateWedgeAttributes( ow1, ow0, f );
706  ovw.m_position = p;
707  ovwidx = m_wedges.add( ovw );
708  }
709 
710  split_copy( eh, vh );
711 
712  auto r0 = find_halfedge( v0, vh );
713  auto s0 = find_halfedge( vh, v1 );
714  auto t0 = find_halfedge( v1, vh );
715  auto u0 = find_halfedge( vh, v0 );
716 
717  auto r1 = next_halfedge_handle( r0 );
718  auto r2 = next_halfedge_handle( r1 );
719 
720  auto s1 = next_halfedge_handle( s0 );
721  auto s2 = next_halfedge_handle( s1 );
722 
723  auto t1 = next_halfedge_handle( t0 );
724  auto t2 = next_halfedge_handle( t1 );
725 
726  auto u1 = next_halfedge_handle( u0 );
727  auto u2 = next_halfedge_handle( u1 );
728 
729  CORE_ASSERT( s0 == h0, "TopologicalMesh: splitEdgeWedge inconsistency" );
730  CORE_ASSERT( t0 == o0, "TopologicalMesh: splitEdgeWedge inconsistency" );
731 
732  auto updateWedgeIndex1 = [this]( WedgeIndex widx_,
733  HalfedgeHandle r0_,
734  HalfedgeHandle r1_,
735  HalfedgeHandle r2_,
736  HalfedgeHandle h1_,
737  HalfedgeHandle h2_ ) {
738  CORE_UNUSED( r2_ );
739  CORE_UNUSED( h2_ );
740 
741  if ( !is_boundary( r0_ ) ) {
742  CORE_ASSERT( r2_ == h2_, "TopologicalMesh: splitEdgeWedge inconsistency" );
743 
744  // Increment here, the first reference is for the other he
745  property( this->m_wedgeIndexPph, r0_ ) = this->m_wedges.newReference( widx_ );
746  property( this->m_wedgeIndexPph, r1_ ) =
747  this->m_wedges.newReference( property( this->m_wedgeIndexPph, h1_ ) );
748  }
749  else { property( this->m_wedgeIndexPph, r0_ ) = WedgeIndex {}; }
750  };
751 
752  auto updateWedgeIndex2 = [this]( WedgeIndex widx_,
753  HalfedgeHandle s0_,
754  HalfedgeHandle s1_,
755  HalfedgeHandle s2_,
756  HalfedgeHandle h0_,
757  HalfedgeHandle h1_ ) {
758  CORE_UNUSED( s1_ );
759  CORE_UNUSED( h1_ );
760 
761  if ( !is_boundary( s0_ ) ) {
762  CORE_ASSERT( s1_ == h1_, "TopologicalMesh: splitEdgeWedge inconsistency" );
763  // do not increment here, since add has set ref to 1
764  property( this->m_wedgeIndexPph, s2_ ) = widx_;
765  // "steal" ref from previous he (actually s0 is h0, u0 is the steal
766  // from o0.
767  property( this->m_wedgeIndexPph, s0_ ) = property( this->m_wedgeIndexPph, h0_ );
768  }
769  else { property( this->m_wedgeIndexPph, s0_ ) = WedgeIndex {}; }
770  };
771 
772  // this update read from o0, must be done before t which reads from o0
773  updateWedgeIndex2( ovwidx, u0, u1, u2, o0, o1 );
774  // those update might be in any order
775  updateWedgeIndex2( hvwidx, s0, s1, s2, h0, h1 );
776  updateWedgeIndex1( hvwidx, r0, r1, r2, h1, h2 );
777  updateWedgeIndex1( ovwidx, t0, t1, t2, o1, o2 );
778 
779  return true;
780 }
781 
782 //-----------------------------------------------------------------------------
783 void TopologicalMesh::collapse( HalfedgeHandle _hh, bool keepFrom ) {
784  HalfedgeHandle h0 = _hh;
785  HalfedgeHandle h1 = next_halfedge_handle( h0 );
786  HalfedgeHandle o0 = opposite_halfedge_handle( h0 );
787  HalfedgeHandle o1 = next_halfedge_handle( o0 );
788 
789  // remove edge
790  collapse_edge( h0, keepFrom );
791 
792  // remove loops
793  if ( next_halfedge_handle( next_halfedge_handle( h1 ) ) == h1 )
794  collapse_loop( next_halfedge_handle( h1 ) );
795  if ( next_halfedge_handle( next_halfedge_handle( o1 ) ) == o1 ) collapse_loop( o1 );
796 }
797 
798 //-----------------------------------------------------------------------------
799 void TopologicalMesh::collapse_edge( HalfedgeHandle _hh, bool keepFrom ) {
800  HalfedgeHandle h = _hh;
801  HalfedgeHandle hn = next_halfedge_handle( h );
802  HalfedgeHandle hp = prev_halfedge_handle( h );
803 
804  HalfedgeHandle o = opposite_halfedge_handle( h );
805  HalfedgeHandle on = next_halfedge_handle( o );
806  HalfedgeHandle ono = opposite_halfedge_handle( on );
807  HalfedgeHandle op = prev_halfedge_handle( o );
808 
809  FaceHandle fh = face_handle( h );
810  FaceHandle fo = face_handle( o );
811 
812  VertexHandle vh = to_vertex_handle( h );
813  VertexHandle vo = to_vertex_handle( o );
814 
815  auto widx = getWedgeIndex( h );
816  if ( widx.isInvalid() ) // i.e. h is boundary
817  widx = getWedgeIndex( op );
818  auto otherWidx = getWedgeIndex( op );
819  if ( otherWidx.isInvalid() ) // i.e. h is boundary
820  otherWidx = getWedgeIndex( h );
821 
822  // halfedge -> vertex
823 
824  // manual iter for from fixup
825  auto currentWidx = widx;
826  auto ringWidx = WedgeIndex {};
827  int phase = 0;
828  HalfedgeHandle start = prev_halfedge_handle( opposite_halfedge_handle( hp ) );
829  HalfedgeHandle vih = start;
830  do {
831  set_vertex_handle( vih, vh );
832  if ( !is_boundary( vih ) ) {
833  if ( !keepFrom ) {
834  if ( phase == 0 ) {
835  CORE_ASSERT( ringWidx.isInvalid(), "" );
836  phase = 1;
837  ringWidx = getWedgeIndex( vih );
838  }
839  if ( phase == 1 && ringWidx != getWedgeIndex( vih ) ) {
840  CORE_ASSERT( ringWidx.isValid(), "" );
841  CORE_ASSERT( getWedgeIndex( vih ).isValid(), "" );
842  phase = 2;
843  currentWidx = otherWidx;
844  }
845  replaceWedgeIndex( vih, currentWidx );
846  }
847  else { m_wedges.setWedgePosition( getWedgeIndex( vih ), point( vh ) ); }
848  }
849  vih = prev_halfedge_handle( opposite_halfedge_handle( vih ) );
850  } while ( vih != start );
851  // Reference version from openmesh
852  // for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it )
853  // {
854  // set_vertex_handle( *vih_it, vh );
855  // if ( !is_boundary( *vih_it ) )
856  // {
857  // if ( !keepFrom ) { replaceWedgeIndex( *vih_it, widx ); }
858  // else
859  // { m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), point( vh ) ); }
860  // }
861  // }
862 
863  // halfedge -> halfedge
864  set_next_halfedge_handle( hp, hn );
865  if ( !is_boundary( hp ) )
866  if ( !keepFrom ) replaceWedgeIndex( hp, widx );
867 
868  set_next_halfedge_handle( op, on );
869 
870  if ( keepFrom ) {
871  if ( !is_boundary( op ) ) replaceWedgeIndex( op, getWedgeIndex( ono ) );
872  }
873  // face -> halfedge
874  if ( fh.is_valid() ) set_halfedge_handle( fh, hn );
875  if ( fo.is_valid() ) set_halfedge_handle( fo, on );
876 
877  // vertex -> halfedge
878  if ( halfedge_handle( vh ) == o ) set_halfedge_handle( vh, hn );
879  adjust_outgoing_halfedge( vh );
880  set_isolated( vo );
881 
882  // delete stuff
883  status( edge_handle( h ) ).set_deleted( true );
884 
885  status( vo ).set_deleted( true );
886 
887  m_wedges.del( getWedgeIndex( h ) );
888  m_wedges.del( getWedgeIndex( o ) );
889 
890  if ( has_halfedge_status() ) {
891  status( h ).set_deleted( true );
892  status( o ).set_deleted( true );
893  }
894 }
895 
896 //-----------------------------------------------------------------------------
897 void TopologicalMesh::collapse_loop( HalfedgeHandle _hh ) {
898  HalfedgeHandle h0 = _hh;
899  HalfedgeHandle h1 = next_halfedge_handle( h0 );
900 
901  HalfedgeHandle o0 = opposite_halfedge_handle( h0 );
902  HalfedgeHandle o1 = opposite_halfedge_handle( h1 );
903 
904  VertexHandle v0 = to_vertex_handle( h0 );
905  VertexHandle v1 = to_vertex_handle( h1 );
906 
907  FaceHandle fh = face_handle( h0 );
908  FaceHandle fo = face_handle( o0 );
909 
910  // is it a loop ?
911  assert( ( next_halfedge_handle( h1 ) == h0 ) && ( h1 != o0 ) );
912 
913  // halfedge -> halfedge
914  set_next_halfedge_handle( h1, next_halfedge_handle( o0 ) );
915  replaceWedgeIndex( h1, getWedgeIndex( o0 ) );
916  set_next_halfedge_handle( prev_halfedge_handle( o0 ), h1 );
917 
918  // halfedge -> face
919  set_face_handle( h1, fo );
920 
921  // vertex -> halfedge
922  set_halfedge_handle( v0, h1 );
923  adjust_outgoing_halfedge( v0 );
924  set_halfedge_handle( v1, o1 );
925  adjust_outgoing_halfedge( v1 );
926 
927  // face -> halfedge
928  if ( fo.is_valid() && halfedge_handle( fo ) == o0 ) { set_halfedge_handle( fo, h1 ); }
929 
930  // delete stuff
931  if ( fh.is_valid() ) {
932  set_halfedge_handle( fh, InvalidHalfedgeHandle );
933  status( fh ).set_deleted( true );
934  }
935  status( edge_handle( h0 ) ).set_deleted( true );
936 
937  m_wedges.del( getWedgeIndex( h0 ) );
938  m_wedges.del( getWedgeIndex( o0 ) );
939 
940  if ( has_halfedge_status() ) {
941  status( h0 ).set_deleted( true );
942  status( o0 ).set_deleted( true );
943  }
944 }
945 
946 void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh, bool keepFromWedges ) {
947  collapse( heh, keepFromWedges );
948 }
949 
951  // Wedge Ref count is already up to date, do not del again !
952 
953  auto offset = m_wedges.computeCleanupOffset();
954  for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) {
955  if ( !status( *he_it ).deleted() ) {
956  auto index = property( m_wedgeIndexPph, *he_it );
957  if ( index.isValid() ) { property( m_wedgeIndexPph, *he_it ) = index - offset[index]; }
958  }
959  }
960  m_wedges.garbageCollection();
961  base::garbage_collection();
962 
963  for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) {
964  ON_ASSERT( auto idx = property( m_wedgeIndexPph, *he_it ); );
965  CORE_ASSERT( !idx.isValid() || !m_wedges.getWedge( idx ).isDeleted(),
966  "references deleted wedge remains after garbage collection" );
967  }
968  for ( size_t i = 0; i < m_wedges.size(); ++i ) {
969  CORE_ASSERT( !m_wedges.getWedge( WedgeIndex { i } ).isDeleted(),
970  "deleted wedge remains after garbage collection" );
971  }
972 }
973 
974 void TopologicalMesh::delete_face( FaceHandle _fh, bool _delete_isolated_vertices ) {
975  for ( auto itr = fh_begin( _fh ); itr.is_valid(); ++itr ) {
976  auto idx = property( m_wedgeIndexPph, *itr );
977  if ( idx.isInvalid() ) {
978  LOG( logWARNING )
979  << "[TopologicalMesh::delete_face] halfedge has an invalid wedge index";
980  }
981  else { m_wedges.del( idx ); }
982  // set an invalid index for the boundary halfedges
983  property( m_wedgeIndexPph, *itr ) = WedgeIndex {};
984  }
985  base::delete_face( _fh, _delete_isolated_vertices );
986 }
987 
989 
990 TopologicalMesh::WedgeIndex
991 TopologicalMesh::WedgeCollection::add( const TopologicalMesh::WedgeData& wd ) {
992  WedgeIndex idx;
993  auto itr = std::find( m_data.begin(), m_data.end(), Wedge { wd } );
994 
995  if ( itr == m_data.end() ) {
996  idx = m_data.size();
997  m_data.emplace_back( wd );
998  }
999  else {
1000  itr->incrementRefCount();
1001  idx = std::distance( m_data.begin(), itr );
1002  }
1003  return idx;
1004 }
1005 
1006 std::vector<int> TopologicalMesh::WedgeCollection::computeCleanupOffset() const {
1007  std::vector<int> ret( m_data.size(), 0 );
1008  int currentOffset = 0;
1009  for ( size_t i = 0; i < m_data.size(); ++i ) {
1010  if ( m_data[i].isDeleted() ) {
1011  ++currentOffset;
1012  ret[i] = -1;
1013  }
1014  else { ret[i] = currentOffset; }
1015  }
1016  return ret;
1017 }
1018 
1019 } // namespace Geometry
1020 } // namespace Core
1021 } // namespace Ra
NormalAttribHandle::Container & normalsWithLock()
void normalsUnlock()
Release lock on vertices normals.
void setVertices(PointAttribHandle::Container &&vertices)
Set vertices.
const NormalAttribHandle::Container & normals() const
Access the vertices normals.
const PointAttribHandle::Container & vertices() const
Access the vertices positions.
Utils::Attrib< T > & getAttrib(const Utils::AttribHandle< T > &h)
AbstractGeometry with per-vertex attributes and layers of indices. Each layer represents a different ...
bool isManifold(VertexHandle vh) const
void updateTriangleMesh(Ra::Core::Geometry::MultiIndexedGeometry &mesh)
void collapse(HalfedgeHandle, bool=false)
bool splitEdge(TopologicalMesh::EdgeHandle eh, Scalar f)
std::set< WedgeIndex > getVertexWedges(OpenMesh::VertexHandle vh) const
unsigned int getWedgeRefCount(const WedgeIndex &idx) const
void garbage_collection()
Remove deleted element from the mesh, including wedges.
const WedgeData & getWedgeData(const WedgeIndex &idx) const
LineMeshPtr Normal(const Core::Vector3 &point, const Core::Vector3 &normal, const Core::Utils::Color &color, Scalar scale)
Definition: Cage.cpp:3