All pastes #2101705 Raw Edit

Unnamed

public text v1 · immutable
#2101705 ·published 2012-01-09 22:04 UTC
rendered paste body
// by Olaf Hall-Holt, 2007-2011
#ifndef _ERIOLHELPER_
#define _ERIOLHELPER_


#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<sstream>
using std::vector;
using std::ostream;
using std::istream;
using std::string;
using std::stringstream;
#include<cassert>
#include<math.h>
using std::ws;
using std::cout;
using std::endl;

template<typename T>
void makeUnique(vector<T> &v)
{
  sort(v.begin(), v.end());
  typename vector<T>::iterator iter = unique(v.begin(), v.end());
  v.erase(iter, v.end());
}
template<class T>
bool memberOf( T j, const vector<T> &possible )
{
  return find(possible.begin(), possible.end(), j) != possible.end();
}
template<class T>
ostream& operator<<(ostream &os, const vector<T> &all)
{
  for(unsigned i=0, i_end=all.size(); i<i_end; ++i)
    os << all[i] << ' ';
  return os;
}
template<class T>
void rotateVector(vector<T> &pt, unsigned n)
{
  assert( n < pt.size() );
  vector<T> tmp(pt);
  pt.clear();
  pt.insert(pt.end(), tmp.begin()+n, tmp.end());
  pt.insert(pt.end(), tmp.begin(), tmp.begin()+n);
}
template<class T>
bool removeIndicesFromVector(vector<int> &toRemove, vector<T> &v)
{
  // assumes that toRemove is sorted
  if ( ! toRemove.empty() ) {
    int j = 0, j_end = v.size();
    vector<T> tmp;
    tmp.reserve(v.size() - toRemove.size());
    for ( unsigned i=0,i_end=toRemove.size(); i<i_end; ++i ) {
      if ( i+1<i_end ) assert( toRemove[i] < toRemove[i+1] );
      while ( j < toRemove[i] ) tmp.push_back(v[j++]);
      ++j;
    }
    while ( j < j_end ) tmp.push_back(v[j++]);
    v = tmp;
    return true;
  }
  return false;
}





