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