@@ -38,62 +38,145 @@ using namespace std;
3838using namespace IECore ;
3939using namespace IECoreScene ;
4040
41+ namespace {
42+
43+ inline void linearInsert ( int *list, int val )
44+ {
45+ while ( *list != -1 )
46+ {
47+ if ( *list == val )
48+ {
49+ return ;
50+ }
51+ list++;
52+ }
53+ *list = val;
54+ }
55+
56+ } // namespace
57+
4158pair<IntVectorDataPtr, IntVectorDataPtr> MeshAlgo::connectedVertices ( const MeshPrimitive *mesh, const Canceller *canceller )
4259{
4360 size_t numVertices = mesh->variableData < V3fVectorData >( " P" , PrimitiveVariable::Vertex )->readable ().size ();
4461 const vector<int > &numVerticesPerFace = mesh->verticesPerFace ()->readable ();
4562 const vector<int > &vertexIds = mesh->vertexIds ()->readable ();
4663
47- vector< set<int > > neighbors ( numVertices );
64+ IntVectorDataPtr offsetsData = new IntVectorData ();
65+ vector<int > &offsets = offsetsData->writable ();
66+ offsets.resize ( numVertices, 0 );
4867
49- int currentVertOffset = 0 ;
68+ Canceller::check ( canceller );
69+
70+ // Start initializing the offsets vector by storing the maximum number of possible neighbours each
71+ // vertex could have. Every time a vertex appears in the vertex id list, that means it's part of
72+ // a polygon, and has two more edges connecting it to two other vertices. In the common case,
73+ // the number we arrive at by this method is twice as high as needed, because in a manifold mesh,
74+ // every edge appears in the face list twice.
75+ for ( int i : vertexIds )
76+ {
77+ offsets[ i ] += 2 ;
78+ }
79+
80+ Canceller::check ( canceller );
81+
82+ // Convert the neighbour counts into offsets to the start of each list of possible neighbours,
83+ // by storing a running total
84+ int totalPossibleNeighbours = 0 ;
85+ for ( int &o : offsets )
86+ {
87+ int count = o;
88+ o = totalPossibleNeighbours;
89+ totalPossibleNeighbours += count;
90+ }
91+
92+ // Allocate storage for all possible neighbours, and collect neighbours from every face.
93+ // On a manifold mesh, only half the storage for each vertex will be used, because every
94+ // vertex pair occurs in two separate faces. ( Unused element will be left at -1 )
95+ Canceller::check ( canceller );
96+ IntVectorDataPtr neighbourListData = new IntVectorData ();
97+ std::vector<int > &neighbourList = neighbourListData->writable ();
98+ neighbourList.resize ( totalPossibleNeighbours, -1 );
99+ int faceStart = 0 ;
50100 for ( auto &vertsPerFace : numVerticesPerFace )
51101 {
52102 Canceller::check ( canceller );
53103
54104 for ( int i = 0 ; i < vertsPerFace; ++i)
55105 {
56- const int & faceVert = vertexIds[ currentVertOffset + i ];
57- const int & faceVertNext = vertexIds[ currentVertOffset + ( i + 1 ) % vertsPerFace ];
58- neighbors[ faceVert ]. insert ( faceVertNext );
59- neighbors[ faceVertNext ]. insert ( faceVert );
106+ int faceVert = vertexIds[ faceStart + i ];
107+ int faceVertNext = vertexIds[ faceStart + ( i + 1 ) % vertsPerFace ];
108+ linearInsert ( &neighbourList[ offsets[ faceVert] ], faceVertNext );
109+ linearInsert ( &neighbourList[ offsets[ faceVertNext] ], faceVert );
60110 }
61- currentVertOffset += vertsPerFace;
111+ faceStart += vertsPerFace;
62112 }
63113
64- int neighborCount = 0 ;
65- int cancelTestCounter = 0 ;
66- for ( auto &n : neighbors )
114+ // Compact the neighbourList to contain only used vertices by removing any -1 values,
115+ // and update offsets accordingly - we also convert the offsets from pointing to the
116+ // start of the lists to the end of the lists at the same time.
117+ int usedOutputIndex = 0 ;
118+ for ( int i = 0 ; i < (int )offsets.size (); i++ )
67119 {
68- if ( cancelTestCounter++ == 1000 )
120+ Canceller::check ( canceller );
121+ int end = i < (int )offsets.size () - 1 ? offsets[i + 1 ] : totalPossibleNeighbours;
122+ int neighbourIndex = offsets[i];
123+ while ( neighbourIndex < end && neighbourList[neighbourIndex] != -1 )
69124 {
70- Canceller::check ( canceller );
71- cancelTestCounter = 0 ;
125+ neighbourList[usedOutputIndex++] = neighbourList[neighbourIndex++];
72126 }
73- neighborCount += n. size () ;
127+ offsets[i] = usedOutputIndex ;
74128 }
129+ neighbourList.resize ( usedOutputIndex );
75130
76- IntVectorDataPtr offsets = new IntVectorData ();
77- IntVectorDataPtr neighborList = new IntVectorData ();
78- vector<int > &offsetsW = offsets->writable ();
79- vector<int > &neighborListW = neighborList->writable ();
131+ // It would be a little simpler to just call neighbourList.shrink_to_fit() here so the output would always
132+ // be exactly sized right, but this reallocation costs about 10% of our performance, so instead I guess
133+ // we'll just document that you may want to call shrink_to_fit() if you're keeping this data around.
134+
135+ return pair<IntVectorDataPtr, IntVectorDataPtr>( neighbourListData, offsetsData );
136+ }
137+
138+ pair<IntVectorDataPtr, IntVectorDataPtr> MeshAlgo::correspondingFaceVertices ( const MeshPrimitive *mesh, const Canceller *canceller )
139+ {
140+ size_t numVertices = mesh->variableData < V3fVectorData >( " P" , PrimitiveVariable::Vertex )->readable ().size ();
141+ const vector<int > &vertexIds = mesh->vertexIds ()->readable ();
80142
81- neighborListW.resize ( neighborCount, -1 );
82- offsetsW.resize ( neighbors.size (), -1 );
143+ IntVectorDataPtr offsetsData = new IntVectorData ();
144+ vector<int > &offsets = offsetsData->writable ();
145+ Canceller::check ( canceller );
146+ offsets.resize ( numVertices, 0 );
83147
84- int ix = 0 ;
85- for ( size_t i = 0 ; i < neighbors. size (); ++i )
148+ // Start initializing the offsets vector by storing the number of face vertices
149+ for ( int i : vertexIds )
86150 {
87- if ( i % 1000 == 0 )
88- {
89- Canceller::check ( canceller );
90- }
91- for ( auto &n : neighbors[ i ] )
92- {
93- neighborListW[ ix++ ] = n;
94- }
95- offsetsW[ i ] = ix;
151+ offsets[ i ]++;
152+ }
153+
154+ Canceller::check ( canceller );
155+
156+ // Convert the counts into offsets to the start of each list of face vertices
157+ int countFaceVertices = 0 ;
158+ for ( int &o : offsets )
159+ {
160+ int count = o;
161+ o = countFaceVertices;
162+ countFaceVertices += count;
163+ }
164+
165+ Canceller::check ( canceller );
166+ IntVectorDataPtr faceVerticesData = new IntVectorData ();
167+ vector<int > &faceVertices = faceVerticesData->writable ();
168+ Canceller::check ( canceller );
169+ faceVertices.resize ( countFaceVertices );
170+
171+ // Now run through all faces, storing face vertex indices in the new list. We increment the offset
172+ // for each face vertex we store, meaning that the indices start out pointing to the beginning of the
173+ // list for each vertex, and end up pointing at the end of the list for each vertex.
174+ for ( unsigned int i = 0 ; i < vertexIds.size (); i++ )
175+ {
176+ int vert = vertexIds[ i ];
177+ faceVertices[ offsets[ vert ] ] = i;
178+ offsets[ vert ] ++;
96179 }
97180
98- return pair<IntVectorDataPtr, IntVectorDataPtr>( neighborList, offsets );
181+ return pair<IntVectorDataPtr, IntVectorDataPtr>( faceVerticesData, offsetsData );
99182}
0 commit comments