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

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


// 
// $Log: SetStructure.h,v $
// Revision 1.12  1994/11/01  19:18:36  fjsoria
// non-inlined destructor fixed for g++
//
// Revision 1.11  1994/08/18  23:39:28  thoth
// DOS-inspired filename rework
//
// Revision 1.10  1994/07/25  17:00:05  thoth
// Name sanitization.
//
// Revision 1.9  1994/05/08  19:37:14  thoth
// New intpointset decomposition capability.
//
// Revision 1.8  1993/05/26  16:51:46  thoth
// Copyright Notices
//
// Revision 1.7  93/05/19  14:45:15  thoth
// now named IA_Array
// 
// Revision 1.6  92/12/16  14:48:21  thoth
// conversion to IA_ mostly complete
// 
// Revision 1.5  92/11/15  15:58:16  thoth
// expect a slight performance increase with preallocation.
// 
// Revision 1.4  92/11/11  12:17:42  thoth
// incremental optimization of SetStructures.
// 
// Revision 1.3  92/11/04  12:00:07  thoth
// new != comparator.
// bugfix relating to optimization of termination constans.
// 
// Revision 1.2  92/10/25  20:55:59  thoth
// made recursion termination constants have sensible names.
// 
// Revision 1.1  92/10/21  14:58:47  thoth
// Initial revision
// 
//

#ifndef SetStructure_h_
#define SetStructure_h_

#include "Array.h"
#include "IntPS.h"

struct IA_real_ss;
struct IA_ss_interval;

struct IA_SetStructure {
  public:
    static const IA_SetStructure	FIRST_ONLY;
    static const IA_SetStructure	SECOND_ONLY;
    static const IA_SetStructure	BOTH;
  private:
    IA_real_ss	*val;
    void copy_on_write();
    
    // verboten
    IA_SetStructure(IA_real_ss *);
  public:
    IA_SetStructure();
    IA_SetStructure(const IA_SetStructure &ss);

#ifdef __NO_INLINE_DESTRUCTORS
    void DestroySetStructure(); 
    ~IA_SetStructure() { DestroySetStructure(); }
#else  
    ~IA_SetStructure();
#endif

    
    IA_SetStructure & operator=(const IA_SetStructure&);
    
    int operator==(const IA_SetStructure& rhs) const { return val == rhs.val; }
    int operator!=(const IA_SetStructure& rhs) const { return val != rhs.val; }
    
    void add_interval(unsigned, IA_SetStructure);
    IA_ss_interval retrieve_interval(unsigned idx) const;
    unsigned nintervals() const;
    void ensure_space(unsigned);
};


struct IA_ss_interval {
    unsigned	count;
    IA_SetStructure	substructure;
    IA_ss_interval() 
    :substructure() { count=0; }
};

struct IA_real_ss {
  private:
    // verboten
    IA_real_ss& operator=(const IA_real_ss&);
  public:
    IA_Array<IA_ss_interval>	ivls;
    int		refcount;
    IA_real_ss()
    :ivls(0) { refcount = 1;}
    IA_real_ss(const IA_real_ss &arg) 
    :ivls(arg.ivls) { refcount=1; }
    IA_real_ss(double) 
    :ivls(1) { refcount=1; ivls.lengthen(2); }
    // the default destructor is correct
};


//
//

/* This structure represents the decomposition of a Yoder that has
   only two shadows, the empty pointset and the plate below.

   Condition 1
   If plate.card() ever turns out to be 1, the one point should be the
   origin.  This way the minkowski sum of bar and plate will == bar.
   This is for optimization purposes.

   Condition 2
   If bar.card()==1 then plate should be the set containing only the
   origin.  Otherwise bar should chase down the decomposition chain.
   This is for optimization purposes.

   */
struct IA_decomp_frag {
    /* This pointset is a subset of a 1-d line that is parallel to one
       of the coordinate axes. */
    IA_Set<IA_Point<int> >	bar;

    /* The minkowski sum of bar and plate is the pointset we decomposed */
    IA_Set<IA_Point<int> >	plate;
};

struct IA_PointSetDecomposition {
private:
    IA_Array<IA_decomp_frag>	fragments;
public:
    IA_PointSetDecomposition() {}
    IA_PointSetDecomposition(const IA_Set<IA_Point<int> > &);

    int nfragments() const { return fragments.len(); }

    IA_decomp_frag get_frag(int idx);
};

#endif
