1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPSphereSource.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 "vtkPSphereSource.h"
16 
17 #include "vtkCellArray.h"
18 #include "vtkFloatArray.h"
19 #include "vtkInformation.h"
20 #include "vtkInformationVector.h"
21 #include "vtkLargeInteger.h"
22 #include "vtkMath.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkPointData.h"
25 #include "vtkPoints.h"
26 #include "vtkPolyData.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 
29 #include <math.h>
30 
31 vtkStandardNewMacro(vtkPSphereSource);
32 
33 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)34 int vtkPSphereSource::RequestData(
35   vtkInformation *vtkNotUsed(request),
36   vtkInformationVector **vtkNotUsed(inputVector),
37   vtkInformationVector *outputVector)
38 {
39   vtkInformation *outInfo = outputVector->GetInformationObject(0);
40 
41   vtkIdType i, j, numOffset;
42   int jStart, jEnd;
43   vtkIdType numPts, numPolys;
44   vtkPoints *newPoints;
45   vtkFloatArray *newNormals;
46   vtkCellArray *newPolys;
47   float x[3], n[3], deltaPhi, deltaTheta, phi, theta, radius, norm;
48   float startTheta, endTheta, startPhi, endPhi;
49   vtkIdType base, thetaResolution, phiResolution;
50   int numPoles = 0;
51   vtkIdType pts[3];
52   vtkPolyData *output = vtkPolyData::SafeDownCast(
53     outInfo->Get(vtkDataObject::DATA_OBJECT()));
54   int piece =
55     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
56   int numPieces =
57     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
58 
59   // I want to modify the ivars resoultion start theta and end theta,
60   // so I will make local copies of them.  THese might be able to be merged
61   // with the other copies of them, ...
62   int localThetaResolution = this->ThetaResolution;
63   float localStartTheta = this->StartTheta;
64   float localEndTheta = this->EndTheta;
65 
66   while (localEndTheta < localStartTheta)
67     {
68     localEndTheta += 360.0;
69     }
70   deltaTheta = (localEndTheta - localStartTheta) / localThetaResolution;
71 
72   // Change the ivars based on pieces.
73   vtkIdType start, end;
74   start = piece * localThetaResolution / numPieces;
75   end = (piece+1) * localThetaResolution / numPieces;
76   localEndTheta = localStartTheta + (float)(end) * deltaTheta;
77   localStartTheta = localStartTheta + (float)(start) * deltaTheta;
78   localThetaResolution = end - start;
79 
80   //
81   // Set things up; allocate memory
82   //
83 
84   vtkDebugMacro("PSphereSource Executing");
85 
86   numPts = this->PhiResolution * localThetaResolution + 2;
87   // creating triangles
88   numPolys = this->PhiResolution * 2 * localThetaResolution;
89 
90   newPoints = vtkPoints::New();
91   newPoints->Allocate(numPts);
92   newNormals = vtkFloatArray::New();
93   newNormals->SetNumberOfComponents(3);
94   newNormals->Allocate(3*numPts);
95 
96   newPolys = vtkCellArray::New();
97   newPolys->Allocate(newPolys->EstimateSize(numPolys, 3));
98   //
99   // Create sphere
100   //
101   // Create north pole if needed
102   if ( this->StartPhi <= 0.0 )
103     {
104     x[0] = this->Center[0];
105     x[1] = this->Center[1];
106     x[2] = this->Center[2] + this->Radius;
107     newPoints->InsertPoint(numPoles,x);
108 
109     x[0] = x[1] = 0.0; x[2] = 1.0;
110     newNormals->InsertTuple(numPoles,x);
111     numPoles++;
112     }
113 
114   // Create south pole if needed
115   if ( this->EndPhi >= 180.0 )
116     {
117     x[0] = this->Center[0];
118     x[1] = this->Center[1];
119     x[2] = this->Center[2] - this->Radius;
120     newPoints->InsertPoint(numPoles,x);
121 
122     x[0] = x[1] = 0.0; x[2] = -1.0;
123     newNormals->InsertTuple(numPoles,x);
124     numPoles++;
125     }
126 
127   // Check data, determine increments, and convert to radians
128   startTheta = (localStartTheta < localEndTheta ? localStartTheta
129                 : localEndTheta);
130   startTheta *= vtkMath::Pi() / 180.0;
131   endTheta = (localEndTheta > localStartTheta ? localEndTheta
132               : localStartTheta);
133   endTheta *= vtkMath::Pi() / 180.0;
134 
135   startPhi = (this->StartPhi < this->EndPhi ? this->StartPhi : this->EndPhi);
136   startPhi *= vtkMath::Pi() / 180.0;
137   endPhi = (this->EndPhi > this->StartPhi ? this->EndPhi : this->StartPhi);
138   endPhi *= vtkMath::Pi() / 180.0;
139 
140   phiResolution = this->PhiResolution - numPoles;
141   deltaPhi = (endPhi - startPhi) / (this->PhiResolution - 1);
142   thetaResolution = localThetaResolution;
143   if (fabs(localStartTheta - localEndTheta) < 360.0)
144     {
145     ++localThetaResolution;
146     }
147   deltaTheta = (endTheta - startTheta) / thetaResolution;
148 
149   jStart = (this->StartPhi <= 0.0 ? 1 : 0);
150   jEnd = (this->EndPhi >= 180.0 ? this->PhiResolution - 1
151         : this->PhiResolution);
152 
153   // Create intermediate points
154   for (i=0; i < localThetaResolution; i++)
155     {
156     theta = localStartTheta * vtkMath::Pi() / 180.0 + i*deltaTheta;
157 
158     for (j=jStart; j<jEnd; j++)
159       {
160       phi = startPhi + j*deltaPhi;
161       radius = this->Radius * sin((double)phi);
162       n[0] = radius * cos((double)theta);
163       n[1] = radius * sin((double)theta);
164       n[2] = this->Radius * cos((double)phi);
165       x[0] = n[0] + this->Center[0];
166       x[1] = n[1] + this->Center[1];
167       x[2] = n[2] + this->Center[2];
168       newPoints->InsertNextPoint(x);
169 
170       if ( (norm = vtkMath::Norm(n)) == 0.0 )
171         {
172         norm = 1.0;
173         }
174       n[0] /= norm; n[1] /= norm; n[2] /= norm;
175       newNormals->InsertNextTuple(n);
176       }
177     }
178 
179   // Generate mesh connectivity
180   base = phiResolution * localThetaResolution;
181 
182   if (fabs(localStartTheta - localEndTheta) < 360.0)
183     {
184     --localThetaResolution;
185     }
186 
187   if ( this->StartPhi <= 0.0 )  // around north pole
188     {
189     for (i=0; i < localThetaResolution; i++)
190       {
191       pts[0] = phiResolution*i + numPoles;
192       pts[1] = (phiResolution*(i+1) % base) + numPoles;
193       pts[2] = 0;
194       newPolys->InsertNextCell(3, pts);
195       }
196     }
197 
198   if ( this->EndPhi >= 180.0 ) // around south pole
199     {
200     numOffset = phiResolution - 1 + numPoles;
201 
202     for (i=0; i < localThetaResolution; i++)
203       {
204       pts[0] = phiResolution*i + numOffset;
205       pts[2] = ((phiResolution*(i+1)) % base) + numOffset;
206       pts[1] = numPoles - 1;
207       newPolys->InsertNextCell(3, pts);
208       }
209     }
210 
211   // bands in-between poles
212   for (i=0; i < localThetaResolution; i++)
213     {
214     for (j=0; j < (phiResolution-1); j++)
215       {
216       pts[0] = phiResolution*i + j + numPoles;
217       pts[1] = pts[0] + 1;
218       pts[2] = ((phiResolution*(i+1)+j) % base) + numPoles + 1;
219       newPolys->InsertNextCell(3, pts);
220 
221       pts[1] = pts[2];
222       pts[2] = pts[1] - 1;
223       newPolys->InsertNextCell(3, pts);
224       }
225     }
226   //
227   // Update ourselves and release memeory
228   //
229   newPoints->Squeeze();
230   output->SetPoints(newPoints);
231   newPoints->Delete();
232 
233   newNormals->Squeeze();
234   output->GetPointData()->SetNormals(newNormals);
235   newNormals->Delete();
236 
237   output->SetPolys(newPolys);
238   newPolys->Delete();
239 
240   return 1;
241 }
242 
243 //----------------------------------------------------------------------------
GetEstimatedMemorySize()244 unsigned long vtkPSphereSource::GetEstimatedMemorySize()
245 {
246   vtkLargeInteger sz;
247   vtkLargeInteger sz2;
248   unsigned long thetaResolution = this->ThetaResolution;
249   vtkInformation *outInfo = this->GetExecutive()->GetOutputInformation(0);
250   int numPieces =
251     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
252 
253   if (numPieces)
254     {
255     thetaResolution /= numPieces;
256     }
257 
258   if (thetaResolution < 1)
259     {
260     thetaResolution = 1;
261     }
262 
263   // ignore poles
264   sz = thetaResolution;
265   sz = sz * (this->PhiResolution + 1);
266   sz2 = thetaResolution;
267   sz2 = sz2 * this->PhiResolution * 2;
268   sz = sz * 3 * sizeof(float);
269   sz2 = sz2 * 4 * sizeof(int);
270 
271   sz = sz + sz2;
272 
273   // convert to kilobytes
274   sz >>= 10;
275 
276   return sz.CastToUnsignedLong();
277 }
278 
PrintSelf(ostream & os,vtkIndent indent)279 void vtkPSphereSource::PrintSelf(ostream& os, vtkIndent indent)
280 {
281   this->Superclass::PrintSelf(os, indent);
282 }
283