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.
 
 
 
 
 
 

470 lines
12 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkSpherePuzzle.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 "vtkSpherePuzzle.h"
#include "vtkAppendPolyData.h"
#include "vtkGarbageCollector.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkLinearExtrusionFilter.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkSphereSource.h"
#include "vtkTransform.h"
#include "vtkTransformFilter.h"
#include <math.h>
vtkCxxRevisionMacro(vtkSpherePuzzle, "$Revision: 1.19 $");
vtkStandardNewMacro(vtkSpherePuzzle);
//----------------------------------------------------------------------------
// Construct a new puzzle.
vtkSpherePuzzle::vtkSpherePuzzle()
{
this->Transform = vtkTransform::New();
this->Reset();
this->Active = 0;
this->SetNumberOfInputPorts(0);
}
//----------------------------------------------------------------------------
// Construct a new puzzle.
vtkSpherePuzzle::~vtkSpherePuzzle()
{
this->Transform->Delete();
this->Transform = NULL;
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::Reset()
{
int idx;
this->Modified();
for (idx = 0; idx < 32; ++idx)
{
this->State[idx] = idx;
this->PieceMask[idx] = 0;
}
this->Transform->Identity();
for (idx = 0; idx < 4; ++idx)
{
this->Colors[0 + idx*8*3] = 255;
this->Colors[1 + idx*8*3] = 0;
this->Colors[2 + idx*8*3] = 0;
this->Colors[3 + idx*8*3] = 255;
this->Colors[4 + idx*8*3] = 175;
this->Colors[5 + idx*8*3] = 0;
this->Colors[6 + idx*8*3] = 255;
this->Colors[7 + idx*8*3] = 255;
this->Colors[8 + idx*8*3] = 0;
this->Colors[9 + idx*8*3] = 0;
this->Colors[10 + idx*8*3] = 255;
this->Colors[11 + idx*8*3] = 0;
this->Colors[12 + idx*8*3] = 0;
this->Colors[13 + idx*8*3] = 255;
this->Colors[14 + idx*8*3] = 255;
this->Colors[15 + idx*8*3] = 0;
this->Colors[16 + idx*8*3] = 0;
this->Colors[17 + idx*8*3] = 255;
this->Colors[18 + idx*8*3] = 175;
this->Colors[19 + idx*8*3] = 0;
this->Colors[20 + idx*8*3] = 255;
this->Colors[21 + idx*8*3] = 255;
this->Colors[22 + idx*8*3] = 50;
this->Colors[23 + idx*8*3] = 150;
}
}
//----------------------------------------------------------------------------
int vtkSpherePuzzle::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()));
// We are about to create/destroy alot of objects. Defer garbage
// collection until we are done.
vtkGarbageCollector::DeferredCollectionPush();
int i, j, k, num;
int color;
vtkAppendPolyData *append = vtkAppendPolyData::New();
vtkSphereSource *sphere = vtkSphereSource::New();
vtkTransformFilter *tf = vtkTransformFilter::New();
vtkUnsignedCharArray *scalars = vtkUnsignedCharArray::New();
vtkPolyData *tmp;
int count = 0;
unsigned char r, g, b;
scalars->SetNumberOfComponents(3);
sphere->SetPhiResolution(4);
sphere->SetThetaResolution(4);
tf->SetTransform(this->Transform);
tf->SetInput(sphere->GetOutput());
for (j = 0; j < 4; ++j)
{
for (i = 0; i < 8; ++i)
{
color = this->State[count] * 3;
sphere->SetStartTheta((360.0 * (double)(i) / 8.0));
sphere->SetEndTheta((360.0 * (double)(i+1) / 8.0));
sphere->SetStartPhi((180.0 * (double)(j) / 4.0));
sphere->SetEndPhi((180.0 * (double)(j+1) / 4.0));
tmp = vtkPolyData::New();
if (this->PieceMask[count])
{ // Spheres original output is transforms input. Put it back.
tf->Update();
tmp->ShallowCopy(tf->GetOutput());
}
else
{ // Piece not involved in partial move. Just use the sphere.
sphere->Update();
tmp->ShallowCopy(sphere->GetOutput());
}
// Now create the colors for the faces.
num = tmp->GetNumberOfPoints();
for (k = 0; k < num; ++k)
{
r = this->Colors[color];
g = this->Colors[color+1];
b = this->Colors[color+2];
// Lighten the active pieces
if (this->Active && this->PieceMask[count])
{
r = r + (unsigned char)((255 - r) * 0.4);
g = g + (unsigned char)((255 - g) * 0.4);
b = b + (unsigned char)((255 - b) * 0.4);
}
scalars->InsertNextValue(r);
scalars->InsertNextValue(g);
scalars->InsertNextValue(b);
}
// append all the pieces.
append->AddInput(tmp);
tmp->FastDelete();
++count;
}
}
append->Update();
// Move the data to the output.
tmp = output;
tmp->CopyStructure(append->GetOutput());
tmp->GetPointData()->PassData(append->GetOutput()->GetPointData());
tmp->GetPointData()->SetScalars(scalars);
sphere->Delete();
scalars->Delete();
append->Delete();
tf->Delete();
// We are done creating/destroying objects.
vtkGarbageCollector::DeferredCollectionPop();
return 1;
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::MarkHorizontal(int section)
{
int i;
for (i = 0; i < 32; ++i)
{
this->PieceMask[i] = 0;
}
// Find the start of the section.
section = section * 8;
for (i = 0; i < 8; ++i)
{
this->PieceMask[i+section] = 1;
}
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::MarkVertical(int section)
{
int i, j, offset;
for (i = 0; i < 32; ++i)
{
this->PieceMask[i] = 1;
}
for (i = 0; i < 4; ++i)
{
offset = (section + i) % 8;
for (j = 0; j < 4; ++j)
{
this->PieceMask[offset+(j*8)] = 0;
}
}
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::MoveHorizontal(int slab, int percentage, int rightFlag)
{
int offset;
int tmp;
int i;
this->Modified();
// Clear out previous partial moves.
this->Transform->Identity();
this->MarkHorizontal(slab);
// Move zero does nothing.
if (percentage <= 0)
{
return;
}
// Offset is used to determine which pieces are involved.
offset = slab * 8;
// Move 100 percent changes state.
if (percentage >= 100)
{ // Just do the state change.
if (rightFlag)
{
tmp = this->State[offset+7];
for (i = 7; i > 0; --i)
{
this->State[i+offset] = this->State[i-1+offset];
}
this->State[offset] = tmp;
}
else
{
tmp = this->State[offset];
for (i = 0; i < 7; ++i)
{
this->State[i+offset] = this->State[i+1+offset];
}
this->State[offset+7] = tmp;
}
return;
}
// Partial move.
// This does not change the state. It is ust for animating
// the move.
// Setup the pieces that are involved in the move.
if ( ! rightFlag)
{
percentage = -percentage;
}
this->Transform->RotateZ(((double)(percentage) / 100.0)
* (360.0 / 8.0) );
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::MoveVertical(int half, int percentage, int rightFlag)
{
int tmp;
int off0, off1, off2, off3;
double theta;
this->Modified();
// Clear out previous partial moves.
this->Transform->Identity();
this->MarkVertical(half);
// Move zero does nothing.
if (percentage <= 0)
{
return;
}
off0 = (4+half) % 8;
off1 = (5+half) % 8;
off2 = (6+half) % 8;
off3 = (7+half) % 8;
// Move 100 percent changes state.
if (percentage >= 100)
{ // Just do the state change.
tmp = this->State[off0];
this->State[off0] = this->State[24+off3];
this->State[24+off3] = tmp;
tmp = this->State[off1];
this->State[off1] = this->State[24+off2];
this->State[24+off2] = tmp;
tmp = this->State[off2];
this->State[off2] = this->State[24+off1];
this->State[24+off1] = tmp;
tmp = this->State[off3];
this->State[off3] = this->State[24+off0];
this->State[24+off0] = tmp;
tmp = this->State[8+off0];
this->State[8+off0] = this->State[16+off3];
this->State[16+off3] = tmp;
tmp = this->State[8+off1];
this->State[8+off1] = this->State[16+off2];
this->State[16+off2] = tmp;
tmp = this->State[8+off2];
this->State[8+off2] = this->State[16+off1];
this->State[16+off1] = tmp;
tmp = this->State[8+off3];
this->State[8+off3] = this->State[16+off0];
this->State[16+off0] = tmp;
return;
}
// Partial move.
// This does not change the state. It is use for animating the move.
if (rightFlag)
{
percentage = -percentage;
}
theta = (double)(half) * vtkMath::Pi() / 4.0;
this->Transform->RotateWXYZ(((double)(percentage)/100.0)*(360.0/2.0),
sin(theta), -cos(theta), 0.0);
}
//----------------------------------------------------------------------------
int vtkSpherePuzzle::SetPoint(double x, double y, double z)
{
double pt[3];
double theta, phi;
int xi, yi;
double xp, yp;
double xn, yn;
this->Modified();
if (x < 0.2 && x > -0.2 && y < 0.2 && y > -0.2 && z < 0.2 && z > -0.2)
{
this->Active = 0;
return 0;
}
// normalize
pt[0] = x;
pt[1] = y;
pt[2] = z;
vtkMath::Normalize(pt);
// Convert this into phi and theta.
theta = 180.0 - atan2(pt[0], pt[1]) * 180 / vtkMath::Pi();
phi = 90.0 - asin(pt[2]) * 180 / vtkMath::Pi();
// Compute the piece the point is in.
xi = (int)(theta * 8.0 / 360.0);
yi = (int)(phi * 8 / 360.0);
xn = (theta/(360.0/8.0)) - (double)(xi);
yn = (phi/(360.0/8.0)) - (double)(yi);
vtkDebugMacro("point: " << x << ", " << y << ", " << z);
vtkDebugMacro("theta: " << theta << ", phi: " << phi);
vtkDebugMacro("theta: " << xi << ", " << xn << ", phi: " << yi << ", " << y);
xp = 1.0 - xn;
yp = 1.0 - yn;
if (xn > 0.2 && xp > 0.2 && yn > 0.2 && yp > 0.2)
{ // Do nothing in the center of the face.
this->Active = 0;
return 0;
}
this->Active = 1;
if (xn < xp && xn < yp && xn < yn)
{
this->VerticalFlag = 1;
this->RightFlag = (yn < yp);
this->Section = xi+2;
this->MarkVertical(this->Section);
return this->Section + this->VerticalFlag * 10 + this->RightFlag * 100;
}
if (xp < xn && xp < yp && xp < yn)
{
this->VerticalFlag = 1;
this->RightFlag = (yp < yn);
this->Section = xi+7;
this->MarkVertical(this->Section);
return this->Section + this->VerticalFlag * 10 + this->RightFlag * 100;
}
// The remaining options move a horizontal slab.
this->VerticalFlag = 0;
this->RightFlag = (xn > xp);
this->Section = yi;
this->MarkHorizontal(this->Section);
return this->Section + this->VerticalFlag * 10 + this->RightFlag * 100;
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::MovePoint(int percentage)
{
if ( ! this->Active)
{
return;
}
this->Modified();
if (this->VerticalFlag)
{
this->MoveVertical(this->Section, percentage, this->RightFlag);
}
else
{
this->MoveHorizontal(this->Section, percentage, this->RightFlag);
}
}
//----------------------------------------------------------------------------
void vtkSpherePuzzle::PrintSelf(ostream& os, vtkIndent indent)
{
int idx;
this->Superclass::PrintSelf(os,indent);
os << indent << "State: " << this->State[0];
for (idx = 1; idx < 16; ++idx)
{
os << ", " << this->State[idx];
}
os << endl;
}