/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: vtkImageSeedConnectivity.cxx,v $
  Language:  C++
  Date:      $Date: 2002/12/11 14:26:22 $
  Version:   $Revision: 1.27 $

  Copyright (c) 1993-2002 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 "vtkImageSeedConnectivity.h"

#include "vtkImageConnector.h"
#include "vtkObjectFactory.h"
#include "vtkImageData.h"

vtkCxxRevisionMacro(vtkImageSeedConnectivity, "$Revision: 1.27 $");
vtkStandardNewMacro(vtkImageSeedConnectivity);

//----------------------------------------------------------------------------
vtkImageSeedConnectivity::vtkImageSeedConnectivity()
{
  this->InputConnectValue = 255;
  this->OutputConnectedValue = 255;
  this->OutputUnconnectedValue = 0;
  this->Seeds = NULL;
  this->Connector = vtkImageConnector::New();
  this->Dimensionality = 3;
}

//----------------------------------------------------------------------------
vtkImageSeedConnectivity::~vtkImageSeedConnectivity()
{
  this->Connector->Delete();
  this->RemoveAllSeeds();
}

//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::RemoveAllSeeds()
{
  vtkImageConnectorSeed *temp;
  while (this->Seeds)
    {
    temp = this->Seeds;
    this->Seeds = temp->Next;
    delete temp;
    }
}

//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::AddSeed(int num, int *index)
{
  int idx, newIndex[3];
  vtkImageConnectorSeed *seed;
  
  if (num > 3)
    {
    num = 3;
    } 
  for (idx = 0; idx < num; ++idx)
    {
    newIndex[idx] = index[idx];
    }
  for (idx = num; idx < 3; ++idx)
    {
    newIndex[idx] = 0;
    }
  seed = this->Connector->NewSeed(newIndex, NULL);
  seed->Next = this->Seeds;
  this->Seeds = seed;
  this->Modified();
}
//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::AddSeed(int i0, int i1, int i2)
{
  int index[3];

  index[0] = i0;
  index[1] = i1;
  index[2] = i2;
  this->AddSeed(3, index);
}
//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::AddSeed(int i0, int i1)
{
  int index[2];

  index[0] = i0;
  index[1] = i1;
  this->AddSeed(2, index);
}

//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::ComputeInputUpdateExtents(vtkDataObject *out)
{
  vtkImageData *input = this->GetInput();

  out = out;
  if (input)
    {
    input->SetUpdateExtent(input->GetWholeExtent());
    }
}

