草庐IT

c# - 在二维点集中寻找洞?

coder 2024-05-21 原文

我有一套2d points .他们是 X,Y coordinates在标准笛卡尔网格系统上(在本例中为 UTM zone )。我需要在该点集中找到孔,最好具有设置找到这些孔的算法的灵敏度的能力。通常,这些点集非常密集,但有些点集的密度要小得多。

它们是什么,如果有帮助的话,是对田间土壤进行采样的点,以获得农业人员显然认为有用的各种特性。有时在这些点样本中有巨大的岩石或沼泽地或充满小湖泊和池塘。

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

我已经编写了找到外部凹边界多边形的算法,并允许他们设置算法形成的多边形的粗糙度或平滑度的灵敏度。在那次运行之后,他们想找到洞并将这些洞作为凹多边形给他们,我猜在某些情况下可能是凸多边形,但这将是边缘情况而不是常态。

问题是我听说过的关于这个主题的唯一论文是那些想要在太空中找到大片空洞的天文学家所做的论文,而我从来没有找到他们的一篇论文,其中显示了实际算法除了粗略的概念描述之外的任何内容。

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

因此,经过冗长的解释之后,我的问题是:有没有人知道我应该搜索什么来找到最好使用定义明确的算法的论文,或者是否有人知道他们可以指出我的算法可以做到这一点?

任何能帮助我解决这个问题的东西都会非常有用并且非常感谢,即使只是正确的搜索词组也会出现潜在的算法或论文。

这将被实现的语言将是 C#,但从 Mathematica 包到 MATLAB or ASM, C, C++, Python, Java or MathCAD 的任何例子中都有例子。只要示例中没有一些调用像 FindTheHole 这样的调用,等等就可以了。等哪里FindTheHole未定义或专用于实现软件,例如MathCAD示例通常有很多。

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

最佳答案