class Color;
double hueDiff(const Color &a, const Color &b);
double hueDiff2(Color a, Color b);
double robustHueDiff(const Color &a, const Color &b);
struct Color {
  double r,g,b;
  Color() { r = 0.; g = 0.; b = 0.; }
  Color(double _r, double _g, double _b) : r(_r), g(_g), b(_b) {}
  Color(istream &is) { is >> r >> g >> b; }
  Color& operator=(const int& i) { 
    r = g = b = i;
    return *this; }
  Color operator+(const Color & p) const {
    return Color(r + p.r, g + p.g, b + p.b); }
  Color operator-(const Color & p) const {
    return Color(r - p.r, g - p.g, b - p.b); }
  Color operator/(double denom) const {
    assert(denom != 0);
    return Color(r/denom,g/denom,b/denom); }
  Color & operator+=(const Color &p) {
    r += p.r; g += p.g; b += p.b;
    return *this; }
  Color & operator/=(double denom) {
    assert(denom != 0);
    r /= denom; g /= denom; b /= denom;
    return *this; }
  double operator*(const Color &p) const {
    return r*p.r + g*p.g + b*p.b; }
  double mag() const {
    return sqrt(r*r + g*g + b*b); }
  double mag2() const {
    return r*r + g*g + b*b; }
  void normalize() {
    double m = mag();
    if ( m != 0 ) { r /= m; g /= m; b /= m; } }
  double& operator[](int channel) {
    if (channel == 0) return r;
    else if (channel == 1) return g;
    else return b; }
  double operator[](int channel) const {
    if (channel == 0) return r;
    else if (channel == 1) return g;
    else return b; }
  friend bool isZero(const Color &c) {
    return 0==c.r && 0==c.g && 0==c.b; }
  friend Color operator*(double s, const Color &c) {
    return Color(s*c.r, s*c.g, s*c.b); }
  friend double dist(const Color &a, const Color &b) {
    // return (a-b).mag();
    return hueDiff(a,b);
  }
  friend double dist2(const Color &a, const Color &b) {
    // return (a-b).mag2();
    return hueDiff2(a,b);
  }
  friend double absDiff(const Color &a, const Color &b) {
    return fabs(a.r-b.r) + fabs(a.g-b.g) + fabs(a.b-b.b); }
  friend Color colorDiff(Color a, Color b) {
    return Color(128,128,128) + (b-a); }
  friend bool isNoColor(Color c) {
    return (c.r==-1e10) && (c.g==-1e10) && (c.b==-1e10); } // must equal noColor
  friend bool approxEqual(const Color &a, const Color &b, double thresh=.01) {
    return fabs(a.r - b.r) < thresh &&
           fabs(a.g - b.g) < thresh &&
           fabs(a.b - b.b) < thresh; }
  friend ostream& operator<<(ostream &os, const Color &p) {
    os << p.r << " " << p.g << " " << p.b;
    return os; }
  friend istream & operator>>(istream& istr, Color &c) {
    c = Color(istr);  return istr; }
};
void sendColor(double, double, double);
void sendColor(Color);
static const Color WHITE(255,255,255);
static const Color BLACK(0,0,0);
static const Color RED(255,0,0);
static const Color ORANGE(255,125,0);
static const Color YELLOW(255,255,0);
static const Color GREEN(0,255,0);
static const Color CYAN(0,255,255);
static const Color BLUE(0,0,255);
static const Color PURPLE(255,0,255);
static const Color DARKRED(125,0,0);
static const Color DARKGREEN(0,125,0);
static const Color DARKBLUE(0,0,125);
static const Color DARKYELLOW(125,125,0);
static const Color DARKPURPLE(125,0,125);
static const Color GREY(125,125,125);
static const Color noColor(-1e10,-1e10,-1e10);

double variance(const vector<Color> &col);

struct PixelLoc {
  int x,y;
  PixelLoc() : x(-1), y(-1) {}
  PixelLoc(int _x, int _y) : x(_x), y(_y) {}
  PixelLoc(istream &is) { is >> x; assert(',' == is.get()); is >> y; }
  int &operator[](int i) {
    return (0==i) ? x : y; }
  int operator[](int i) const {
    return (0==i) ? x : y; }
  PixelLoc &operator+=(const PixelLoc &b) {
    x += b.x; y += b.y; return *this; }
  PixelLoc &operator-=(const PixelLoc &b) {
    x -= b.x; y -= b.y; return *this; }
  PixelLoc &operator*=(int s) {
    x *= s; y *= s; return *this; }
  bool operator<(const PixelLoc &b) const {
    if (x!=b.x) return x<b.x; return y<b.y; }
  bool operator==(const PixelLoc &b) const {
    return x==b.x && y==b.y; }
  bool operator!=(const PixelLoc &b) const {
    return !(*this==b); }
  friend PixelLoc operator+(const PixelLoc &a, const PixelLoc &b) {
    return PixelLoc(a.x + b.x, a.y + b.y); }
  friend PixelLoc operator-(const PixelLoc &a, const PixelLoc &b) {
    return PixelLoc(a.x - b.x, a.y - b.y); }
  friend PixelLoc operator*(int s, const PixelLoc &a) {
    return PixelLoc(s*a.x, s*a.y); }
  friend double dist2(PixelLoc a, PixelLoc b) {
    double dx = a.x - b.x, dy = a.y - b.y;
    return dx*dx + dy*dy; }
  friend double dist(PixelLoc a, PixelLoc b) {
    return sqrt(dist2(a,b)); }
  friend bool isNilLoc(PixelLoc a) {
    return (a.x==-1000000000) && (a.y==-1000000000); }  // must equal nilLoc
  friend ostream& operator<<(ostream &os, const PixelLoc &p) {
    os << p.x << "," << p.y;
    return os; }
  friend istream & operator>>(istream& istr, PixelLoc &p) {
    p = PixelLoc(istr);  return istr; }
};
static const PixelLoc UP(0, -1);
static const PixelLoc LEFT(-1, 0);
static const PixelLoc DOWN(0, 1);
static const PixelLoc RIGHT(1, 0);
static const PixelLoc nilLoc(-1000000000,-1000000000);

