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