//
//	Copyright 1993, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//
//
// $Log: bit-conv.desc,v $
// Revision 1.3  1994/02/12  19:36:51  thoth
// Rehack of template operation specifications.
//
// Revision 1.2  1993/12/29  17:16:45  thoth
// Bit Discrete Image now uses Bit type.
//
// Revision 1.1  1993/11/29  22:25:25  thoth
// Initial revision
//
// 
// The XOR for the hit-miss transform is implemented using logical operators
// instead of the bitwise '^' to guarantee that only values of 1 and 0
// result.
// convolution hit_miss zero=1 I(IA_Bit) I(IA_Bit) T(IA_Bit)
// Emacs: -*- C++ -*-

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


//
// $Log: img-templ-product,v $
// Revision 1.11.1.3  1995/01/13  19:37:42  thoth
// CoreImage has been re-merged with Image.  All special stuff should be
// friends of FBI now.
//
// Revision 1.11.1.2  1995/01/09  18:19:53  thoth
// Boxy pointset constructor replaced by function.
//
// Revision 1.11.1.1  1994/12/28  18:08:25  thoth
// boxy IPSet constructor is obsolete.
// detect dimension mismatch earlier.
//
// Revision 1.11  1994/12/22  16:31:05  fjsoria
// extra "," in linear product
//
// Revision 1.10  1994/07/25  17:26:39  thoth
// Name sanitization
//
// Revision 1.9  1994/03/30  14:01:44  thoth
// zero_extension is now a template function.
//
// Revision 1.8  1994/03/14  15:53:13  thoth
// We now use the FBI to extract the baseptr.
//
// Revision 1.7  1994/02/22  18:49:39  thoth
// We now efficiently evaluate lazy template-template convolutions
// convolved with images.
//
// Revision 1.6  1994/02/12  19:45:43  thoth
// Forward and Backward convolutions are now specified separately.
//
// Revision 1.5  1994/01/31  15:50:18  thoth
// fixed typing error in invariant convolutions.
//
// Revision 1.4  1994/01/07  15:10:00  thoth
// Image class is now CoreImage and named image types are
// Image<P,T>.
//
// Revision 1.3  1993/12/29  17:33:18  thoth
// New operator scheme that prevents the need for trivial Image conversions.
//
// Revision 1.2  1993/11/17  18:29:46  thoth
// We now have support for forward convolutions.
// IPSIter is now PSIter<IntPoint>.
//
// Revision 1.1  1993/09/15  13:02:08  thoth
// Initial revision
//
// Revision 1.5  93/05/27  11:48:55  thoth
// Copyright Notices
// 
// Revision 1.4  93/04/29  11:20:56  thoth
// Faster(?) extension for VectorDIs.
// 
// Revision 1.3  93/04/17  18:56:44  jnw
// Fixed to match IA_Point<int> membername (dim)
// 
// Revision 1.2  93/04/08  13:21:59  thoth
// internal helper functions are now static.
// 
// Revision 1.1  93/03/18  11:39:42  thoth
// Initial revision
// 

//
// backward convolutions
//

static IA_Image<IA_Point<int>,IA_Bit>
backw_hit_miss_inv_core(IA_Point<int> src_infimum,
	      IA_Point<int> src_width,
	      const IA_Bit *src_data, // length is prod(src_width)
	      const IA_Image<IA_Point<int>,IA_Bit> &templ,
	      IA_Set<IA_Point<int> > dest_ps)
{
    const int	dimen = src_width.dim();

    IA_Set<IA_Point<int> >	templ_ps = templ.domain();
    int		templ_sz = templ_ps.card();
    IA_Bit	*const templ_data = new IA_Bit[templ_sz];
    int	*const templ_offsets = new int[templ_sz];

    {
	IA_Bit	*d_scan = templ_data;
	int	*o_scan = templ_offsets;
	IA_IPIter<IA_Point<int>,IA_Bit>	iter(templ);
	IA_Point<int>	ip;
	while (iter(ip, *d_scan)) {
	    *o_scan = ip[0];
	    for (unsigned i=1; i<dimen; i++) {
		*o_scan *= src_width[i];
		*o_scan += ip[i];
	    }
	    d_scan++;
	    o_scan++;
	}
    }

    IA_PSIter<IA_Point<int> >	iter(dest_ps);
    IA_Point<int>	ip;
    IA_Bit *const	dest_data = new IA_Bit[dest_ps.card()];
    IA_Bit *	valp = dest_data;
    while (iter(ip)) {
	int	offset= ip[0] - src_infimum[0];
	unsigned i;
	for (i=1; i<dimen; i++) {
	    offset *= src_width[i];
	    offset += ip[i] - src_infimum[i];
	}
	const IA_Bit *const base = src_data + offset;

	// _IVAL_=(base[templ_offsets[i]])
	// _TVAL_=(templ_data[i])
	// _IRESULT_=(*valp)

	IA_Bit a = 1; ;

	for (i=0; i<templ_sz; i++) {
	    a =  (a & IA_Bit((base[templ_offsets[i]]) == (templ_data[i]))); ;
	}
	{
	    (*valp) = a; ;
	}
	valp++;
    }
    delete[] templ_offsets;
    delete[] templ_data;

    return IA_Image<IA_Point<int>,IA_Bit>(dest_ps, dest_data, dest_ps.card(), 1);
}

