#include "Rectangle.hpp"
#include "Engine.hpp"
#include "Line.hpp"
#include "Image.hpp"
#include <unistd.h>
#include "Scene.hpp"
#include "Text.hpp"
#include "Timer.hpp"
#include <time.h>
#include "ResourcesManager.hpp"
#include <string>
#include <stdlib.h>
#include "VertexBuffer.hpp"
#include "GLState.hpp"
#include "Scissors.hpp"
#include <kst/Logger.hpp>
#include "VertexBuffer.hpp"
#include <set>
#include <vector>
#include <SDL/SDL.h>
#include "kst/File.hpp"

using namespace glider;

const int CELL_SIZE=15;

struct AngleRange{
  int sa,ea;
  bool closed;
  static const int SCALED_PI_2 =90000000;
  static const int SCALED_PI  =180000000;
  static const int SCALED_PIx2=360000000;
  AngleRange(int argSa=0,int argEa=0):sa(argSa),ea(argEa),closed(false){}
  void setSa(int argSa)
  {
    if(!closed && ((sa<ea && argSa>ea)||(sa>ea && argSa<sa && argSa>ea)))closed=true;
    sa=argSa;
  }
  void setEa(int argEa)
  {
    if(!closed && ((sa<ea && sa>argEa)||(sa>ea && argEa>ea && argEa<sa)))closed=true;
    ea=argEa;
  }
  bool operator<(const AngleRange& other)const
  {
    return ea<other.ea;
  }
  double saScaled()
  {
    return sa/1000000.0;
  }
  double eaScaled()
  {
    return ea/1000000.0;
  }
  int middle()
  {
    if(sa<ea)return (sa+ea)/2;
    return (sa+ea+SCALED_PIx2)%SCALED_PIx2;
  }
  void shrinkCorners(int saPrc,int eaPrc)
  {
    if(sa>ea)
    {
      ea+=AngleRange::SCALED_PIx2;
    }
    uint64_t mid=middle();
    uint64_t val=mid-sa;
    val*=saPrc;
    val/=100;
    sa=(mid-val)%AngleRange::SCALED_PIx2;
    val=ea-mid;
    val*=eaPrc;
    val/=100;
    ea=(mid+val)%AngleRange::SCALED_PIx2;
  }
  int diff()
  {
    if(sa<ea)return ea-sa;
    return (ea+SCALED_PIx2-sa)%SCALED_PIx2;
  }
  bool inRange(int a)
  {
    if(closed)return false;
    if(sa<ea)return a>=sa && a<=ea;
    return a>=sa || a<=ea;
  }
  void mirror45()
  {
    sa=(SCALED_PI*2+SCALED_PI/2-sa)%(SCALED_PI*2);
    ea=(SCALED_PI*2+SCALED_PI/2-ea)%(SCALED_PI*2);
    std::swap(sa,ea);
  }
  void mirror90()
  {
    sa=(SCALED_PI*3-sa)%(SCALED_PI*2);
    ea=(SCALED_PI*3-ea)%(SCALED_PI*2);
    std::swap(sa,ea);
  }
  void mirror180()
  {
    sa=(SCALED_PI*4-sa)%(SCALED_PI*2);
    ea=(SCALED_PI*4-ea)%(SCALED_PI*2);
    std::swap(sa,ea);
  }
};

struct FovCell{
  AngleRange r;
  uint8_t sac,eac;
  uint8_t o1,o2;
  Posi<int> p;
  bool tempBlock;
  bool delayBlock;
  int range;
  bool operator<(const FovCell& other)const
  {
    return r<other.r;
  }
  void swapp()
  {
    std::swap(p.x,p.y);
  }
  void swapc()
  {
    std::swap(sac,eac);
  }
};


struct Cell{
  bool block;
  bool vis;
  bool tempBlock;
  bool delayBlock;
  int corners[4];
  FovCell fc;
  int r;
  std::string log;
};

typedef std::vector<Cell> Row;
typedef std::vector<Row> Matrix;

