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

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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 "vtkBezierPatch.h"

#include "vtkMath.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkBezierPatch, "$Revision: 1.3 $");
vtkStandardNewMacro(vtkBezierPatch);

vtkBezierPatch::vtkBezierPatch()
{
}

vtkBezierPatch::~vtkBezierPatch()
{
}

void vtkBezierPatch::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "Control points: " << "\n";
  for(unsigned int i=0; i<10; i++)
    {
    double * xyz = this->Handles+3*i;
    os << indent << "(" << xyz[0] << "," << xyz[1] << "," << xyz[2] << ")\n";
    }
}

void vtkBezierPatch::SetHandlePosition(vtkIdType id, double xyz[3])
{
  this->SetHandlePosition(id,xyz[0],xyz[1],xyz[2]);
}

void vtkBezierPatch::SetHandlePosition(vtkIdType id, double x, double y, double z)
{
  if( id >= 10 )
    {
    return;
    }
  double * ptr = this->Handles + 3 * id;
  *ptr++ = x;
  *ptr++ = y;
  *ptr++ = z;
}

void vtkBezierPatch::GetHandlePosition(vtkIdType id, double xyz[3])
{
  if( id >= 10 )
    {
    return;
    }
  double * ptr = this->Handles + 3 * id;
  xyz[0] = *ptr++;
  xyz[1] = *ptr++;
  xyz[2] = *ptr++;
}

double * vtkBezierPatch::GetHandlePosition(vtkIdType id)
{
  if( id >= 10 || id < 0 )
    {
    return 0;
    }
  double * ptr = this->Handles + 3 * id;
  return ptr;
}


// This method applies the Casteljau Algorithm for evaluating the coordinates
// of a point in the Bezier patch by computing successive linear interpolations.
//
void vtkBezierPatch::Evaluate(double u, double v,double * point)
{
  if( u<0.0 || u>1.0 || v <0.0 || v>1.0 ) // barycentric coordinates
    {
    return;
    }

  // Barycentric coordinates are redundant
  // we know that they should sum up to 1.0
  //
  const double w = 1.0 - u - v;
  
  double b2[18]; // nodes of second degree
  double b1[9];  // nodes of first  degree

  this->LinearInterpolation(u,v,w,this->Handles+ 0,this->Handles+ 3,this->Handles+ 6, b2+ 0);
  this->LinearInterpolation(u,v,w,this->Handles+ 3,this->Handles+ 9,this->Handles+12, b2+ 3);
  this->LinearInterpolation(u,v,w,this->Handles+ 6,this->Handles+12,this->Handles+15, b2+ 6);
  this->LinearInterpolation(u,v,w,this->Handles+ 9,this->Handles+18,this->Handles+21, b2+ 9);
  this->LinearInterpolation(u,v,w,this->Handles+12,this->Handles+21,this->Handles+24, b2+12);
  this->LinearInterpolation(u,v,w,this->Handles+15,this->Handles+24,this->Handles+27, b2+15);

  this->LinearInterpolation(u,v,w, b2+ 0, b2+ 3, b2+ 6, b1+ 0);
  this->LinearInterpolation(u,v,w, b2+ 3, b2+ 9, b2+12, b1+ 3);
  this->LinearInterpolation(u,v,w, b2+ 6, b2+12, b2+15, b1+ 6);

  this->LinearInterpolation(u,v,w, b1+ 0, b1+ 3, b1+ 6, point);
}