vector<PixelLoc> getNbr8(PixelLoc pos);

struct Coord {
  double x,y;
  Coord(): x(0), y(0) {}
  Coord(double _x, double _y): x(_x), y(_y) {}
  Coord(istream &is) { is >> x; is >> ws; assert(is.get() == ','); is >> y; }

  double dot(Coord c) const {
    return x*c.x+y*c.y; }
  double operator*(Coord c) const {
    return dot(c); }
  Coord& operator+=(const Coord& c) {
    x += c.x;
    y += c.y;
    return *this; }
  Coord& operator-=(const Coord& c) {
    x -= c.x;
    y -= c.y;
    return *this; }
  Coord& operator*=(double s) {
    x *= s;
    y *= s;
    return *this; }
  double mag() const {
    return sqrt(x*x + y*y); }
  void normalize() {
    double len = mag();
    if (len) { x /= len; y /= len; } }
  void moveToward(Coord intersection, double howMuch);
  friend bool closeTo(double a, double b, double thresh=0.00001) {
    return fabs(a-b) < thresh; }
  bool closeTo(Coord b, double thresh=0.00001) const {
    return dist2(*this, b) < thresh; }
  void draw() const;

  friend Coord operator+(Coord a, Coord b) {
    return Coord(a.x + b.x, a.y + b.y); }
  friend Coord operator-(Coord a, Coord b) {
    return Coord(a.x - b.x, a.y - b.y); }
  friend Coord operator*(double s, Coord c) {
    return Coord(s*c.x, s*c.y); }
  friend Coord operator/(Coord c,double s) {
    assert(s != 0);
    return Coord(c.x/s, c.y/s); }
  friend double dist2(Coord a, Coord b) {
    double dx = a.x - b.x, dy = a.y - b.y;
    return dx*dx + dy*dy; }
  friend double dist(Coord a, Coord b) {
    return sqrt(dist2(a,b)); }
  friend Coord quarterTurn(Coord c, bool inv=false) {
    return inv ? Coord(c.y, -c.x) : Coord(-c.y, c.x); }
  friend PixelLoc asPixelLoc(Coord c) {
    return PixelLoc( floor(c.x),  floor(c.y) ); }
  friend Coord asCoord(PixelLoc a) {
    return Coord(a.x, a.y); }
  friend Coord asShiftedCoord(const PixelLoc &a) {
    return Coord(a.x + .5, a.y + .5); }
  friend bool isNoCoord(Coord c) {
    return (c.x==1e10) && (c.y==1e10); }  // must equal noCoord
// friend Coord warpPoint(Coord p, double *mat);
  friend ostream & operator<<(ostream& ostr, const Coord& c) {
    ostr << c.x << "," << c.y;
    return ostr; }
  friend istream & operator>>(istream& is, Coord &c) { is >> ws;
    // if ( EOF == is.peek() ) is.setstate(ios::badbit); else
    c = Coord(is);
    return is; }
};
static const Coord noCoord(1e+10, 1e+10); // see isNoCoord above

static const double EPSILON = 1e-10;

double angleOf(Coord dir);
double angleOf(Coord a, Coord b, Coord c);
double shorterAngleDiff(double, double);
double fullAngleDiff(double, double);
double jitter(double width=0.00001);
Coord asCoord(PixelLoc a);
Coord asShiftedCoord(const PixelLoc &a);
bool closeTo(double a, double b, double thresh);