/*const char* testmap[]={
"########################################",
"#......................................#",
"#......................................#",
"#........................#########.....#",
"#......########..........#.......#.....#",
"#......#......############.......#.....#",
"#......#.........................|.....#",
"#......#......###########........|.....#",
"#......###--###.........#........#.....#",
"#.......................###.######.....#",
"#.........................#.#..........#",
"#......................####.####.......#",
"#.......#.#.#.#.#......................#",
"#........#.#.#.#.......#########.......#",
"#.......#.#.#.#.#......................#",
"#........#.#.#.#.......................#",
"#...........................#..........#",
"#.......#...................#..........#",
"#...........................###........#",
"#....#.................................#",
"#.............#........................#",
"#....................#.................#",
"#..#......#.........#..................#",
"#............###.####..................#",
"#.......#...........#.........##.......#",
"#............###.####.........##.......#",
"#......#.......#.#.....................#",
"#..............###.....................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#.........*****........##--##..........#",
"#....**.......*........#....#..........#",
"#.............*........|....|..........#",
"#.............*........|....|..........#",
"#.............*........#....#..........#",
"#......................##..##..........#",
"#......................................#",
"#......................................#",
"########################################",
};*/




int px;
int py;
int sightRadius=15;
VertexBuffer* vb;
Line* lsa;
Line* lea;
Text* info;

void drawMap(Matrix& m)
{
  int H=m.size();
  int W=m[0].size();
  Color clr;
  ClrVector& c=vb->getCBuf();
  for(int y=0;y<H;++y)
  {
    for(int x=0;x<W;++x)
    {
      if(m[y][x].block)clr=Color::white;else clr=Color::blue;
      if(x==px && y==py)clr=Color::red;
      if(m[y][x].tempBlock)
      {
        clr=Color::green;
      }
      if(m[y][x].delayBlock)
      {
        clr=Color::gray;
      }
      if(!m[y][x].vis)
      {
        clr=clr/2;
      }
      for(int i=0;i<4;++i)
      {
        c[(x+y*W)*4+i]=clr;
      }
    }
  }
  vb->update();
}

namespace kst{
void customformat(kst::FormatBuffer& buf,double v,int w,int p)
{
  char buf2[64];
  size_t len=sprintf(buf2,"%*.*lf",w,p,v);
  buf.Append(buf2,len);
}
}

class CircularFov{
public:

  CircularFov():debug(true)
  {
  }

  static int getAngle(double x,double y,double quadrant)
  {
    return (atan(y/x)+quadrant)*(AngleRange::SCALED_PI_2)/M_PI_2;
  }

  void prepare(int maxRadius)
  {
    if(fov.empty())fov.push_back(Ring());
    for(int r=fov.size();r<=maxRadius;++r)
    {
      fov.push_back(Ring());
      Ring& ring=fov.back();
      //double rr=r*r;//(r+0.5)*(r+0.5);
      for(int y=0;y<=r;++y)
      {
        for(int x=y;x<=r;++x)
        {
          if(x==0 && y==0)continue;
          double dx=x;//-0.5;
          double dy=y;//-0.5;
          if(floor(sqrt(dx*dx+dy*dy))<=r)
          {
            Pos p(x,y);
            if(processed.find(p)!=processed.end())continue;
            processed.insert(p);
            int sa,ea,sac,eac,o1,o2;
            /*if(x==0)
            {
              sa=getAngle(0.5,y-0.5,0);
              ea=getAngle(-0.5,y-0.5,M_PI_2);
            }else
            {*/
            if(y==0)
            {
              sa=getAngle(x-0.5,-0.5,M_PI*2);
              ea=getAngle(x-0.5,0.5,0)-1;
              sac=3;
              eac=0;
              o1=0;
              o2=7;
            }else if(x==y)
            {
              sa=getAngle(x+0.5,y-0.5,0);
              ea=getAngle(x-0.5,y+0.5,0);
              sac=2;
              eac=0;
              o1=0;
              o2=1;
            }else
            {
              sa=getAngle(x+0.5,y-0.5,0);
              ea=getAngle(x-0.5,y+0.5,0);
              sac=2;
              eac=0;
              o1=o2=0;
            }
            //}
            ring.push_back(FovCell());
            FovCell& fc=ring.back();
            fc.r.sa=sa+5;
            fc.r.ea=ea-5;
            fc.sac=sac;
            fc.eac=eac;
            fc.o1=o1;
            fc.o2=o2;
            fc.p=p;
          }
        }
      }
      size_t end=ring.size();
      for(size_t i=0;i<end;++i)
      {
        FovCell fc=ring[i];
        if(fc.p.x==fc.p.y)continue;
        fc.swapp();
        fc.r.mirror45();
        fc.sac=fc.sac==0?2:fc.sac==2?0:fc.sac;
        fc.eac=fc.eac==0?2:fc.eac==2?0:fc.eac;
        fc.swapc();
        fc.o1=1;
        fc.o2=fc.o2==7?2:1;
        ring.push_back(fc);
      }
      end=ring.size();
      int ct[4]={1,0,3,2};
      for(size_t i=0;i<end;++i)
      {
        FovCell fc=ring[i];
        if(fc.p.x==0)continue;
        fc.p.x=-fc.p.x;
        fc.r.mirror90();
        fc.sac=ct[fc.sac];
        fc.eac=ct[fc.eac];
        fc.swapc();
        fc.o1=fc.o1==0?3:2;
        fc.o2=fc.o2==7?4:fc.o2==0?3:2;
        ring.push_back(fc);
      }
      end=ring.size();
      int ct2[4]={3,2,1,0};
      for(size_t i=0;i<end;++i)
      {
        FovCell fc=ring[i];
        if(fc.p.y==0)continue;
        fc.p.y=-fc.p.y;
        fc.r.mirror180();
        fc.sac=ct2[fc.sac];
        fc.eac=ct2[fc.eac];
        fc.swapc();
        fc.o1=7-fc.o1;
        fc.o2=7-fc.o2;
        ring.push_back(fc);
      }
      //std::sort(ring.begin(),ring.end());
    }
  }

