ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
vtkPMergeConnected.cxx
Go to the documentation of this file.
1 #include "vtkPMergeConnected.h"
2 
3 #include <cstring>
4 #include <iostream>
5 #include <map>
6 
7 #include <vtkCellData.h>
8 #include <vtkFloatArray.h>
9 #include <vtkIdList.h>
10 #include <vtkIdTypeArray.h>
11 #include <vtkInformation.h>
12 #include <vtkInformationVector.h>
13 #include <vtkMultiBlockDataSet.h>
14 #include <vtkMultiProcessController.h>
15 #include <vtkObjectFactory.h>
16 #include <vtkPointData.h>
17 #include <vtkPolyhedron.h>
18 #include <vtkStreamingDemandDrivenPipeline.h>
19 #include <vtkUnstructuredGrid.h>
20 
21 #include <vtkSmartPointer.h>
22 #define VTK_CREATE(type, name) vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
23 #define VTK_NEW(type, name) name = vtkSmartPointer<type>::New()
24 
26 
28 {
29  this->SetNumberOfInputPorts(1);
30  this->SetNumberOfOutputPorts(1);
31 
32  this->Controller = NULL;
33  this->SetController(vtkMultiProcessController::GetGlobalController());
34 }
35 
37 {
38  this->SetController(nullptr);
39 }
40 
41 void vtkPMergeConnected::PrintSelf(ostream& os, vtkIndent indent)
42 {
43  this->Superclass::PrintSelf(os, indent);
44  os << indent << "vtkPMergeConnected filter"
45  << "\n";
46 }
47 
48 void vtkPMergeConnected::SetController(vtkMultiProcessController* c)
49 {
50  if ((c == NULL) || (c->GetNumberOfProcesses() == 0))
51  {
52  this->NumProcesses = 1;
53  this->MyId = 0;
54  }
55 
56  if (this->Controller == c)
57  {
58  return;
59  }
60 
61  this->Modified();
62 
63  if (this->Controller != NULL)
64  {
65  this->Controller->UnRegister(this);
66  this->Controller = NULL;
67  }
68 
69  if (c == NULL)
70  {
71  return;
72  }
73 
74  this->Controller = c;
75 
76  c->Register(this);
77  this->NumProcesses = c->GetNumberOfProcesses();
78  this->MyId = c->GetLocalProcessId();
79 }
80 
81 int vtkPMergeConnected::RequestData(vtkInformation* vtkNotUsed(request),
82  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
83 {
84  // Get the info objects
85  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
86  vtkInformation* outInfo = outputVector->GetInformationObject(0);
87 
88  // Get the input and output
89  vtkMultiBlockDataSet* input =
90  vtkMultiBlockDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
91  vtkMultiBlockDataSet* output =
92  vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
93 
94  int piece, numPieces;
95  piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
96  numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
97 
98  // Read file
99  vtkMultiProcessController* contr = this->Controller;
100 
101  int sum = 0;
102  int oops = ((piece != this->MyId) || (numPieces != this->NumProcesses));
103 
104  for (unsigned int i = piece; i < input->GetNumberOfBlocks(); i += numPieces)
105  {
106  vtkUnstructuredGrid* ugrid = vtkUnstructuredGrid::SafeDownCast(input->GetBlock(i));
107  if (!ugrid)
108  {
109  vtkErrorMacro("Blocks in the input data are not vtkUnstructuredGrid");
110  oops += 1;
111  break;
112  }
113 
114  vtkCellData* cd = ugrid->GetCellData();
115  vtkPointData* pd = ugrid->GetPointData();
116  vtkIdTypeArray* prid_array = vtkIdTypeArray::SafeDownCast(pd->GetArray("RegionId"));
117  vtkIdTypeArray* crid_array = vtkIdTypeArray::SafeDownCast(cd->GetArray("RegionId"));
118  vtkFloatArray* vol_array = vtkFloatArray::SafeDownCast(cd->GetArray("Volumes"));
119 
120  if (!prid_array || !crid_array || !vol_array)
121  {
122  vtkErrorMacro(
123  "Input data does not have expected arrays. vtkPMergeConnected expects input data"
124  " to have 'RegionId' arrays on points and cells and a 'Volumes' array on the cells.");
125  oops += 1;
126  break;
127  }
128  }
129 
130  contr->Reduce(&oops, &sum, 1, vtkCommunicator::SUM_OP, 0);
131  contr->Broadcast(&sum, 1, 0);
132 
133  if (sum > 0)
134  return 1;
135 
136  if (!contr)
137  return 1;
138 
139  output->CopyStructure(input);
140 
141  int i, j, tb;
142  tb = input->GetNumberOfBlocks();
143  for (i = piece; i < tb; i += numPieces)
144  {
145  vtkUnstructuredGrid* ugrid = vtkUnstructuredGrid::SafeDownCast(input->GetBlock(i));
146 
147  VTK_CREATE(vtkUnstructuredGrid, ugrid_out);
148  ugrid_out->SetPoints(ugrid->GetPoints());
149 
150  vtkCellData* cd = ugrid->GetCellData();
151  vtkPointData* pd = ugrid->GetPointData();
152  vtkCellData* ocd = ugrid_out->GetCellData();
153  vtkPointData* opd = ugrid_out->GetPointData();
154 
155  vtkIdTypeArray* prid_array = vtkIdTypeArray::SafeDownCast(pd->GetArray("RegionId"));
156  vtkIdTypeArray* crid_array = vtkIdTypeArray::SafeDownCast(cd->GetArray("RegionId"));
157  vtkFloatArray* vol_array = vtkFloatArray::SafeDownCast(cd->GetArray("Volumes"));
158 
159  VTK_CREATE(vtkIdTypeArray, oprid_array);
160  VTK_CREATE(vtkIdTypeArray, ocrid_array);
161  VTK_CREATE(vtkFloatArray, ovol_array);
162 
163  // point data "RegionId" keep their old id for now
164  oprid_array->DeepCopy(prid_array);
165  oprid_array->SetName("RegionId");
166 
167  // Checking RegionId range
168  double rid_range[2];
169  crid_array->GetRange(rid_range, 0);
170 
171  // Initialize the size of rid arrays
172  ocrid_array->SetName("RegionId");
173  ovol_array->SetName("Volumes");
174 
175  ocrid_array->SetNumberOfComponents(1);
176  ovol_array->SetNumberOfComponents(1);
177 
178  // Compute cell/point data
179  for (j = rid_range[0]; j <= rid_range[1]; j++)
180  {
181  // Compute face stream of merged polyhedron cell
182  VTK_CREATE(vtkIdList, mcell);
183  MergeCellsOnRegionId(ugrid, j, mcell);
184  ugrid_out->InsertNextCell(VTK_POLYHEDRON, mcell);
185 
186  // "RegionId" cells keep their old id
187  ocrid_array->InsertNextValue(j);
188 
189  // Sum up individual volumes
190  float vol = MergeCellDataOnRegionId(vol_array, crid_array, j);
191  ovol_array->InsertNextValue(vol);
192  }
193 
194  // Add new data arrays
195  opd->AddArray(oprid_array);
196  ocd->AddArray(ocrid_array);
197  ocd->AddArray(ovol_array);
198 
199  output->SetBlock(i, ugrid_out);
200  }
201 
202  // Convert local region id to global id
203  LocalToGlobalRegionId(contr, output);
204 
205  return 1;
206 }
207 
208 // Convert local region id to global ones
209 void vtkPMergeConnected::LocalToGlobalRegionId(
210  vtkMultiProcessController* contr, vtkMultiBlockDataSet* data)
211 {
212  int i, j;
213  int rank, num_p, tb;
214  num_p = contr->GetNumberOfProcesses();
215  rank = contr->GetLocalProcessId();
216  tb = data->GetNumberOfBlocks();
217 
218  // Gather information about number of regions in each block
219  std::vector<int> all_num_regions_local;
220  all_num_regions_local.resize(tb);
221 
222  memset(all_num_regions_local.data(), 0, sizeof(int) * tb);
223  for (i = rank; i < tb; i += num_p)
224  {
225  vtkUnstructuredGrid* ugrid = vtkUnstructuredGrid::SafeDownCast(data->GetBlock(i));
226  vtkIdTypeArray* crid_array =
227  vtkIdTypeArray::SafeDownCast(ugrid->GetCellData()->GetArray("RegionId"));
228 
229  double rid_range[2];
230  crid_array->GetRange(rid_range, 0);
231  all_num_regions_local[i] = rid_range[1] - rid_range[0] + 1;
232  }
233 
234  std::vector<int> all_num_regions;
235  all_num_regions.resize(tb);
236  contr->AllReduce(all_num_regions_local.data(), all_num_regions.data(), tb, vtkCommunicator::SUM_OP);
237 
238  // Compute and adding offset and make local id global
239  for (i = rank; i < tb; i += num_p)
240  {
241  vtkUnstructuredGrid* ugrid = vtkUnstructuredGrid::SafeDownCast(data->GetBlock(i));
242  vtkIdTypeArray* crid_array =
243  vtkIdTypeArray::SafeDownCast(ugrid->GetCellData()->GetArray("RegionId"));
244  vtkIdTypeArray* prid_array =
245  vtkIdTypeArray::SafeDownCast(ugrid->GetPointData()->GetArray("RegionId"));
246 
247  int num_cells = crid_array->GetNumberOfTuples();
248  int num_points = prid_array->GetNumberOfTuples();
249 
250  VTK_CREATE(vtkIdTypeArray, ocrid_array);
251  VTK_CREATE(vtkIdTypeArray, oprid_array);
252 
253  ocrid_array->SetNumberOfComponents(1);
254  oprid_array->SetNumberOfComponents(1);
255  ocrid_array->SetNumberOfTuples(num_cells);
256  oprid_array->SetNumberOfTuples(num_points);
257  ocrid_array->SetName("RegionId");
258  oprid_array->SetName("RegionId");
259 
260  int offset = 0;
261  for (j = 0; j < i; j++)
262  offset += all_num_regions[j];
263 
264  // vtkIdTypeArray doesn't update range when replace elements, hack around
265  for (j = 0; j < num_cells; j++)
266  ocrid_array->InsertValue(j, offset + crid_array->GetValue(j));
267  for (j = 0; j < num_points; j++)
268  oprid_array->InsertValue(j, offset + prid_array->GetValue(j));
269 
270  ugrid->GetCellData()->RemoveArray("RegionId");
271  ugrid->GetCellData()->AddArray(ocrid_array);
272 
273  ugrid->GetPointData()->RemoveArray("Regionid");
274  ugrid->GetPointData()->AddArray(oprid_array);
275  }
276 }
277 
278 // Comparison function to sort point id list
279 int compare_ids(const void* a, const void* b)
280 {
281  vtkIdType A = *(static_cast<const vtkIdType*>(a));
282  vtkIdType B = *(static_cast<const vtkIdType*>(b));
283  return (static_cast<int>(A - B));
284 }
285 
286 // Generate FaceWithKey struct from vtkIdList to use for indexing
287 vtkPMergeConnected::FaceWithKey* vtkPMergeConnected::IdsToKey(vtkIdList* ids)
288 {
289  FaceWithKey* facekey = new FaceWithKey[1];
290 
291  int num_pts = ids->GetNumberOfIds();
292  vtkIdType* key = new vtkIdType[num_pts];
293  vtkIdType* orig = new vtkIdType[num_pts];
294 
295  int i;
296  for (i = 0; i < num_pts; i++)
297  orig[i] = ids->GetId(i);
298  memcpy(key, orig, sizeof(vtkIdType) * num_pts);
299  qsort(key, num_pts, sizeof(vtkIdType), compare_ids);
300 
301  facekey->num_pts = num_pts;
302  facekey->key = key;
303  facekey->orig = orig;
304 
305  return facekey;
306 }
307 
308 // Compare function in face_map
310 {
311  bool operator()(FaceWithKey const* a, FaceWithKey const* b) const
312  {
313  int i, ret = 0;
314 
315  if (a->num_pts == b->num_pts)
316  {
317  for (i = 0; i < a->num_pts; i++)
318  {
319  if (a->key[i] != b->key[i])
320  {
321  ret = a->key[i] - b->key[i];
322  break;
323  }
324  }
325  }
326  else
327  ret = a->num_pts - b->num_pts;
328 
329  return ret < 0;
330  }
331 };
332 
333 // Delete a FaceWithKey struct
334 void vtkPMergeConnected::delete_key(FaceWithKey* key)
335 {
336  delete[] key->key;
337  delete[] key->orig;
338  delete[] key;
339 }
340 
341 // Face stream of a polyhedron cell in the following format:
342 // numCellFaces, numFace0Pts, id1, id2, id3, numFace1Pts,id1, id2, id3, ...
343 void vtkPMergeConnected::MergeCellsOnRegionId(
344  vtkUnstructuredGrid* ugrid, int target, vtkIdList* facestream)
345 {
346  int i, j;
347 
348  vtkIdTypeArray* rids = vtkIdTypeArray::SafeDownCast(ugrid->GetCellData()->GetArray("RegionId"));
349 
350  // Initially set -1 for number of faces in facestream
351  facestream->InsertNextId(-1);
352 
353  std::map<FaceWithKey*, int, cmp_ids> face_map;
354  std::map<FaceWithKey*, int, cmp_ids>::iterator it;
355 
356  // Create face map and count how many times a face is shared.
357  for (i = 0; i < rids->GetNumberOfTuples(); i++)
358  {
359  if (rids->GetTuple1(i) == target)
360  {
361  vtkPolyhedron* cell = vtkPolyhedron::SafeDownCast(ugrid->GetCell(i));
362  for (j = 0; j < cell->GetNumberOfFaces(); j++)
363  {
364  vtkCell* face = cell->GetFace(j);
365  vtkIdList* pts = face->GetPointIds();
366  FaceWithKey* key = IdsToKey(pts);
367 
368  it = face_map.find(key);
369  if (it == face_map.end())
370  face_map[key] = 1;
371  else
372  it->second++;
373  }
374  }
375  }
376 
377  // Keep those unshared faces and build up a new cell
378  int face_count = 0;
379  for (it = face_map.begin(); it != face_map.end(); ++it)
380  {
381  FaceWithKey* key = (*it).first;
382  int count = (*it).second;
383 
384  if (count > 2)
385  std::cerr << "error in building up face map" << std::endl;
386  else if (count == 1)
387  {
388  facestream->InsertNextId(key->num_pts);
389  for (i = 0; i < key->num_pts; i++)
390  facestream->InsertNextId(key->orig[i]);
391  face_count++;
392  }
393  delete_key(key);
394  }
395  facestream->SetId(0, face_count);
396 }
397 
398 // For original cell data, sum them up if possible in merging the connected cells
399 float vtkPMergeConnected::MergeCellDataOnRegionId(
400  vtkFloatArray* data_array, vtkIdTypeArray* rid_array, vtkIdType target)
401 {
402  int i;
403  float val = 0;
404 
405  for (i = 0; i < rid_array->GetNumberOfTuples(); i++)
406  if (rid_array->GetTuple1(i) == target)
407  val += data_array->GetTuple1(i);
408 
409  return val;
410 }
411 
412 int vtkPMergeConnected::FillOutputPortInformation(int port, vtkInformation* info)
413 {
414  if (port == 0)
415  {
416  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
417 
418  return 1;
419  }
420 
421  return 0;
422 }
int count
int offset
#define NULL
vtkDataArray * data_array
Definition: VtkUtils.cpp:75
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *)
void PrintSelf(ostream &os, vtkIndent indent)
int FillOutputPortInformation(int port, vtkInformation *info)
std::vector< unsigned int > face
a[190]
GraphType data
Definition: graph_cut.cc:138
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
bool operator()(FaceWithKey const *a, FaceWithKey const *b) const
vtkStandardNewMacro(vtkPMergeConnected)
#define VTK_CREATE(type, name)
int compare_ids(const void *a, const void *b)