1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkEdgeTable.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkEdgeTable.h"
16 #include "vtkIdList.h"
17 #include "vtkObjectFactory.h"
18 #include "vtkPoints.h"
19 #include "vtkVoidArray.h"
20 
21 vtkStandardNewMacro(vtkEdgeTable);
22 
23 //------------------------------------------------------------------------------
24 // Instantiate object based on maximum point id.
vtkEdgeTable()25 vtkEdgeTable::vtkEdgeTable()
26 {
27   this->Table = nullptr;
28   this->Attributes = nullptr;
29   this->PointerAttributes = nullptr;
30   this->Points = nullptr;
31 
32   this->TableMaxId = -1;
33   this->TableSize = 0;
34 
35   this->Position[0] = 0;
36   this->Position[1] = -1;
37   this->NumberOfEdges = 0;
38 }
39 
40 //------------------------------------------------------------------------------
41 // Free memory and return to instantiated state.
Initialize()42 void vtkEdgeTable::Initialize()
43 {
44   vtkIdType i;
45 
46   if (this->Table)
47   {
48     for (i = 0; i < this->TableSize; i++)
49     {
50       if (this->Table[i])
51       {
52         this->Table[i]->Delete();
53       }
54     }
55     delete[] this->Table;
56     this->Table = nullptr;
57     this->TableMaxId = -1;
58 
59     if (this->StoreAttributes == 1)
60     {
61       for (i = 0; i < this->TableSize; i++)
62       {
63         if (this->Attributes[i])
64         {
65           this->Attributes[i]->Delete();
66         }
67       }
68       delete[] this->Attributes;
69       this->Attributes = nullptr;
70     }
71     else if (this->StoreAttributes == 2)
72     {
73       for (i = 0; i < this->TableSize; i++)
74       {
75         if (this->PointerAttributes[i])
76         {
77           this->PointerAttributes[i]->Delete();
78         }
79       }
80       delete[] this->PointerAttributes;
81       this->PointerAttributes = nullptr;
82     }
83   } // if table defined
84 
85   if (this->Points)
86   {
87     this->Points->Delete();
88     this->Points = nullptr;
89   }
90 
91   this->TableSize = 0;
92   this->NumberOfEdges = 0;
93 }
94 
95 //------------------------------------------------------------------------------
96 // Free memory and return to instantiated state.
Reset()97 void vtkEdgeTable::Reset()
98 {
99   vtkIdType i;
100 
101   if (this->Table)
102   {
103     for (i = 0; i < this->TableSize; i++)
104     {
105       if (this->Table[i])
106       {
107         this->Table[i]->Reset();
108       }
109     }
110 
111     if (this->StoreAttributes == 1 && this->Attributes)
112     {
113       for (i = 0; i < this->TableSize; i++)
114       {
115         if (this->Attributes[i])
116         {
117           this->Attributes[i]->Reset();
118         }
119       }
120     }
121     else if (this->StoreAttributes == 2 && this->PointerAttributes)
122     {
123       for (i = 0; i < this->TableSize; i++)
124       {
125         if (this->PointerAttributes[i])
126         {
127           this->PointerAttributes[i]->Reset();
128         }
129       }
130     }
131   } // if table defined
132 
133   this->TableMaxId = -1;
134 
135   if (this->Points)
136   {
137     this->Points->Reset();
138   }
139 
140   this->NumberOfEdges = 0;
141 }
142 
143 //------------------------------------------------------------------------------
~vtkEdgeTable()144 vtkEdgeTable::~vtkEdgeTable()
145 {
146   this->Initialize();
147 }
148 
149 //------------------------------------------------------------------------------
InitEdgeInsertion(vtkIdType numPoints,int storeAttributes)150 int vtkEdgeTable::InitEdgeInsertion(vtkIdType numPoints, int storeAttributes)
151 {
152   vtkIdType i;
153 
154   numPoints = (numPoints < 1 ? 1 : numPoints);
155 
156   // Discard old memory if not enough has been previously allocated
157   this->StoreAttributes = storeAttributes;
158   this->TableMaxId = -1;
159 
160   if (numPoints > this->TableSize)
161   {
162     this->Initialize();
163     this->Table = new vtkIdList*[numPoints];
164     for (i = 0; i < numPoints; i++)
165     {
166       this->Table[i] = nullptr;
167     }
168 
169     if (this->StoreAttributes == 1)
170     {
171       this->Attributes = new vtkIdList*[numPoints];
172       for (i = 0; i < numPoints; i++)
173       {
174         this->Attributes[i] = nullptr;
175       }
176     }
177     else if (this->StoreAttributes == 2)
178     {
179       this->PointerAttributes = new vtkVoidArray*[numPoints];
180       for (i = 0; i < numPoints; i++)
181       {
182         this->PointerAttributes[i] = nullptr;
183       }
184     }
185     this->TableSize = numPoints;
186   }
187 
188   // Otherwise, reuse the old memory
189   else
190   {
191     this->Reset();
192   }
193 
194   this->Position[0] = 0;
195   this->Position[1] = -1;
196 
197   this->NumberOfEdges = 0;
198 
199   return 1;
200 }
201 
202 //------------------------------------------------------------------------------
203 // Return non-negative if edge (p1,p2) is an edge; otherwise -1.
IsEdge(vtkIdType p1,vtkIdType p2)204 vtkIdType vtkEdgeTable::IsEdge(vtkIdType p1, vtkIdType p2)
205 {
206   vtkIdType index, search;
207 
208   if (p1 < p2)
209   {
210     index = p1;
211     search = p2;
212   }
213   else
214   {
215     index = p2;
216     search = p1;
217   }
218 
219   if (index > this->TableMaxId || this->Table[index] == nullptr)
220   {
221     return (-1);
222   }
223   else
224   {
225     vtkIdType loc;
226     if ((loc = this->Table[index]->IsId(search)) == (-1))
227     {
228       return (-1);
229     }
230     else
231     {
232       if (this->StoreAttributes == 1)
233       {
234         return this->Attributes[index]->GetId(loc);
235       }
236       else
237       {
238         return 1;
239       }
240     }
241   }
242 }
243 
244 //------------------------------------------------------------------------------
245 // Return non-negative if edge (p1,p2) is an edge; otherwise -1.
IsEdge(vtkIdType p1,vtkIdType p2,void * & ptr)246 void vtkEdgeTable::IsEdge(vtkIdType p1, vtkIdType p2, void*& ptr)
247 {
248   vtkIdType index, search;
249 
250   if (p1 < p2)
251   {
252     index = p1;
253     search = p2;
254   }
255   else
256   {
257     index = p2;
258     search = p1;
259   }
260 
261   if (index > this->TableMaxId || this->Table[index] == nullptr)
262   {
263     ptr = nullptr;
264   }
265   else
266   {
267     vtkIdType loc;
268     if ((loc = this->Table[index]->IsId(search)) == (-1))
269     {
270       ptr = nullptr;
271     }
272     else
273     {
274       if (this->StoreAttributes == 2)
275       {
276         ptr = this->PointerAttributes[index]->GetVoidPointer(loc);
277       }
278       else
279       {
280         ptr = nullptr;
281       }
282     }
283   }
284 }
285 
286 //------------------------------------------------------------------------------
287 // Insert the edge (p1,p2) into the table. It is the user's responsibility to
288 // check if the edge has already been inserted.
InsertEdge(vtkIdType p1,vtkIdType p2)289 vtkIdType vtkEdgeTable::InsertEdge(vtkIdType p1, vtkIdType p2)
290 {
291   vtkIdType index, search;
292 
293   if (p1 < p2)
294   {
295     index = p1;
296     search = p2;
297   }
298   else
299   {
300     index = p2;
301     search = p1;
302   }
303 
304   if (index >= this->TableSize)
305   {
306     this->Resize(index + 1);
307   }
308 
309   if (index > this->TableMaxId)
310   {
311     this->TableMaxId = index;
312   }
313 
314   if (this->Table[index] == nullptr)
315   {
316     this->Table[index] = vtkIdList::New();
317     this->Table[index]->Allocate(6, 12);
318     if (this->StoreAttributes == 1)
319     {
320       if (this->Attributes[index])
321       {
322         this->Attributes[index]->Delete();
323       }
324       this->Attributes[index] = vtkIdList::New();
325       this->Attributes[index]->Allocate(6, 12);
326     }
327   }
328 
329   this->Table[index]->InsertNextId(search);
330   if (this->StoreAttributes == 1)
331   {
332     this->Attributes[index]->InsertNextId(this->NumberOfEdges);
333   }
334   this->NumberOfEdges++;
335 
336   return (this->NumberOfEdges - 1);
337 }
338 
339 //------------------------------------------------------------------------------
InsertEdge(vtkIdType p1,vtkIdType p2,vtkIdType attributeId)340 void vtkEdgeTable::InsertEdge(vtkIdType p1, vtkIdType p2, vtkIdType attributeId)
341 {
342   vtkIdType index, search;
343 
344   if (p1 < p2)
345   {
346     index = p1;
347     search = p2;
348   }
349   else
350   {
351     index = p2;
352     search = p1;
353   }
354 
355   if (index >= this->TableSize)
356   {
357     this->Resize(index + 1);
358   }
359 
360   if (index > this->TableMaxId)
361   {
362     this->TableMaxId = index;
363   }
364 
365   if (this->Table[index] == nullptr)
366   {
367     this->Table[index] = vtkIdList::New();
368     this->Table[index]->Allocate(6, 12);
369     if (this->StoreAttributes == 1)
370     {
371       this->Attributes[index] = vtkIdList::New();
372       this->Attributes[index]->Allocate(6, 12);
373     }
374   }
375 
376   this->NumberOfEdges++;
377   this->Table[index]->InsertNextId(search);
378   if (this->StoreAttributes)
379   {
380     this->Attributes[index]->InsertNextId(attributeId);
381   }
382 }
383 
384 //------------------------------------------------------------------------------
InsertEdge(vtkIdType p1,vtkIdType p2,void * ptr)385 void vtkEdgeTable::InsertEdge(vtkIdType p1, vtkIdType p2, void* ptr)
386 {
387   vtkIdType index, search;
388 
389   if (p1 < p2)
390   {
391     index = p1;
392     search = p2;
393   }
394   else
395   {
396     index = p2;
397     search = p1;
398   }
399 
400   if (index >= this->TableSize)
401   {
402     this->Resize(index + 1);
403   }
404 
405   if (index > this->TableMaxId)
406   {
407     this->TableMaxId = index;
408   }
409 
410   if (this->Table[index] == nullptr)
411   {
412     this->Table[index] = vtkIdList::New();
413     this->Table[index]->Allocate(6, 12);
414     if (this->StoreAttributes == 2)
415     {
416       this->PointerAttributes[index] = vtkVoidArray::New();
417       this->PointerAttributes[index]->Allocate(6, 12);
418     }
419   }
420 
421   this->NumberOfEdges++;
422   this->Table[index]->InsertNextId(search);
423   if (this->StoreAttributes == 2)
424   {
425     this->PointerAttributes[index]->InsertNextVoidPointer(ptr);
426   }
427 }
428 
429 //------------------------------------------------------------------------------
430 // Initialize traversal of edges in table.
InitTraversal()431 void vtkEdgeTable::InitTraversal()
432 {
433   this->Position[0] = 0;
434   this->Position[1] = -1;
435 }
436 
437 // Traverse list of edges in table. Return the edge as (p1,p2), where p1 and
438 // p2 are point id's. Method return value is <0 if the list is exhausted;
439 // otherwise a valid id >=0. The value of p1 is guaranteed to be <= p2. The
440 // return value is an id that can be used for accessing attributes.
GetNextEdge(vtkIdType & p1,vtkIdType & p2)441 vtkIdType vtkEdgeTable::GetNextEdge(vtkIdType& p1, vtkIdType& p2)
442 {
443   for (; this->Position[0] <= this->TableMaxId; this->Position[0]++, this->Position[1] = (-1))
444   {
445     if (this->Table[this->Position[0]] != nullptr &&
446       ++this->Position[1] < this->Table[this->Position[0]]->GetNumberOfIds())
447     {
448       p1 = this->Position[0];
449       p2 = this->Table[this->Position[0]]->GetId(this->Position[1]);
450       if (this->StoreAttributes == 1)
451       {
452         return this->Attributes[this->Position[0]]->GetId(this->Position[1]);
453       }
454       else
455       {
456         return (-1);
457       }
458     }
459   }
460 
461   return (-1);
462 }
463 
464 //------------------------------------------------------------------------------
465 // Traverse list of edges in table. Return the edge as (p1,p2), where p1 and
466 // p2 are point id's. The value of p1 is guaranteed to be <= p2. The
467 // return value is either 1 for success or 0 if the list is exhausted.
GetNextEdge(vtkIdType & p1,vtkIdType & p2,void * & ptr)468 int vtkEdgeTable::GetNextEdge(vtkIdType& p1, vtkIdType& p2, void*& ptr)
469 {
470   for (; this->Position[0] <= this->TableMaxId; this->Position[0]++, this->Position[1] = (-1))
471   {
472     if (this->Table[this->Position[0]] != nullptr &&
473       ++this->Position[1] < this->Table[this->Position[0]]->GetNumberOfIds())
474     {
475       p1 = this->Position[0];
476       p2 = this->Table[this->Position[0]]->GetId(this->Position[1]);
477       if (this->StoreAttributes == 2)
478       {
479         this->IsEdge(p1, p2, ptr);
480       }
481       else
482       {
483         ptr = nullptr;
484       }
485       return 1;
486     }
487   }
488   return 0;
489 }
490 
Resize(vtkIdType size)491 vtkIdList** vtkEdgeTable::Resize(vtkIdType size)
492 {
493   vtkIdList** newTableArray;
494   vtkIdList** newAttributeArray;
495   vtkVoidArray** newPointerAttributeArray;
496   vtkIdType newSize, i;
497   vtkIdType extend = this->TableSize / 2 + 1;
498 
499   if (size >= this->TableSize)
500   {
501     newSize = this->TableSize + extend * (((size - this->TableSize) / extend) + 1);
502   }
503   else
504   {
505     newSize = size;
506   }
507 
508   size = (size < this->TableSize ? size : this->TableSize);
509   newTableArray = new vtkIdList*[newSize];
510   // NOLINTNEXTLINE(bugprone-sizeof-expression)
511   memcpy(newTableArray, this->Table, size * sizeof(*newTableArray));
512   for (i = size; i < newSize; i++)
513   {
514     newTableArray[i] = nullptr;
515   }
516   this->TableSize = newSize;
517   delete[] this->Table;
518   this->Table = newTableArray;
519 
520   if (this->StoreAttributes == 1)
521   {
522     newAttributeArray = new vtkIdList*[newSize];
523     // NOLINTNEXTLINE(bugprone-sizeof-expression)
524     memcpy(newAttributeArray, this->Attributes, size * sizeof(*newAttributeArray));
525     for (i = size; i < newSize; i++)
526     {
527       newAttributeArray[i] = nullptr;
528     }
529     delete[] this->Attributes;
530     this->Attributes = newAttributeArray;
531   }
532   else if (this->StoreAttributes == 2)
533   {
534     newPointerAttributeArray = new vtkVoidArray*[newSize];
535     // NOLINTNEXTLINE(bugprone-sizeof-expression)
536     memcpy(newPointerAttributeArray, this->Attributes, size * sizeof(*newPointerAttributeArray));
537     for (i = size; i < newSize; i++)
538     {
539       newPointerAttributeArray[i] = nullptr;
540     }
541     delete[] this->PointerAttributes;
542     this->PointerAttributes = newPointerAttributeArray;
543   }
544 
545   return this->Table;
546 }
547 
548 //------------------------------------------------------------------------------
InitPointInsertion(vtkPoints * newPts,vtkIdType estSize)549 int vtkEdgeTable::InitPointInsertion(vtkPoints* newPts, vtkIdType estSize)
550 {
551   // Initialize
552   if (this->Table)
553   {
554     this->Initialize();
555   }
556   if (newPts == nullptr)
557   {
558     vtkErrorMacro(<< "Must define points for point insertion");
559     return 0;
560   }
561   if (this->Points != nullptr)
562   {
563     this->Points->Delete();
564   }
565   // Set up the edge insertion
566   this->InitEdgeInsertion(estSize, 1);
567 
568   this->Points = newPts;
569   this->Points->Register(this);
570 
571   return 1;
572 }
573 
574 //------------------------------------------------------------------------------
InsertUniquePoint(vtkIdType p1,vtkIdType p2,double x[3],vtkIdType & ptId)575 int vtkEdgeTable::InsertUniquePoint(vtkIdType p1, vtkIdType p2, double x[3], vtkIdType& ptId)
576 {
577   vtkIdType loc = this->IsEdge(p1, p2);
578 
579   if (loc != -1)
580   {
581     ptId = loc;
582     return 0;
583   }
584   else
585   {
586     ptId = this->InsertEdge(p1, p2);
587     this->Points->InsertPoint(ptId, x);
588     return 1;
589   }
590 }
591 
592 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)593 void vtkEdgeTable::PrintSelf(ostream& os, vtkIndent indent)
594 {
595   this->Superclass::PrintSelf(os, indent);
596 
597   os << indent << "NumberOfEdges: " << this->GetNumberOfEdges() << "\n";
598 }
599