  void generateFov(Matrix& m,int maxRadius)
  {
    if(fov.size()<maxRadius+1)
    {
      prepare(maxRadius);
    }
    int H=m.size();
    int W=m[0].size();
    for(int y=0;y<H;++y)
    {
      for(int x=0;x<W;++x)
      {
        m[y][x].vis=false;
      }
    }
    for(int i=0;i<8;++i)b[i].clear();
    for(int ri=1;ri<=maxRadius;++ri)
    {
      Ring& ring=fov[ri];
      for(Ring::iterator it=ring.begin(),end=ring.end();it!=end;++it)
      {
        FovCell fc=*it;
        int x=px+fc.p.x;
        int y=py+fc.p.y;
        if(x<0 || x>=W || y<0 || y>=H)continue;
        Cell& c=m[y][x];
        fc.delayBlock=c.delayBlock;
        fc.tempBlock=c.tempBlock;
        fc.range=ri+2;
        c.fc=fc;
        c.r=ri;
        c.log="";
        AngleRange r=fc.r;
        bool totalBlock=false;
        bool saBlock;
        int bso=-1,bsi=-1;
        int beo=-1,bei=-1;
        bool usedTempBlock=false;
        for(int k=0;k<2;++k)
        {
          int o=fc.o1;
          if(k==1)
          {
            if(fc.o1==fc.o2)break;
            o=fc.o2;
          }

          for(size_t i=0;i<b[o].size();++i)
          {
            FovCell bc=b[o][i];
            if(bc.delayBlock && bc.range>=ri)continue;
            if(bc.tempBlock && bc.range<ri)continue;
            saBlock=false;
            if(!c.block && r.inRange(bc.r.sa) && r.inRange(bc.r.ea))
            {
              if(debug)
              {
                c.log+=FORMAT("sa=%{:,3},ea=%{:,3} totally blocked by %d,%d:%{:,3},%{:,3}\n",r.saScaled(),r.eaScaled(),px+bc.p.x,py+bc.p.y,bc.r.saScaled(),bc.r.eaScaled());;
              }
              totalBlock=true;
              usedTempBlock=usedTempBlock || bc.tempBlock;
              break;
            }
            if(bc.r.inRange(r.sa)/*  && bc.ea>sa*/)
            {
              if(debug)
              {
                c.log+=FORMAT("sa=%{:,3} blocked by %d,%d:%{:,3},%{:,3}\n",r.saScaled(),px+bc.p.x,py+bc.p.y,bc.r.saScaled(),bc.r.eaScaled());
              }
              r.setSa(bc.r.ea);
              saBlock=true;
              bso=o;bsi=i;
              usedTempBlock=usedTempBlock || bc.tempBlock;
            }
            if(bc.r.inRange(r.ea)/* && bc.sa<ea*/)
            {
              if(debug)
              {
                c.log+=FORMAT("ea=%{:,3} blocked by %d,%d:%{:,3},%{:,3}\n",r.eaScaled(),px+bc.p.x,py+bc.p.y,bc.r.saScaled(),bc.r.eaScaled());
              }
              r.setEa(bc.r.sa);
              beo=o;bei=i;
              usedTempBlock=usedTempBlock || bc.tempBlock;
              if(saBlock)
              {
                totalBlock=true;
                break;
              }
            }
            if(r.closed)break;
          }
          if(r.closed || totalBlock)break;
        }
        if(c.block)
        {
          c.vis=usedTempBlock || (!totalBlock && !r.closed);
          if(debug)
          {
            c.log+=FORMAT("vis r.sa=%{:,3},r.ea=%{:,3} %{}\n",r.saScaled(),r.eaScaled(),r.closed?"closed":"");
          }
        }else
        {
          if(!totalBlock)
          {
            int r1=r.diff();
            int r2=fc.r.diff();
            if(debug)
            {
              c.log+=FORMAT("vis r.sa=%{:,3},r.ea=%{:,3}\ndiff=%d, fc.diff=%d\nmid=%d\n",r.saScaled(),r.eaScaled(),r1,r2,fc.r.middle());
            }
            c.vis=r1>=r2/2 || (r1>=r2/5 && r.inRange(fc.r.middle()));
          }
        }

        if(c.vis && c.block)
        {
          if(c.corners[fc.sac]!=100 || c.corners[fc.eac]!=100)
          {
            fc.r.shrinkCorners(c.corners[fc.sac],c.corners[fc.eac]);
            c.fc=fc;
          }
          int used=0;

          /*if(bso!=-1 && !fc.delayBlock && !fc.tempBlock)
          {
            FovCell& bfc=b[bso][bsi];
            if(!bfc.tempBlock && !bfc.delayBlock)
            {
              used++;
              if(debug)
              {
                c.log+=FORMAT("extended ea of %d,%d from %{:,3} to %{:,3}\n",bfc.p.x+px,bfc.p.y+py,bfc.r.eaScaled(),fc.r.eaScaled());
              }
              bfc.r.ea=fc.r.ea;
            }
          }
          if(beo!=-1 && !fc.delayBlock && !fc.tempBlock)
          {
            FovCell& bfc=b[beo][bei];
            if(!bfc.tempBlock && !bfc.delayBlock)
            {
              used++;
              if(debug)
              {
                c.log+=FORMAT("extended sa of %d,%d from %{:,3} to %{:,3}\n",bfc.p.x+px,bfc.p.y+py,bfc.r.saScaled(),fc.r.saScaled());
              }
              bfc.r.sa=fc.r.sa;
            }
          }*/
          if(used==0)
          {
            b[fc.o1].push_back(fc);
          }
          if(fc.o1!=fc.o2)
          {
            b[fc.o2].push_back(fc);
          }
        }

      }
      for(int i=0;i<8;++i)
      {
        b[i].insert(b[i].end(),t[i].begin(),t[i].end());
        t[i].clear();
      }
    }
    info->setText(FORMAT("bc[]={%{},%{},%{},%{},%{},%{},%{},%{}}",
        b[0].size(),b[1].size(),b[2].size(),b[3].size(),b[4].size(),b[5].size(),b[6].size(),b[7].size()));
    drawMap(m);
  }

//protected:
  typedef std::vector<FovCell> Ring;
  typedef std::vector<Ring> Circle;

