/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkSphereSource.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkSphereSource.h" #include "vtkCellArray.h" #include "vtkFloatArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include vtkCxxRevisionMacro(vtkSphereSource, "$Revision: 1.69 $"); vtkStandardNewMacro(vtkSphereSource); //---------------------------------------------------------------------------- // Construct sphere with radius=0.5 and default resolution 8 in both Phi // and Theta directions. Theta ranges from (0,360) and phi (0,180) degrees. vtkSphereSource::vtkSphereSource(int res) { res = res < 4 ? 4 : res; this->Radius = 0.5; this->Center[0] = 0.0; this->Center[1] = 0.0; this->Center[2] = 0.0; this->ThetaResolution = res; this->PhiResolution = res; this->StartTheta = 0.0; this->EndTheta = 360.0; this->StartPhi = 0.0; this->EndPhi = 180.0; this->LatLongTessellation = 0; this->SetNumberOfInputPorts(0); } //---------------------------------------------------------------------------- int vtkSphereSource::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the ouptut vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); int i, j; int jStart, jEnd, numOffset; int numPts, numPolys; vtkPoints *newPoints; vtkFloatArray *newNormals; vtkCellArray *newPolys; double x[3], n[3], deltaPhi, deltaTheta, phi, theta, radius, norm; double startTheta, endTheta, startPhi, endPhi; int base, numPoles=0, thetaResolution, phiResolution; vtkIdType pts[4]; int piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); int numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); if (numPieces > this->ThetaResolution) { numPieces = this->ThetaResolution; } if (piece >= numPieces) { // Although the super class should take care of this, // it cannot hurt to check here. return 1; } // I want to modify the ivars resoultion start theta and end theta, // so I will make local copies of them. THese might be able to be merged // with the other copies of them, ... int localThetaResolution = this->ThetaResolution; double localStartTheta = this->StartTheta; double localEndTheta = this->EndTheta; while (localEndTheta < localStartTheta) { localEndTheta += 360.0; } deltaTheta = (localEndTheta - localStartTheta) / localThetaResolution; // Change the ivars based on pieces. int start, end; start = piece * localThetaResolution / numPieces; end = (piece+1) * localThetaResolution / numPieces; localEndTheta = localStartTheta + (double)(end) * deltaTheta; localStartTheta = localStartTheta + (double)(start) * deltaTheta; localThetaResolution = end - start; // Set things up; allocate memory // vtkDebugMacro("SphereSource Executing piece index " << piece << " of " << numPieces << " pieces."); numPts = this->PhiResolution * localThetaResolution + 2; // creating triangles numPolys = this->PhiResolution * 2 * localThetaResolution; newPoints = vtkPoints::New(); newPoints->Allocate(numPts); newNormals = vtkFloatArray::New(); newNormals->SetNumberOfComponents(3); newNormals->Allocate(3*numPts); newNormals->SetName("Normals"); newPolys = vtkCellArray::New(); newPolys->Allocate(newPolys->EstimateSize(numPolys, 3)); // Create sphere // // Create north pole if needed if ( this->StartPhi <= 0.0 ) { x[0] = this->Center[0]; x[1] = this->Center[1]; x[2] = this->Center[2] + this->Radius; newPoints->InsertPoint(numPoles,x); x[0] = x[1] = 0.0; x[2] = 1.0; newNormals->InsertTuple(numPoles,x); numPoles++; } // Create south pole if needed if ( this->EndPhi >= 180.0 ) { x[0] = this->Center[0]; x[1] = this->Center[1]; x[2] = this->Center[2] - this->Radius; newPoints->InsertPoint(numPoles,x); x[0] = x[1] = 0.0; x[2] = -1.0; newNormals->InsertTuple(numPoles,x); numPoles++; } // Check data, determine increments, and convert to radians startTheta = (localStartTheta < localEndTheta ? localStartTheta : localEndTheta); startTheta *= vtkMath::Pi() / 180.0; endTheta = (localEndTheta > localStartTheta ? localEndTheta : localStartTheta); endTheta *= vtkMath::Pi() / 180.0; startPhi = (this->StartPhi < this->EndPhi ? this->StartPhi : this->EndPhi); startPhi *= vtkMath::Pi() / 180.0; endPhi = (this->EndPhi > this->StartPhi ? this->EndPhi : this->StartPhi); endPhi *= vtkMath::Pi() / 180.0; phiResolution = this->PhiResolution - numPoles; deltaPhi = (endPhi - startPhi) / (this->PhiResolution - 1); thetaResolution = localThetaResolution; if (fabs(localStartTheta - localEndTheta) < 360.0) { ++localThetaResolution; } deltaTheta = (endTheta - startTheta) / thetaResolution; jStart = (this->StartPhi <= 0.0 ? 1 : 0); jEnd = (this->EndPhi >= 180.0 ? this->PhiResolution - 1 : this->PhiResolution); this->UpdateProgress(0.1); // Create intermediate points for (i=0; i < localThetaResolution; i++) { theta = localStartTheta * vtkMath::Pi() / 180.0 + i*deltaTheta; for (j=jStart; jRadius * sin((double)phi); n[0] = radius * cos((double)theta); n[1] = radius * sin((double)theta); n[2] = this->Radius * cos((double)phi); x[0] = n[0] + this->Center[0]; x[1] = n[1] + this->Center[1]; x[2] = n[2] + this->Center[2]; newPoints->InsertNextPoint(x); if ( (norm = vtkMath::Norm(n)) == 0.0 ) { norm = 1.0; } n[0] /= norm; n[1] /= norm; n[2] /= norm; newNormals->InsertNextTuple(n); } this->UpdateProgress (0.10 + 0.50*i/static_cast(localThetaResolution)); } // Generate mesh connectivity base = phiResolution * localThetaResolution; if (fabs(localStartTheta - localEndTheta) < 360.0) { --localThetaResolution; } if ( this->StartPhi <= 0.0 ) // around north pole { for (i=0; i < localThetaResolution; i++) { pts[0] = phiResolution*i + numPoles; pts[1] = (phiResolution*(i+1) % base) + numPoles; pts[2] = 0; newPolys->InsertNextCell(3, pts); } } if ( this->EndPhi >= 180.0 ) // around south pole { numOffset = phiResolution - 1 + numPoles; for (i=0; i < localThetaResolution; i++) { pts[0] = phiResolution*i + numOffset; pts[2] = ((phiResolution*(i+1)) % base) + numOffset; pts[1] = numPoles - 1; newPolys->InsertNextCell(3, pts); } } this->UpdateProgress (0.70); // bands in-between poles for (i=0; i < localThetaResolution; i++) { for (j=0; j < (phiResolution-1); j++) { pts[0] = phiResolution*i + j + numPoles; pts[1] = pts[0] + 1; pts[2] = ((phiResolution*(i+1)+j) % base) + numPoles + 1; if ( !this->LatLongTessellation ) { newPolys->InsertNextCell(3, pts); pts[1] = pts[2]; pts[2] = pts[1] - 1; newPolys->InsertNextCell(3, pts); } else { pts[3] = pts[2] - 1; newPolys->InsertNextCell(4, pts); } } this->UpdateProgress (0.70 + 0.30*i/static_cast(localThetaResolution)); } // Update ourselves and release memeory // newPoints->Squeeze(); output->SetPoints(newPoints); newPoints->Delete(); newNormals->Squeeze(); output->GetPointData()->SetNormals(newNormals); newNormals->Delete(); newPolys->Squeeze(); output->SetPolys(newPolys); newPolys->Delete(); return 1; } //---------------------------------------------------------------------------- void vtkSphereSource::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Theta Resolution: " << this->ThetaResolution << "\n"; os << indent << "Phi Resolution: " << this->PhiResolution << "\n"; os << indent << "Theta Start: " << this->StartTheta << "\n"; os << indent << "Phi Start: " << this->StartPhi << "\n"; os << indent << "Theta End: " << this->EndTheta << "\n"; os << indent << "Phi End: " << this->EndPhi << "\n"; os << indent << "Radius: " << this->Radius << "\n"; os << indent << "Center: (" << this->Center[0] << ", " << this->Center[1] << ", " << this->Center[2] << ")\n"; os << indent << "LatLong Tessellation: " << this->LatLongTessellation << "\n"; } //---------------------------------------------------------------------------- int vtkSphereSource::RequestInformation( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_BOUNDING_BOX(), this->Center[0] - this->Radius, this->Center[0] + this->Radius, this->Center[1] - this->Radius, this->Center[1] + this->Radius, this->Center[2] - this->Radius, this->Center[2] + this->Radius); return 1; }