static IA_Image<IA_Point<int>,IA_Bit>
backw_hit_miss_inv(const IA_Image<IA_Point<int>,IA_Bit> &img,
	 const IA_Image<IA_Point<int>,IA_Bit> &invtempl,
	 IA_Set<IA_Point<int> > dest_ps)
{
    if (img.domain().dim() != invtempl.domain().dim()) {
	ia_throw(Template_DimensionMismatch2_Exception(__FILE__, __LINE__));
	return IA_Image<IA_Point<int>,IA_Bit>();
    }

    IA_Point<int>	inf_ = dest_ps.inf()+invtempl.domain().inf();
    IA_Point<int>	sup_ = dest_ps.sup()+invtempl.domain().sup();
    IA_Set<IA_Point<int> >	src_ps = IA_boxy_pset(inf_,sup_);

    IA_Bit	*const src_data = new IA_Bit[src_ps.card()];

    zero_extend(img, src_ps, (IA_Bit*)src_data, IA_Bit(1));
    IA_Image<IA_Point<int>,IA_Bit>	rval =
	backw_hit_miss_inv_core(inf_, sup_-inf_ + 1, src_data, invtempl, dest_ps);

    delete[] src_data;

    return rval;
}

IA_Image<IA_Point<int>,IA_Bit>
hit_miss(const IA_Image<IA_Point<int>,IA_Bit> &img_,
     const IA_DDTemplate<IA_Image<IA_Point<int>,IA_Bit> > &templ_,
     IA_Set<IA_Point<int> > dest_ps)
{
    IA_Image<IA_Point<int>,IA_Bit>	img(img_);
    /*PROMOTE*/IA_DDTemplate<IA_Image<IA_Point<int>,IA_Bit> >	templ(templ_);

#ifdef KNOWN_IA_lazy_hit_miss_IA_Bit
    if (templ.is_a(IA_lazy_inv_hit_miss_IA_Bit::s_type())) {
	const IA_lazy_inv_hit_miss_IA_Bit	*t =
	    (const IA_lazy_inv_hit_miss_IA_Bit *)IA_FBI<IA_Point<int>, IA_Point<int>, IA_Bit, IA_Bit, IA_Bit>::extract_baseptr(templ);
	IA_Set<IA_Point<int> >	bigger_ps = IA_boxy_pset(
	    IA_Point<int>(dest_ps.inf()+
			(t->rhs(extend_to_point(0, t->rhs.domain().dim()))
			 .domain().inf())),
	    IA_Point<int>(dest_ps.sup()+
			(t->rhs(extend_to_point(0, t->rhs.domain().dim()))
			 .domain().sup()))
	    );
	return hit_miss(hit_miss(img, t->lhs, bigger_ps), t->rhs, dest_ps);
    } else
#else
#define UNKNOWN_IA_lazy_hit_miss_IA_Bit
#endif
	if (templ.is_a(IA_InvariantDT<IA_Image<IA_Point<int>,IA_Bit> >::s_type())) {
	return backw_hit_miss_inv
	    (img, ((IA_InvariantDT<IA_Image<IA_Point<int>,IA_Bit> >*)IA_FBI<IA_Point<int>, IA_Point<int>, IA_Bit, IA_Bit, IA_Bit>::extract_baseptr(templ))->value, dest_ps);
//    } else if (templ.type() == IA_Lazy_REDUCT_DT<IA_Image<IA_Point<int>,IA_Bit> >::s_type()) {
    } else {
	IA_Bit *const	dest_data = new IA_Bit[dest_ps.card()];
	IA_Bit	*valp = dest_data;
	IA_PSIter<IA_Point<int> >	dest_iter(dest_ps);
	IA_Point<int>	base_ip;
	while (dest_iter(base_ip)) {
	    IA_Image<IA_Point<int>,IA_Bit>	tv = templ(base_ip);

	    IA_IPIter<IA_Point<int>,IA_Bit>	templ_iter(tv);
	    IA_Point<int>	templ_ip;
	    IA_Bit	templ_val;

	    // _IVAL_=img(ip)
	    // _TVAL_=templ_val
	    // _IRESULT_=(*valp)

	    IA_Bit a = 1; ;

	    while ( templ_iter(templ_ip, templ_val) ) {
		const IA_Point<int>	ip = templ_ip; //+base_ip;
		if (! img.domain().contains(ip))
		    continue;
		a =  (a & IA_Bit(img(ip) == templ_val)); ;
	    }
	    {
		(*valp) = a; ;
	    }
	    valp++;
	}
	return IA_Image<IA_Point<int>,IA_Bit>(dest_ps, dest_data,
					   dest_ps.card(), 1);
    }
}

