Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在二维点集中查找孔?_C#_Algorithm_Geometry_Computational Geometry - Fatal编程技术网

C# 在二维点集中查找孔?

C# 在二维点集中查找孔?,c#,algorithm,geometry,computational-geometry,C#,Algorithm,Geometry,Computational Geometry,我有一组2d点。它们是标准笛卡尔网格系统上的X,Y坐标(在本例中为UTM区域)。我需要找到那个点集中的洞,最好能设置找到这些洞的算法的灵敏度。通常,这些点集非常密集,但有些点集的密度可能会小得多 如果有帮助的话,它们是指对农田土壤进行取样,以确定农业人员显然认为有用的各种性质的点。有时在这些点样中会有巨大的岩石或沼泽地,或布满小湖泊和池塘 他们希望我从点集中找到大致定义这些孔的凹多边形 我已经写了一个算法,可以找到外凹边界多边形,并允许他们设置算法形成的多边形的粗糙度或平滑度的灵敏度。运行之后,

我有一组
2d点
。它们是标准笛卡尔网格系统上的
X,Y坐标
(在本例中为
UTM区域
)。我需要找到那个点集中的洞,最好能设置找到这些洞的算法的灵敏度。通常,这些点集非常密集,但有些点集的密度可能会小得多

如果有帮助的话,它们是指对农田土壤进行取样,以确定农业人员显然认为有用的各种性质的点。有时在这些点样中会有巨大的岩石或沼泽地,或布满小湖泊和池塘

他们希望我从点集中找到大致定义这些孔的凹多边形

我已经写了一个算法,可以找到外凹边界多边形,并允许他们设置算法形成的多边形的粗糙度或平滑度的灵敏度。运行之后,他们希望找到孔,并将这些孔作为凹多边形提供给他们,我猜在某些情况下可能是凸的,但这将是边缘情况,而不是标准

问题是,我所听过的关于这个主题的论文中,只有天文学家的论文,他们想在太空中找到大口袋的空空间,而我从来没有找到过他们的论文中有一篇,除了粗略的概念描述之外,还有实际的算法

我尝试过谷歌和各种学术论文搜索等,但到目前为止我还没有发现多少有用的东西。这让我想知道,也许这类问题有一个名字,但我不知道,所以我在寻找错误的东西或什么

所以在那冗长的解释之后,我的问题是:有没有人知道我应该搜索什么来找到关于这方面的论文,最好是使用定义良好的算法,或者有人知道一种算法可以做到这一点,他们可以指给我看

任何能帮助我解决这个问题的东西都会非常有用,并且非常感激,即使只是正确的搜索短语,也能找到潜在的算法或论文

< >将在C语言中实现的语言,但是从Mathematica包到 Matlab或ASM,C,C++,Python的任何例子都有。Java或MathCAD等。只要示例中没有指向
FindTheHole
等的调用就可以了。其中
FindTheHole
没有定义或是实现软件的专有,例如
MathCAD
示例通常有很多这样的调用

下面是实际点集的两个示例,一个密集点集和一个稀疏点集,以及我需要找到的区域:

我不知道有什么算法是现成的,但有一件事你可以尝试一下(这是我的第一个冲动),那就是类似于无网格方法计算密度的方法,比如

如果可以计算空间中任意点的密度值(而不仅仅是给定的采样点),则可以将孔的边界定义为密度函数的水平集曲线。也就是说,孔是密度下降到某个阈值以下(您可能允许用户配置)的地方。你可以用类似的方法找到边界

如果你想了解这些密度插值函数是如何工作的,如果你愿意的话,我可以(尽我所能)提供

我不知道这到底能起多大作用,但希望它能给你一些指导。