struct BBox {
  PixelLoc ul;
  int w,h;
  BBox(): ul(0,0), w(-1), h(-1) {}
  BBox(PixelLoc pos): ul(pos), w(1), h(1) {}
  BBox(PixelLoc pos, int _w, int _h): ul(pos), w(_w), h(_h) {}
  BBox(PixelLoc pos, PixelLoc pos2): ul(pos), w(pos2.x-pos.x+1), h(pos2.y-pos.y+1) {}
  BBox(const vector<Coord> &pt): ul(0,0), w(-1), h(-1) {
    if ( !pt.empty() ) {
      ul = asPixelLoc(pt[0]); w = h = 1;
      for ( unsigned i=1,i_end=pt.size(); i<i_end; ++i ) expand(pt[i]);
    } }
  BBox(const BBox &a, const BBox &b): ul(a.ul), w(a.w), h(a.h) {
    expand(b.ul);
    expand(b.ul + PixelLoc(b.w-1,b.h-1)); }
  int minX() const { return ul.x; }
  int minY() const { return ul.y; }
  int maxX() const { return ul.x+w-1; }
  int maxY() const { return ul.y+h-1; }
  PixelLoc minXY() const { return ul; }
  PixelLoc maxXY() const { return PixelLoc( maxX(), maxY() ); }
  int xLim() const { return ul.x + w; }
  int yLim() const { return ul.y + h; }
  bool contains( PixelLoc p ) const {
    return p.x >= ul.x && p.x < xLim() &&
           p.y >= ul.y && p.y < yLim(); }
  bool contains( Coord p ) const {
    return p.x >= ul.x && p.x < xLim() &&
           p.y >= ul.y && p.y < yLim(); }
  //Added method for convenience
  bool contains(double x, double y) {
    return (contains(Coord(x,y) ) ); }
  void incrX() { ++w; }
  void incrY() { ++h; }
  void decrX() { --ul.x; ++w; }
  void decrY() { --ul.y; ++h; }
  void expand(Coord c) {
    if ( c.x < ul.x ) {
      w += (ul.x - floor(c.x));
      ul.x = floor(c.x);
    }
    if ( c.y < ul.y ) {
      h += (ul.y - floor(c.y));
      ul.y = floor(c.y);
    }
    if ( c.x >= ul.x+w ) w = ceil(c.x) - ul.x;
    if ( c.y >= ul.y+h ) h = ceil(c.y) - ul.y;
  }
  void expand(PixelLoc p) { expand( asShiftedCoord(p) ); }
  void expand(BBox b) { expand(b.ul);
                        expand(b.ul + PixelLoc(b.w-1,b.h-1)); }
  void expandByOne() { --ul.x; --ul.y; w+=2; h+=2; }
  bool overlaps(int amin, int amax, int bmin, int bmax) const
    { return (amin <= bmax) && (bmin <= amax); }
  bool overlaps(const BBox &bb) const {
    return overlaps(bb.minX(), bb.maxX(), minX(), maxX()) &&
           overlaps(bb.minY(), bb.maxY(), minY(), maxY()); }
  bool contains(const BBox &bb) const {
    return contains(bb.minXY()) && contains(bb.maxXY()); }
  vector<PixelLoc> pixelsInside() const { vector<PixelLoc> res;
    PixelLoc pos;
    for ( pos.y = minY(); pos.y <= maxY(); ++pos.y )
    for ( pos.x = minX(); pos.x <= maxX(); ++pos.x )
      res.push_back(pos);
    return res; }
  void draw() const;
  friend ostream& operator<<(ostream &os, const BBox &b) {
    os << b.w << "x" << b.h << "+" << b.ul.x << "+" << b.ul.y;
    return os; }
};

class Segment;
class Arc;
class Curvelet;
BBox computeBBox(const Segment &, double offset=0);
BBox computeBBox(const Arc &, double offset=0);
BBox computeBBox(const Curvelet &);
bool overlaps(const BBox &, const Segment &);