  Circle fov;
  std::set<Posi<int> > processed;
 std::vector<FovCell> b[8],t[8];
  bool debug;
};

CircularFov cf;

class MyEventHandler:public EventHandler{
public:
  MyEventHandler(Matrix& argM):m(argM)
  {
    viewAt.x=-1;
    viewAt.y=-1;
  }
  void onActiveChange(bool active)
  {
  }
  void onMouseEvent(MouseEvent& argEvent)
  {
    if(argEvent.eventType==metButtonPress && argEvent.eventButton==1)
    {
      int x=argEvent.x/CELL_SIZE;
      int y=argEvent.y/CELL_SIZE;
      if(x<0 || x>=(int)m[0].size() || y<0 || y>=(int)m.size())return;
      viewAt.x=x;
      viewAt.y=y;
      updateViewAt();
    }
    if(argEvent.eventType==metButtonPress && argEvent.eventButton==3)
    {
      viewAt.x=-1;viewAt.y=-1;
      lsa->setSource(Pos(0,0));
      lsa->setDestination(Pos(10,0));
      lea->setSource(Pos(0,0));
      lea->setDestination(Pos(0,10));
    }
  }
  void updateViewAt()
  {
    int x=viewAt.x;
    int y=viewAt.y;
    if(x==-1 || y==-1)return;
    //printf("select %d,%d\n",x,y);
    char buf[256];
    sprintf(buf,"x=%d,y=%d,r=%d,sa=%.3lf,ea=%.3lf\nsac=%d,eac=%d\n",x,y,m[y][x].r,m[y][x].fc.r.saScaled(),m[y][x].fc.r.eaScaled(),m[y][x].fc.sac,m[y][x].fc.eac);
    std::string txt=buf;
    txt+=m[y][x].log;
    //if(!m[y][x].vis)
    //{
      //Posi<int> bp=m[y][x].;
      //sprintf(buf+len,"\nbsa=%.3lf,bea=%.3lf",m[y][x].bfc.sa/1000000.0,m[y][x].bfc.ea/1000000.0);
      /*
      m[bp.y][bp.x].mark=true;
      m[lastMark.y][lastMark.x].mark=false;
      lastMark=bp;*/
    //}
    info->setText(txt.c_str());
    Pos src=Pos(px*CELL_SIZE+CELL_SIZE/2.0,py*CELL_SIZE+CELL_SIZE/2.0);
    lsa->setSource(src);
    lea->setSource(src);
    Pos p;
    int mr=(sightRadius+1)*CELL_SIZE;
    double sa=m[y][x].fc.r.sa*M_PI/AngleRange::SCALED_PI;
    p.x=src.x+mr*cos(sa);
    p.y=src.y+mr*sin(sa);
    lsa->setDestination(p);
    double ea=m[y][x].fc.r.ea*M_PI/AngleRange::SCALED_PI;
    p.x=src.x+mr*cos(ea);
    p.y=src.y+mr*sin(ea);
    lea->setDestination(p);
  }
  void onKeyboardEvent(KeyboardEvent& argEvent)
  {
    if(argEvent.keySym==keyboard::GK_ESCAPE)
    {
      engine.exitApp();
    }
    if(argEvent.eventType==ketPress)
    {
      int ox=px;
      int oy=py;
      if(argEvent.keySym==keyboard::GK_UP || argEvent.keySym==keyboard::GK_w)py--;
      if(argEvent.keySym==keyboard::GK_DOWN || argEvent.keySym==keyboard::GK_s)py++;
      if(argEvent.keySym==keyboard::GK_LEFT || argEvent.keySym==keyboard::GK_a)px--;
      if(argEvent.keySym==keyboard::GK_RIGHT || argEvent.keySym==keyboard::GK_d)px++;
      if(argEvent.keySym==keyboard::GK_KP_PLUS){sightRadius++;ox=-1;}
      if(argEvent.keySym==keyboard::GK_KP_MINUS && sightRadius>2){sightRadius--;ox=-1;}
      if(px<0 || px>=(int)m[0].size() || py<0 || py>=(int)m.size() || m[py][px].block)
      {
        px=ox;
        py=oy;
      }
      if(ox!=px || oy!=py)
      {
        cf.generateFov(m,sightRadius);
        updateViewAt();
      }
      if(argEvent.keySym==keyboard::GK_t)
      {
        uint32_t start=SDL_GetTicks();
        cf.debug=false;
        for(int i=0;i<1000;++i)
        {
          cf.generateFov(m,sightRadius);
        }
        cf.debug=true;
        uint32_t duration=SDL_GetTicks()-start;
        info->setText(FORMAT("time=%d",duration));
      }
    }
  }
  void onResize(){};
  void onQuit()
  {
    engine.exitApp();
  }

