1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkConeSource.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 "vtkConeSource.h"
16 
17 #include "vtkCellArray.h"
18 #include "vtkDoubleArray.h"
19 #include "vtkFloatArray.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationVector.h"
22 #include "vtkMath.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkPolyData.h"
25 #include "vtkStreamingDemandDrivenPipeline.h"
26 #include "vtkTransform.h"
27 
28 #include <cmath>
29 
30 vtkStandardNewMacro(vtkConeSource);
31 
32 //------------------------------------------------------------------------------
33 // Construct with default resolution 6, height 1.0, radius 0.5, and capping
34 // on.
vtkConeSource(int res)35 vtkConeSource::vtkConeSource(int res)
36 {
37   res = (res < 0 ? 0 : res);
38   this->Resolution = res;
39   this->Height = 1.0;
40   this->Radius = 0.5;
41   this->Capping = 1;
42 
43   this->Center[0] = 0.0;
44   this->Center[1] = 0.0;
45   this->Center[2] = 0.0;
46 
47   this->Direction[0] = 1.0;
48   this->Direction[1] = 0.0;
49   this->Direction[2] = 0.0;
50 
51   this->OutputPointsPrecision = SINGLE_PRECISION;
52 
53   this->SetNumberOfInputPorts(0);
54 }
55 
56 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)57 int vtkConeSource::RequestData(vtkInformation* vtkNotUsed(request),
58   vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
59 {
60   // get the info objects
61   vtkInformation* outInfo = outputVector->GetInformationObject(0);
62 
63   double angle;
64   int numLines, numPolys, numPts;
65   double x[3], xbot;
66   int i;
67   vtkIdType pts[VTK_CELL_SIZE];
68   vtkPoints* newPoints;
69   vtkCellArray* newLines = nullptr;
70   vtkCellArray* newPolys = nullptr;
71   vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
72   // for streaming
73   int piece;
74   int numPieces;
75   int maxPieces;
76   int start, end;
77   int createBottom;
78 
79   piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
80   if (piece >= this->Resolution && !(piece == 0 && this->Resolution == 0))
81   {
82     return 1;
83   }
84   numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
85   maxPieces = this->Resolution != 0 ? this->Resolution : 1;
86   if (numPieces > maxPieces)
87   {
88     numPieces = maxPieces;
89   }
90   if (piece >= maxPieces)
91   {
92     // Super class should do this for us,
93     // but I put this condition in any way.
94     return 1;
95   }
96   start = maxPieces * piece / numPieces;
97   end = (maxPieces * (piece + 1) / numPieces) - 1;
98   createBottom = (this->Capping && (start == 0));
99 
100   vtkDebugMacro("ConeSource Executing");
101 
102   if (this->Resolution)
103   {
104     angle = 2.0 * vtkMath::Pi() / this->Resolution;
105   }
106   else
107   {
108     angle = 0.0;
109   }
110 
111   // Set things up; allocate memory
112   //
113   switch (this->Resolution)
114   {
115     case 0:
116       numPts = 2;
117       numLines = 1;
118       newLines = vtkCellArray::New();
119       newLines->AllocateEstimate(numLines, numPts);
120       break;
121 
122     case 1:
123     case 2:
124       numPts = 2 * this->Resolution + 1;
125       numPolys = this->Resolution;
126       newPolys = vtkCellArray::New();
127       newPolys->AllocateEstimate(numPolys, 3);
128       break;
129 
130     default:
131       if (createBottom)
132       {
133         // piece 0 has cap.
134         numPts = this->Resolution + 1;
135         numPolys = end - start + 2;
136       }
137       else
138       {
139         numPts = end - start + 3;
140         numPolys = end - start + 2;
141       }
142       newPolys = vtkCellArray::New();
143       newPolys->AllocateEstimate(numPolys, this->Resolution);
144       break;
145   }
146   newPoints = vtkPoints::New();
147 
148   // Set the desired precision for the points in the output.
149   if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
150   {
151     newPoints->SetDataType(VTK_DOUBLE);
152   }
153   else
154   {
155     newPoints->SetDataType(VTK_FLOAT);
156   }
157 
158   newPoints->Allocate(numPts);
159 
160   // Create cone
161   //
162   x[0] = this->Height / 2.0; // zero-centered
163   x[1] = 0.0;
164   x[2] = 0.0;
165   pts[0] = newPoints->InsertNextPoint(x);
166 
167   xbot = -this->Height / 2.0;
168 
169   switch (this->Resolution)
170   {
171     case 0:
172       x[0] = xbot;
173       x[1] = 0.0;
174       x[2] = 0.0;
175       pts[1] = newPoints->InsertNextPoint(x);
176       newLines->InsertNextCell(2, pts);
177       break;
178 
179     case 2: // fall through this case to use the code in case 1
180       x[0] = xbot;
181       x[1] = 0.0;
182       x[2] = -this->Radius;
183       pts[1] = newPoints->InsertNextPoint(x);
184       x[0] = xbot;
185       x[1] = 0.0;
186       x[2] = this->Radius;
187       pts[2] = newPoints->InsertNextPoint(x);
188       newPolys->InsertNextCell(3, pts);
189       VTK_FALLTHROUGH;
190 
191     case 1:
192       x[0] = xbot;
193       x[1] = -this->Radius;
194       x[2] = 0.0;
195       pts[1] = newPoints->InsertNextPoint(x);
196       x[0] = xbot;
197       x[1] = this->Radius;
198       x[2] = 0.0;
199       pts[2] = newPoints->InsertNextPoint(x);
200       newPolys->InsertNextCell(3, pts);
201       break;
202 
203     default: // General case: create Resolution triangles and single cap
204       // create the bottom.
205       if (createBottom)
206       {
207         for (i = 0; i < this->Resolution; i++)
208         {
209           x[0] = xbot;
210           x[1] = this->Radius * cos(i * angle);
211           x[2] = this->Radius * sin(i * angle);
212           // Reverse the order
213           pts[this->Resolution - i - 1] = newPoints->InsertNextPoint(x);
214         }
215         newPolys->InsertNextCell(this->Resolution, pts);
216       }
217 
218       pts[0] = 0;
219       if (!createBottom)
220       {
221         // we need to create the points also
222         x[0] = xbot;
223         x[1] = this->Radius * cos(start * angle);
224         x[2] = this->Radius * sin(start * angle);
225         pts[1] = newPoints->InsertNextPoint(x);
226         for (i = start; i <= end; ++i)
227         {
228           x[1] = this->Radius * cos((i + 1) * angle);
229           x[2] = this->Radius * sin((i + 1) * angle);
230           pts[2] = newPoints->InsertNextPoint(x);
231           newPolys->InsertNextCell(3, pts);
232           pts[1] = pts[2];
233         }
234       }
235       else
236       {
237         // bottom and points have already been created.
238         for (i = start; i <= end; i++)
239         {
240           pts[1] = i + 1;
241           pts[2] = i + 2;
242           if (pts[2] > this->Resolution)
243           {
244             pts[2] = 1;
245           }
246           newPolys->InsertNextCell(3, pts);
247         }
248       } // createBottom
249 
250   } // switch
251 
252   // A non-default origin and/or direction requires transformation
253   //
254   if (this->Center[0] != 0.0 || this->Center[1] != 0.0 || this->Center[2] != 0.0 ||
255     this->Direction[0] != 1.0 || this->Direction[1] != 0.0 || this->Direction[2] != 0.0)
256   {
257     vtkTransform* t = vtkTransform::New();
258     t->Translate(this->Center[0], this->Center[1], this->Center[2]);
259     double vMag = vtkMath::Norm(this->Direction);
260     if (this->Direction[0] < 0.0)
261     {
262       // flip x -> -x to avoid instability
263       t->RotateWXYZ(180.0, (this->Direction[0] - vMag) / 2.0, this->Direction[1] / 2.0,
264         this->Direction[2] / 2.0);
265       t->RotateWXYZ(180.0, 0, 1, 0);
266     }
267     else
268     {
269       t->RotateWXYZ(180.0, (this->Direction[0] + vMag) / 2.0, this->Direction[1] / 2.0,
270         this->Direction[2] / 2.0);
271     }
272     if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
273     {
274       double* ipts = static_cast<vtkDoubleArray*>(newPoints->GetData())->GetPointer(0);
275       for (i = 0; i < numPts; i++, ipts += 3)
276       {
277         t->TransformPoint(ipts, ipts);
278       }
279     }
280     else
281     {
282       float* ipts = static_cast<vtkFloatArray*>(newPoints->GetData())->GetPointer(0);
283       for (i = 0; i < numPts; i++, ipts += 3)
284       {
285         t->TransformPoint(ipts, ipts);
286       }
287     }
288 
289     t->Delete();
290   }
291 
292   // Update ourselves
293   //
294   output->SetPoints(newPoints);
295   newPoints->Delete();
296 
297   if (newPolys)
298   {
299     newPolys->Squeeze(); // we may have estimated size; reclaim some space
300     output->SetPolys(newPolys);
301     newPolys->Delete();
302   }
303   else
304   {
305     output->SetLines(newLines);
306     newLines->Delete();
307   }
308 
309   return 1;
310 }
311 
312 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)313 int vtkConeSource::RequestInformation(vtkInformation* vtkNotUsed(request),
314   vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
315 {
316   vtkInformation* outInfo = outputVector->GetInformationObject(0);
317   outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
318   return 1;
319 }
320 
321 //------------------------------------------------------------------------------
SetAngle(double angle)322 void vtkConeSource::SetAngle(double angle)
323 {
324   this->SetRadius(this->Height * tan(vtkMath::RadiansFromDegrees(angle)));
325 }
326 
327 //------------------------------------------------------------------------------
GetAngle()328 double vtkConeSource::GetAngle()
329 {
330   return vtkMath::DegreesFromRadians(atan2(this->Radius, this->Height));
331 }
332 
333 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)334 void vtkConeSource::PrintSelf(ostream& os, vtkIndent indent)
335 {
336   this->Superclass::PrintSelf(os, indent);
337 
338   os << indent << "Resolution: " << this->Resolution << "\n";
339   os << indent << "Height: " << this->Height << "\n";
340   os << indent << "Radius: " << this->Radius << "\n";
341   os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");
342   os << indent << "Center: (" << this->Center[0] << ", " << this->Center[1] << ", "
343      << this->Center[2] << ")\n";
344   os << indent << "Direction: (" << this->Direction[0] << ", " << this->Direction[1] << ", "
345      << this->Direction[2] << ")\n";
346   os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n";
347 }
348