//----------------------------------------------------------------------------
void vtkImageSeedConnectivity::ExecuteData(vtkDataObject *)
{
  vtkImageData *inData = this->GetInput();
  vtkImageData *outData = this->GetOutput();
  vtkImageConnectorSeed *seed;
  int idx0, idx1, idx2;
  int inInc0, inInc1, inInc2;
  int outInc0, outInc1, outInc2;
  int min0, max0, min1, max1, min2, max2;
  unsigned char *inPtr0, *inPtr1, *inPtr2;
  unsigned char *outPtr0, *outPtr1, *outPtr2;
  unsigned char temp1, temp2;
  int temp;

  outData->SetExtent(this->GetOutput()->GetWholeExtent());
  outData->AllocateScalars();
  
  if (inData->GetScalarType() != VTK_UNSIGNED_CHAR ||
      outData->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkErrorMacro("Execute: Both input and output must have scalar type UnsignedChar");
    return;
    }

  // Pick an intermediate value (In some cases, we could eliminate the last threshold.)
  temp1 = 1;
  while (temp1 == this->InputConnectValue || 
         temp1 == this->OutputUnconnectedValue ||
         temp1 == this->OutputConnectedValue)
    {
    ++temp1;
    }
  temp2 = temp1 + 1;
  while (temp2 == this->InputConnectValue || 
         temp2 == this->OutputUnconnectedValue ||
         temp2 == this->OutputConnectedValue)
    {
    ++temp2;
    }
  
  //-------
  // threshold to eliminate unknown values ( only intermediate and 0)
  inData->GetIncrements(inInc0, inInc1, inInc2);
  this->GetOutput()->GetExtent(min0, max0, min1, max1, min2, max2);
  outData->GetIncrements(outInc0, outInc1, outInc2);
  inPtr2 = (unsigned char *)(inData->GetScalarPointer(min0,min1,min2));
  outPtr2 = (unsigned char *)(outData->GetScalarPointer(min0,min1,min2));
  for (idx2 = min2; idx2 <= max2; ++idx2)
    {
    inPtr1 = inPtr2;
    outPtr1 = outPtr2;
    for (idx1 = min1; idx1 <= max1; ++idx1)
      {
      inPtr0 = inPtr1;
      outPtr0 = outPtr1;
      for (idx0 = min0; idx0 <= max0; ++idx0)
        {
        if (*inPtr0 == this->InputConnectValue)
          {
          *outPtr0 = temp1;
          }
        else
          {
          *outPtr0 = 0;
          }
        inPtr0 += inInc0;
        outPtr0 += outInc0;
        }
      inPtr1 += inInc1;
      outPtr1 += outInc1;
      }
    inPtr2 += inInc2;
    outPtr2 += outInc2;
    }
  
  this->UpdateProgress(0.2);
  if (this->AbortExecute)
    {
    return;
    }
  
  //-------
  // find actual seeds in this image. (only scan along the first axis for now)
  this->Connector->RemoveAllSeeds();
  seed = this->Seeds;
  while (seed)
    {
    temp = seed->Index[0];
    // make sure z value of seed is acceptable
    if (seed->Index[2] < min2)
      {
      seed->Index[2] = min2;
      }
    if (seed->Index[2] > max2)
      {
      seed->Index[2] = max2;
      }
    outPtr0 = (unsigned char *)(outData->GetScalarPointer(seed->Index));
    for (idx0 = temp; idx0 <= max0; ++idx0)
      {
      if (*outPtr0 == temp1)
        { // we found our seed
        seed->Index[0] = idx0;
        this->Connector->AddSeed(this->Connector->NewSeed(seed->Index, outPtr0));
        seed->Index[0] = temp;
        break;
        }
      outPtr0 += outInc0;
      }
    seed = seed->Next;
    }

  this->UpdateProgress(0.5);
  if (this->AbortExecute)
    {
    return;
    }

  //-------
  // connect
  this->Connector->SetUnconnectedValue(temp1);
  this->Connector->SetConnectedValue(temp2);
  this->Connector->MarkData(outData, this->Dimensionality, 
                            this->GetOutput()->GetExtent());

  this->UpdateProgress(0.9);
  if (this->AbortExecute)
    {
    return;
    }

  //-------
  // Threshold to convert intermediate values into OutputUnconnectedValues
  outPtr2 = (unsigned char *)(outData->GetScalarPointer(min0,min1,min2));
  for (idx2 = min2; idx2 <= max2; ++idx2)
    {
    outPtr1 = outPtr2;
    for (idx1 = min1; idx1 <= max1; ++idx1)
      {
      outPtr0 = outPtr1;
      for (idx0 = min0; idx0 <= max0; ++idx0)
        {
        if (*outPtr0 == temp2)
          {
          *outPtr0 = this->OutputConnectedValue;
          }
        else
          {
          *outPtr0 = this->OutputUnconnectedValue;
          }
        outPtr0 += outInc0;
        }
      outPtr1 += outInc1;
      }
     outPtr2 += outInc2;
    }
}


void vtkImageSeedConnectivity::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if ( this->Connector )
    {
    os << indent << "Connector: " << this->Connector << "\n";
    }
  else
    {
    os << indent << "Connector: (none)\n";
    }

  os << indent << "Dimensionality: " << this->Dimensionality << "\n";
  os << indent << "InputConnectValue: " << this->InputConnectValue << "\n";
  os << indent << "OutputConnectedValue: " << this->OutputConnectedValue << "\n";
  os << indent << "OutputUnconnectedValue: " << this->OutputUnconnectedValue << "\n";
}

