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.

1618 lines
41 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkImageCanvasSource2D.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 "vtkImageCanvasSource2D.h"
#include "vtkImageCast.h"
#include "vtkImageClip.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkImageData.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include <math.h>
//
// Special classes for manipulating data
//
// For the fill functionality (use connector ??)
class vtkImageCanvasSource2DPixel { //;prevent man page generation
public:
static vtkImageCanvasSource2DPixel *New()
{ return new vtkImageCanvasSource2DPixel ;}
int X;
int Y;
void *Pointer;
vtkImageCanvasSource2DPixel *Next;
};
vtkCxxRevisionMacro(vtkImageCanvasSource2D, "$Revision: 1.44.4.1 $");
vtkStandardNewMacro(vtkImageCanvasSource2D);
//----------------------------------------------------------------------------
// Construct an instance of vtkImageCanvasSource2D with no data.
vtkImageCanvasSource2D::vtkImageCanvasSource2D()
{
this->SetNumberOfInputPorts(0);
this->ImageData = vtkImageData::New();
this->ImageData->SetScalarType(VTK_DOUBLE);
this->WholeExtent[0] = 0;
this->WholeExtent[1] = 0;
this->WholeExtent[2] = 0;
this->WholeExtent[3] = 0;
this->WholeExtent[4] = 0;
this->WholeExtent[5] = 0;
this->DrawColor[0] = this->DrawColor[1] =
this->DrawColor[2] = this->DrawColor[3] = 0.0;
this->DefaultZ = 0;
this->Ratio[0] = this->Ratio[1] = this->Ratio[2] = 1.0;
}
//----------------------------------------------------------------------------
// Destructor: Deleting a vtkImageCanvasSource2D automatically
// deletes the associated
// vtkImageData. However, since the data is reference counted, it may not
// actually be deleted.
vtkImageCanvasSource2D::~vtkImageCanvasSource2D()
{
this->ImageData->Delete();
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
int idx;
os << indent << "ImageData: (" << this->ImageData << ")\n";
os << indent << "DefaultZ: " << this->DefaultZ << endl;
os << indent << "DrawColor: (" << this->DrawColor[0];
for (idx = 1; idx < 4; ++idx)
{
os << ", " << this->DrawColor[idx];
}
os << ")\n";
os << indent << "Ratio: ("
<< this->Ratio[0] << ", " << this->Ratio[1] << ", " << this->Ratio[2]
<< ")\n";
}
#define vtkMAX(x, y) (((x)>(y))?(x):(y))
#define vtkMIN(x, y) (((x)<(y))?(x):(y))
//----------------------------------------------------------------------------
// Draw a data. Only implentented for 2D extents.
template <class T>
void vtkImageCanvasSource2DDrawImage(vtkImageData *image, vtkImageData *simage,
T *ptr, T *sptr,
int min0, int max0, int min1, int max1)
{
T *ptr0, *ptr1, *ptrV;
T *sptr0, *sptr1, *sptrV;
int idx0, idx1, idxV;
vtkIdType inc0, inc1, inc2;
vtkIdType sinc0, sinc1, sinc2;
int maxV, smaxV;
int sinc;
image->GetIncrements(inc0, inc1, inc2);
simage->GetIncrements(sinc0, sinc1, sinc2);
maxV = image->GetNumberOfScalarComponents() - 1;
smaxV = simage->GetNumberOfScalarComponents() - 1;
ptr1 = ptr;
sptr1 = sptr;
for (idx1 = min1; idx1 <= max1; ++idx1)
{
ptr0 = ptr1;
sptr0 = sptr1;
for (idx0 = min0; idx0 <= max0; ++idx0)
{
ptrV = ptr0;
sptrV = sptr0;
sinc = 0;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *(sptrV + sinc);
ptrV++;
if ( sinc < smaxV )
{
sinc++;
}
}
//sptrV += smaxV;
ptr0 += inc0;
sptr0 += sinc0;
}
ptr1 += inc1;
sptr1 += sinc1;
}
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::DrawImage(int x0, int y0,
vtkImageData* image, int sx, int sy,
int width, int height)
{
if ( !image )
{
return;
}
vtkImageClip* clip = vtkImageClip::New();
clip->SetInput(image);
int *extent;
int ext[6];
// int z = this->DefaultZ;
image->GetWholeExtent(ext);
if ( sx < 0 )
{
sx = ext[0];
}
if ( sy < 0 )
{
sy = ext[2];
}
if ( width < 0 )
{
width = ext[1] - ext[0] + 1;
}
else
{
width = vtkMIN(width, ext[1] - ext[0] + 1);
}
if ( height < 0 )
{
height = ext[3] - ext[2] + 1;
}
else
{
height = vtkMIN(height, ext[3] - ext[2] + 1);
}
ext[0] = vtkMAX(sx, ext[0]);
ext[1] = vtkMAX(sx+width-1, ext[1]);
ext[2] = vtkMAX(sy, ext[2]);
ext[3] = vtkMAX(sy+height-1, ext[3]);
clip->SetOutputWholeExtent(ext);
vtkImageCast* ic = vtkImageCast::New();
ic->SetInputConnection(clip->GetOutputPort());
ic->SetOutputScalarType(this->ImageData->GetScalarType());
ic->Update();
int min0, max0, min1, max1;
min0 = x0;
min1 = y0;
max0 = x0 + width -1;
max1 = y0 + height -1;
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
min0 = int(double(min0) * this->Ratio[0]);
max0 = int(double(max0) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
min1 = int(double(min1) * this->Ratio[1]);
max1 = int(double(max1) * this->Ratio[1]);
}
// if (this->Ratio[2] != 1.0)
// {
// z = int(double(z) * this->Ratio[2]);
// }
// Clip the data to keep in in bounds
extent = this->ImageData->GetExtent();
min0 = (min0 < extent[0]) ? extent[0] : min0;
max0 = (max0 < extent[0]) ? extent[0] : max0;
min0 = (min0 > extent[1]) ? extent[1] : min0;
max0 = (max0 > extent[1]) ? extent[1] : max0;
min1 = (min1 < extent[2]) ? extent[2] : min1;
max1 = (max1 < extent[2]) ? extent[2] : max1;
min1 = (min1 > extent[3]) ? extent[3] : min1;
max1 = (max1 > extent[3]) ? extent[3] : max1;
//z = (z < extent[4]) ? extent[4] : z;
//z = (z > extent[5]) ? extent[5] : z;
void *ptr;
void *sptr;
ptr = this->ImageData->GetScalarPointer(min0, min1, 0);
sptr = ic->GetOutput()->GetScalarPointer(ext[0], ext[2], 0);
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(vtkImageCanvasSource2DDrawImage(this->ImageData,
ic->GetOutput(),
(VTK_TT *)(ptr),
(VTK_TT *)(sptr),
min0,max0, min1,max1));
default:
vtkErrorMacro(<< "FillBox: Cannot handle ScalarType.");
}
ic->Delete();
clip->Delete();
this->Modified();
}
//----------------------------------------------------------------------------
// Draw a data. Only implentented for 2D extents.
template <class T>
void vtkImageCanvasSource2DFillBox(vtkImageData *image,
double *drawColor, T *ptr,
int min0, int max0, int min1, int max1)
{
T *ptr0, *ptr1, *ptrV;
int idx0, idx1, idxV;
vtkIdType inc0, inc1, inc2;
int maxV;
double *pf;
image->GetIncrements(inc0, inc1, inc2);
maxV = image->GetNumberOfScalarComponents() - 1;
ptr1 = ptr;
for (idx1 = min1; idx1 <= max1; ++idx1)
{
ptr0 = ptr1;
for (idx0 = min0; idx0 <= max0; ++idx0)
{
ptrV = ptr0;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
ptr0 += inc0;
}
ptr1 += inc1;
}
}
//----------------------------------------------------------------------------
// Draw a data. Only implentented for 2D extents.
void vtkImageCanvasSource2D::FillBox(int min0, int max0, int min1, int max1)
{
int *extent;
void *ptr;
int z = this->DefaultZ;
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
min0 = int(double(min0) * this->Ratio[0]);
max0 = int(double(max0) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
min1 = int(double(min1) * this->Ratio[1]);
max1 = int(double(max1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
// Clip the data to keep in in bounds
extent = this->ImageData->GetExtent();
min0 = (min0 < extent[0]) ? extent[0] : min0;
max0 = (max0 < extent[0]) ? extent[0] : max0;
min0 = (min0 > extent[1]) ? extent[1] : min0;
max0 = (max0 > extent[1]) ? extent[1] : max0;
min1 = (min1 < extent[2]) ? extent[2] : min1;
max1 = (max1 < extent[2]) ? extent[2] : max1;
min1 = (min1 > extent[3]) ? extent[3] : min1;
max1 = (max1 > extent[3]) ? extent[3] : max1;
z = (z < extent[4]) ? extent[4] : z;
z = (z > extent[5]) ? extent[5] : z;
ptr = this->ImageData->GetScalarPointer(min0, min1, z);
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(vtkImageCanvasSource2DFillBox(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
min0,max0, min1,max1));
default:
vtkErrorMacro(<< "FillBox: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Fill a tube (thick line for initial 2D implementation.
template <class T>
void vtkImageCanvasSource2DFillTube(vtkImageData *image,
double *drawColor, T *ptr,
int a0, int a1, int b0, int b1,
double radius)
{
T *ptr0, *ptr1, *ptrV;
int idx0, idx1, idxV;
vtkIdType inc0, inc1, inc2;
int min0, max0, min1, max1, min2, max2, maxV;
double *pf;
int n0, n1;
int ak, bk, k;
double fract;
double v0, v1;
// Compute vector of tube.
n0 = a0 - b0;
n1 = a1 - b1;
// compute the projects of the two points a and b on this vector.
ak = n0 * a0 + n1 * a1;
bk = n0 * b0 + n1 * b1;
// Make sure the vector is pointing in the correct direction.
if (ak < bk)
{
ak = -ak;
bk = -bk;
n0 = -n0;
n1 = -n1;
}
image->GetExtent(min0, max0, min1, max1, min2, max2);
maxV = image->GetNumberOfScalarComponents() - 1;
// Loop trough whole extent.
image->GetIncrements(inc0, inc1, inc2);
ptr1 = ptr;
for (idx1 = min1; idx1 <= max1; ++idx1)
{
ptr0 = ptr1;
for (idx0 = min0; idx0 <= max0; ++idx0)
{
// check to see if pixel is in the tube.
// project point onto normal vector.
k = n0 * idx0 + n1 * idx1;
// Check that point is inbetween end points.
if ( k >= bk && k <= ak)
{
// Compute actual projection point.
fract = (double)(k - bk) / (double)(ak - bk);
v0 = b0 + fract * (double)(a0 - b0);
v1 = b1 + fract * (double)(a1 - b1);
// Compute distance to tube
v0 -= (double)(idx0);
v1 -= (double)(idx1);
if (radius >= sqrt(v0*v0 + v1*v1))
{
ptrV = ptr0;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
}
}
ptr0 += inc0;
}
ptr1 += inc1;
}
}
//----------------------------------------------------------------------------
// Fill a tube (thick line for initial 2D implementation).
void vtkImageCanvasSource2D::FillTube(int a0, int a1,
int b0, int b1, double radius)
{
void *ptr;
int z = this->DefaultZ;
int *extent = this->ImageData->GetExtent();
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
a0 = int(double(a0) * this->Ratio[0]);
b0 = int(double(b0) * this->Ratio[0]);
radius = int(double(radius) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
a1 = int(double(a1) * this->Ratio[1]);
b1 = int(double(b1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
z = (z < extent[4]) ? extent[4] : z;
z = (z > extent[5]) ? extent[5] : z;
ptr = this->ImageData->GetScalarPointer(extent[0], extent[2], z);
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DFillTube(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
a0,a1, b0,b1,
radius));
default:
vtkErrorMacro(<< "FillTube: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Fill a triangle (rasterize)
template <class T>
void vtkImageCanvasSource2DFillTriangle(vtkImageData *image,
double *drawColor, T *ptr,
int a0, int a1, int b0, int b1,
int c0, int c1, int z)
{
int temp;
double longT, shortT; // end points of intersection of trainge and row.
double longStep, shortStep;
int left, right;
int idx0, idx1, idxV;
int min0, max0, min1, max1, min2, max2;
int maxV;
double *pf;
maxV = image->GetNumberOfScalarComponents() - 1;
// index1 of b must be between a, and c
if((b1 < a1 && a1 < c1) || (b1 > a1 && a1 > c1))
{ // swap b and a
temp = b0; b0 = a0; a0 = temp;
temp = b1; b1 = a1; a1 = temp;
}
if((b1 < c1 && c1 < a1) || (b1 > c1 && c1 > a1))
{ // swap b and c
temp = b0; b0 = c0; c0 = temp;
temp = b1; b1 = c1; c1 = temp;
}
// Make life easier and order points so that ay < by < cy
if(c1 < a1)
{ // swap c and a
temp = a0; a0 = c0; c0 = temp;
temp = a1; a1 = c1; c1 = temp;
}
image->GetExtent(min0, max0, min1, max1, min2, max2);
z = (z < min2) ? min2 : z;
z = (z > max2) ? max2 : z;
// for all rows: compute 2 points, intersection of triangle edges and row
longStep = (double)(c0 - a0) / (double)(c1 - a1 + 1);
longT = (double)(a0) + (0.5 * longStep);
shortStep = (double)(b0 - a0) / (double)(b1 - a1 + 1);
shortT = (double)(a0) + (0.5 * shortStep);
for (idx1 = a1; idx1 < b1; ++idx1)
{
// Fill row long to short (y = idx1)
left = (int)(shortT + 0.5);
right = (int)(longT + 0.5);
if (left > right)
{
temp = left; left = right; right = temp;
}
for (idx0 = left; idx0 <= right; ++idx0)
{
if (idx0 >= min0 && idx0 <= max0 && idx1 >= min1 && idx1 <= max1)
{
ptr = (T *)(image->GetScalarPointer(idx0, idx1, z));
if (ptr)
{
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptr = (T)(*pf++);
ptr++;
}
}
}
}
longT += longStep;
shortT += shortStep;
}
// fill the second half of the triangle
shortStep = (double)(c0 - b0) / (double)(c1 - b1 + 1);
shortT = (double)(b0) + (0.5 * shortStep);
for (idx1 = b1; idx1 < c1; ++idx1)
{
// Fill row long to short (y = idx1)
left = (int)(shortT + 0.5);
right = (int)(longT + 0.5);
if (left > right)
{
temp = left; left = right; right = temp;
}
for (idx0 = left; idx0 <= right; ++idx0)
{
if (idx0 >= min0 && idx0 <= max0 && idx1 >= min1 && idx1 <= max1)
{
ptr = (T *)(image->GetScalarPointer(idx0, idx1, z));
if (ptr)
{
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptr = (T)(*pf++);
ptr++;
}
}
}
}
longT += longStep;
shortT += shortStep;
}
}
//----------------------------------------------------------------------------
// Fill a tube (thick line for initial 2D implementation).
void vtkImageCanvasSource2D::FillTriangle(int a0,int a1, int b0,int b1,
int c0,int c1)
{
void *ptr;
int z = this->DefaultZ;
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
a0 = int(double(a0) * this->Ratio[0]);
b0 = int(double(b0) * this->Ratio[0]);
c0 = int(double(c0) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
a1 = int(double(a1) * this->Ratio[1]);
b1 = int(double(b1) * this->Ratio[1]);
c1 = int(double(c1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
ptr = this->ImageData->GetScalarPointer();
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DFillTriangle(this->ImageData,
this->DrawColor, (VTK_TT *)(ptr),
a0,a1, b0,b1, c0,c1, z));
default:
vtkErrorMacro(<< "FillTriangle: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Draw a point. Only implentented for 2D images.
template <class T>
void vtkImageCanvasSource2DDrawPoint(vtkImageData *image,
double *drawColor, T *ptr,
int p0, int p1, int z)
{
int min0, max0, min1, max1, min2, max2, maxV;
int idxV;
double *pf;
image->GetExtent(min0, max0, min1, max1, min2, max2);
z = (z < min2) ? min2 : z;
z = (z > max2) ? max2 : z;
maxV = image->GetNumberOfScalarComponents() - 1;
if (p0 >= min0 && p0 <= max0 && p1 >= min1 && p1 <= max1)
{
ptr = (T *)(image->GetScalarPointer(p0, p1, z));
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptr = (T)(*pf++);
ptr++;
}
}
}
//----------------------------------------------------------------------------
// Draw a circle
void vtkImageCanvasSource2D::DrawPoint(int p0, int p1)
{
void *ptr = NULL;
int z = this->DefaultZ;
vtkDebugMacro(<< "Drawing a point: (" << p0 << ", " << p1 << ")");
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
p0 = int(double(p0) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
p1 = int(double(p1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DDrawPoint(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
p0, p1,
z));
default:
vtkErrorMacro(<< "DrawPoint: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Draw a circle. Only implentented for 2D images.
template <class T>
void vtkImageCanvasSource2DDrawCircle(vtkImageData *image,
double *drawColor, T *ptr,
int c0, int c1, double radius, int z)
{
int min0, max0, min1, max1, min2, max2, maxV;
int idxV;
double *pf;
int numberOfSteps;
double thetaCos, thetaSin;
double x, y, temp;
int p0, p1;
int idx;
radius += 0.1;
image->GetExtent(min0, max0, min1, max1, min2, max2);
z = (z < min2) ? min2 : z;
z = (z > max2) ? max2 : z;
maxV = image->GetNumberOfScalarComponents() - 1;
numberOfSteps = (int)(ceil(6.2831853 * radius));
thetaCos = cos(1.0 / radius);
thetaSin = sin(1.0 / radius);
x = radius;
y = 0.0;
for (idx = 0; idx < numberOfSteps; ++idx)
{
p0 = c0+(int)(x);
p1 = c1+(int)(y);
if (p0 >= min0 && p0 <= max0 && p1 >= min1 && p1 <= max1)
{
ptr = (T *)(image->GetScalarPointer(p0, p1, z));
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptr = (T)(*pf++);
ptr++;
}
}
// rotate the point
temp = thetaCos * x + thetaSin * y;
y = thetaCos * y - thetaSin * x;
x = temp;
}
}
//----------------------------------------------------------------------------
// Draw a circle
void vtkImageCanvasSource2D::DrawCircle(int c0, int c1, double radius)
{
void *ptr = NULL;
int z = this->DefaultZ;
vtkDebugMacro(<< "Drawing a circle: center = (" << c0 << ", " << c1
<< "), radius = " << radius);
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
c0 = int(double(c0) * this->Ratio[0]);
radius = int(double(radius) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
c1 = int(double(c1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DDrawCircle(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
c0, c1,
radius,
z));
default:
vtkErrorMacro(<< "DrawCircle: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Draw a line. Only implentented for 2D images.
// First point is already shifted to origin.
template <class T>
void vtkImageCanvasSource2DDrawSegment(vtkImageData *image,
double *drawColor, T *ptr,
int p0, int p1)
{
double f0, f1;
double s0, s1;
int numberOfSteps;
int maxV;
int idx, idxV;
vtkIdType inc0, inc1, inc2;
double *pf;
T *ptrV;
image->GetIncrements(inc0, inc1, inc2);
maxV = image->GetNumberOfScalarComponents() - 1;
// make sure we are stepping in the positive direction.
if (p0 < 0)
{
p0 = -p0;
inc0 = -inc0;
}
if (p1 < 0)
{
p1 = -p1;
inc1 = -inc1;
}
// Compute the number of steps needed.
if (p0 > p1)
{
numberOfSteps = p0;
}
else
{
numberOfSteps = p1;
}
// Compute the step vector.
s0 = (double)(p0) / (double)(numberOfSteps);
s1 = (double)(p1) / (double)(numberOfSteps);
f0 = f1 = 0.5;
ptrV = ptr;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
for (idx = 0; idx < numberOfSteps; ++idx)
{
f0 += s0;
if (f0 > 1.0)
{
ptr += inc0;
f0 -= 1.0;
}
f1 += s1;
if (f1 > 1.0)
{
ptr += inc1;
f1 -= 1.0;
}
ptrV = ptr;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
}
}
//----------------------------------------------------------------------------
// Draw a Segment from point a to point b.
void vtkImageCanvasSource2D::DrawSegment(int a0, int a1, int b0, int b1)
{
int *extent;
void *ptr;
int z = this->DefaultZ;
vtkDebugMacro(<< "Drawing a segment: " << a0 << ", " << a1 << " to "
<< b0 << ", " << b1);
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
a0 = int(double(a0) * this->Ratio[0]);
b0 = int(double(b0) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
a1 = int(double(a1) * this->Ratio[1]);
b1 = int(double(b1) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
// check to make sure line segment is in bounds.
extent = this->ImageData->GetExtent();
z = (z < extent[4]) ? extent[4] : z;
z = (z > extent[5]) ? extent[5] : z;
if (a0 < extent[0] || a0 > extent[1] || b0 < extent[0] || b0 > extent[1] ||
a1 < extent[2] || a1 > extent[3] || b1 < extent[2] || b1 > extent[3])
{
if ( ! this->ClipSegment(a0,a1,b0,b1))
{
// non of the segment is in the data.
return;
}
}
ptr = this->ImageData->GetScalarPointer(b0, b1, z);
a0 -= b0;
a1 -= b1;
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DDrawSegment(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
a0, a1));
default:
vtkErrorMacro(<< "DrawSegment: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
// Clips a line segment so it will be in bounds.
// If the entire segment is out of bounds, the method returns 0.
int vtkImageCanvasSource2D::ClipSegment(int &a0, int &a1, int &b0, int &b1)
{
int min0, max0, min1, max1, min2, max2;
double fract;
this->ImageData->GetExtent(min0, max0, min1, max1, min2, max2);
// Check planes
// Both out of bounds
if (a0 < min0 && b0 < min0)
{
return 0;
}
// first out of bounds.
if (a0 < min0 && b0 >= min0)
{
// interpolate to find point on bounding plane.
fract = (double)(b0 - min0) / (double)(b0 - a0);
a0 = min0;
a1 = b1 + (int)(fract * (double)(a1 - b1));
}
// second out of bounds.
if (b0 < min0 && a0 >= min0)
{
// interpolate to find point on bounding plane.
fract = (double)(a0 - min0) / (double)(a0 - b0);
b0 = min0;
b1 = a1 + (int)(fract * (double)(b1 - a1));
}
// Both out of bounds
if (a0 > max0 && b0 > max0)
{
return 0;
}
// first out of bounds.
if (a0 > max0 && b0 <= max0)
{
// interpolate to find point on bounding plane.
fract = (double)(b0 - max0) / (double)(b0 - a0);
a0 = max0;
a1 = b1 + (int)(fract * (double)(a1 - b1));
}
// second out of bounds.
if (b0 > max0 && a0 <= max0)
{
// interpolate to find point on bounding plane.
fract = (double)(a0 - max0) / (double)(a0 - b0);
b0 = max0;
b1 = a1 + (int)(fract * (double)(b1 - a1));
}
// Both out of bounds
if (a1 < min1 && b1 < min1)
{
return 0;
}
// first out of bounds.
if (a1 < min1 && b1 >= min1)
{
// interpolate to find point on bounding plane.
fract = (double)(b1 - min1) / (double)(b1 - a1);
a1 = min1;
a0 = b0 + (int)(fract * (double)(a0 - b0));
}
// second out of bounds.
if (b1 < min1 && a1 >= min1)
{
// interpolate to find point on bounding plane.
fract = (double)(a1 - min1) / (double)(a1 - b1);
b1 = min1;
b0 = a0 + (int)(fract * (double)(b0 - a0));
}
// Both out of bounds
if (a1 > max1 && b1 > max1)
{
return 0;
}
// first out of bounds.
if (a1 > max1 && b1 <= max1)
{
// interpolate to find point on bounding plane.
fract = (double)(b1 - max1) / (double)(b1 - a1);
a1 = max1;
a0 = b0 + (int)(fract * (double)(a0 - b0));
}
// second out of bounds.
if (b1 > max1 && a1 <= max1)
{
// interpolate to find point on bounding plane.
fract = (double)(a1 - max1) / (double)(a1 - b1);
b1 = max1;
b0 = a0 + (int)(fract * (double)(b0 - a0));
}
this->Modified();
return 1;
}
//----------------------------------------------------------------------------
// Draw a line. Only implentented for 3D images.
// First point is already shifted to origin.
template <class T>
void vtkImageCanvasSource2DDrawSegment3D(vtkImageData *image,
double *drawColor,
T *ptr, int p0, int p1, int p2)
{
double f0, f1, f2;
double s0, s1, s2;
int numberOfSteps;
int idx, idxV, maxV;
vtkIdType inc0, inc1, inc2;
double *pf;
T *ptrV;
image->GetIncrements(inc0, inc1, inc2);
maxV = image->GetNumberOfScalarComponents() - 1;
// make sure we are stepping in the positive direction.
if (p0 < 0)
{
p0 = -p0;
inc0 = -inc0;
}
if (p1 < 0)
{
p1 = -p1;
inc1 = -inc1;
}
if (p2 < 0)
{
p2 = -p2;
inc2 = -inc2;
}
// Compute the number of steps needed.
numberOfSteps = (p0 > p1) ? p0 : p1;
numberOfSteps = (numberOfSteps > p2) ? numberOfSteps : p2;
// Compute the step vector.
s0 = (double)(p0) / (double)(numberOfSteps);
s1 = (double)(p1) / (double)(numberOfSteps);
s2 = (double)(p2) / (double)(numberOfSteps);
f0 = f1 = f2 = 0.5;
ptrV = ptr;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
for (idx = 0; idx < numberOfSteps; ++idx)
{
f0 += s0;
if (f0 > 1.0)
{
ptr += inc0;
f0 -= 1.0;
}
f1 += s1;
if (f1 > 1.0)
{
ptr += inc1;
f1 -= 1.0;
}
f2 += s2;
if (f2 > 1.0)
{
ptr += inc2;
f2 -= 1.0;
}
ptrV = ptr;
pf = drawColor;
// Assign color to pixel.
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = (T)(*pf++);
ptrV++;
}
}
}
//----------------------------------------------------------------------------
// Draw a Segment from point a to point b.
// No clipping or bounds checking.
void vtkImageCanvasSource2D::DrawSegment3D(double *a, double *b)
{
void *ptr;
int a0, a1, a2;
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
a[0] = int(double(a[0]) * this->Ratio[0]);
b[0] = int(double(b[0]) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
a[1] = int(double(a[1]) * this->Ratio[1]);
b[1] = int(double(b[1]) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
a[2] = int(double(a[2]) * this->Ratio[2]);
b[2] = int(double(b[2]) * this->Ratio[2]);
}
ptr = this->ImageData->GetScalarPointer((int)(b[0] + 0.5),
(int)(b[1] + 0.5),
(int)(b[2] + 0.5));
a0 = (int)(a[0] - b[0] + 0.5);
a1 = (int)(a[1] - b[1] + 0.5);
a2 = (int)(a[2] - b[2] + 0.5);
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DDrawSegment3D(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
a0, a1, a2));
default:
vtkErrorMacro(<< "DrawSegment3D: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
template <class T>
void vtkImageCanvasSource2DFill(vtkImageData *image, double *color,
T *ptr, int x, int y)
{
vtkImageCanvasSource2DPixel *pixel;
vtkImageCanvasSource2DPixel *first, *last;
vtkImageCanvasSource2DPixel *heap = NULL;
int min0, max0, min1, max1, min2, max2, maxV;
int idxV;
vtkIdType inc0, inc1, inc2;
T fillColor[10];
T drawColor[10];
T *ptrV, *ptrC;
int temp;
image->GetExtent(min0, max0, min1, max1, min2, max2);
maxV = image->GetNumberOfScalarComponents() - 1;
image->GetIncrements(inc0, inc1, inc2);
// Copy the fill color and make sure it differs from drawColor.
ptrV = ptr;
temp = 1;
for (idxV = 0; idxV <= maxV; ++idxV)
{
// Save the fill color
fillColor[idxV] = *ptrV;
drawColor[idxV] = (T)(color[idxV]);
if (*ptrV != drawColor[idxV])
{
temp = 0;
}
ptrV++;
}
if (temp)
{ // fill the same as draw
cerr << "Fill: Cannot handle draw color same as fill color\n";
return;
}
// Create the seed
pixel = vtkImageCanvasSource2DPixel::New();
pixel->X = x;
pixel->Y = y;
pixel->Pointer = (void *)(ptr);
pixel->Next = NULL;
first = last = pixel;
// change the seeds color
ptrV = (T *)(last->Pointer);
ptrC = drawColor;
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *ptrC++;
ptrV++;
}
while (first)
{
ptr = (T *)(first->Pointer);
// check bounds for -x neighbor
if (first->X > min0)
{
// Get the neighbor
ptrV = ptr - inc0;
// compare color
ptrC = fillColor;
temp = 1;
for (idxV = 0; idxV <= maxV; ++idxV)
{
if (*ptrV != *ptrC++)
{
temp = 0;
break;
}
ptrV++;
}
if (temp)
{ // color match add a new seed to end of list
if (heap)
{
pixel = heap;
heap = heap->Next;
}
else
{
pixel = vtkImageCanvasSource2DPixel::New();
}
pixel->X = first->X-1;
pixel->Y = first->Y;
pixel->Pointer = (void *)(ptr - inc0);
pixel->Next = NULL;
last->Next = pixel;
last = pixel;
// change the seeds color
ptrV = (T *)(last->Pointer);
ptrC = drawColor;
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *ptrC++;
ptrV++;
}
}
}
// check bounds for +x neighbor
if (first->X < max0)
{
// Get the neighbor
ptrV = ptr + inc0;
// compare color
ptrC = fillColor;
temp = 1;
for (idxV = 0; idxV <= maxV; ++idxV)
{
if (*ptrV != *ptrC++)
{
temp = 0;
break;
}
ptrV++;
}
if (temp)
{ // color match add a new seed to end of list
if (heap)
{
pixel = heap;
heap = heap->Next;
}
else
{
pixel = vtkImageCanvasSource2DPixel::New();
}
pixel->X = first->X+1;
pixel->Y = first->Y;
pixel->Pointer = (void *)(ptr + inc0);
pixel->Next = NULL;
last->Next = pixel;
last = pixel;
// change the seeds color
ptrV = (T *)(last->Pointer);
ptrC = drawColor;
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *ptrC++;
ptrV++;
}
}
}
// check bounds for -y neighbor
if (first->Y > min1)
{
// Get the neighbor
ptrV = ptr - inc1;
// compare color
ptrC = fillColor;
temp = 1;
for (idxV = 0; idxV <= maxV; ++idxV)
{
if (*ptrV != *ptrC++)
{
temp = 0;
break;
}
ptrV++;
}
if (temp)
{ // color match add a new seed to end of list
if (heap)
{
pixel = heap;
heap = heap->Next;
}
else
{
pixel = vtkImageCanvasSource2DPixel::New();
}
pixel->X = first->X;
pixel->Y = first->Y-1;
pixel->Pointer = (void *)(ptr - inc1);
pixel->Next = NULL;
last->Next = pixel;
last = pixel;
// change the seeds color
ptrV = (T *)(last->Pointer);
ptrC = drawColor;
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *ptrC++;
ptrV++;
}
}
}
// check bounds for +y neighbor
if (first->Y < max1)
{
// Get the neighbor
ptrV = ptr + inc1;
// compare color
ptrC = fillColor;
temp = 1;
for (idxV = 0; idxV <= maxV; ++idxV)
{
if (*ptrV != *ptrC++)
{
temp = 0;
break;
}
ptrV++;
}
if (temp)
{ // color match add a new seed to end of list
if (heap)
{
pixel = heap;
heap = heap->Next;
}
else
{
pixel = vtkImageCanvasSource2DPixel::New();
}
pixel->X = first->X;
pixel->Y = first->Y+1;
pixel->Pointer = (void *)(ptr + inc1);
pixel->Next = NULL;
last->Next = pixel;
last = pixel;
// change the seeds color
ptrV = (T *)(last->Pointer);
ptrC = drawColor;
for (idxV = 0; idxV <= maxV; ++idxV)
{
*ptrV = *ptrC++;
ptrV++;
}
}
}
// remove the first from the list.
pixel = first;
first = first->Next;
pixel->Next = heap;
heap = pixel;
}
// free the heap
while (heap)
{
pixel = heap;
heap = heap->Next;
delete pixel;
}
}
//----------------------------------------------------------------------------
// Fill a colored area with another color. (like connectivity)
// All pixels connected to pixel (x, y) get replaced by draw color.
void vtkImageCanvasSource2D::FillPixel(int x, int y)
{
void *ptr;
int *ext = this->ImageData->GetExtent();
int z = this->DefaultZ;
// Pre-multiply coords if needed
if (this->Ratio[0] != 1.0)
{
x = int(double(x) * this->Ratio[0]);
}
if (this->Ratio[1] != 1.0)
{
y = int(double(y) * this->Ratio[1]);
}
if (this->Ratio[2] != 1.0)
{
z = int(double(z) * this->Ratio[2]);
}
z = (z < ext[4]) ? ext[4] : z;
z = (z > ext[5]) ? ext[5] : z;
ptr = this->ImageData->GetScalarPointer(x, y, z);
switch (this->ImageData->GetScalarType())
{
vtkTemplateMacro(
vtkImageCanvasSource2DFill(this->ImageData,
this->DrawColor,
(VTK_TT *)(ptr),
x, y));
default:
vtkErrorMacro(<< "Fill: Cannot handle ScalarType.");
}
this->Modified();
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::SetExtent(int *extent)
{
this->SetExtent(extent[0], extent[1],
extent[2], extent[3],
extent[4], extent[5]);
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::SetExtent(int xMin, int xMax,
int yMin, int yMax,
int zMin, int zMax)
{
int modified = 0;
if (this->WholeExtent[0] != xMin)
{
modified = 1;
this->WholeExtent[0] = xMin ;
}
if (this->WholeExtent[1] != xMax)
{
modified = 1;
this->WholeExtent[1] = xMax ;
}
if (this->WholeExtent[2] != yMin)
{
modified = 1;
this->WholeExtent[2] = yMin ;
}
if (this->WholeExtent[3] != yMax)
{
modified = 1;
this->WholeExtent[3] = yMax ;
}
if (this->WholeExtent[4] != zMin)
{
modified = 1;
this->WholeExtent[4] = zMin ;
}
if (this->WholeExtent[5] != zMax)
{
modified = 1;
this->WholeExtent[5] = zMax ;
}
if (modified)
{
this->Modified();
this->ImageData->SetExtent(this->WholeExtent);
this->ImageData->AllocateScalars();
}
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::SetScalarType(int t)
{
if (this->ImageData->GetScalarType() != t)
{
this->Modified();
this->ImageData->SetScalarType(t);
this->ImageData->AllocateScalars();
}
}
//----------------------------------------------------------------------------
void vtkImageCanvasSource2D::SetNumberOfScalarComponents(int t)
{
if (this->ImageData->GetNumberOfScalarComponents() != t)
{
this->Modified();
this->ImageData->SetNumberOfScalarComponents(t);
this->ImageData->AllocateScalars();
}
}
//----------------------------------------------------------------------------
int vtkImageCanvasSource2D::RequestInformation (
vtkInformation * vtkNotUsed(request),
vtkInformationVector** vtkNotUsed( inputVector ),
vtkInformationVector *outputVector)
{
// get the info objects
vtkInformation* outInfo = outputVector->GetInformationObject(0);
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
this->WholeExtent,6);
vtkDataObject::SetPointDataActiveScalarInfo
(outInfo, this->ImageData->GetScalarType(),
this->ImageData->GetNumberOfScalarComponents());
return 1;
}
//----------------------------------------------------------------------------
int vtkImageCanvasSource2D::RequestData (
vtkInformation * vtkNotUsed(request),
vtkInformationVector** vtkNotUsed( inputVector ),
vtkInformationVector *outputVector)
{
// get the data object
vtkInformation *outInfo = outputVector->GetInformationObject(0);
vtkImageData *output = vtkImageData::SafeDownCast
(outInfo->Get(vtkDataObject::DATA_OBJECT()) );
output->ShallowCopy(this->ImageData);
return 1;
}