class Image {  // matrix we can draw on the screen
public:
  enum ChannelType { NONE_CHAN, BOOL_CHAN, CHAR_CHAN, INT_CHAN, FLOAT_CHAN, DOUBLE_CHAN, MMAP_CHAN };
  string name;
  bool isSimpleFormat;  // homemade format for a tiny segmentation
  bool readOnly, writeOnly;  // for mmap
  int mmapOffset, numBytes, fd;  // for mmap
  float imageScale;  // for display
  Coord windowUL;    // for display
  float perPixelScale;  // for display

private:
  unsigned width, height, numChannels;
  ChannelType channelType;
  vector<bool> boolData;
  vector<unsigned char> charData;
  vector<int> intData;
  vector<float> floatData;
  vector<double> doubleData;
  unsigned char *mmapRoot, *mmapData;

  void assertInImage(unsigned x, unsigned y) const
          { assert(x < width); assert(y < height); }
public:
  static unsigned char clamp255(double d)
          { return (d<0) ? 0 : (d>255) ? 255 : round(d); }
  void initData();
  void initZoomParameters();
  void init(istream &, bool useMmap=false);
  Image(): isSimpleFormat(false), width(0), height(0),
     numChannels(0), channelType(NONE_CHAN) {}
  Image(unsigned w, unsigned h, ChannelType t, unsigned d):
     isSimpleFormat(false), width(w), height(h),
     numChannels(d), channelType(t) { initData(); initZoomParameters(); }
  Image(istream &);
  Image(const char *fname, bool useMmap=false);
  Image(unsigned w, unsigned h, unsigned d, const char *fname); // mmap write
  ~Image();