这里有一个想法:

  • 对于每个点
    x
    查找距离
    d(x,y)
    (其中
    y
    是距离
    x
    最近的邻居)。如上所述定义
    f(x)=d(x,y)
  • f(x)
    的均值和方差
  • 找出“异常值”——它们的
    f
    值与平均值相差甚远的点,至少相差α标准差。(\alpha是算法的参数)
  • 这将检测“孔”-您现在需要做的就是设置每个孔的异常值

    • 可以帮上忙。在三角剖分中,输入点不在任何三角形的外接圆内。因此,孔边界点将由覆盖该孔的较大/较宽三角形连接。在您的案例中,三角剖分将有许多大小相似的三角形,以及一些覆盖孔的较大三角形。可能只需过滤较大的过滤器并连接它们就可以找到一个洞。

      这是我的爱好者的非科学解决方案:

      1-使用最小预定义步长(dx,dy)扫描所有2D区域。对于每一步,coord都会找到一个更大的圆圈,里面没有任何点。放弃半径小于预定义大小的所有圆

      2-现在找到所有碰撞圆组,轻松测试距离和半径,在单独的列表中存储和分组。(如果您想了解如何对它们进行分组的更多详细信息,请询问,这非常容易)

      3-找到每组圆的凹边界多边形,这与找到一组点周围的凸多边形的算法非常相似,你的上一个问题向量之间的角度是相关的

      注释

      优化提示:在第1步之前,您可以将所有点存储在栅格矩阵中,从而简化距离计算,并将其限制在给定圆半径的近栅格正方形内

      精度:扫描步长和允许的最小圆半径值越小,精度越高


      不是我自己测试的,但我相信它是有效的。祝你好运

      似乎可以通过图像上的(二进制)数学形态学来解决这个问题

      创建白色图像并绘制所有点。然后将它们“充气”成比正常水平和垂直间距大的矩形。你可以通过所谓的侵蚀操作和rec来实现
      pre_graph = gabriel_graph(point)
      graph = {}
      for a in pre_graph:
          graph[a] = {}
          angle_sorted = sort(pre_graph[a], key=calc_angle_from(a))
          for i,b in enumerate(angle_sorted):
              clockwise = angle_sorted[(i - 1) % len(angle_sorted)]
              counterclockwise = angle_sorted[(i + 1) % len(angle_sorted)]
              graph[a][b] = (clockwise, counterclockwise)
      
      polygons = []
      for A in points:
          for B in graph[A]:
              for direction in [0,1]:
                  polygon = [A]
                  next_point = B:
                  while next != A:
                      polygon.append(next)
                      next_point = graph[A][B][direction]
                  if polygon[0] == min(polygon): # This should avoid duplicates
                      polygons.add(polygon)
      
      void main_compute(int N)
          {
          // cell storage for density computation
          struct _cell
              {
              double x0,x1,y0,y1; // bounding area of points inside cell
              int cnt;            // points inside cell
              _cell(){}; _cell(_cell& a){ *this=a; }; ~_cell(){}; _cell* operator = (const _cell *a) { *this=*a; return this; }; /*_cell* operator = (const _cell &a) { ...copy... return this; };*/
              };
          // line storage for hole area
          struct _line
              {
              double x0,y0,x1,y1; // line edge points
              int id;             // id of hole for segmentation/polygonize
              int i0,i1,j0,j1;    // index in map[][]
              _line(){}; _line(_line& a){ *this=a; }; ~_line(){}; _line* operator = (const _line *a) { *this=*a; return this; }; /*_line* operator = (const _line &a) { ...copy... return this; };*/
              };
      
          int i,j,k,M=N*N;        // M = max N^2 but usualy is much much less so dynamic list will be better
          double mx,my;           // scale to map
          _cell *m;               // cell ptr
          glview2D::_pnt *p;      // point ptr
          double x0,x1,y0,y1;     // used area (bounding box)
          _cell **map=NULL;       // cell grid
          _line *lin=NULL;        // temp line list for hole segmentation
          int lins=0;             // actual usage/size of lin[M]
      
          // scan point cloud for bounding box (if it is known then skip it)
          p=&view.pnt[0];
          x0=p->p[0]; x1=x0;
          y0=p->p[1]; y1=y0;
          for (i=0;i<view.pnt.num;i++)
              {
              p=&view.pnt[i];
              if (x0>p->p[0]) x0=p->p[0];
              if (x1<p->p[0]) x1=p->p[0];
              if (y0>p->p[1]) y0=p->p[1];
              if (y1<p->p[1]) y1=p->p[1];
              }
          // compute scale for coordinate to map index conversion
          mx=double(N)/(x1-x0);   // add avoidance of division by zero if empty point cloud !!!
          my=double(N)/(y1-y0);
          // dynamic allocation of map[N][N],lin[M]
          lin=new _line[M];
          map=new _cell*[N];
          for (i=0;i<N;i++) map[i]=new _cell[N];
          // reset map[N][N]
          for (i=0;i<N;i++)
           for (j=0;j<N;j++)
            map[i][j].cnt=0;
          // compute point cloud density
          for (k=0;k<view.pnt.num;k++)
              {
              p=&view.pnt[k];
              i=double((p->p[0]-x0)*mx); if (i<0) i=0; if (i>=N) i=N-1;
              j=double((p->p[1]-y0)*my); if (j<0) j=0; if (j>=N) j=N-1;
              m=&map[i][j];
              if (!m->cnt)
                  {
                  m->x0=p->p[0];
                  m->x1=p->p[0];
                  m->y0=p->p[1];
                  m->y1=p->p[1];
                  }
              if (m->cnt<0x7FFFFFFF) m->cnt++;    // avoid overflow
              if (m->x0>p->p[0]) m->x0=p->p[0];
              if (m->x1<p->p[0]) m->x1=p->p[0];
              if (m->y0>p->p[1]) m->y0=p->p[1];
              if (m->y1<p->p[1]) m->y1=p->p[1];
              }
          // find holes (map[i][j].cnt==0) or (map[i][j].cnt<=treshold)
          // and create lin[] list of H,V lines covering holes
          for (j=0;j<N;j++) // search lines
              {
              for (i=0;i<N;)
                  {
                  int i0,i1;
                  for (;i<N;i++) if (map[i][j].cnt==0) break; i0=i-1; // find start of hole
                  for (;i<N;i++) if (map[i][j].cnt!=0) break; i1=i;   // find end of hole
                  if (i0< 0) continue;                // skip bad circumstances (edges or no hole found)
                  if (i1>=N) continue;
                  if (map[i0][j].cnt==0) continue;
                  if (map[i1][j].cnt==0) continue;
                  _line l;
                  l.i0=i0; l.x0=map[i0][j].x1;
                  l.i1=i1; l.x1=map[i1][j].x0;
                  l.j0=j ; l.y0=0.25*(map[i0][j].y0+map[i0][j].y1+map[i1][j].y0+map[i1][j].y1);
                  l.j1=j ; l.y1=l.y0;
                  lin[lins]=l; lins++;
                  }
              }
          for (i=0;i<N;i++) // search columns
              {
              for (j=0;j<N;)
                  {
                  int j0,j1;
                  for (;j<N;j++) if (map[i][j].cnt==0) break; j0=j-1; // find start of hole
                  for (;j<N;j++) if (map[i][j].cnt!=0) break; j1=j;   // find end of hole
                  if (j0< 0) continue;                // skip bad circumstances (edges or no hole found)
                  if (j1>=N) continue;
                  if (map[i][j0].cnt==0) continue;
                  if (map[i][j1].cnt==0) continue;
                  _line l;
                  l.i0=i ; l.y0=map[i][j0].y1;
                  l.i1=i ; l.y1=map[i][j1].y0;
                  l.j0=j0; l.x0=0.25*(map[i][j0].x0+map[i][j0].x1+map[i][j1].x0+map[i][j1].x1);
                  l.j1=j1; l.x1=l.x0;
                  lin[lins]=l; lins++;
                  }
              }
          // segmentate lin[] ... group lines of the same hole together by lin[].id
          // segmentation based on vector lines data
          // you can also segmentate the map[][] directly as bitmap during hole detection
          for (i=0;i<lins;i++) lin[i].id=i;   // all lines are separate
          for (;;)                            // join what you can
              {
              int e=0,i0,i1;
              _line *a,*b;
              for (a=lin,i=0;i<lins;i++,a++)
                  {
                  for (b=a,j=i;j<lins;j++,b++)
                   if (a->id!=b->id)
                      {
                      // do 2D lines a,b intersect ?
                      double xx0,yy0,xx1,yy1;
                      double kx0,ky0,dx0,dy0,t0;
                      double kx1,ky1,dx1,dy1,t1;
                      double x0=a->x0,y0=a->y0;
                      double x1=a->x1,y1=a->y1;
                      double x2=b->x0,y2=b->y0;
                      double x3=b->x1,y3=b->y1;
                      // discart lines with non intersecting bound rectangles
                      double a0,a1,b0,b1;
                      if (x0<x1) { a0=x0; a1=x1; } else { a0=x1; a1=x0; }
                      if (x2<x3) { b0=x2; b1=x3; } else { b0=x3; b1=x2; }
                      if (a1<b0) continue;
                      if (a0>b1) continue;
                      if (y0<y1) { a0=y0; a1=y1; } else { a0=y1; a1=y0; }
                      if (y2<y3) { b0=y2; b1=y3; } else { b0=y3; b1=y2; }
                      if (a1<b0) continue;
                      if (a0>b1) continue;
                      // compute intersection
                      kx0=x0; ky0=y0; dx0=x1-x0; dy0=y1-y0;
                      kx1=x2; ky1=y2; dx1=x3-x2; dy1=y3-y2;
                      t1=divide(dx0*(ky0-ky1)+dy0*(kx1-kx0),(dx0*dy1)-(dx1*dy0));
                      xx1=kx1+(dx1*t1);
                      yy1=ky1+(dy1*t1);
                      if (fabs(dx0)>=fabs(dy0)) t0=divide(kx1-kx0+(dx1*t1),dx0);
                      else                      t0=divide(ky1-ky0+(dy1*t1),dy0);
                      xx0=kx0+(dx0*t0);
                      yy0=ky0+(dy0*t0);
                      // check if intersection exists
                      if (fabs(xx1-xx0)>1e-6) continue;
                      if (fabs(yy1-yy0)>1e-6) continue;
                      if ((t0<0.0)||(t0>1.0)) continue;
                      if ((t1<0.0)||(t1>1.0)) continue;
                      // if yes ... intersection point = xx0,yy0
                      e=1; break;
                      }
                  if (e) break;                       // join found ... stop searching
                  }
              if (!e) break;                          // no join found ... stop segmentation
              i0=a->id;                               // joid ids ... rename i1 to i0
              i1=b->id;
              for (a=lin,i=0;i<lins;i++,a++)
               if (a->id==i1)
                a->id=i0;
              }
      
          // visualize lin[]
          for (i=0;i<lins;i++)
              {
              glview2D::_lin l;
              l.p0.p[0]=lin[i].x0;
              l.p0.p[1]=lin[i].y0;
              l.p1.p[0]=lin[i].x1;
              l.p1.p[1]=lin[i].y1;
      //      l.col=0x0000FF00;
              l.col=(lin[i].id*0x00D00C10A)+0x00800000;   // color is any function of ID
              view.lin.add(l);
              }
      
          // dynamic deallocation of map[N][N],lin[M]
          for (i=0;i<N;i++) delete[] map[i];
          delete[] map;
          delete[] lin;
          }
      //---------------------------------------------------------------------------
      
      //---------------------------------------------------------------------------
      class holes
          {
      public:
          int xs,ys,n;            // cell grid x,y - size  and points count
          int **map;              // points density map[xs][ys]
                                  // i=(x-x0)*g2l;    x=x0+(i*l2g);
                                  // j=(y-y0)*g2l;    y=y0+(j*l2g);
          double mg2l,ml2g;       // scale to/from global/map space   (x,y) <-> map[i][j]
          double x0,x1,y0,y1;     // used area (bounding box)
      
          struct _line
              {
              int id;             // id of hole for segmentation/polygonize
              int i0,i1,j0,j1;    // index in map[][]
              _line(){}; _line(_line& a){ *this=a; }; ~_line(){}; _line* operator = (const _line *a) { *this=*a; return this; }; /*_line* operator = (const _line &a) { ...copy... return this; };*/
              };
          List<_line> lin;
          int lin_i0;             // start index for perimeter lines (smaller indexes are the H,V lines inside hole)
      
          struct _point
              {
              int i,j;            // index in map[][]
              int p0,p1;          // previous next point
              int used;
              _point(){}; _point(_point& a){ *this=a; }; ~_point(){}; _point* operator = (const _point *a) { *this=*a; return this; }; /*_point* operator = (const _point &a) { ...copy... return this; };*/
              };
          List<_point> pnt;
      
          // class init and internal stuff
          holes()  { xs=0; ys=0; n=0; map=NULL; mg2l=1.0; ml2g=1.0;  x0=0.0; y0=0.0; x1=0.0; y1=0.0; lin_i0=0; };
          holes(holes& a){ *this=a; };
          ~holes() { _free(); };
          holes* operator = (const holes *a) { *this=*a; return this; };
          holes* operator = (const holes &a)
              {
              xs=0; ys=0; n=a.n; map=NULL;
              mg2l=a.mg2l; x0=a.x0; x1=a.x1;
              ml2g=a.ml2g; y0=a.y0; y1=a.y1;
              _alloc(a.xs,a.ys);
              for (int i=0;i<xs;i++)
              for (int j=0;j<ys;j++) map[i][j]=a.map[i][j];
              return this;
              }
          void _free() { if (map) { for (int i=0;i<xs;i++) if (map[i]) delete[] map[i]; delete[] map; } xs=0; ys=0; }
          void _alloc(int _xs,int _ys) { int i=0; _free(); xs=_xs; ys=_ys; map=new int*[xs]; if (map) for (i=0;i<xs;i++) { map[i]=new int[ys]; if (map[i]==NULL) { i=-1; break; } } else i=-1; if (i<0) _free(); }
      
          // scann boundary box interface
          void scann_beg();
          void scann_pnt(double x,double y);
          void scann_end();
      
          // dynamic allocations
          void cell_size(double sz);      // compute/allocate grid from grid cell size = sz x sz
      
          // scann holes interface
          void holes_beg();
          void holes_pnt(double x,double y);
          void holes_end();
      
          // global(x,y) <- local map[i][j] + half cell offset
          inline void l2g(double &x,double &y,int i,int j) { x=x0+((double(i)+0.5)*ml2g); y=y0+((double(j)+0.5)*ml2g); }
          // local map[i][j] <- global(x,y)
          inline void g2l(int &i,int &j,double x,double y) { i=     double((x-x0) *mg2l); j=     double((y-y0) *mg2l); }
          };
      //---------------------------------------------------------------------------
      void holes::scann_beg()
          {
          x0=0.0; y0=0.0; x1=0.0; y1=0.0; n=0;
          }
      //---------------------------------------------------------------------------
      void holes::scann_pnt(double x,double y)
          {
          if (!n) { x0=x; y0=y; x1=x; y1=y; }
          if (n<0x7FFFFFFF) n++;  // avoid overflow
          if (x0>x) x0=x; if (x1<x) x1=x;
          if (y0>y) y0=y; if (y1<y) y1=y;
          }
      //---------------------------------------------------------------------------
      void holes::scann_end()
          {
          }
      //---------------------------------------------------------------------------
      void holes::cell_size(double sz)
          {
          int x,y;
          if (sz<1e-6) sz=1e-6;
          x=ceil((x1-x0)/sz);
          y=ceil((y1-y0)/sz);
          _alloc(x,y);
          ml2g=sz; mg2l=1.0/sz;
          }
      //---------------------------------------------------------------------------
      void holes::holes_beg()
          {
          int i,j;
          for (i=0;i<xs;i++)
           for (j=0;j<ys;j++)
            map[i][j]=0;
          }
      //---------------------------------------------------------------------------
      void holes::holes_pnt(double x,double y)
          {
          int i,j;
          g2l(i,j,x,y);
          if ((i>=0)&&(i<xs))
           if ((j>=0)&&(j<ys))
            if (map[i][j]<0x7FFFFFFF) map[i][j]++;    // avoid overflow
          }
      //---------------------------------------------------------------------------
      void holes::holes_end()
          {
          int i,j,e,i0,i1;
          List<int> ix;       // hole lines start/stop indexes for speed up the polygonization
          _line *a,*b,l;
          _point *aa,*bb,p;
          lin.num=0; lin_i0=0;// clear lines
          ix.num=0;           // clear indexes
      
          // find holes (map[i][j].cnt==0) or (map[i][j].cnt<=treshold)
          // and create lin[] list of H,V lines covering holes
          for (j=0;j<ys;j++) // search lines
           for (i=0;i<xs;)
              {
              int i0,i1;
              for (;i<xs;i++) if (map[i][j]==0) break; i0=i-1;    // find start of hole
              for (;i<xs;i++) if (map[i][j]!=0) break; i1=i;      // find end of hole
              if (i0<  0) continue;               // skip bad circumstances (edges or no hole found)
              if (i1>=xs) continue;
              if (map[i0][j]==0) continue;
              if (map[i1][j]==0) continue;
              l.i0=i0;
              l.i1=i1;
              l.j0=j ;
              l.j1=j ;
              l.id=-1;
              lin.add(l);
              }
          for (i=0;i<xs;i++) // search columns
           for (j=0;j<ys;)
              {
              int j0,j1;
              for (;j<ys;j++) if (map[i][j]==0) break; j0=j-1;    // find start of hole
              for (;j<ys;j++) if (map[i][j]!=0) break; j1=j  ;    // find end of hole
              if (j0<  0) continue;               // skip bad circumstances (edges or no hole found)
              if (j1>=ys) continue;
              if (map[i][j0]==0) continue;
              if (map[i][j1]==0) continue;
              l.i0=i ;
              l.i1=i ;
              l.j0=j0;
              l.j1=j1;
              l.id=-1;
              lin.add(l);
              }
          // segmentate lin[] ... group lines of the same hole together by lin[].id
          // segmentation based on vector lines data
          // you can also segmentate the map[][] directly as bitmap during hole detection
          for (i=0;i<lin.num;i++) lin[i].id=i;    // all lines are separate
          for (;;)                            // join what you can
              {
              for (e=0,a=lin.dat,i=0;i<lin.num;i++,a++)
                  {
                  for (b=a,j=i;j<lin.num;j++,b++)
                   if (a->id!=b->id)
                      {
                      // if a,b not intersecting or neighbouring
                      if (a->i0>b->i1) continue;
                      if (b->i0>a->i1) continue;
                      if (a->j0>b->j1) continue;
                      if (b->j0>a->j1) continue;
                      // if they do mark e for join groups
                      e=1; break;
                      }
                  if (e) break;                       // join found ... stop searching
                  }
              if (!e) break;                          // no join found ... stop segmentation
              i0=a->id;                               // joid ids ... rename i1 to i0
              i1=b->id;
              for (a=lin.dat,i=0;i<lin.num;i++,a++)
               if (a->id==i1)
                a->id=i0;
              }
          // sort lin[] by id
          for (e=1;e;) for (e=0,a=&lin[0],b=&lin[1],i=1;i<lin.num;i++,a++,b++)
           if (a->id>b->id) { l=*a; *a=*b; *b=l; e=1; }
          // re id lin[] and prepare start/stop indexes
          for (i0=-1,i1=-1,a=&lin[0],i=0;i<lin.num;i++,a++)
           if (a->id==i1) a->id=i0;
            else { i0++; i1=a->id; a->id=i0; ix.add(i); }
          ix.add(lin.num);
      
          // polygonize
          lin_i0=lin.num;
          for (j=1;j<ix.num;j++)  // process hole
              {
              i0=ix[j-1]; i1=ix[j];
              // create border pnt[] list (unique points only)
              pnt.num=0; p.used=0; p.p0=-1; p.p1=-1;
              for (a=&lin[i0],i=i0;i<i1;i++,a++)
                  {
                  p.i=a->i0;
                  p.j=a->j0;
                  map[p.i][p.j]=0;
                  for (aa=&pnt[0],e=0;e<pnt.num;e++,aa++)
                   if ((aa->i==p.i)&&(aa->j==p.j)) { e=-1; break; }
                  if (e>=0) pnt.add(p);
                  p.i=a->i1;
                  p.j=a->j1;
                  map[p.i][p.j]=0;
                  for (aa=&pnt[0],e=0;e<pnt.num;e++,aa++)
                   if ((aa->i==p.i)&&(aa->j==p.j)) { e=-1; break; }
                  if (e>=0) pnt.add(p);
                  }
              // mark not border points
              for (aa=&pnt[0],i=0;i<pnt.num;i++,aa++)
               if (!aa->used)                     // ignore marked points
                if ((aa->i>0)&&(aa->i<xs-1))      // ignore map[][] border points
                 if ((aa->j>0)&&(aa->j<ys-1))
                  {                               // ignore if any non hole cell around
                  if (map[aa->i-1][aa->j-1]>0) continue;
                  if (map[aa->i-1][aa->j  ]>0) continue;
                  if (map[aa->i-1][aa->j+1]>0) continue;
                  if (map[aa->i  ][aa->j-1]>0) continue;
                  if (map[aa->i  ][aa->j+1]>0) continue;
                  if (map[aa->i+1][aa->j-1]>0) continue;
                  if (map[aa->i+1][aa->j  ]>0) continue;
                  if (map[aa->i+1][aa->j+1]>0) continue;
                  aa->used=1;
                  }
              // delete marked points
              for (aa=&pnt[0],e=0,i=0;i<pnt.num;i++,aa++)
               if (!aa->used) { pnt[e]=*aa; e++; } pnt.num=e;
      
              // connect neighbouring points distance=1
              for (i0=   0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
               if (aa->used<2)
                for (i1=i0+1,bb=&pnt[i1];i1<pnt.num;i1++,bb++)
                 if (bb->used<2)
                  {
                  i=aa->i-bb->i; if (i<0) i=-i; e =i;
                  i=aa->j-bb->j; if (i<0) i=-i; e+=i;
                  if (e!=1) continue;
                  aa->used++; if (aa->p0<0) aa->p0=i1; else aa->p1=i1;
                  bb->used++; if (bb->p0<0) bb->p0=i0; else bb->p1=i0;
                  }
              // try to connect neighbouring points distance=sqrt(2)
              for (i0=   0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
               if (aa->used<2)
                for (i1=i0+1,bb=&pnt[i1];i1<pnt.num;i1++,bb++)
                 if (bb->used<2)
                  if ((aa->p0!=i1)&&(aa->p1!=i1))
                   if ((bb->p0!=i0)&&(bb->p1!=i0))
                  {
                  if ((aa->used)&&(aa->p0==bb->p0)) continue; // avoid small closed loops
                  i=aa->i-bb->i; if (i<0) i=-i; e =i*i;
                  i=aa->j-bb->j; if (i<0) i=-i; e+=i*i;
                  if (e!=2) continue;
                  aa->used++; if (aa->p0<0) aa->p0=i1; else aa->p1=i1;
                  bb->used++; if (bb->p0<0) bb->p0=i0; else bb->p1=i0;
                  }
              // try to connect to closest point
              int ii,dd;
              for (i0=   0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
               if (aa->used<2)
                  {
                  for (ii=-1,i1=i0+1,bb=&pnt[i1];i1<pnt.num;i1++,bb++)
                   if (bb->used<2)
                    if ((aa->p0!=i1)&&(aa->p1!=i1))
                     if ((bb->p0!=i0)&&(bb->p1!=i0))
                      {
                      i=aa->i-bb->i; if (i<0) i=-i; e =i*i;
                      i=aa->j-bb->j; if (i<0) i=-i; e+=i*i;
                      if ((ii<0)||(e<dd)) { ii=i1; dd=e; }
                      }
                  if (ii<0) continue;
                  i1=ii; bb=&pnt[i1];
                  aa->used++; if (aa->p0<0) aa->p0=i1; else aa->p1=i1;
                  bb->used++; if (bb->p0<0) bb->p0=i0; else bb->p1=i0;
                  }
      
              // add connected points to lin[] ... this is hole perimeter !!!
              // lines are 2 x duplicated so some additional code for sort the order of line swill be good idea
              l.id=lin[ix[j-1]].id;
              for (i0=0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
                  {
                  l.i0=aa->i;
                  l.j0=aa->j;
                  // [edit3] this avoid duplicating lines
                  if (aa->p0>i0) { bb=&pnt[aa->p0]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  if (aa->p1>i0) { bb=&pnt[aa->p1]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  //if (aa->p0>=0) { bb=&pnt[aa->p0]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  //if (aa->p1>=0) { bb=&pnt[aa->p1]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  }
              }
          }
      //---------------------------------------------------------------------------
      
      h.scann_beg(); for (i=0;i<view.pnt.num;i++) { p=view.pnt[i].p0.p; h.scann_pnt(p[0],p[1]); } h.scann_end();
      h.cell_size(2.5);
      h.holes_beg(); for (i=0;i<view.pnt.num;i++) { p=view.pnt[i].p0.p; h.holes_pnt(p[0],p[1]); } h.holes_end();
      
      int i,j;
      holes h;                // holes class
      double *p;              // input point list ptr
      
      h.scann_beg(); for (i=0;i<view.pnt.num;i++) { p=view.pnt[i].p0.p; h.scann_pnt(p[0],p[1]); } h.scann_end();
      h.cell_size(2.5);
      h.holes_beg(); for (i=0;i<view.pnt.num;i++) { p=view.pnt[i].p0.p; h.holes_pnt(p[0],p[1]); } h.holes_end();
      
      DWORD coltab[]=
          {
          0x000000FF,
          0x0000FF00,
          0x00FF0000,
          0x0000FFFF,
          0x00FFFF00,
          0x00FF00FF,
          0x00FFFFFF,
          0x00000088,
          0x00008800,
          0x00880000,
          0x00008888,
          0x00888800,
          0x00880088,
          0x00888888,
          };
      
      for (i=0;i<h.lin.num;i++)                   // draw lin[]
          {
          glview2D::_lin a;
          holes::_line *b=&h.lin[i];
          h.l2g(a.p0.p[0],a.p0.p[1],b->i0,b->j0);
          h.l2g(a.p1.p[0],a.p1.p[1],b->i1,b->j1);
          if (i<h.lin_i0) // H,V lines inside hole(b->id) .. gray  [edit3] was <= which is wrong and miss-color first perimeter line
              {
              a.col=0x00808080;
              }
          else{               // hole(b->id) perimeter lines ... each hole different collor
              if ((b->id>=0)&&(b->id<14)) a.col=coltab[b->id];
              if (b->id==-1) a.col=0x00FFFFFF;    // special debug lines
              if (b->id==-2) a.col=0x00AA8040;    // special debug lines
              }
          view.lin.add(a); // here draw your line or add it to your polygon instead
          }
      
              /* add connected points to lin[] ... this is hole perimeter !!!
              // lines are 2 x duplicated so some additional code for sort the order of line swill be good idea
              l.id=lin[ix[j-1]].id;
              for (i0=0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
                  {
                  l.i0=aa->i;
                  l.j0=aa->j;
                  // [edit3] this avoid duplicating lines
                  if (aa->p0>i0) { bb=&pnt[aa->p0]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  if (aa->p1>i0) { bb=&pnt[aa->p1]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  //if (aa->p0>=0) { bb=&pnt[aa->p0]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  //if (aa->p1>=0) { bb=&pnt[aa->p1]; l.i1=bb->i; l.j1=bb->j; lin.add(l); }
                  } */
      
          // add connected points to lin[] ... this is hole perimeter !!!
          l.id=lin[ix[j-1]].id;
          // add index of points instead points
          int lin_i1=lin.num;
          for (i0=0,aa=&pnt[i0];i0<pnt.num;i0++,aa++)
              {
              l.i0=i0;
              if (aa->p0>i0) { l.i1=aa->p0; lin.add(l); }
              if (aa->p1>i0) { l.i1=aa->p1; lin.add(l); }
              }
          // reorder perimeter lines
          for (i0=lin_i1,a=&lin[i0];i0<lin.num-1;i0++,a++)
           for (i1=i0+1  ,b=&lin[i1];i1<lin.num  ;i1++,b++)
              {
              if (a->i1==b->i0) { a++; l=*a; *a=*b; *b=l;                                a--; break; }
              if (a->i1==b->i1) { a++; l=*a; *a=*b; *b=l; i=a->i0; a->i0=a->i1; a->i1=i; a--; break; }
              }
          // convert point indexes to points
          for (i0=lin_i1,a=&lin[i0];i0<lin.num;i0++,a++)
              {
              bb=&pnt[a->i0]; a->i0=bb->i; a->j0=bb->j;
              bb=&pnt[a->i1]; a->i1=bb->i; a->j1=bb->j;
              }