一些怎么样位图+矢量方法如下:

  • 获取点云区域覆盖的边界框

    如果还不知道,请执行此操作。应该很简单O(N)循环遍历所有点。
  • 创建 map[N][N]该地区的

    它是该区域的“位图”,便于数据密度计算。只需从 area(x,y) -> map[i][j] 创建投影例如简单的规模。网格尺寸 N 也是精度 输出和 必须大于平均点距离!!! 所以每个电池map[][]覆盖区域至少有一个点(如果不在孔区域内)。
  • 计算 map[][] 的每个单元格的数据密度

    像馅饼一样简单map[][].cnt (积分计数器)到 zero并通过简单的计算 O(N)循环在哪里做map[i][j].cnt++所有 points(x,y)
  • 创建未使用区域列表 (map[][].cnt==0)(map[][].cnt<=treshold)

    为简单起见,我用水平线和垂直线来做
  • 分割输出

    只需将同一孔的线组合在一起(相交的...矢量方法),也可以在项目符号 中完成#4 通过洪水填充(位图方法)
  • 多边形化输出

    的所有边缘点H、V 线 相同的孔/组并创建多边形(对它们进行排序,使它们的连接不相交)。有很多关于这个的库、算法和源代码。

  • 我的这种方法的源代码:
    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;
        }
    //---------------------------------------------------------------------------
    

    忽略我的 glview2D东西(这是我的几何图形渲染引擎)
  • view.pnt[]是您的点的动态列表(由随机生成)
  • view.lin[]是动态列表输出 H、V 线 仅用于可视化
  • lin[]是你的线路输出

  • 这是输出:



    我懒得添加多边形化了,现在你可以看到分割有效(着色)。如果您还需要多边形化的帮助,请评论我,但我认为这应该没有任何问题。

    复杂度估计取决于整体空洞覆盖

    但对于大部分代码,它是 O(N)和用于孔搜索/分割 ~O((M^2)+(U^2))在哪里:
  • N是点数
  • M是 map 网格大小
  • U H、V 线 计数取决于孔...
  • M << N, U << M*M

  • 如您所见 3783积分30x30上图中的网格几乎花了9ms在我的设置上

    [Edit1] 玩了一点矢量多边形化



    对于简单的孔很好,但对于更复杂的孔,还有一些问题

    [Edit2] 终于有一点时间了,所以这里是:

    这是用于以更愉快/易于管理的形式进行孔/多边形搜索的简单类:
    //---------------------------------------------------------------------------
    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); }
                }
            }
        }
    //---------------------------------------------------------------------------
    

    你只需要更换我的List<T>模板与 std::list或其他任何(我无法分享的模板)。它是 T 的动态一维数组...
  • List<int> x;int x[]; 相同
  • x.add();将空项目添加到 x
  • x.add(a);将项目添加到 x
  • x.reset()清除数组
  • x.allocate(size)预分配空间以避免在运行缓慢时重新分配
  • x.num是 x[] 中的项目数 ... 项目中使用的大小

  • 在原始代码中只是静态数组,因此如果您感到困惑,请改为检查它。

    现在如何使用它:
    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();
    

    哪里view.pnt[]是输入点列表及其内部:view.pnt[i].p0.p[ 2 ]= { x,y }
    输出在 h.lin[]lin_i0在哪里:
  • h.lin[i] i= < 0,lin_i0 )是内部 H、V 线
  • h.lin[i] i= < lin_i0,h.lin.num )是周长

  • 周边线没有排序并且重复两次,所以只需对它们进行排序并删除重复项(太懒了)。内lin[]id .. id0,1,2,3,...该线路所属的和 i,j map 内的坐标。所以为了正确输出到您的世界坐标中,请执行以下操作:
    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
        }
    
  • 我的 view.lin[]有成员(member):p0,p1,这些点为 view.pnt[]col这是颜色

  • 当孔太小时,我只看到一个问题 (diameter < 3 cells)否则没问题

    [edit4] 重新排序周边线

    这样做而不是这样:
            /* 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;
            }
    

    [Edit5] 如何在内部进行多边形化 holes::holes_end作品

    作为输入,您需要所有 的列表H、V 线 lin[]按孔和密度图分割/分组/排序 map[][] .
  • 穿过所有孔
  • 循环通过加工孔的所有 H、V 线

    创建所有唯一线端点的列表 pnt[] (没有重复)。因此,为每条线取 2 个端点,并查看每个点是否已在列表中。如果不添加它,否则忽略它。
  • 从列表中删除所有非边界点

    因此,通过查看密度 map[][] 中的 4 个邻居来移除所有与非孔区域没有接触的点。
  • 对点进行连通分量分析
  • 套装used=0; p0=-1; p1=-1;对于 pnt[] 中的所有点列表
  • 连接点 distance=1

    遍历所有点 pnt[]used<2这意味着它们尚未完全使用,并且对于每个这样的点搜索 pnt[]再次为另一个这样的点,也有distance = 1到它。这意味着它是它的 4 个邻居,因此应该连接 添加 他们的展位的连接信息(使用 p0p1 未使用的索引 (-1) )并增加两个点的使用量。
  • 尝试用 distance=sqrt(2) 连接点

    几乎与相同#2 除了现在选择 8 个邻居的对角线的距离。这次也避免了闭环,所以不要连接已经连接到它的点。
  • 尝试连接最近的点

    再次与 几乎相同#2,#3 但选择最近的点,同时避免闭环。
  • pnt[] 形成多边形

    所以选择列表中的第一个点并将其添加到多边形中。然后将连接点添加到它(无论您以哪种方式开始 p0p1 )。然后添加它的连接点(不同于之前添加到多边形的点以避免前后循环)。添加尽可能多的点数 pnt[] .
  • 关于c# - 在二维点集中寻找洞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21816562/

    有关c# - 在二维点集中寻找洞?的更多相关文章

    1. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

      几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

    2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

      如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

    3. C# 到 Ruby sha1 base64 编码 - 2

      我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

    4. 基于C#实现简易绘图工具【100010177】 - 2

      C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

    5. Ruby -> 写入二维数组 - 2

      我正在处理http://prepwork.appacademy.io/mini-curriculum/array/中概述的数组问题我正在尝试创建函数my_transpose,它接受一个矩阵并返回其转置。我对写入二维数组感到很困惑!这是一个代码片段,突出了我的困惑。rows=[[0,1,2],[3,4,5],[6,7,8]]columns=Array.new(3,Array.new(3))putscolumns.to_s#Outputisa3x3arrayfilledwithnilcolumns[0][0]=0putscolumns.to_s#Outputis[[0,nil,nil],[

    6. c# - C# 中的 Flatten Ruby 方法 - 2

      我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

    7. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

      我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

    8. c# - Ruby 等效于 C# Linq 聚合方法 - 2

      什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

    9. 最新版人脸识别小程序 图片识别 生成二维码签到 地图上选点进行位置签到 计算签到距离 课程会议活动打卡日常考勤 上课签到打卡考勤口令签到 - 2

      技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进

    10. c# - 先学什么? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭8年前。Improvethisquestion几年前我去学校学习编程,毕业后我找到了一份系统管理方面的工作,这就是我职业生涯的方向。我想重新开始某种开发,并且一直在“玩”C#和ASP.NET,但我已经听到很多关于其他"new"语言的讨论(新的意思是它们是新的)我)喜欢Ruby和F#。我想我想知道我是否在浪费时间学习主要的MS语言,而不是成为一名通才。很长一段时间没有离开开发社区(如果我曾经离开过的话)让我在潮流中挣扎,我不想落在时代的

    随机推荐