  unsigned getWidth() const { return width; }
  unsigned getHeight() const { return height; }
  unsigned getNumChannels() const { return numChannels; }
  ChannelType getChannelType() const { return channelType; }
  string basicImageInfo() const {
     stringstream ss;
     ss << name << " " << width << "x" << height;
     return ss.str(); }
  bool hasType(int n, ChannelType t) {
     return (n == static_cast<int>(numChannels)) && (t == channelType); }
  void *getData() {  // for low-level access
    //  low level access doesn't work correctly with bool, due to packing?
    // if ( BOOL_CHAN == channelType ) return &(boolData[0]); else
    if ( CHAR_CHAN == channelType ) return &(charData[0]);
    else if ( INT_CHAN == channelType ) return &(intData[0]);
    else if ( FLOAT_CHAN == channelType ) return &(floatData[0]);
    else if ( DOUBLE_CHAN == channelType ) return &(doubleData[0]);
    else if ( MMAP_CHAN == channelType ) return mmapData;
    else assert(false);
  }
  const void *getData() const {
    //  low level access doesn't work correctly with bool, due to packing?
    // if ( BOOL_CHAN == channelType ) return &(boolData[0]); else
    if ( CHAR_CHAN == channelType ) return &(charData[0]);
    else if ( INT_CHAN == channelType ) return &(intData[0]);
    else if ( FLOAT_CHAN == channelType ) return &(floatData[0]);
    else if ( DOUBLE_CHAN == channelType ) return &(doubleData[0]);
    else if ( MMAP_CHAN == channelType ) return mmapData;
    else assert(false);
  }
  bool getBoolPixel(PixelLoc p, unsigned channel=0) const {
    assert( BOOL_CHAN == channelType );
    assert( channel < numChannels );
    assertInImage(p.x,p.y);
    return boolData[numChannels*(p.y*width+p.x)+channel];
  }
  unsigned char getCharPixel(PixelLoc p, unsigned channel=0) const {
    assert( channel < numChannels );
    assertInImage(p.x,p.y);
    if ( CHAR_CHAN == channelType )
      return charData[numChannels*(p.y*width+p.x)+channel];
    else {
      assert( MMAP_CHAN == channelType);
      assert(readOnly);
      return mmapData[numChannels*(p.y*width+p.x)+channel];
    }
  }
  Color getPixel(PixelLoc p) const {
    assert( 3 == numChannels );
    assertInImage(p.x,p.y);
    if ( CHAR_CHAN == channelType )
      return Color(charData[numChannels*(p.y*width+p.x)+0],
                   charData[numChannels*(p.y*width+p.x)+1],
                   charData[numChannels*(p.y*width+p.x)+2] );
    else {
      assert( MMAP_CHAN == channelType);
      assert(readOnly);
      return Color(mmapData[numChannels*(p.y*width+p.x)+0],
                   mmapData[numChannels*(p.y*width+p.x)+1],
                   mmapData[numChannels*(p.y*width+p.x)+2] );
    }
  }
  int getIntPixel(PixelLoc p, unsigned channel=0) const {
    assert( INT_CHAN == channelType );
    assert( channel < numChannels );
    assertInImage(p.x,p.y);
    return intData[numChannels*(p.y*width+p.x)+channel];
  }
  float getFloatPixel(PixelLoc p, unsigned channel=0) const {
    assert( FLOAT_CHAN == channelType );
    assert( channel < numChannels );
    assertInImage(p.x,p.y);
    return floatData[numChannels*(p.y*width+p.x)+channel];
  }
  double getDoublePixel(PixelLoc p, unsigned channel=0) const {
    assert( DOUBLE_CHAN == channelType );
    assert( channel < numChannels );
    assertInImage(p.x,p.y);
    return doubleData[numChannels*(p.y*width+p.x)+channel];
  }
  void setPixel(PixelLoc p, bool col, unsigned chan=0 ) {
    assert( BOOL_CHAN == channelType );
    assert( chan < numChannels );
    assertInImage(p.x,p.y);
    boolData[numChannels*(p.y*width+p.x)+chan] = col; }
  void setPixel(PixelLoc p, unsigned char col, unsigned chan=0 ) {
    assert( chan < numChannels );
    assertInImage(p.x,p.y);
    if ( CHAR_CHAN == channelType )
      charData[numChannels*(p.y*width+p.x)+chan] = col;
    else {
      assert( MMAP_CHAN == channelType);
      assert(writeOnly);
      mmapData[numChannels*(p.y*width+p.x)+chan] = col; } }
  void setPixel(PixelLoc p, int col, unsigned chan=0 ) {
    assert( INT_CHAN == channelType );
    assert( chan < numChannels );
    assertInImage(p.x,p.y);
    intData[numChannels*(p.y*width+p.x)+chan] = col; }
  void setPixel(PixelLoc p, float col, unsigned chan=0 ) {
    assert( FLOAT_CHAN == channelType );
    assert( chan < numChannels );
    assertInImage(p.x,p.y);
    floatData[numChannels*(p.y*width+p.x)+chan] = col; }
  void setPixel(PixelLoc p, double col, unsigned chan=0 ) {
    assert( DOUBLE_CHAN == channelType );
    assert( chan < numChannels );
    assertInImage(p.x,p.y);
    doubleData[numChannels*(p.y*width+p.x)+chan] = col; }
  void setPixel(PixelLoc p, Color col) {
    assert( 3 == numChannels );
    assertInImage(p.x,p.y);
    if ( CHAR_CHAN == channelType ) {
      charData[numChannels*(p.y*width+p.x)+0] = clamp255(col.r);
      charData[numChannels*(p.y*width+p.x)+1] = clamp255(col.g);
      charData[numChannels*(p.y*width+p.x)+2] = clamp255(col.b);
    } else {
      assert(MMAP_CHAN == channelType);
      assert(writeOnly);
      mmapData[numChannels*(p.y*width+p.x)+0] = clamp255(col.r);
      mmapData[numChannels*(p.y*width+p.x)+1] = clamp255(col.g);
      mmapData[numChannels*(p.y*width+p.x)+2] = clamp255(col.b);
    }
  }
  void flipX();
  void flipY();
  void flipXY();
  void print(ostream &os, bool justHeader=false, bool forceChar=false) const;
  void print(const char *) const;
  void draw(Coord offset=noCoord, bool img2=false) const;
  void readFromFrameBuffer();
  Color getWindowAvg(const BBox &);
  double getWindowAvgGray(const BBox &);
  void lowPassFilter();
  void edgeDetect(bool vert);
  void subSample();
};

namespace ImageUI {

