Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

406 lines
11 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkSuperquadricSource.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.
=========================================================================*/
/* vtkSuperquadric originally written by Michael Halle,
Brigham and Women's Hospital, July 1998.
Based on "Rigid physically based superquadrics", A. H. Barr,
in "Graphics Gems III", David Kirk, ed., Academic Press, 1992.
*/
#include "vtkSuperquadricSource.h"
#include "vtkCellArray.h"
#include "vtkFloatArray.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include <math.h>
vtkCxxRevisionMacro(vtkSuperquadricSource, "$Revision: 1.23 $");
vtkStandardNewMacro(vtkSuperquadricSource);
static void evalSuperquadric(double u, double v,
double du, double dv,
double n, double e,
double dims[3],
double alpha,
double xyz[3],
double nrm[3]);
// Description:
vtkSuperquadricSource::vtkSuperquadricSource(int res)
{
res = res < 4 ? 4 : res;
this->Toroidal = 0;
this->Thickness = 0.3333;
this->PhiRoundness = 0.0;
this->SetPhiRoundness(1.0);
this->ThetaRoundness = 0.0;
this->SetThetaRoundness(1.0);
this->Center[0] = this->Center[1] = this->Center[2] = 0.0;
this->Scale[0] = this->Scale[1] = this->Scale[2] = 1.0;
this->Size = .5;
this->ThetaResolution = 0;
this->SetThetaResolution(res);
this->PhiResolution = 0;
this->SetPhiResolution(res);
this->SetNumberOfInputPorts(0);
}
void vtkSuperquadricSource::SetPhiResolution(int i)
{
if(i < 4)
{
i = 4;
}
i = (i+3)/4*4; // make it divisible by 4
if(i > VTK_MAX_SUPERQUADRIC_RESOLUTION)
{
i = VTK_MAX_SUPERQUADRIC_RESOLUTION;
}
if (this->PhiResolution != i)
{
this->PhiResolution = i;
this->Modified ();
}
}
void vtkSuperquadricSource::SetThetaResolution(int i)
{
if(i < 8)
{
i = 8;
}
i = (i+7)/8*8; // make it divisible by 8
if(i > VTK_MAX_SUPERQUADRIC_RESOLUTION)
{
i = VTK_MAX_SUPERQUADRIC_RESOLUTION;
}
if (this->ThetaResolution != i)
{
this->ThetaResolution = i;
this->Modified ();
}
}
void vtkSuperquadricSource::SetThetaRoundness(double e)
{
if(e < VTK_MIN_SUPERQUADRIC_ROUNDNESS)
{
e = VTK_MIN_SUPERQUADRIC_ROUNDNESS;
}
if (this->ThetaRoundness != e)
{
this->ThetaRoundness = e;
this->Modified();
}
}
void vtkSuperquadricSource::SetPhiRoundness(double e)
{
if(e < VTK_MIN_SUPERQUADRIC_ROUNDNESS)
{
e = VTK_MIN_SUPERQUADRIC_ROUNDNESS;
}
if (this->PhiRoundness != e)
{
this->PhiRoundness = e;
this->Modified();
}
}
static const double SQ_SMALL_OFFSET = 0.01;
int vtkSuperquadricSource::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;
vtkIdType numPts;
vtkPoints *newPoints;
vtkFloatArray *newNormals;
vtkFloatArray *newTCoords;
vtkCellArray *newPolys;
vtkIdType *ptidx;
double pt[3], nv[3], dims[3];
double len;
double alpha;
double deltaPhi, deltaTheta, phi, theta;
double phiLim[2], thetaLim[2];
double deltaPhiTex, deltaThetaTex;
int base, pbase;
vtkIdType numStrips;
int ptsPerStrip;
int phiSubsegs, thetaSubsegs, phiSegs, thetaSegs;
int iq, jq, rowOffset;
double thetaOffset, phiOffset;
double texCoord[2];
dims[0] = this->Scale[0] * this->Size;
dims[1] = this->Scale[1] * this->Size;
dims[2] = this->Scale[2] * this->Size;
if(this->Toroidal)
{
phiLim[0] = -vtkMath::Pi();
phiLim[1] = vtkMath::Pi();
thetaLim[0] = -vtkMath::Pi();
thetaLim[1] = vtkMath::Pi();
alpha = (1.0 / this->Thickness);
dims[0] /= (alpha + 1.0);
dims[1] /= (alpha + 1.0);
dims[2] /= (alpha + 1.0);
}
else
{
//Ellipsoidal
phiLim[0] = -vtkMath::Pi() / 2.0;
phiLim[1] = vtkMath::Pi() / 2.0;
thetaLim[0] = -vtkMath::Pi();
thetaLim[1] = vtkMath::Pi();
alpha = 0.0;
}
deltaPhi = (phiLim[1] - phiLim[0]) / this->PhiResolution;
deltaPhiTex = 1.0 / this->PhiResolution;
deltaTheta = (thetaLim[1] - thetaLim[0]) / this->ThetaResolution;
deltaThetaTex = 1.0 / this->ThetaResolution;
phiSegs = 4;
thetaSegs = 8;
phiSubsegs = this->PhiResolution / phiSegs;
thetaSubsegs = this->ThetaResolution / thetaSegs;
numPts = (this->PhiResolution + phiSegs)*(this->ThetaResolution + thetaSegs);
// creating triangles
numStrips = this->PhiResolution * thetaSegs;
ptsPerStrip = thetaSubsegs*2 + 2;
//
// Set things up; allocate memory
//
newPoints = vtkPoints::New();
newPoints->Allocate(numPts);
newNormals = vtkFloatArray::New();
newNormals->SetNumberOfComponents(3);
newNormals->Allocate(3*numPts);
newNormals->SetName("Normals");
newTCoords = vtkFloatArray::New();
newTCoords->SetNumberOfComponents(2);
newTCoords->Allocate(2*numPts);
newTCoords->SetName("TextureCoords");
newPolys = vtkCellArray::New();
newPolys->Allocate(newPolys->EstimateSize(numStrips,ptsPerStrip));
// generate!
for(iq = 0; iq < phiSegs; iq++)
{
for(i = 0; i <= phiSubsegs; i++)
{
phi = phiLim[0] + deltaPhi*(i + iq*phiSubsegs);
texCoord[1] = deltaPhiTex*(i + iq*phiSubsegs);
// SQ_SMALL_OFFSET makes sure that the normal vector isn't
// evaluated exactly on a crease; if that were to happen,
// large shading errors can occur.
if(i == 0)
{
phiOffset = SQ_SMALL_OFFSET*deltaPhi;
}
else if (i == phiSubsegs)
{
phiOffset = -SQ_SMALL_OFFSET*deltaPhi;
}
else
{
phiOffset = 0.0;
}
for(jq = 0; jq < thetaSegs; jq++)
{
for(j = 0; j <= thetaSubsegs; j++)
{
theta = thetaLim[0] + deltaTheta*(j + jq*thetaSubsegs);
texCoord[0] = deltaThetaTex*(j + jq*thetaSubsegs);
if(j == 0)
{
thetaOffset = SQ_SMALL_OFFSET*deltaTheta;
}
else if (j == thetaSubsegs)
{
thetaOffset = -SQ_SMALL_OFFSET*deltaTheta;
}
else
{
thetaOffset = 0.0;
}
evalSuperquadric(theta, phi,
thetaOffset, phiOffset,
this->PhiRoundness, this->ThetaRoundness,
dims, alpha, pt, nv);
if((len = vtkMath::Norm(nv)) == 0.0)
{
len = 1.0;
}
nv[0] /= len; nv[1] /= len; nv[2] /= len;
if(!this->Toroidal &&
((iq == 0 && i == 0) || (iq == (phiSegs-1) && i == phiSubsegs))) {
// we're at a pole:
// make sure the pole is at the same location for all evals
// (the superquadric evaluation is numerically unstable
// at the poles)
pt[0] = pt[2] = 0.0;
}
pt[0] += this->Center[0];
pt[1] += this->Center[1];
pt[2] += this->Center[2];
newPoints->InsertNextPoint(pt);
newNormals->InsertNextTuple(nv);
newTCoords->InsertNextTuple(texCoord);
}
}
}
}
// mesh!
// build triangle strips for efficiency....
ptidx = new vtkIdType[ptsPerStrip];
rowOffset = this->ThetaResolution+thetaSegs;
for(iq = 0; iq < phiSegs; iq++)
{
for(i = 0; i < phiSubsegs; i++)
{
pbase = rowOffset*(i +iq*(phiSubsegs+1));
for(jq = 0; jq < thetaSegs; jq++)
{
base = pbase + jq*(thetaSubsegs+1);
for(j = 0; j <= thetaSubsegs; j++)
{
ptidx[2*j] = base + rowOffset + j;
ptidx[2*j+1] = base + j;
}
newPolys->InsertNextCell(ptsPerStrip, ptidx);
}
}
}
delete[] ptidx;
output->SetPoints(newPoints);
newPoints->Delete();
output->GetPointData()->SetNormals(newNormals);
newNormals->Delete();
output->GetPointData()->SetTCoords(newTCoords);
newTCoords->Delete();
output->SetStrips(newPolys);
newPolys->Delete();
return 1;
}
void vtkSuperquadricSource::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Toroidal: " << (this->Toroidal ? "On\n" : "Off\n");
os << indent << "Size: " << this->Size << "\n";
os << indent << "Thickness: " << this->Thickness << "\n";
os << indent << "Theta Resolution: " << this->ThetaResolution << "\n";
os << indent << "Theta Roundness: " << this->ThetaRoundness << "\n";
os << indent << "Phi Resolution: " << this->PhiResolution << "\n";
os << indent << "Phi Roundness: " << this->PhiRoundness << "\n";
os << indent << "Center: (" << this->Center[0] << ", "
<< this->Center[1] << ", " << this->Center[2] << ")\n";
os << indent << "Scale: (" << this->Scale[0] << ", "
<< this->Scale[1] << ", " << this->Scale[2] << ")\n";
}
static double cf(double w, double m, double a)
{
double c;
double sgn;
c = cos(w);
sgn = c < 0.0 ? -1.0 : 1.0;
return a + sgn*pow(sgn*c, m);
}
static double sf(double w, double m)
{
double s;
double sgn;
s = sin(w);
sgn = s < 0.0 ? -1.0 : 1.0;
return sgn*pow(sgn*s, m);
}
static void evalSuperquadric(double u, double v, // parametric coords
double du, double dv, // offsets for normals
double n, double e, // roundness params
double dims[3], // x, y, z dimensions
double alpha, // hole size
double xyz[3], // output coords
double nrm[3]) // output normals
{
double cf1, cf2;
cf1 = cf(v, n, alpha);
xyz[0] = dims[0] * cf1 * sf(u, e);
xyz[1] = dims[1] * sf(v, n);
xyz[2] = dims[2] * cf1 * cf(u, e, 0.0);
cf2 = cf(v+dv, 2.0-n, 0.0);
nrm[0] = 1.0/dims[0] * cf2 * sf(u+du, 2.0-e);
nrm[1] = 1.0/dims[1] * sf(v+dv, 2.0-n);
nrm[2] = 1.0/dims[2] * cf2 * cf(u+du, 2.0-e, 0.0);
}