Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
11namespace Ra {
12namespace Core {
13namespace Geometry {
14
15using namespace Utils; // log, AttribXXX
16
18
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
64bool 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
114void 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
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
165void 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
188template <typename T>
189void 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
196template <typename T>
197void 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
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
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
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
401void 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
413void TopologicalMesh::updateTriangleMeshNormals( Ra::Core::Geometry::MultiIndexedGeometry& out ) {
414 auto& normals = out.normalsWithLock();
415 updateTriangleMeshNormals( normals );
416 out.normalsUnlock();
417}
418
419void 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
439void TopologicalMesh::updatePositions( const Ra::Core::Geometry::MultiIndexedGeometry& triMesh ) {
440 updatePositions( triMesh.vertices() );
441}
442
443void 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
452void 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
460void 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
503template <typename T>
504void 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
514TopologicalMesh::interpolateWedgeAttributes( const TopologicalMesh::WedgeData& w1,
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
527void 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
617void 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
647bool 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//-----------------------------------------------------------------------------
783void 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//-----------------------------------------------------------------------------
799void 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//-----------------------------------------------------------------------------
897void 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
946void 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
974void 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
990TopologicalMesh::WedgeIndex
991TopologicalMesh::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
1006std::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)
void setIndices(IndexContainerType &&indices)
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)
WedgeIndex getWedgeIndex(OpenMesh::HalfedgeHandle heh) const
void replaceWedgeIndex(OpenMesh::HalfedgeHandle he, const WedgeIndex &widx)
void collapse(HalfedgeHandle he, bool keepFromVertex=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
HalfedgeHandle halfedge_handle(VertexHandle vh, FaceHandle fh) const
T distance(T... args)
T emplace_back(T... args)
T find_if(T... args)
T move(T... args)
This namespace contains everything "low level", related to data, datastuctures, and computation.
Definition Cage.cpp:4
LineMeshPtr Normal(const Core::Vector3 &point, const Core::Vector3 &normal, const Core::Utils::Color &color, Scalar scale)
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T push_back(T... args)
T size(T... args)
T str(T... args)
T swap(T... args)