Skip to content

Commit f8e4049

Browse files
MeshAlgo::MeshSplitter : Preserve vertex order
1 parent bc4a373 commit f8e4049

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

src/IECoreScene/MeshAlgoSplit.cpp

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,8 @@ class Reindexer
490490
m_newIndices( m_newIndicesData->writable() ),
491491
m_blockSize( blockSize ),
492492
m_fromOldIds( ( numOriginalIds - 1 ) / blockSize + 1 ),
493-
m_numIdsUsed( 0 )
493+
m_numIdsUsed( 0 ),
494+
m_indicesComputed( false )
494495
{
495496
m_newIndices.reserve( numIndices );
496497
}
@@ -510,19 +511,53 @@ class Reindexer
510511
block = std::make_unique< std::vector<int> >( m_blockSize, -1 );
511512
}
512513

513-
int &r = (*block)[ subIndex ];
514-
if( r == -1 )
514+
// We initially record that this index is used just by marking it with a 0, against the background of -1.
515+
// Once computeIndices is called, the 0 will be replaced with a new index, only counting indices that are
516+
// used.
517+
(*block)[ subIndex ] = 0;
518+
519+
m_newIndices.push_back( id );
520+
}
521+
522+
void computeIndices()
523+
{
524+
if( m_indicesComputed )
525+
{
526+
return;
527+
}
528+
529+
m_indicesComputed = true;
530+
531+
for( unsigned int blockId = 0; blockId < m_fromOldIds.size(); blockId++ )
515532
{
516-
// Id isn't used yet, we need to set this location in the block, and use it
517-
r = m_numIdsUsed;
518-
m_numIdsUsed++;
533+
auto &block = m_fromOldIds[ blockId ];
534+
if( !block )
535+
{
536+
continue;
537+
}
538+
539+
for( int i = 0; i < m_blockSize; i++ )
540+
{
541+
if( (*block)[i] != -1 )
542+
{
543+
(*block)[i] = m_numIdsUsed;
544+
m_numIdsUsed++;
545+
}
546+
}
519547
}
520548

521-
m_newIndices.push_back( r );
549+
for( int &id : m_newIndices )
550+
{
551+
int blockId = id / m_blockSize;
552+
int subIndex = id % m_blockSize;
553+
554+
id = (*m_fromOldIds[ blockId ])[subIndex];
555+
}
522556
}
523557

