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.
460 lines
12 KiB
460 lines
12 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkImageMandelbrotSource.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 "vtkImageMandelbrotSource.h"
|
|
|
|
#include "vtkImageData.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
#include "vtkPointData.h"
|
|
|
|
vtkCxxRevisionMacro(vtkImageMandelbrotSource, "$Revision: 1.43 $");
|
|
vtkStandardNewMacro(vtkImageMandelbrotSource);
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageMandelbrotSource::vtkImageMandelbrotSource()
|
|
{
|
|
this->MaximumNumberOfIterations = 100;
|
|
this->WholeExtent[0] = 0;
|
|
this->WholeExtent[1] = 250;
|
|
this->WholeExtent[2] = 0;
|
|
this->WholeExtent[3] = 250;
|
|
this->WholeExtent[4] = 0;
|
|
this->WholeExtent[5] = 0;
|
|
|
|
this->SampleCX[0] = 0.01;
|
|
this->SampleCX[1] = 0.01;
|
|
this->SampleCX[2] = 0.01;
|
|
this->SampleCX[3] = 0.01;
|
|
|
|
this->SizeCX[0] = 2.5;
|
|
this->SizeCX[1] = 2.5;
|
|
this->SizeCX[2] = 2.0;
|
|
this->SizeCX[3] = 1.5;
|
|
|
|
this->ConstantSize = 1;
|
|
|
|
this->OriginCX[0] = -1.75;
|
|
this->OriginCX[1] = -1.25;
|
|
this->OriginCX[2] = 0.0;
|
|
this->OriginCX[3] = 0.0;
|
|
|
|
this->ProjectionAxes[0] = 0;
|
|
this->ProjectionAxes[1] = 1;
|
|
this->ProjectionAxes[2] = 2;
|
|
|
|
this->SetNumberOfInputPorts(0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageMandelbrotSource::~vtkImageMandelbrotSource()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "OriginC: (" << this->OriginCX[0] << ", "
|
|
<< this->OriginCX[1] << ")\n";
|
|
os << indent << "OriginX: (" << this->OriginCX[2] << ", "
|
|
<< this->OriginCX[3] << ")\n";
|
|
|
|
os << indent << "SampleC: (" << this->SampleCX[0] << ", "
|
|
<< this->SampleCX[1] << ")\n";
|
|
os << indent << "SampleX: (" << this->SampleCX[2] << ", "
|
|
<< this->SampleCX[3] << ")\n";
|
|
|
|
double *size = this->GetSizeCX();
|
|
os << indent << "SizeC: (" << size[0] << ", " << size[1] << ")\n";
|
|
os << indent << "SizeX: (" << size[2] << ", " << size[3] << ")\n";
|
|
|
|
if (this->ConstantSize)
|
|
{
|
|
os << indent << "ConstantSize\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "ConstantSpacing\n";
|
|
}
|
|
|
|
os << indent << "WholeExtent: (" << this->WholeExtent[0] << ", "
|
|
<< this->WholeExtent[1] << ", " << this->WholeExtent[2] << ", "
|
|
<< this->WholeExtent[3] << ", " << this->WholeExtent[4] << ", "
|
|
<< this->WholeExtent[5] << ")\n";
|
|
os << "MaximumNumberOfIterations: " << this->MaximumNumberOfIterations << endl;
|
|
|
|
os << indent << "ProjectionAxes: (" << this->ProjectionAxes[0] << ", "
|
|
<< this->ProjectionAxes[1] << this->ProjectionAxes[2] << ")\n";
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::SetWholeExtent(int extent[6])
|
|
{
|
|
int idx, modified = 0;
|
|
double saveSize[4];
|
|
|
|
this->GetSizeCX(saveSize);
|
|
|
|
|
|
for (idx = 0; idx < 6; ++idx)
|
|
{
|
|
if (this->WholeExtent[idx] != extent[idx])
|
|
{
|
|
this->WholeExtent[idx] = extent[idx];
|
|
modified = 1;
|
|
}
|
|
}
|
|
|
|
if (modified)
|
|
{
|
|
this->Modified();
|
|
if (this->ConstantSize)
|
|
{
|
|
this->SetSizeCX(saveSize[0], saveSize[1], saveSize[2], saveSize[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::SetProjectionAxes(int x, int y, int z)
|
|
{
|
|
double saveSize[4];
|
|
|
|
if (this->ProjectionAxes[0] == x && this->ProjectionAxes[1] == y &&
|
|
this->ProjectionAxes[2] == z)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Modified();
|
|
this->GetSizeCX(saveSize);
|
|
this->ProjectionAxes[0] = x;
|
|
this->ProjectionAxes[1] = y;
|
|
this->ProjectionAxes[2] = z;
|
|
if (this->ConstantSize)
|
|
{
|
|
this->SetSizeCX(saveSize[0], saveSize[1], saveSize[2], saveSize[3]);
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::SetWholeExtent(int minX, int maxX,
|
|
int minY, int maxY,
|
|
int minZ, int maxZ)
|
|
{
|
|
int extent[6];
|
|
|
|
extent[0] = minX; extent[1] = maxX;
|
|
extent[2] = minY; extent[3] = maxY;
|
|
extent[4] = minZ; extent[5] = maxZ;
|
|
this->SetWholeExtent(extent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::SetSizeCX(double cReal, double cImag,
|
|
double xReal, double xImag)
|
|
{
|
|
int axis;
|
|
int idx;
|
|
int d;
|
|
|
|
double *s = this->GetSizeCX();
|
|
if (s[0] == cReal && s[1] == cImag && s[2] == xReal && s[3] == xImag)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
|
|
// Set this because information can be carried over for collapsed axes.
|
|
this->SizeCX[0] = cReal;
|
|
this->SizeCX[1] = cImag;
|
|
this->SizeCX[2] = xReal;
|
|
this->SizeCX[3] = xImag;
|
|
|
|
// Now compute the gold standard (for non collapsed axes.
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
d = this->WholeExtent[idx*2+1] - this->WholeExtent[idx*2];
|
|
if (d > 0)
|
|
{
|
|
axis = this->ProjectionAxes[idx];
|
|
this->SampleCX[axis] = this->SizeCX[axis] / ((double) d);
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double* vtkImageMandelbrotSource::GetSizeCX()
|
|
{
|
|
int axis;
|
|
int idx;
|
|
int d;
|
|
|
|
// Recompute the size for the spacing (gold standard).
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
d = this->WholeExtent[idx*2+1] - this->WholeExtent[idx*2];
|
|
if (d > 0)
|
|
{
|
|
axis = this->ProjectionAxes[idx];
|
|
this->SizeCX[axis] = this->SampleCX[axis] * ((double) d);
|
|
}
|
|
}
|
|
|
|
return this->SizeCX;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::GetSizeCX(double s[4])
|
|
{
|
|
double *p = this->GetSizeCX();
|
|
|
|
s[0] = p[0];
|
|
s[1] = p[1];
|
|
s[2] = p[2];
|
|
s[3] = p[3];
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkImageMandelbrotSource::RequestInformation (
|
|
vtkInformation * vtkNotUsed(request),
|
|
vtkInformationVector** vtkNotUsed( inputVector ),
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info objects
|
|
vtkInformation* outInfo = outputVector->GetInformationObject(0);
|
|
|
|
int idx, axis;
|
|
double origin[3];
|
|
double spacing[3];
|
|
|
|
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
|
|
this->WholeExtent,6);
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
axis = this->ProjectionAxes[idx];
|
|
if (axis >= 0 && axis < 4)
|
|
{
|
|
origin[idx] = this->OriginCX[axis];
|
|
spacing[idx] = this->SampleCX[axis];
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro("Bad projection axis.");
|
|
origin[idx] = 0.0;
|
|
spacing[idx] = 1.0;
|
|
}
|
|
}
|
|
|
|
outInfo->Set(vtkDataObject::SPACING(),spacing,3);
|
|
outInfo->Set(vtkDataObject::ORIGIN(),origin,3);
|
|
vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_FLOAT, 1);
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// We may want separate zooms for mandelbrot and julia.
|
|
void vtkImageMandelbrotSource::Zoom(double factor)
|
|
{
|
|
if (factor == 1.0)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
this->SampleCX[0] *= factor;
|
|
this->SampleCX[1] *= factor;
|
|
this->SampleCX[2] *= factor;
|
|
this->SampleCX[3] *= factor;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMandelbrotSource::Pan(double x, double y, double z)
|
|
{
|
|
int idx, axis;
|
|
double pan[3];
|
|
|
|
if (x == 0.0 && y == 0.0 && z == 0.0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Modified();
|
|
pan[0]=x; pan[1]=y; pan[2]=z;
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
axis = this->ProjectionAxes[idx];
|
|
if (axis >= 0 && axis < 4)
|
|
{
|
|
this->OriginCX[axis] += this->SampleCX[axis] * pan[idx];
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
vtkImageMandelbrotSource::CopyOriginAndSample(vtkImageMandelbrotSource *source)
|
|
{
|
|
int idx;
|
|
|
|
for (idx = 0; idx < 4; ++idx)
|
|
{
|
|
this->OriginCX[idx] = source->OriginCX[idx];
|
|
this->SampleCX[idx] = source->SampleCX[idx];
|
|
}
|
|
|
|
this->Modified();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkImageMandelbrotSource::RequestData(
|
|
vtkInformation* vtkNotUsed( request ),
|
|
vtkInformationVector** vtkNotUsed(inputVector),
|
|
vtkInformationVector* outputVector)
|
|
{
|
|
// get the output
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
vtkImageData *data = vtkImageData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
// We need to allocate our own scalars since we are overriding
|
|
// the superclasses "Execute()" method.
|
|
int *ext = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
|
|
data->SetExtent(ext);
|
|
data->AllocateScalars();
|
|
|
|
int a0, a1, a2;
|
|
float *ptr;
|
|
int min0, max0;
|
|
int idx0, idx1, idx2;
|
|
vtkIdType inc0, inc1, inc2;
|
|
double *origin, *sample;
|
|
double p[4];
|
|
unsigned long count = 0;
|
|
unsigned long target;
|
|
|
|
// Name the array appropriately.
|
|
data->GetPointData()->GetScalars()->SetName("Iterations");
|
|
|
|
if (data->GetNumberOfPoints() <= 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Copy origin into pixel
|
|
for (idx0 = 0; idx0 < 4; ++idx0)
|
|
{
|
|
p[idx0] = this->OriginCX[idx0];
|
|
}
|
|
|
|
ptr = (float *)(data->GetScalarPointerForExtent(ext));
|
|
|
|
vtkDebugMacro("Generating Extent: " << ext[0] << " -> " << ext[1] << ", "
|
|
<< ext[2] << " -> " << ext[3]);
|
|
|
|
// Get min and max of axis 0 because it is the innermost loop.
|
|
min0 = ext[0];
|
|
max0 = ext[1];
|
|
data->GetContinuousIncrements(ext, inc0, inc1, inc2);
|
|
|
|
target = (unsigned long)((ext[5]-ext[4]+1)*(ext[3]-ext[2]+1)/50.0);
|
|
target++;
|
|
|
|
a0 = this->ProjectionAxes[0];
|
|
a1 = this->ProjectionAxes[1];
|
|
a2 = this->ProjectionAxes[2];
|
|
origin = this->OriginCX;
|
|
sample = this->SampleCX;
|
|
|
|
if (a0<0 || a1<0 || a2<0 || a0>3 || a1>3 || a2>3)
|
|
{
|
|
vtkErrorMacro("Bad projection axis");
|
|
return 0;
|
|
}
|
|
for (idx2 = ext[4]; idx2 <= ext[5]; ++idx2)
|
|
{
|
|
p[a2] = (double)(origin[a2]) + (double)(idx2)*(sample[a2]);
|
|
for (idx1 = ext[2]; !this->AbortExecute && idx1 <= ext[3]; ++idx1)
|
|
{
|
|
if (!(count%target))
|
|
{
|
|
this->UpdateProgress(count/(50.0*target));
|
|
}
|
|
count++;
|
|
p[a1] = (double)(origin[a1]) + (double)(idx1)*(sample[a1]);
|
|
for (idx0 = min0; idx0 <= max0; ++idx0)
|
|
{
|
|
p[a0] = (double)(origin[a0]) + (double)(idx0)*(sample[a0]);
|
|
|
|
*ptr = (float)(this->EvaluateSet(p));
|
|
|
|
++ptr;
|
|
// inc0 is 0
|
|
}
|
|
ptr += inc1;
|
|
}
|
|
ptr += inc2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
double vtkImageMandelbrotSource::EvaluateSet(double p[4])
|
|
{
|
|
unsigned short count = 0;
|
|
double v0, v1;
|
|
double cReal, cImag, zReal, zImag;
|
|
double zReal2, zImag2;
|
|
|
|
cReal = p[0];
|
|
cImag = p[1];
|
|
zReal = p[2];
|
|
zImag = p[3];
|
|
|
|
zReal2 = zReal * zReal;
|
|
zImag2 = zImag * zImag;
|
|
v0 = 0.0;
|
|
v1 = (zReal2 + zImag2);
|
|
while ( v1 < 4.0 && count < this->MaximumNumberOfIterations)
|
|
{
|
|
zImag = 2.0 * zReal * zImag + cImag;
|
|
zReal = zReal2 - zImag2 + cReal;
|
|
zReal2 = zReal * zReal;
|
|
zImag2 = zImag * zImag;
|
|
++count;
|
|
v0 = v1;
|
|
v1 = (zReal2 + zImag2);
|
|
}
|
|
|
|
if (count == this->MaximumNumberOfIterations)
|
|
{
|
|
return (double)count;
|
|
}
|
|
|
|
return (double)count + (4.0 - v0)/(v1 - v0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|