1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkDensifyPointCloudFilter.cxx
5 
6   Copyright (c) Kitware, Inc.
7   All rights reserved.
8   See LICENSE file 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 "vtkDensifyPointCloudFilter.h"
16 
17 #include "vtkObjectFactory.h"
18 #include "vtkStaticPointLocator.h"
19 #include "vtkPointSet.h"
20 #include "vtkPoints.h"
21 #include "vtkPointData.h"
22 #include "vtkFloatArray.h"
23 #include "vtkIdList.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkMath.h"
27 #include "vtkSMPTools.h"
28 #include "vtkSMPThreadLocalObject.h"
29 #include "vtkArrayListTemplate.h" // For processing attribute data
30 
31 vtkStandardNewMacro(vtkDensifyPointCloudFilter);
32 
33 
34 //----------------------------------------------------------------------------
35 // Helper classes to support efficient computing, and threaded execution.
36 namespace {
37 
38 //----------------------------------------------------------------------------
39 // Count the number of points that need generation
40 template <typename T>
41 struct CountPoints
42 {
43   T *InPoints;
44   vtkStaticPointLocator *Locator;
45   vtkIdType *Count;
46   int NeighborhoodType;
47   int NClosest;
48   double Radius;
49   double Distance;
50 
51   // Don't want to allocate working arrays on every thread invocation. Thread local
52   // storage prevents lots of new/delete.
53   vtkSMPThreadLocalObject<vtkIdList> PIds;
54 
CountPoints__anon570adc490111::CountPoints55   CountPoints(T *inPts, vtkStaticPointLocator *loc, vtkIdType *count, int ntype,
56               int nclose, double r, double d) : InPoints(inPts), Locator(loc),
57                                                 Count(count), NeighborhoodType(ntype),
58                                                 NClosest(nclose), Radius(r), Distance(d)
59   {
60   }
61 
62   // Just allocate a little bit of memory to get started.
Initialize__anon570adc490111::CountPoints63   void Initialize()
64   {
65     vtkIdList*& pIds = this->PIds.Local();
66     pIds->Allocate(128); //allocate some memory
67   }
68 
operator ()__anon570adc490111::CountPoints69   void operator() (vtkIdType pointId, vtkIdType endPointId)
70   {
71     T *x, *p = this->InPoints + 3*pointId;
72     vtkStaticPointLocator *loc = this->Locator;
73     vtkIdType *count = this->Count + pointId;
74     vtkIdList*& pIds = this->PIds.Local();
75     vtkIdType i, id, numIds, numNewPts;
76     double px[3], py[3];
77     int ntype = this->NeighborhoodType;
78     double radius = this->Radius;
79     int nclose = this->NClosest;
80     double d2 = this->Distance * this->Distance;
81 
82     for ( ; pointId < endPointId; ++pointId, p+=3 )
83     {
84       numNewPts = 0;
85       px[0] = static_cast<double>(p[0]);
86       px[1] = static_cast<double>(p[1]);
87       px[2] = static_cast<double>(p[2]);
88       if ( ntype == vtkDensifyPointCloudFilter::N_CLOSEST )
89       {
90         // use nclose+1 because we want to discount ourselves
91         loc->FindClosestNPoints(nclose+1, px, pIds);
92       }
93       else // ntype == vtkDensifyPointCloudFilter::RADIUS
94       {
95         loc->FindPointsWithinRadius(radius, px, pIds);
96       }
97       numIds = pIds->GetNumberOfIds();
98 
99       for ( i=0; i < numIds; ++i)
100       {
101         id = pIds->GetId(i);
102         if ( id > pointId ) //only process points of larger id
103         {
104           x = this->InPoints + 3*id;
105           py[0] = static_cast<double>(x[0]);
106           py[1] = static_cast<double>(x[1]);
107           py[2] = static_cast<double>(x[2]);
108 
109           if ( vtkMath::Distance2BetweenPoints(px,py) >= d2 )
110           {
111             numNewPts++;
112           }
113         }//larger id
114       }//for all neighbors
115       *count++ = numNewPts;
116     }//for all points in this batch
117   }
118 
Reduce__anon570adc490111::CountPoints119   void Reduce()
120   {
121   }
122 
Execute__anon570adc490111::CountPoints123   static void Execute(vtkIdType numPts, T *pts, vtkStaticPointLocator *loc,
124                       vtkIdType *count, int ntype, int nclose, double r, double d)
125   {
126     CountPoints countPts(pts, loc, count, ntype, nclose, r, d);
127     vtkSMPTools::For(0, numPts, countPts);
128   }
129 
130 }; //CountPoints
131 
132 //----------------------------------------------------------------------------
133 // Count the number of points that need generation
134 template <typename T>
135 struct GeneratePoints
136 {
137   T *InPoints;
138   vtkStaticPointLocator *Locator;
139   const vtkIdType *Offsets;
140   int NeighborhoodType;
141   int NClosest;
142   double Radius;
143   double Distance;
144   ArrayList Arrays;
145 
146   // Don't want to allocate working arrays on every thread invocation. Thread local
147   // storage prevents lots of new/delete.
148   vtkSMPThreadLocalObject<vtkIdList> PIds;
149 
GeneratePoints__anon570adc490111::GeneratePoints150   GeneratePoints(T *inPts, vtkStaticPointLocator *loc, vtkIdType *offset,
151                  int ntype, int nclose, double r, double d, vtkIdType numPts,
152                  vtkPointData *attr) : InPoints(inPts), Locator(loc), Offsets(offset),
153                                        NeighborhoodType(ntype), NClosest(nclose),
154                                        Radius(r), Distance(d)
155   {
156     this->Arrays.AddSelfInterpolatingArrays(numPts, attr);
157   }
158 
159   // Just allocate a little bit of memory to get started.
Initialize__anon570adc490111::GeneratePoints160   void Initialize()
161   {
162     vtkIdList*& pIds = this->PIds.Local();
163     pIds->Allocate(128); //allocate some memory
164   }
165 
operator ()__anon570adc490111::GeneratePoints166   void operator() (vtkIdType pointId, vtkIdType endPointId)
167   {
168     T *x, *p = this->InPoints + 3*pointId;
169     T *newX;
170     vtkStaticPointLocator *loc = this->Locator;
171     vtkIdList*& pIds = this->PIds.Local();
172     vtkIdType i, id, numIds;
173     vtkIdType outPtId = this->Offsets[pointId];
174     double px[3], py[3];
175     int ntype = this->NeighborhoodType;
176     double radius = this->Radius;
177     int nclose = this->NClosest;
178     double d2 = this->Distance * this->Distance;
179 
180     for ( ; pointId < endPointId; ++pointId, p+=3 )
181     {
182       px[0] = static_cast<double>(p[0]);
183       px[1] = static_cast<double>(p[1]);
184       px[2] = static_cast<double>(p[2]);
185       if ( ntype == vtkDensifyPointCloudFilter::N_CLOSEST )
186       {
187         // use nclose+1 because we want to discount ourselves
188         loc->FindClosestNPoints(nclose+1, px, pIds);
189       }
190       else // ntype == vtkDensifyPointCloudFilter::RADIUS
191       {
192         loc->FindPointsWithinRadius(radius, px, pIds);
193       }
194       numIds = pIds->GetNumberOfIds();
195 
196       for ( i=0; i < numIds; ++i)
197       {
198         id = pIds->GetId(i);
199         if ( id > pointId ) //only process points of larger id
200         {
201           x = this->InPoints + 3*id;
202           py[0] = static_cast<double>(x[0]);
203           py[1] = static_cast<double>(x[1]);
204           py[2] = static_cast<double>(x[2]);
205 
206           if ( vtkMath::Distance2BetweenPoints(px,py) >= d2 )
207           {
208             newX = this->InPoints + 3*outPtId;
209             *newX++ = static_cast<T>(0.5 * (px[0]+py[0]));
210             *newX++ = static_cast<T>(0.5 * (px[1]+py[1]));
211             *newX++ = static_cast<T>(0.5 * (px[2]+py[2]));
212             this->Arrays.InterpolateEdge(pointId,id,0.5,outPtId);
213             outPtId++;
214           }
215         }//larger id
216       }//for all neighbor points
217     }//for all points in this batch
218   }
219 
Reduce__anon570adc490111::GeneratePoints220   void Reduce()
221   {
222   }
223 
Execute__anon570adc490111::GeneratePoints224   static void Execute(vtkIdType numInPts, T *pts, vtkStaticPointLocator *loc,
225                       vtkIdType *offsets, int ntype, int nclose, double r,
226                       double d, vtkIdType numOutPts, vtkPointData *PD)
227   {
228     GeneratePoints genPts(pts, loc, offsets, ntype, nclose, r, d, numOutPts, PD);
229     vtkSMPTools::For(0, numInPts, genPts);
230   }
231 
232 }; //GeneratePoints
233 
234 } //anonymous namespace
235 
236 
237 //================= Begin VTK class proper =======================================
238 //----------------------------------------------------------------------------
vtkDensifyPointCloudFilter()239 vtkDensifyPointCloudFilter::vtkDensifyPointCloudFilter()
240 {
241 
242   this->NeighborhoodType = vtkDensifyPointCloudFilter::N_CLOSEST;
243   this->Radius = 1.0;
244   this->NumberOfClosestPoints = 6;
245   this->TargetDistance = 0.5;
246   this->MaximumNumberOfIterations = 3;
247   this->InterpolateAttributeData = true;
248   this->MaximumNumberOfPoints = VTK_ID_MAX;
249 }
250 
251 //----------------------------------------------------------------------------
252 vtkDensifyPointCloudFilter::~vtkDensifyPointCloudFilter() = default;
253 
254 //----------------------------------------------------------------------------
255 // Produce the output data
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)256 int vtkDensifyPointCloudFilter::RequestData(
257   vtkInformation *vtkNotUsed(request),
258   vtkInformationVector **inputVector,
259   vtkInformationVector *outputVector)
260 {
261   // get the info objects
262   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
263   vtkInformation *outInfo = outputVector->GetInformationObject(0);
264 
265   // get the input and output
266   vtkPointSet *input = vtkPointSet::SafeDownCast(
267     inInfo->Get(vtkDataObject::DATA_OBJECT()));
268   vtkPolyData *output = vtkPolyData::SafeDownCast(
269     outInfo->Get(vtkDataObject::DATA_OBJECT()));
270 
271   // Check the input
272   if ( !input || !output )
273   {
274     return 1;
275   }
276   vtkIdType numPts = input->GetNumberOfPoints();
277   if ( numPts < 1 )
278   {
279     return 1;
280   }
281 
282   // Start by building the locator, creating the output points and otherwise
283   // and prepare for iteration.
284   int iterNum;
285   vtkStaticPointLocator *locator = vtkStaticPointLocator::New();
286 
287   vtkPoints *inPts = input->GetPoints();
288   int pointsType = inPts->GetDataType();
289   vtkPoints *newPts = inPts->NewInstance();
290   newPts->DeepCopy(inPts);
291   output->SetPoints(newPts);
292   vtkPointData *outPD=nullptr;
293   if ( this->InterpolateAttributeData )
294   {
295     outPD = output->GetPointData();
296     outPD->DeepCopy(input->GetPointData());
297     outPD->InterpolateAllocate(outPD,numPts);
298   }
299 
300   vtkIdType ptId, numInPts, numNewPts;
301   vtkIdType npts, offset, *offsets;
302   void *pts=nullptr;
303   double d = this->TargetDistance;
304 
305   // Loop over the data, bisecting connecting edges as required.
306   for ( iterNum=0; iterNum < this->MaximumNumberOfIterations; ++iterNum )
307   {
308     // Prepare to process
309     locator->SetDataSet(output);
310     locator->Modified();
311     locator->BuildLocator();
312 
313     // Count the number of points to create
314     numInPts = output->GetNumberOfPoints();
315     offsets = new vtkIdType [numInPts];
316     pts = output->GetPoints()->GetVoidPointer(0);
317     switch (pointsType)
318     {
319       vtkTemplateMacro(CountPoints<VTK_TT>::Execute(numInPts,
320                       (VTK_TT *)pts, locator, offsets, this->NeighborhoodType,
321                       this->NumberOfClosestPoints, this->Radius, d));
322     }
323 
324     // Prefix sum to count the number of points created and build offsets
325     numNewPts = 0;
326     offset = numInPts;
327     for (ptId=0; ptId < numInPts; ++ptId)
328     {
329       npts = offsets[ptId];
330       offsets[ptId] = offset;
331       offset += npts;
332     }
333     numNewPts = offset - numInPts;
334 
335     // Check convergence
336     if ( numNewPts == 0 || offset > this->MaximumNumberOfPoints )
337     {
338       delete [] offsets;
339       break;
340     }
341 
342     // Now add points and attribute data if requested. Allocate memory
343     // for points and attributes.
344     newPts->InsertPoint(offset,0.0,0.0,0.0); //side effect reallocs memory
345     pts = output->GetPoints()->GetVoidPointer(0);
346     switch (pointsType)
347     {
348       vtkTemplateMacro(GeneratePoints<VTK_TT>::Execute(numInPts,
349                        (VTK_TT *)pts, locator, offsets, this->NeighborhoodType,
350                        this->NumberOfClosestPoints, this->Radius, d,
351                        offset, outPD));
352     }
353 
354     delete [] offsets;
355   } //while max num of iterations not exceeded
356 
357   // Clean up
358   locator->Delete();
359   newPts->Delete();
360 
361   return 1;
362 }
363 
364 
365 //----------------------------------------------------------------------------
366 int vtkDensifyPointCloudFilter::
FillInputPortInformation(int,vtkInformation * info)367 FillInputPortInformation(int, vtkInformation *info)
368 {
369   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPointSet");
370   return 1;
371 }
372 
373 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)374 void vtkDensifyPointCloudFilter::PrintSelf(ostream& os, vtkIndent indent)
375 {
376   this->Superclass::PrintSelf(os,indent);
377 
378   os << indent << "Neighborhood Type: " << this->GetNeighborhoodType() << "\n";
379   os << indent << "Radius: " << this->Radius << "\n";
380   os << indent << "Number Of Closest Points: "
381      << this->NumberOfClosestPoints << "\n";
382   os << indent << "Target Distance: " << this->TargetDistance << endl;
383   os << indent << "Maximum Number of Iterations: "
384      << this->MaximumNumberOfIterations << "\n";
385   os << indent << "Interpolate Attribute Data: "
386      << (this->InterpolateAttributeData ? "On\n" : "Off\n");
387   os << indent << "Maximum Number Of Points: "
388      << this->MaximumNumberOfPoints << "\n";
389 }
390