// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// bspline.C
//
// Author:               Sameer Nene
// Date:                 06/15/94
// Version:              1.0.0
// Modification History:
// Bugs:
//
// Classes:
//   BSpline
//
// Notes:
//   This module contains implementation of classes declared in bspline.h
//
// ----------------------------------------------------------------------------
#include "persistent.h"
#include "interpolation.h"
#include "persinterp.h"
#include "bspline.h"
#include "vector.h"

void* BSpline::d_protocol = (void*)(&BSpline::d_protocol);
void* BSpline::d_ipProtocol = &BSpline::d_ipProtocol;

BSpline::BSpline()
{
}

BSpline::BSpline(int i) : d_controlary(i)
{
}

void BSpline::formKnotVector(Vector *v)
{
  int i = v -> length() - 3, l;
  
  for(l = 0; l < 3; ++l)
    v -> element(l, 0.);
  while(l < i + 1) {
    v -> element(l, l - 2);
    ++l;
  }
  while(l < i + 3)
    v -> element(l++, i - 2);
}  

double BSpline::basis(int i, double t, const Vector &knot)
{
  double xi = knot.element(i), xi1 = knot.element(i + 1),
    xi2 = knot.element(i + 2), xi3 = knot.element(i + 3);
  double t1 = t - xi, t2 = xi3 - t, t3 = xi2 - xi, t4 = xi2 - xi1,
    t5 = xi3 - xi1;
  
  if(t >= xi && t < xi1)
    return (t1 * t1) / (t3 * (xi1 - xi));
  if(t >= xi1 && t < xi2)
    return (t1 * (xi2 - t)) / (t3 * t4) + ((xi3 - t) * (t - xi1)) / (t5 * t4);
  if(t >= xi2 && t < xi3)
    return (t2 * t2) / (t5 * (xi3 - xi2));
  if(t >= xi3 && i == knot.length() - 4)
    return 1.;

  return 0.;
}

int BSpline::hasProtocol(void* protocol) const
{
  return d_protocol == protocol || PersistentInterpolation::hasProtocol(protocol);
}

int BSpline::hasInterpolationProtocol(void *protocol) const
{
  return d_ipProtocol == protocol || PersistentInterpolation::hasInterpolationProtocol(protocol);
}

BSpline* BSpline::safeCast(Persistent *p)
{
  return p -> hasProtocol(d_protocol) ? (BSpline*)p : 0;
}

BSpline* BSpline::safeCast(Interpolation *ip)
{
  return ip -> hasInterpolationProtocol(d_ipProtocol) ? (BSpline*)ip : 0;
}
