// Emacs: -*- C++ -*-

//
//	Copyright 1993, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//


static char ContinuousImage_rcsid[] = "$Id: ContinuousImage.c,v 1.3 93/06/10 17:23:32 thoth Exp $";

//
// $Log:	ContinuousImage.c,v $
// Revision 1.3  93/06/10  17:23:32  thoth
// Workaround for 3.0.1 bug.
// 
// Revision 1.2  93/05/27  11:28:16  thoth
// Copyright Notices
// 
// Revision 1.1  93/05/26  17:15:02  thoth
// Initial revision
// 

#include "ContinuousImage.h"
#include "OtherCI.h"
#include "IPSIter.h"

#include "PredicatePS.h"

template <class T>
void IA_ContinuousImage<T>::set_and_reference_image(IA_BaseCI<T> *i)
{
  i->incr_ref();
  this->bcip = i;
}

template <class T>
void IA_ContinuousImage<T>::disassociate_image()
{
  if (bcip->decr_ref() <=0)
    delete bcip;

  bcip = 0;
}

template <class T>
IA_ContinuousImage<T>::IA_ContinuousImage(const IA_OtherCI<T>& i)
{
  set_and_reference_image(i.clone_self());
}

template <class T>
IA_ContinuousImage<T>::IA_ContinuousImage(const IA_ContinuousImage<T> &i)
{
  set_and_reference_image(i.bcip);
}

template <class T>
IA_ContinuousImage<T>::~IA_ContinuousImage()
{
  disassociate_image();
}

template <class T>
IA_ContinuousImage<T> & IA_ContinuousImage<T>::operator=(const IA_ContinuousImage<T> &im)
{
    IA_BaseCI<T>	*temp = im.bcip;
    temp->incr_ref();

    disassociate_image();

    this->bcip = temp;

    return *this;
}

//
//
//

template <class T>
IA_DiscreteImage<T> IA_ContinuousImage<T>::restrict(const IA_IntPointSet &ips)
    const
{
  IA_IPSIter	iter(ips);
  int	sz = ips.card();
  int	len=0;
  IA_IntPoint	*aip = new IA_IntPoint[sz];
  T	*vals = new T[sz];
  int	rejects=0;

  while (iter(aip[len])) {
    if (!this->domain().contains(aip[len])) {
      rejects++;
      continue;
    }

    vals[len] = (*this)(aip[len]);
    len++;
  }

  IA_IntPointSet	newips(ips);
  if (rejects)
      newips = IA_IntPointSet(ips.dim(), aip, len);

  delete[] aip;

  return IA_DiscreteImage<T>(newips, vals, len, 1);
}


//
//
//

class IA_PPCompositionFPS: public IA_PSPred<IA_FloatPoint> {
    IA_FloatPoint	(*f)(const IA_FloatPoint&);
    IA_FloatPointSet	base;
  public:
    IA_PPCompositionFPS(IA_FloatPoint (*f_)(const IA_FloatPoint&),
			const IA_FloatPointSet &base_)
    :IA_PSPred<IA_FloatPoint>(base_.dim()), f(f_), base(base_) {
    }
    IA_PSPred<IA_FloatPoint> *clone_self() const {
	return new IA_PPCompositionFPS(*this);
    }
    int contains(const IA_FloatPoint &ip) const {
	// Uglier than Rosanne bug:
	IA_FloatPoint (*f2)(const IA_FloatPoint&) = f;
	return base.contains(f2(ip));
    }
};

template <class T>
class IA_PPCompositionCI: public IA_OtherCI<T> {
    IA_FloatPoint	(*f)(const IA_FloatPoint&);
    IA_ContinuousImage<T>	im;
  public:
    IA_PPCompositionCI( IA_FloatPoint (*f_)(const IA_FloatPoint&),
		       const IA_ContinuousImage<T> &im_)
    :IA_OtherCI<T>(IA_PPCompositionFPS(f_, im_.domain())), f(f_), im(im_) {
    }
    T operator()(const IA_FloatPoint&p) const {
	IA_FloatPoint (*f2)(const IA_FloatPoint&) = f;
	return im(f2(p));
    }
    IA_OtherCI<T>* clone_self() const {
	return new IA_PPCompositionCI<T>(*this);
    }
#if 0
    T *range(unsigned *n) const {
	return im.range(n);
    }
#endif
};

template <class T>
IA_ContinuousImage<T> compose(const IA_ContinuousImage<T> &i,
			      IA_FloatPoint (*f)(const IA_FloatPoint&))
{
    return IA_PPCompositionCI<T>(f, i);
}

//
//
//


class IA_PPCompClosureFPS: public IA_PSPred<IA_FloatPoint> {
    IA_PPCompClosure<IA_FloatPoint, IA_FloatPoint> *f;
    IA_FloatPointSet	base;
  public:
    IA_PPCompClosureFPS( const IA_PPCompClosure<IA_FloatPoint, IA_FloatPoint> &f_,
			const IA_FloatPointSet &base_)
    :IA_PSPred<IA_FloatPoint>(base_.dim()), f(f_.clone_self()), base(base_) {
    }
    IA_PPCompClosureFPS(const IA_PPCompClosureFPS &other)
    :IA_PSPred<IA_FloatPoint>(other.base.dim()), f(other.f->clone_self()),
     base(other.base) {
    }
    ~IA_PPCompClosureFPS() { delete f; }

    IA_PSPred<IA_FloatPoint> *clone_self() const {
	return new IA_PPCompClosureFPS(*this);
    }
    int contains(const IA_FloatPoint &ip) const {
	return base.contains((*f)(ip));
    }
};

template <class T>
class IA_PPCompClosureCI: public IA_OtherCI<T> {
    IA_PPCompClosure<IA_FloatPoint, IA_FloatPoint> *f;
    IA_ContinuousImage<T>	im;
  public:
    IA_PPCompClosureCI( const IA_PPCompClosure<IA_FloatPoint, IA_FloatPoint> &f_,
		       const IA_ContinuousImage<T> &im_)
    :IA_OtherCI<T>(IA_PPCompClosureFPS(f_, im_.domain())),
     f(f_.clone_self()), im(im_) {
    }
    IA_PPCompClosureCI(const IA_PPCompClosureCI &other) 
    :IA_OtherCI<T>(IA_PPCompClosureFPS(*other.f, other.im.domain())),
     f(other.f->clone_self()), im(other.im) { }
    ~IA_PPCompClosureCI() { delete f; }

    T operator()(const IA_FloatPoint&p) const {
	return im((*f)(p));
    }
    IA_OtherCI<T>* clone_self() const {
	return new IA_PPCompClosureCI<T>(*this);
    }
#if 0
    T *range(unsigned *n) const {
	return im.range(n);
    }
#endif
};


template <class T>
IA_ContinuousImage<T> compose
(const IA_ContinuousImage<T>& im,
 const IA_PPCompClosure<IA_FloatPoint, IA_FloatPoint> &f)
{
    return IA_PPCompClosureCI<T>(f, im);
}