524558
// Don't add the index, but just test if it is a part of the reindex. If it is an
525559
// id which has already been added, return the new id, otherwise return -1
560+
// You must call computeIndices() after calling addIndex and before calling this function.
526561
inline int testIndex( int id )
527562
{
528563
int blockId = id / m_blockSize;
@@ -541,6 +576,7 @@ class Reindexer
541576
// Get the new indices. Call after calling addIndex for every original index
542577
IntVectorDataPtr getNewIndices()
543578
{
579+
computeIndices();
544580
return m_newIndicesData;
545581
}
546582

@@ -550,6 +586,7 @@ class Reindexer
550586
template <typename T >
551587
void remapData( const std::vector<T> &in, std::vector<T> &out )
552588
{
589+
computeIndices();
553590
out.resize( m_numIdsUsed );
554591
for( unsigned int i = 0; i < m_fromOldIds.size(); i++ )
555592
{
@@ -574,6 +611,7 @@ class Reindexer
574611
// original id corresponding to each id of the output
575612
void getDataRemapping( std::vector<int> &dataRemap )
576613
{
614+
computeIndices();
577615
dataRemap.resize( m_numIdsUsed );
578616
for( unsigned int i = 0; i < m_fromOldIds.size(); i++ )
579617
{
@@ -605,13 +643,16 @@ class Reindexer
605643
// Store the mapping from old ids to new ids. The outer vector holds a unique_ptr for each
606644
// block of m_blockSize ids in the original id range. These pointers are null if no ids from
607645
// that block have been used. Once a block is used, it is allocated with a vector that is set
608-
// to -1 for ids which have not been used, and the new corresponding id for ids which have been
609-
// used
646+
// to -1 for ids which have not been used, and zeros for ids which have been used. When computeIndices()
647+
// is called, all used elements get a new id assigned, relative to just the used ids.
610648
std::vector< std::unique_ptr< std::vector< int > > > m_fromOldIds;
611649

612650
// How many unique ids have appeared in the indices added so far
613651
int m_numIdsUsed;
614652

653+
// Whether we have yet computed the new indices for each used index
654+
bool m_indicesComputed;
655+
615656
};
616657

617658
struct ResamplePrimitiveVariableFunctor

test/IECoreScene/MeshAlgoSplitTest.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,29 @@ def accumulateInPython2( iterable ):
170170
newVerticesPerFace = []
171171
newVertIndices = []
172172
mapFaceVert = []
173-
reverseIndices = []
173+
174+
usedIndices = set()
174175
for i in r:
175176
vpf = mesh.verticesPerFace[i]
176177
newVerticesPerFace.append( vpf )
177178
for j in range( vpf ):
178179
origFaceVert = faceIndices[i] + j
179180
origVert = mesh.vertexIds[ origFaceVert ]
180-
newIndex = reindex.setdefault( origVert, len( reindex ) )
181-
if len( reindex ) > len( reverseIndices ):
182-
reverseIndices.append( origVert )
181+
182+
usedIndices.add( origVert )
183+
184+
usedIndices = sorted( usedIndices )
185+
186+
for i in range( len( usedIndices ) ):
187+
reindex[ usedIndices[i] ] = i
188+
189+
for i in r:
190+
vpf = mesh.verticesPerFace[i]
191+
for j in range( vpf ):
192+
origFaceVert = faceIndices[i] + j
193+
origVert = mesh.vertexIds[ origFaceVert ]
194+
195+
newIndex = usedIndices.index( origVert )
183196
newVertIndices.append( newIndex )
184197
mapFaceVert.append( origFaceVert )
185198

@@ -226,7 +239,7 @@ def accumulateInPython2( iterable ):
226239
if p.interpolation == interp.Constant:
227240
d = p.data.copy()
228241
elif p.interpolation in [ interp.Vertex, interp.Varying ]:
229-
d = type( p.data )( [ pd[i] for i in reverseIndices] )
242+
d = type( p.data )( [ pd[i] for i in usedIndices] )
230243
elif p.interpolation == interp.FaceVarying:
231244
d = type( p.data )( [ pd[i] for i in mapFaceVert ] )
232245
elif p.interpolation == interp.Uniform:
@@ -269,8 +282,8 @@ def testCanSplitUsingIntegerPrimvar( self ) :
269282
p12 = imath.V3f( 1, 2, 0 )
270283
p22 = imath.V3f( 2, 2, 0 )
271284

272-
self.assertEqual( s0["P"].data, IECore.V3fVectorData( [p00, p10, p11, p01, p20, p21], IECore.GeometricData.Interpretation.Point ) )
273-
self.assertEqual( s1["P"].data, IECore.V3fVectorData( [p01, p11, p12, p02, p21, p22], IECore.GeometricData.Interpretation.Point ) )
285+
self.assertEqual( s0["P"].data, IECore.V3fVectorData( [p00, p10, p20, p01, p11, p21], IECore.GeometricData.Interpretation.Point ) )
286+
self.assertEqual( s1["P"].data, IECore.V3fVectorData( [p01, p11, p21, p02, p12, p22], IECore.GeometricData.Interpretation.Point ) )
274287

275288
def testSplitsFully( self ) :
276289
mesh = IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( 0 ), imath.V2f( 2 ) ), imath.V2i( 2 ) )
@@ -303,8 +316,8 @@ def testSplitsFully( self ) :
303316
if s0["s"].data[0] != 'a':
304317
s0,s1 = s1,s0
305318

306-
self.assertEqual( s0["P"].data, IECore.V3fVectorData( [p00, p10, p11, p01, p21, p22, p12], IECore.GeometricData.Interpretation.Point ) )
307-
self.assertEqual( s1["P"].data, IECore.V3fVectorData( [p10, p20, p21, p11, p01, p12, p02], IECore.GeometricData.Interpretation.Point ) )
319+
self.assertEqual( s0["P"].data, IECore.V3fVectorData( [p00, p10, p01, p11, p21, p12, p22], IECore.GeometricData.Interpretation.Point ) )
320+
self.assertEqual( s1["P"].data, IECore.V3fVectorData( [p10, p20, p01, p11, p21, p02, p12], IECore.GeometricData.Interpretation.Point ) )
308321

309322
def testSplitUsingIndexedPrimitiveVariable( self ) :
310323

0 commit comments

Comments
 (0)