// pointset_example.05.c      An example of a ClosurePS point set


#include "IntPS.h"
#include "ClosurePS.h"


// An IA_PPCompositionIPS point set represents a point set
//   constructed from a point-to-point mapping function, f,
//   applied to a base point set, base.
//
// The contains function of the newly defined point set when applied to a
// point p checks to see if f(p) is in the base point set.
//
// This is useful for transforming comprehensive point sets.

class IA_PPCompositionIPS: public IA_ClosurePS<IA_Point<int> > {
private:
    IA_Point<int>	        ( *ppcFunc )(const IA_Point<int>&);
    IA_Set<IA_Point<int> >	base;
public:

    // This is the constructor function.
    // Its two arguments are the mapping function and the base point set
    IA_PPCompositionIPS(const IA_Set<IA_Point<int> > &base_,
			IA_Point<int> (*f_)(const IA_Point<int>&))
    :IA_ClosurePS<IA_Point<int> >(base_.dim()),  // initialize base class
     base(base_), ppcFunc(f_) {
    }

    // clone self  is an abstract virtual in IA_ClosurePS<T>.
    // It must return a copy of *this.
    IA_ClosurePS<IA_Point<int> > *clone_self() const {
	return new IA_PPCompositionIPS(*this);
    }

    // contains  is an abstract virtual in IA_ClosurePS<T>.
    // It must return 1 when its argument is contained in the point set
    // and 0 otherwise.

    int contains(const IA_Point<int> &ip) const {
	return base.contains( ppcFunc(ip) );     // invoke ppcFunc()
    }
};

int pos_half_plane(const IA_Point<int> &p) {
//    return p(0) > 0;
    return p[0] > 0;
}


IA_Point<int> translate_minus_1(const IA_Point<int> &p) {
    return p-1;
}


int main() {

    IA_Set<IA_Point<int> >
	ips4( 2,	        // dimension of the point set
	      pos_half_plane ); // pointer to predicate function
    				// defining this set


    // ips5 is the point set created by composing point set ips4 with
    // the point-to-point function translate_minus_1.
    IA_Set<IA_Point<int> >
	ips5( IA_PPCompositionIPS(ips4, translate_minus_1) );


    cout << ips4.contains(IA_Point<int>(1,1)) << "\n";
    // <1 1> is in the positive half plane of 2D space

    cout << ips5.contains(IA_Point<int>(1,1)) << "\n";
    // translate_minus_1(<1 1>) is <0 0>, which is not in ips4!

    cout << ips5.contains(IA_Point<int>(10,10)) << "\n";
    // translate_minus_1(<10 10>) is <9 9> which is in ips4

    return 0;
}