  void onFrameUpdate(int mcsec)
  {
  }
  Matrix& m;
  Posi<int> viewAt;
};



int GliderAppMain(int argc,char* argv[])
{
  kst::Logger::Init("simple.log");
  engine.setVSync(false);
  engine.selectResolution(1024,768,false);
  //engine.selectResolution(800,480,false);
  engine.setResolution();
  engine.setFpsLimit(60);


  //const int W=strlen(testmap[0]);
  //const int H=sizeof(testmap)/sizeof(testmap[0]);
  kst::File f;
  kst::Logger* lg=kst::Logger::getLogger("init");
  try{
    f.ROpen("testmap.txt");
  }catch(std::exception& e)
  {
    LOGERROR(lg,"exception:%s",e.what());
    return 0;
  }
  Matrix m;
  //m.resize(H,Row(W,Cell()));

  //for(int y=0;y<H;++y)
  size_t y=0;
  std::string line;
  while(f.ReadLine(line))
  {
    m.push_back(Row(line.size(),Cell()));
    if(line.size()!=m[0].size())
    {
      LOGERROR(lg,"invalid line[%d] length=%d in testmap.txt, expected %d",y,line.size(),m[0].size());
      return 0;
    }
    for(size_t x=0;x<line.size();++x)
    {
      Cell& c=m[y][x];
      c.tempBlock=line[x]=='*';
      c.delayBlock=line[x]=='|' || line[x]=='-';
      c.block=line[x]=='#' || c.tempBlock || c.delayBlock;
      c.vis=true;
      c.corners[0]=100;
      c.corners[1]=100;
      c.corners[2]=100;
      c.corners[3]=100;
    }
    ++y;
  }
  int W=m[0].size();
  int H=m.size();
  int cornAngle=60;
  for(int y=0;y<H;++y)
  {
    for(int x=0;x<W;++x)
    {
      if(m[y][x].block)
      {
        if(y>0 && x>0 && !m[y-1][x].block && !m[y][x-1].block)
        {
          m[y][x].corners[3]=cornAngle;
        }
        if(y>0 && x<W-1 && !m[y-1][x].block && !m[y][x+1].block)
        {
          m[y][x].corners[2]=cornAngle;
        }
        if(y<H-1 && x<W-1 && !m[y+1][x].block && !m[y][x+1].block)
        {
          m[y][x].corners[1]=cornAngle;
        }
        if(y<H-1 && x>0 && !m[y+1][x].block && !m[y][x-1].block)
        {
          m[y][x].corners[0]=cornAngle;
        }
      }
    }
  }
  px=W/2;
  py=H/2;

  MyEventHandler meh(m);
  engine.assignHandler(&meh);


  engine.enableKeyboardRepeat();
  Scene sc;
  FontRef fnt1=manager.getFont("FSEX300.ttf",16);
  Text* txt=new Text(fnt1,"hello");
  txt->setPosition(Pos(10,10));
  vb=new VertexBuffer;
  lsa=new Line(Pos(0,0),Pos(10,0));
  lea=new Line(Pos(0,0),Pos(0,10));
  info=new Text(fnt1,"Info");
  info->setPosition(Pos(W*CELL_SIZE,0));
  VxVector& v=vb->getVBuf();
  ClrVector& c=vb->getCBuf();
  for(int y=0;y<H;++y)
  {
    for(int x=0;x<W;++x)
    {
      //glider::Rectangle* r=new glider::Rectangle(Rect(x*15,y*15,10,10),Color(1,0.1+x/20+y/20,0.1));
      //sc.addObject(r);
      Rect(x*CELL_SIZE+1,y*CELL_SIZE+1,CELL_SIZE-2,CELL_SIZE-2).pushQuad(v);
      c.push4(Color::gray);
    }
  }
  vb->update();
  cf.prepare(sightRadius);
  cf.generateFov(m,sightRadius);
  drawMap(m);
  sc.addObject(vb);
  sc.addObject(lsa);
  sc.addObject(lea);
  sc.addObject(info);
  //sc.addObject(txt);
  engine.loop(&sc);

//  for(CircularFov::Ring::iterator it=cf.fov[2].begin(),end=cf.fov[2].end();it!=end;++it)
//  {
//    FovCell& fc=*it;
//    printf("%d,%d:%.3lf-%.3lf\n",fc.p.x,fc.p.y,fc.sa/1000000.0,fc.ea/1000000.0);
//  }
//  for(CircularFov::Ring::iterator it=cf.fov[3].begin(),end=cf.fov[3].end();it!=end;++it)
//  {
//    FovCell& fc=*it;
//    printf("%d,%d:%.3lf-%.3lf\n",fc.p.x,fc.p.y,fc.sa/1000000.0,fc.ea/1000000.0);
//  }

  return 0;
}
