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