  extern vector<Image *> allImages;
  extern int currImageIndex, currImageIndex2;
  extern Image *faceMapImage, *sourceColorImage;
  // extern float imageScale0;  // there may also exist others in Lattice
  // extern Coord windowUL0;    //   to control other images separately
  extern double windowPixelWidth, windowPixelHeight;
  extern double windowPixelWidth2, windowPixelHeight2;  // for dualView
  extern double snapRange;
  extern bool tetherMotion, dualView;
  extern BBox bbox;

  enum UIMode {NORMAL, ADJUST, ADD_VERTEX, SELECT, CORRESP, LATTICE, PIXELSEG};

  float &imageScale(bool img2);
  Coord &windowUL(bool img2);
  double getWindowPixelWidth(bool img2);
  double getWindowPixelHeight(bool img2);
  void addImage(const char *f);
  Image* currImage(bool img2=false);
  int currImageWidth(bool img2=false);
  int currImageHeight(bool img2=false);
  Image *getFaceMap();
  void drawImage(bool img2);
  void drawImgBBox();
  bool isValidIndex(int);
  void setImageIndexChar(char, bool img2);
  void setImageIndex(int, bool toTitle=false, bool img2=false);
  void putImageNameInWindowTitle(bool img2);
  void setImage(Image *img, bool img2=false);
  void incrImageIndex(bool fwd=true, bool img2=false);
  Coord asImageCoord(int x, int y, bool img2=false);
  void cropImage();
  void frameGrab(const char *fname=0);
}

class PixelEdge;
bool inImage(PixelLoc);
bool inImage(const Image *, PixelLoc);
bool inImage(Coord);
bool inImage(const Image *, Coord);
bool inImage(const PixelEdge &e);
bool onImageBorder(const PixelEdge &e);

class Color;
Color asColor(PixelLoc pos, Image *img=0);
vector<Color> asColor(const vector<PixelLoc> &loc);
Color asColorOrGray(PixelLoc pos, Image *img=0);
Color asBoundedColor(PixelLoc pos, Image *img=0);
Color asInterpolatedColor(Coord pt, Image *img=0);
double asGray(PixelLoc pos, Image *img=0);
double asInterpolatedGray(Coord pt, Image *img=0);

struct Matrix3x3
{
  double m[9];
  double &operator()(int i, int j) { return m[3*j+i]; }
  const double &operator()(int i, int j) const { return m[3*j+i]; }
  Matrix3x3() { for(int i=0;i<9;++i) m[i] = 0; }
  Matrix3x3(bool t) { for(int i=0;i<9;++i) m[i] = 0; m[0]=m[4]=m[8]=t; }
  Matrix3x3(double angle) { for(int i=0;i<9;++i) m[i] = 0;
      m[0] = m[4] = cos(angle);  m[1] = m[3] = sin(angle); m[1]*=-1; m[8] = 1; }
  Matrix3x3(Coord trans) { for(int i=0;i<9;++i) m[i] = 0;
      m[2] = trans.x; m[5] = trans.y; m[8] = 1; }
  Matrix3x3(istream &is) { for(int i=0;i<9;++i) is >> m[i]; }
  Matrix3x3 &operator*=(double scale)
    { for(int i=0;i<9;++i) m[i] *= scale; return *this; }
};
static const Matrix3x3 zero3x3, identity3x3(true);

Matrix3x3 operator*( double s, const Matrix3x3 &m );
Matrix3x3 operator+( const Matrix3x3 &m1, const Matrix3x3 &m2 );
Matrix3x3 operator*( const Matrix3x3 &m1, const Matrix3x3 &m2 );
Color operator*( const Matrix3x3 &m, const Color &c );
Coord operator*( const Matrix3x3 &m, const Coord &c );  // projective!
ostream & operator<<(ostream & ostr,const Matrix3x3 &);
double determinant( const Matrix3x3 &m );
Matrix3x3 invert( const Matrix3x3 &m );
Color solve3x3(double a, double b, double c,   double d,
               double e, double f, double g,   double h,
               double i, double j, double k,   double l);