// convolution hit_miss zero=1 I(IA_Bit) T(IA_Bit) I(IA_Bit)
// Emacs: -*- C++ -*-

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


//
// $Log: templ-img-product,v $
// Revision 1.6.1.2  1995/01/13  19:37:42  thoth
// CoreImage has been re-merged with Image.  All special stuff should be
// friends of FBI now.
//
// Revision 1.6.1.1  1994/12/28  16:56:06  thoth
// Conversion to classes for throw.
//
// Revision 1.6  1994/07/25  17:26:39  thoth
// Name sanitization
//
// Revision 1.5  1994/04/15  13:20:18  thoth
// zero_extend is now a function template.
//
// Revision 1.4  1994/03/30  14:02:11  thoth
// zero_extension is now a template function.
//
// Revision 1.3  1994/03/14  15:54:35  thoth
// We now use the FBI to extract the baseptr.
//
// Revision 1.2  1994/02/24  18:26:06  thoth
// prepare for alterations in sed script that allow passing of base
// template container type instead of derived.
//
// Revision 1.1  1994/02/12  19:45:43  thoth
// Initial revision
//


//
// foward convolutions
//

static IA_Image<IA_Point<int>,IA_Bit>
forw_hit_miss_inv_core(IA_Point<int> src_infimum,
	      IA_Point<int> src_width,
	      const IA_Bit *src_data, // length is prod(src_width)
	      const IA_Image<IA_Point<int>,IA_Bit> &templ,
	      IA_Set<IA_Point<int> > dest_ps)
{
    const int	dimen = src_width.dim();

    IA_Set<IA_Point<int> >	templ_ps = templ.domain();
    int		templ_sz = templ_ps.card();
    IA_Bit	*const templ_data = new IA_Bit[templ_sz];
    int	*const templ_offsets = new int[templ_sz];

    {
	IA_Bit	*d_scan = templ_data;
	int	*o_scan = templ_offsets;
	IA_IPIter<IA_Point<int>,IA_Bit>	iter(templ);
	IA_Point<int>	ip;
	while (iter(ip, *d_scan)) {
	    *o_scan = -ip[0];
	    for (unsigned i=1; i<dimen; i++) {
		*o_scan *= src_width[i];
		*o_scan -= ip[i];
	    }
	    d_scan++;
	    o_scan++;
	}
    }

    IA_PSIter<IA_Point<int> >	iter(dest_ps);
    IA_Point<int>	ip;
    IA_Bit *const	dest_data = new IA_Bit[dest_ps.card()];
    IA_Bit *	valp = dest_data;
    while (iter(ip)) {
	int	offset= ip[0] - src_infimum[0];
	unsigned i;
	for (i=1; i<dimen; i++) {
	    offset *= src_width[i];
	    offset += ip[i] - src_infimum[i];
	}
	const IA_Bit *const base = src_data + offset;

	// _IVAL_=(base[templ_offsets[i]])
	// _TVAL_=(templ_data[i])
	// _IRESULT_=(*valp)

	IA_Bit a = 1; ;

	for (i=0; i<templ_sz; i++) {
	    a =  (a & IA_Bit((base[templ_offsets[i]]) == (templ_data[i]))); ;
	}
	{
	    (*valp) = a; ;
	}
	valp++;
    }
    delete[] templ_offsets;
    delete[] templ_data;

    return IA_Image<IA_Point<int>,IA_Bit>(dest_ps, dest_data, dest_ps.card(), 1);
}

