/* FILE: imageatlas.h                 -*-Mode: c++-*-
 *
 * Atlas class derived from Oxs_Atlas class that uses an import
 * image file for region demarcation.
 */

#ifndef _OXS_IMAGEATLAS
#define _OXS_IMAGEATLAS

#include <string>
#include <vector>

#include "threevector.h"
#include "util.h"
#include "atlas.h"

OC_USE_STD_NAMESPACE;
OC_USE_STRING;

/* End includes */
struct OxsImageAtlasColorData { // For private use only
public:
  OC_REAL8m red,green,blue; // Values, [0,1]
  OC_INDEX region_id;
  OxsImageAtlasColorData():red(0.),green(0.),blue(0.),region_id(0) {}
  OC_BOOL SetColor(const String& colorstr);
  OC_REAL8m DistanceSq(OC_REAL8m r,OC_REAL8m g,OC_REAL8m b) const;
};
// The next 3 operators are defined so MSVC++ 5.0 will accept
// vector<OxsImageAtlasColorData>, but are left undefined because
// they don't make no sense.
OC_BOOL operator<(const OxsImageAtlasColorData&,const OxsImageAtlasColorData&);
OC_BOOL operator>(const OxsImageAtlasColorData&,const OxsImageAtlasColorData&);
OC_BOOL operator==(const OxsImageAtlasColorData&,const OxsImageAtlasColorData&);

typedef OC_INDEX OxsImageAtlasPixelType; // For private use only
/// This can me made wider or narrower if more or fewer regions are
/// needed.  The size affects the memory usage of the 'pixel' array in
/// Oxs_ImageAtlas.

class Oxs_ImageAtlas:public Oxs_Atlas {
private:
  OxsImageAtlasPixelType* pixel;
  OC_INDEX image_width,image_height;

  enum ViewPlane { xy, zx, yz } view;
  // View plane selection:
  //  Default is "xy", for which
  //   x increases from left to right of image, and
  //   y increases from bottom to top of image.
  //  Selection "zx" specifies
  //   z increases from left to right of image, and
  //   x increases from bottom to top of image.
  //  Selection "yz" specifies
  //   y increases from left to right of image, and
  //   z increases from bottom to top of image.
  OC_REAL8m row_offset,row_scale,column_offset,column_scale;

  vector<String> region_name; // Region names
  vector<Oxs_Box> region_bbox; // Region bounding boxes

  void FillPixels(const char* filename,
		  vector<OxsImageAtlasColorData>& color_data,
		  OC_REAL8m matcherror,OC_INDEX default_id,int autocolor);
  /// Note: The last parameter, autocolor, is a temporary hack for
  ///       large region count support.

  static OC_BOOL
  FindBestMatchRegion(OC_REAL8m r, OC_REAL8m g, OC_REAL8m b,
		      const vector<OxsImageAtlasColorData>& color_data,
		      OC_INDEX& match_id, OC_REAL8m& match_distsq);
  /// Returns 0 if color_data is empty. Otherwise sets match_id and
  /// match_distsq to best fit, and returns 1.

  void InitializeRegionBBoxes(const Oxs_Box& world);
  /// Uses world, view and pixel data to setup bounding boxes
  /// for each region.  NB: view, pixel, image_width,
  /// image_height, and row/column_scale/offset variables
  /// _must_ be set up *before* calling this function!

public:
  virtual const char* ClassName() const; // ClassName() is
  /// automatically generated by the OXS_EXT_REGISTER macro.

  Oxs_ImageAtlas(const char* name,
		  Oxs_Director* newdtr,
		  const char* argstr);   // MIF block argument string

  ~Oxs_ImageAtlas();

  void GetWorldExtents(Oxs_Box &mybox) const { mybox = region_bbox[0]; }
  /// Fills mybox with bounding box for the atlas.  Region 0
  /// is the special region "universe."  The stored bbox for region 0
  /// is by fiat the atlas bounding box.

  OC_BOOL GetRegionExtents(OC_INDEX id,Oxs_Box &mybox) const;
  /// If 0<id<GetRegionCount, then sets mybox to bounding box
  /// for the specified region, and returns 1.  If id is 0,
  /// sets mybox to atlas bounding box, and returns 1.
  /// Otherwise, leaves mybox untouched and returns 0.

  OC_INDEX GetRegionId(const ThreeVector& point) const;
  /// Returns the id number for the region containing point.
  /// The return value is 0 if the point is not contained in
  /// the atlas, i.e., belongs to the "universe" region.

  OC_INDEX GetRegionId(const String& name) const;
  /// Given a region id string (name), returns
  /// the corresponding region id index.  If
  /// "name" is not included in the atlas, then
  /// -1 is returned.  Note: If name == "universe",
  /// then the return value will be 0.

  OC_BOOL GetRegionName(OC_INDEX id,String& name) const;
  /// Given an id number, fills in "name" with
  /// the corresponding region id string.  Returns
  /// 1 on success, 0 if id is invalid.  If id is 0,
  /// then name is set to "universe", and the return
  /// value is 1.

  OC_INDEX GetRegionCount() const {
    return static_cast<OC_INDEX>(region_name.size());
  }
  /// Valid RegionId numbers range from 0 to GetRegionCount() - 1,
  /// inclusive, where 0 is the special "universe" region.

};

#endif // _OXS_IMAGEATLAS