Color solve2x2(double a, double b,   double d,
               double e, double f,   double h );
void solveNxN(int N, double *A0, double *x);
class Segment;
Matrix3x3 computeTRS(const Segment &a, const Segment &b);
Matrix3x3 computeHomography(const vector<Coord> &p, const vector<Coord> &q);

class Segment;
class Arc;
class Curvelet;
class Curve;

struct CPoly {
  vector<Coord> bdy;
  string text;
  Color bdyColor, fillColor;
  bool widen, thick;
  CPoly() : widen(false), thick(false) {}
  void draw() const;
  bool selected;
  
  int midX();
  int midY();


  // globals
  static vector<CPoly> allCPoly, allCPoly2, mouseInfo;
  static bool showCPoly;
  static void drawAll(bool img2=false);
  
  //New Methods
  void changeBackgroundColor(Color col); 
  void changeFillColor(Color col);
  void select();
  void unselect();
  void toggleSelect();
  vector <Coord> getCoords();

  bool isInside(Coord c);
  bool isInside(double x, double y);
  static void pointToPolygon(double x, double y, bool inSecondWindow);
  static void removeCPoly(int first, int last, bool inSecondWindow);
  static void pop_backCPoly(unsigned int numRemoved, bool inSecondWindow);

};

struct CPolyGroup {  
  vector <CPoly*> poly;
  Color color;
  void setColor(Color col);
  void colorAdjust(CPoly* cpoly);
  void push_back(CPoly* cpoly);
  void remove(CPoly* cpoly);
};

//vector<CPolyGroup> CPolyGroup::groups;

	

void addCPoly(Coord, Color col=RED);
void addCPoly2(Coord, Color col=RED);
void addCPoly(Coord, Coord, Color col=WHITE, bool w=false);
void addCPoly2(Coord, Coord, Color col=WHITE, bool w=false);
void addCPoly(const vector<Coord> &pt, Color col=WHITE, bool w=false);
void addCPoly2(const vector<Coord> &pt, Color col=WHITE, bool w=false);
void addCPoly(Coord, double, Color col=RED);
void addCPoly2(Coord, double, Color col=RED);
void addCPoly(PixelEdge, Color col=WHITE);
void addCPoly(const Segment &, Color col=WHITE);
void addCPoly(const Arc &, Color col=WHITE);
void addCPoly(const Curvelet &, Color col=WHITE, bool left=true);
void addCPoly(const Curve &, Color col=WHITE);

void moveImgBBox(PixelLoc delta);
void zoomInBy(double s, int x, int y, bool img2);
void zoomInBy(double s, Coord fixed, bool img2);
void resizeWindow(double s, bool img2); // in gl.cpp
void doubleWindow();         // in gl.cpp
void resetZoom(bool img2);
void reshape(bool img2);  // in ui.cpp
void reshape(int w, int h, bool img2);  // in ui.cpp
void estimateImageScale(int w, int h, float &scale);
void fitWindowToImage(bool updateScale, bool img2);
void drawMouseInfo(int x, int y, bool shiftPressed, bool ctrlPressed);
void undrawMouseInfo();
void drawWindow(bool img2=false);
void drawNumber(Coord pt, double d);
void sendWidth(float w);
void sendPointSize(float s);
void printTitle(const char *s);
void printTitle(bool t);
void printTitle(const char *s, double d);
void printTitle(const char *s, int i);
void printTitle(const char *s, bool t);
void printTitle(double t);
void printTitle(Coord c);
void printTitle(const Curvelet &c);
void printTitle(const Curve &c);
void displayAllConnections(bool sameBdy, int i);
void displayConnectionInfo(bool sameBdy, int i=0, int j=0, bool init=false);
void mysrand(long val);

  

static const double DEFAULT_LINE_WIDTH = 1.5;

#ifdef VIEW3D
class Poly3;
void printTitle(const Poly3 &m);
#endif

#endif // _ERIOLHELPER_