text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    $RCSfile: vtkSQSphereSource.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 "vtkSQSphereSource.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 "vtkPVInformationKeys.h"
  
  #include "vtkSQMetaDataKeys.h"
  
  #include <math.h>
  
  vtkStandardNewMacro(vtkSQSphereSource);
  
  //----------------------------------------------------------------------------
  // 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.
  vtkSQSphereSource::vtkSQSphereSource(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->DescriptiveName=0;
  
    this->SetNumberOfInputPorts(0);
  }
  
  //----------------------------------------------------------------------------
  vtkSQSphereSource::~vtkSQSphereSource()
  {
    this->SetDescriptiveName(0);
  }
  
  //----------------------------------------------------------------------------
  int vtkSQSphereSource::RequestData(
    vtkInformation *vtkNotUsed(request),
    vtkInformationVector **vtkNotUsed(inputVector),
    vtkInformationVector *outputVector)
  {
    // get the info object
    vtkInformation *outInfo = outputVector->GetInformationObject(0);
  
    // Set the descriptiove name (if used).
    if (this->DescriptiveName && strlen(this->DescriptiveName))
      {
      outInfo->Set(vtkSQMetaDataKeys::DESCRIPTIVE_NAME(),this->DescriptiveName);
      }
  
    // 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; j<jEnd; j++)
        {
        phi = startPhi + j*deltaPhi;
        radius = this->Radius * 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<float>(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<double>(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 vtkSQSphereSource::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 vtkSQSphereSource::RequestInformation(
    vtkInformation *vtkNotUsed(request),
    vtkInformationVector **vtkNotUsed(inputVector),
    vtkInformationVector *outputVector)
  {
    // get the info object
    vtkInformation *outInfo = outputVector->GetInformationObject(0);
  
    outInfo->Set(CAN_HANDLE_PIECE_REQUEST(),
                 1);
  
    outInfo->Set(vtkPVInformationKeys::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;
  }
  