1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkVolumeOfRevolutionFilter.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 "vtkVolumeOfRevolutionFilter.h"
16 
17 #include "vtkCellArray.h"
18 #include "vtkCellData.h"
19 #include "vtkCellIterator.h"
20 #include "vtkGenericCell.h"
21 #include "vtkIdList.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkMath.h"
25 #include "vtkMergePoints.h"
26 #include "vtkNew.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkPolyData.h"
30 #include "vtkUnsignedCharArray.h"
31 #include "vtkUnstructuredGrid.h"
32 
33 #include <vector>
34 
35 vtkStandardNewMacro(vtkVolumeOfRevolutionFilter);
36 
37 namespace
38 {
39 struct AxisOfRevolution
40 {
41   double Position[3];
42   double Direction[3];
43 };
44 
RevolvePoint(const double in[3],const AxisOfRevolution * axis,double angleInRadians,double out[3])45 void RevolvePoint(
46   const double in[3], const AxisOfRevolution* axis, double angleInRadians, double out[3])
47 {
48   double c = cos(angleInRadians);
49   double cm = 1. - c;
50   double s = sin(angleInRadians);
51 
52   double translated[3];
53   vtkMath::Subtract(in, axis->Position, translated);
54 
55   double dot = vtkMath::Dot(translated, axis->Direction);
56   double cross[3];
57   vtkMath::Cross(translated, axis->Direction, cross);
58 
59   for (vtkIdType i = 0; i < 3; i++)
60   {
61     out[i] =
62       ((translated[i] * c + axis->Direction[i] * dot * cm - cross[i] * s) + axis->Position[i]);
63   }
64 }
65 
RevolvePoints(vtkDataSet * pts,vtkPoints * newPts,AxisOfRevolution * axis,double sweepAngle,int resolution,vtkPointData * outPd,bool partialSweep)66 void RevolvePoints(vtkDataSet* pts, vtkPoints* newPts, AxisOfRevolution* axis, double sweepAngle,
67   int resolution, vtkPointData* outPd, bool partialSweep)
68 {
69   double angleInRadians = vtkMath::RadiansFromDegrees(sweepAngle / resolution);
70 
71   vtkIdType n2DPoints = pts->GetNumberOfPoints();
72   vtkIdType counter = 0;
73   double p2d[3], p3d[3];
74 
75   for (int i = 0; i < resolution + partialSweep; i++)
76   {
77     for (int id = 0; id < n2DPoints; id++)
78     {
79       pts->GetPoint(id, p2d);
80       RevolvePoint(p2d, axis, i * angleInRadians, p3d);
81       newPts->SetPoint(counter, p3d);
82       outPd->CopyData(pts->GetPointData(), i, counter);
83       counter++;
84     }
85   }
86 }
87 
88 template <int CellType>
89 void Revolve(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution, vtkCellArray* connectivity,
90   vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId, vtkCellData* outCd,
91   bool partialSweep);
92 
93 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)94 void Revolve<VTK_VERTEX>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
95   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
96   vtkCellData* outCd, bool partialSweep)
97 {
98   vtkIdType newPtIds[2], newCellId;
99 
100   newPtIds[0] = pointIds->GetId(0);
101 
102   for (int i = 0; i < resolution; i++)
103   {
104     newPtIds[1] = (pointIds->GetId(0) + ((i + 1) % (resolution + partialSweep)) * n2DPoints);
105     newCellId = connectivity->InsertNextCell(2, newPtIds);
106     types->InsertNextValue(VTK_LINE);
107     outCd->CopyData(inCd, cellId, newCellId);
108     newPtIds[0] = newPtIds[1];
109   }
110 }
111 
112 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)113 void Revolve<VTK_POLY_VERTEX>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
114   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
115   vtkCellData* outCd, bool partialSweep)
116 {
117   vtkNew<vtkIdList> pointId;
118   pointId->SetNumberOfIds(1);
119   for (vtkIdType i = 0; i < pointIds->GetNumberOfIds(); i++)
120   {
121     pointId->SetId(0, pointIds->GetId(i));
122     Revolve<VTK_VERTEX>(
123       pointId, n2DPoints, resolution, connectivity, types, inCd, cellId, outCd, partialSweep);
124   }
125 }
126 
127 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)128 void Revolve<VTK_LINE>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
129   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
130   vtkCellData* outCd, bool partialSweep)
131 {
132   static const int nPoints = 2;
133 
134   vtkIdType newPtIds[2 * nPoints], newCellId;
135 
136   for (vtkIdType i = 0; i < nPoints; i++)
137   {
138     newPtIds[i] = pointIds->GetId(i);
139   }
140 
141   for (int i = 0; i < resolution; i++)
142   {
143     for (vtkIdType j = 0; j < nPoints; j++)
144     {
145       newPtIds[2 * nPoints - 1 - j] =
146         pointIds->GetId(j) + ((i + 1) % (resolution + partialSweep)) * n2DPoints;
147     }
148     newCellId = connectivity->InsertNextCell(2 * nPoints, newPtIds);
149     types->InsertNextValue(VTK_QUAD);
150     outCd->CopyData(inCd, cellId, newCellId);
151     for (vtkIdType j = 0; j < nPoints; j++)
152     {
153       newPtIds[nPoints - 1 - j] = newPtIds[j + nPoints];
154     }
155   }
156 }
157 
158 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)159 void Revolve<VTK_POLY_LINE>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
160   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
161   vtkCellData* outCd, bool partialSweep)
162 {
163   vtkNew<vtkIdList> newPointIds;
164   newPointIds->SetNumberOfIds(2);
165   newPointIds->SetId(0, pointIds->GetId(0));
166   for (vtkIdType i = 1; i < pointIds->GetNumberOfIds(); i++)
167   {
168     newPointIds->SetId(1, pointIds->GetId(i));
169     Revolve<VTK_LINE>(
170       newPointIds, n2DPoints, resolution, connectivity, types, inCd, cellId, outCd, partialSweep);
171     newPointIds->SetId(0, pointIds->GetId(i));
172   }
173 }
174 
175 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)176 void Revolve<VTK_TRIANGLE>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
177   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
178   vtkCellData* outCd, bool partialSweep)
179 {
180   static const int nPoints = 3;
181 
182   vtkIdType newPtIds[2 * nPoints], newCellId;
183 
184   for (vtkIdType i = 0; i < nPoints; i++)
185   {
186     newPtIds[i] = pointIds->GetId(i);
187   }
188 
189   for (int i = 0; i < resolution; i++)
190   {
191     for (vtkIdType j = 0; j < nPoints; j++)
192     {
193       newPtIds[j + nPoints] =
194         pointIds->GetId(j) + ((i + 1) % (resolution + partialSweep)) * n2DPoints;
195     }
196     newCellId = connectivity->InsertNextCell(2 * nPoints, newPtIds);
197     types->InsertNextValue(VTK_WEDGE);
198     outCd->CopyData(inCd, cellId, newCellId);
199     for (vtkIdType j = 0; j < nPoints; j++)
200     {
201       newPtIds[j] = newPtIds[j + nPoints];
202     }
203   }
204 }
205 
206 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)207 void Revolve<VTK_TRIANGLE_STRIP>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
208   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
209   vtkCellData* outCd, bool partialSweep)
210 {
211   vtkNew<vtkIdList> newPointIds;
212   newPointIds->SetNumberOfIds(3);
213   newPointIds->SetId(0, pointIds->GetId(0));
214   newPointIds->SetId(1, pointIds->GetId(1));
215   for (vtkIdType i = 2; i < pointIds->GetNumberOfIds(); i++)
216   {
217     newPointIds->SetId(2, pointIds->GetId(i));
218     Revolve<VTK_TRIANGLE>(
219       newPointIds, n2DPoints, resolution, connectivity, types, inCd, cellId, outCd, partialSweep);
220     newPointIds->SetId(0, pointIds->GetId(i));
221     newPointIds->SetId(1, pointIds->GetId(i - 1));
222   }
223 }
224 
225 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)226 void Revolve<VTK_QUAD>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
227   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
228   vtkCellData* outCd, bool partialSweep)
229 {
230   static const int nPoints = 4;
231 
232   vtkIdType newPtIds[2 * nPoints], newCellId;
233 
234   for (vtkIdType i = 0; i < nPoints; i++)
235   {
236     newPtIds[i] = pointIds->GetId(i);
237   }
238 
239   for (int i = 0; i < resolution; i++)
240   {
241     for (vtkIdType j = 0; j < nPoints; j++)
242     {
243       newPtIds[j + nPoints] =
244         pointIds->GetId(j) + ((i + 1) % (resolution + partialSweep)) * n2DPoints;
245     }
246     newCellId = connectivity->InsertNextCell(2 * nPoints, newPtIds);
247     types->InsertNextValue(VTK_HEXAHEDRON);
248     outCd->CopyData(inCd, cellId, newCellId);
249     for (vtkIdType j = 0; j < nPoints; j++)
250     {
251       newPtIds[j] = newPtIds[j + nPoints];
252     }
253   }
254 }
255 
256 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)257 void Revolve<VTK_PIXEL>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
258   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
259   vtkCellData* outCd, bool partialSweep)
260 {
261   static const int nPoints = 4;
262 
263   vtkIdType newPtIds[2 * nPoints], newCellId;
264 
265   for (vtkIdType i = 0; i < nPoints; i++)
266   {
267     newPtIds[i] = pointIds->GetId(i);
268   }
269 
270   for (int i = 0; i < resolution; i++)
271   {
272     for (vtkIdType j = 0; j < nPoints; j++)
273     {
274       newPtIds[j + nPoints] =
275         pointIds->GetId(j) + ((i + 1) % (resolution + partialSweep)) * n2DPoints;
276     }
277     newCellId = connectivity->InsertNextCell(2 * nPoints, newPtIds);
278     types->InsertNextValue(VTK_HEXAHEDRON);
279     outCd->CopyData(inCd, cellId, newCellId);
280     for (vtkIdType j = 0; j < nPoints; j++)
281     {
282       newPtIds[j] = newPtIds[j + nPoints];
283     }
284   }
285 }
286 
287 template <>
Revolve(vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)288 void Revolve<VTK_POLYGON>(vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
289   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
290   vtkCellData* outCd, bool partialSweep)
291 {
292   // A swept polygon creates a polyhedron with two polygon faces and <nPoly>
293   // quad faces, comprised from 2*<nPoly> points. Because polyhedra have a
294   // special connectivity format, the length of the connectivity array is
295   // 1 + (<nPoly>+2) + 2*<nPoly> + 4*<nPoly> = 7*<nPoly> + 3.
296   // ^        ^           ^           ^
297   // integer describing # of faces (<nPoly> + 2)
298   //          ^           ^           ^
299   //          integers describing # of points per face
300   //                      ^           ^
301   //                      point ids for the two polygon faces
302   //                                  ^
303   //                                  point ids for the 4 quad faces
304 
305   int nPoly = pointIds->GetNumberOfIds();
306   std::vector<vtkIdType> newPtIds(7 * nPoly + 3);
307   // newFacePtIds are pointers to the point arrays describing each face
308   std::vector<vtkIdType*> newFacePtIds(nPoly + 2);
309   vtkIdType newCellId;
310 
311   newPtIds[0] = nPoly + 2;
312   newPtIds[1] = nPoly;
313   newPtIds[nPoly + 2] = nPoly;
314   newFacePtIds[0] = &newPtIds[2];
315   newFacePtIds[1] = &newPtIds[nPoly + 3];
316   for (vtkIdType i = 0; i < nPoly; i++)
317   {
318     // All of the subsequent faces have four point ids
319     newPtIds[3 + 2 * nPoly + 5 * i] = 4;
320     newFacePtIds[2 + i] = &newPtIds[4 + 2 * nPoly + 5 * i];
321     newFacePtIds[0][i] = pointIds->GetId(i);
322   }
323 
324   for (int i = 0; i < resolution; i++)
325   {
326     for (vtkIdType j = 0; j < nPoly; j++)
327     {
328       newFacePtIds[1][nPoly - 1 - j] =
329         pointIds->GetId(j) + ((i + 1) % (resolution + partialSweep)) * n2DPoints;
330     }
331     for (vtkIdType j = 0; j < nPoly; j++)
332     {
333       newFacePtIds[j + 2][0] = newFacePtIds[0][j];
334       newFacePtIds[j + 2][1] = newFacePtIds[0][(j + 1) % nPoly];
335       newFacePtIds[j + 2][2] = newFacePtIds[1][(2 * nPoly - 2 - j) % nPoly];
336       newFacePtIds[j + 2][3] = newFacePtIds[1][nPoly - 1 - j];
337     }
338     newCellId = connectivity->InsertNextCell(7 * nPoly + 3, &newPtIds[0]);
339     types->InsertNextValue(VTK_POLYHEDRON);
340     outCd->CopyData(inCd, cellId, newCellId);
341     for (vtkIdType j = 0; j < nPoly; j++)
342     {
343       newFacePtIds[0][j] = newFacePtIds[1][nPoly - 1 - j];
344     }
345   }
346 }
347 
RevolveCell(int cellType,vtkIdList * pointIds,vtkIdType n2DPoints,int resolution,vtkCellArray * connectivity,vtkUnsignedCharArray * types,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,bool partialSweep)348 int RevolveCell(int cellType, vtkIdList* pointIds, vtkIdType n2DPoints, int resolution,
349   vtkCellArray* connectivity, vtkUnsignedCharArray* types, vtkCellData* inCd, vtkIdType cellId,
350   vtkCellData* outCd, bool partialSweep)
351 {
352   int returnValue = 0;
353 #define RevolveCellCase(CellType)                                                                  \
354   case CellType:                                                                                   \
355     Revolve<CellType>(                                                                             \
356       pointIds, n2DPoints, resolution, connectivity, types, inCd, cellId, outCd, partialSweep);    \
357     break
358 
359   switch (cellType)
360   {
361     RevolveCellCase(VTK_VERTEX);
362     RevolveCellCase(VTK_POLY_VERTEX);
363     RevolveCellCase(VTK_LINE);
364     RevolveCellCase(VTK_POLY_LINE);
365     RevolveCellCase(VTK_TRIANGLE);
366     RevolveCellCase(VTK_TRIANGLE_STRIP);
367     RevolveCellCase(VTK_POLYGON);
368     RevolveCellCase(VTK_PIXEL);
369     RevolveCellCase(VTK_QUAD);
370     default:
371       returnValue = 1;
372   }
373   return returnValue;
374 #undef RevolveCellCase
375 }
376 }
377 
378 //------------------------------------------------------------------------------
vtkVolumeOfRevolutionFilter()379 vtkVolumeOfRevolutionFilter::vtkVolumeOfRevolutionFilter()
380 {
381   this->SweepAngle = 360.0;
382   this->Resolution = 12; // 30 degree increments
383   this->AxisPosition[0] = this->AxisPosition[1] = this->AxisPosition[2] = 0.;
384   this->AxisDirection[0] = this->AxisDirection[1] = 0.;
385   this->AxisDirection[2] = 1.;
386   this->OutputPointsPrecision = DEFAULT_PRECISION;
387 }
388 
389 //------------------------------------------------------------------------------
390 vtkVolumeOfRevolutionFilter::~vtkVolumeOfRevolutionFilter() = default;
391 
392 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)393 int vtkVolumeOfRevolutionFilter::RequestData(vtkInformation* vtkNotUsed(request),
394   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
395 {
396   // get the info objects
397   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
398   vtkInformation* outInfo = outputVector->GetInformationObject(0);
399 
400   // get the input and output
401   vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
402   vtkUnstructuredGrid* output =
403     vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
404   vtkPointData* inPd = input->GetPointData();
405   vtkCellData* inCd = input->GetCellData();
406   vtkPointData* outPd = output->GetPointData();
407   vtkCellData* outCd = output->GetCellData();
408 
409   vtkNew<vtkPoints> outPts;
410 
411   // Check to see that the input data is amenable to this operation
412   vtkCellIterator* it = input->NewCellIterator();
413   for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell())
414   {
415     int cellDimension = it->GetCellDimension();
416     if (cellDimension > 2)
417     {
418       vtkErrorMacro(<< "All cells must have a topological dimension < 2.");
419       return 1;
420     }
421   }
422   it->Delete();
423 
424   // Set up output points
425   if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
426   {
427     vtkPointSet* inputPointSet = vtkPointSet::SafeDownCast(input);
428     if (inputPointSet)
429     {
430       outPts->SetDataType(inputPointSet->GetPoints()->GetDataType());
431     }
432     else
433     {
434       outPts->SetDataType(VTK_FLOAT);
435     }
436   }
437   else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
438   {
439     outPts->SetDataType(VTK_FLOAT);
440   }
441   else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
442   {
443     outPts->SetDataType(VTK_DOUBLE);
444   }
445 
446   // determine whether or not the sweep angle is a full 2*pi
447   bool partialSweep = false;
448   if (fabs(360. - fabs(this->SweepAngle)) > 1024 * VTK_DBL_EPSILON)
449   {
450     partialSweep = true;
451   }
452 
453   // Set up output points and point data
454   outPts->SetNumberOfPoints(input->GetNumberOfPoints() * (this->Resolution + partialSweep));
455   outPd->CopyAllocate(inPd, input->GetNumberOfPoints() * (this->Resolution + partialSweep));
456 
457   // Set up output cell data
458   vtkIdType nNewCells = input->GetNumberOfCells() * this->Resolution;
459   outCd->CopyAllocate(inCd, nNewCells);
460 
461   vtkNew<vtkUnsignedCharArray> outTypes;
462   vtkNew<vtkCellArray> outCells;
463 
464   AxisOfRevolution axis;
465   for (vtkIdType i = 0; i < 3; i++)
466   {
467     axis.Position[i] = this->AxisPosition[i];
468     axis.Direction[i] = this->AxisDirection[i];
469   }
470 
471   RevolvePoints(input, outPts, &axis, this->SweepAngle, this->Resolution, outPd, partialSweep);
472 
473   it = input->NewCellIterator();
474   for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell())
475   {
476     if (RevolveCell(it->GetCellType(), it->GetPointIds(), input->GetNumberOfPoints(),
477           this->Resolution, outCells, outTypes, inCd, it->GetCellId(), outCd, partialSweep) == 1)
478     {
479       vtkWarningMacro(<< "No method for revolving cell type " << it->GetCellType()
480                       << ". Skipping.");
481     }
482   }
483   it->Delete();
484 
485   output->SetPoints(outPts);
486   output->SetCells(outTypes, outCells);
487 
488   return 1;
489 }
490 
491 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)492 int vtkVolumeOfRevolutionFilter::FillInputPortInformation(int, vtkInformation* info)
493 {
494   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
495   return 1;
496 }
497 
498 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)499 void vtkVolumeOfRevolutionFilter::PrintSelf(ostream& os, vtkIndent indent)
500 {
501   this->Superclass::PrintSelf(os, indent);
502 
503   os << indent << "Resolution: " << this->Resolution << "\n";
504   os << indent << "Sweep Angle: " << this->SweepAngle << "\n";
505   os << indent << "Axis Position: (" << this->AxisPosition[0] << "," << this->AxisPosition[1] << ","
506      << this->AxisPosition[2] << ")\n";
507   os << indent << "Axis Direction: (" << this->AxisPosition[0] << "," << this->AxisDirection[1]
508      << "," << this->AxisDirection[2] << ")\n";
509   os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n";
510 }
511