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

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

static char copyright[] = "Copyright 1993, Center for Computer Vision and Visualization,\nUniversity of Florida.  All rights reserved.\n";

static char rcsid[] = "$Id: BoxyIPS.c,v 1.15 1993/09/15 12:30:23 thoth Exp $";

// 
// $Log: BoxyIPS.c,v $
// Revision 1.15  1993/09/15  12:30:23  thoth
// Pointset behavior controls have moved to IA::
//
// Revision 1.14  93/08/08  13:11:38  thoth
// Optimization to reduce Point-Point op=
// 
// Revision 1.13  93/07/15  11:35:19  thoth
// Add support for iterator virtual method.
// 
// Revision 1.12  93/05/28  15:05:08  thoth
// removed dependency on with-ia-pointset*
// 
// Revision 1.11  93/05/26  16:40:59  thoth
// Copyright Notices.
// 
// Revision 1.10  93/04/19  23:27:24  thoth
// Convert BaseIPS to IA_BasePS<IA_IntPoint>
// 
// Revision 1.9  93/04/17  15:19:54  thoth
// IA_IntPoint upgrades (dim, inf, sup)
// 
// Revision 1.8  93/04/16  15:50:02  thoth
// use IA_IntPoint instead of IntPoint.
// 
// Revision 1.7  92/12/16  14:47:56  thoth
// conversion to IA_ mostly complete
// 
// Revision 1.6  92/12/07  12:04:32  thoth
// new IntPoint index(unsigned) operation for use with "other" iterators.
// 
// Revision 1.5  92/09/30  10:26:47  thoth
// contains now accepts const Point<>&
// type() system now based on address of static data member
// 
// Revision 1.4  92/09/20  14:04:48  thoth
// new infimum and supremum methods for point sets.
// 
// Revision 1.3  92/09/03  13:31:04  thoth
// hash_self now deals with unsigneds
// 
// Revision 1.2  92/08/26  13:42:26  thoth
// meaningful exception types
// 
// Revision 1.1  92/08/23  13:29:54  thoth
// Initial revision
// 
// 

#include "ia.h"
#include "BoxyIPS.h"
#include "BoxyIPSIter.h"
#include "IntPointSet.h"

#ifdef IA_PRII
#pragma implementation
#endif

char IA_BoxyIPS::type_;

// construct a BoxyIPS given two corners of the hyperrectangle
IA_BoxyIPS::IA_BoxyIPS(const IA_IntPoint& p1, const IA_IntPoint& p2)
: IA_BasePS<IA_IntPoint>(p1.dim()), start(::inf(p1,p2)), end(::sup(p1,p2))
{
    // we should throw a different error when there is a mismatch.
 
    // dimen can not be zero.  The two points must have equal dimension
    if (p1.dim()==0) {
	ia_throw(IA::POINT_UNINITIALIZED, __FILE__, __LINE__);
	return;
    }
#if 0				// This error is thrown by inf and sup
    if (p1.dim() != p2.dim()) {
	ia_throw(IA::PSET_DIMENSION_MISMATCH, __FILE__, __LINE__);
	return;
    }
#endif
}

IA_BoxyIPS& IA_BoxyIPS::operator=(const IA_BoxyIPS& bps)
{
    this->dimen = bps.dimen;
    this->start = bps.start;
    this->end = bps.end;

    return *this;
}

// The following code uses the member initialization syntax.  It's
// faster than allowing the no-argument constructor for members and
// then using assignment.
IA_BoxyIPS::IA_BoxyIPS(const IA_BoxyIPS& bps)
: IA_BasePS<IA_IntPoint>(bps.dimen),
  start(bps.start),
  end(bps.end)
{
}

int IA_BoxyIPS::equal(IA_BasePS<IA_IntPoint> * psb) const
{
    return psb->type() == type() &&
	*this == *(IA_BoxyIPS*)psb;
}

unsigned IA_BoxyIPS::hash_self(unsigned modulus) const
{
    unsigned	sigma = 0;
    for (unsigned i=0; i<this->dimen; i++) {
	sigma += this->start[i];
	sigma += this->end[i];
    }
    return sigma % modulus;
}

int IA_BoxyIPS::operator==(const IA_BoxyIPS& bps) const
{
    if (this->dimen != bps.dimen)
	return 0;

    return this->start == bps.start && this->end == bps.end;
}

int IA_BoxyIPS::contains(const IA_IntPoint &ip) const
{
    return this->start <= ip && ip <= this->end;
}

unsigned IA_BoxyIPS::index(const IA_IntPoint &ip) const
{
    if (!this->contains(ip)) {
	if (IA::throw_on_index_uncontained)
	    ia_throw(IA::PSET_INDEX_UNCONTAINED, __FILE__,__LINE__);
	return IA::index_of_uncontained;
    }

    unsigned offset=0;
    for (unsigned i=0; i<this->dimen; i++) {
	offset *= width(i);
	offset += ip[i] - this->start[i];
    }
    return offset;
}

IA_IntPoint IA_BoxyIPS::index(unsigned idx) const
{
    int	*rval = new int[dimen];
    for (int i = dimen-1; i>=0; i--) {
	rval[i] = idx % width(i) + start[i];
	idx /= width(i);
    }

    if (idx) {
	if (IA::throw_on_index_uncontained)
	    ia_throw(IA::PSET_INDEX_UNCONTAINED, __FILE__,__LINE__);
	// the index was outside the card
	return IA_IntPoint();
    } else {
	// give away the array
	return IA_IntPoint(rval, dimen, 1);
    }
}

unsigned IA_BoxyIPS::card() const
{
    unsigned	size=1;

    for (unsigned idx=0; idx < this->dimen; idx++) {
	size *= width(idx);
    }
    return size;
}

IA_BasePSIter<IA_IntPoint> * IA_BoxyIPS::iterator() const
{
    // cast away const
    return new IA_BoxyIPSIter((IA_BoxyIPS*)this);
}

void IA_BoxyIPS::output(ostream &o, unsigned indent) const
{
  for (unsigned i=0; i<indent; i++)
    o << ' ';
  o << start << ".." << end << '\n';
}