static
IA_Image<IA_Point<int>,IA_Bit>
forw_hit_miss_inv(const IA_Image<IA_Point<int>,IA_Bit> &img,
	const IA_Image<IA_Point<int>,IA_Bit> &invtempl,
	IA_Set<IA_Point<int> > dest_ps)
{
    if (img.domain().dim() != invtempl.domain().dim()) {
	ia_throw(Template_DimensionMismatch2_Exception(__FILE__, __LINE__));
	return IA_Image<IA_Point<int>,IA_Bit>();
    }

    IA_Point<int>	inf_ = dest_ps.inf()-invtempl.domain().sup();
    IA_Point<int>	sup_ = dest_ps.sup()-invtempl.domain().inf();
    IA_Set<IA_Point<int> >	src_ps = IA_boxy_pset(inf_,sup_);

    IA_Bit	*const src_data = new IA_Bit[src_ps.card()];

    zero_extend(img, src_ps, (IA_Bit*)src_data, IA_Bit(1));
    IA_Image<IA_Point<int>,IA_Bit>	rval =
	forw_hit_miss_inv_core(inf_, sup_-inf_ + 1, src_data, invtempl, dest_ps);

    delete[] src_data;

    return rval;
}

IA_Image<IA_Point<int>,IA_Bit>
hit_miss(const IA_DDTemplate<IA_Image<IA_Point<int>,IA_Bit> > &templ_,
     const IA_Image<IA_Point<int>,IA_Bit> &img_,
     IA_Set<IA_Point<int> > dest_ps)
{
    IA_Image<IA_Point<int>,IA_Bit>	img(img_);
    /*PROMOTE*/IA_DDTemplate<IA_Image<IA_Point<int>,IA_Bit> > templ(templ_);

    if (templ.type() == IA_InvariantDT<IA_Image<IA_Point<int>,IA_Bit> >::s_type()) {
	return forw_hit_miss_inv
	    (img, ((IA_InvariantDT<IA_Image<IA_Point<int>,IA_Bit> >*)IA_FBI<IA_Point<int>, IA_Point<int>, IA_Bit, IA_Bit, IA_Bit>::extract_baseptr(templ))->value, dest_ps);
    } else {
	unsigned	size = dest_ps.card();
	IA_Bit *const	dest_data = new IA_Bit[size];

	for (int i=0; i<size; i++) {
	    // _IRESULT_=dest_data[i]
	    // IA_Bit a = 1; ;
	    dest_data[i]=1;
	}

	IA_PSIter<IA_Point<int> >	src_iter(img.domain());
	IA_Point<int>	base_ip;
	while (src_iter(base_ip)) {
	    IA_Image<IA_Point<int>,IA_Bit>	tv = templ(base_ip);

	    IA_IPIter<IA_Point<int>,IA_Bit>	templ_iter(tv);
	    IA_Point<int>	templ_ip;
	    IA_Bit	templ_val;
	    IA_Bit	ival = img(base_ip);

	    // _IVAL_=ival
	    // _TVAL_=templ_val
	    // _IRESULT_=(*valp)

	    while ( templ_iter(templ_ip, templ_val) ) {
		const IA_Point<int>	ip = templ_ip; //+base_ip;
		if (! dest_ps.contains(templ_ip))
		    continue;
		unsigned	offset = dest_ps.index(templ_ip);
		IA_Bit	*valp = dest_data + offset;
//		cout << "templ(" << base_ip << ") =  " << tv << " and templ()("
//		     << templ_ip <<") = " << templ_val << endl;
		(*valp) = ((*valp) & IA_Bit(ival == templ_val)); ;
	    }
	}
	return IA_Image<IA_Point<int>,IA_Bit>(dest_ps, dest_data,
						      size, 1);
    }
}

