Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.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_Arcgis_Shapefile_Polygons - Fatal编程技术网

C# 实现一种检测自相交多边形的蛮力算法

C# 实现一种检测自相交多边形的蛮力算法,c#,algorithm,arcgis,shapefile,polygons,C#,Algorithm,Arcgis,Shapefile,Polygons,我最初实现了Hoey-Shamos算法,但是它对于未来的可维护性来说太复杂了(我对此没有发言权),而且它没有正确地报告,所以我将使用一个优化的暴力算法 我的问题是:如何优化此代码以使其可用 目前,我的代码包含一个嵌套的for循环,将同一列表迭代两次 编辑:将行转换为哈希集并使用两个foreach循环。。。从扫描10000次中减少了大约45秒。这还不够 foreach (Line2D g in lines) { foreach (Line2D h in lin

我最初实现了Hoey-Shamos算法,但是它对于未来的可维护性来说太复杂了(我对此没有发言权),而且它没有正确地报告,所以我将使用一个优化的暴力算法

我的问题是:如何优化此代码以使其可用

目前,我的代码包含一个嵌套的for循环,将同一列表迭代两次

编辑:将行转换为哈希集并使用两个foreach循环。。。从扫描10000次中减少了大约45秒。这还不够

foreach (Line2D g in lines)
{                   
foreach (Line2D h in lines)
{
    if (g.intersectsLine(h))
    {
        return false;
    }
}                  

 } // end 'lines' for each loop
如果我强制我的“intersectsLine()”方法返回false(出于测试目的),扫描10000条记录(我有700000条记录)仍然需要8秒钟。这太长了,所以我需要优化这段代码

在与所有其他行进行比较后,我尝试从列表中删除行,但是存在准确性问题(不知道为什么),并且速度增加几乎不明显

这是我的交叉线方法。我找到了另一种方法,但在所有方法调用和诸如此类的情况下,它看起来会更慢。在我看来,计算坡度似乎不需要太多的计算(如果我错了,请纠正我?)

公共布尔交叉线(Line2D比较线)
{
//调整线(比较线);
如果(此.Equals)(比较线)||
P2.等于(比较线P1)||
P1.等于(比较线P2))
{
返回false;
}
双firstLineSlopeX、firstLineSlopeY、secondLineSlopeX、secondLineSlopeY;
firstLineSlopeX=X2-X1;
firstLineSlopeY=Y2-Y1;
secondLineSlopeX=comparedLine.X2-comparedLine.X1;
secondLineSlopeY=comparedLine.Y2-comparedLine.Y1;
双s,t;
s=(-firstLineSlopeY*(X1-比较行.X1)+firstLineSlopeX*(Y1-比较行.Y1))/(-secondLineSlopeX*第一行slopey+第一行slopex*第二行slopey);
t=(secondLineSlopeX*(Y1-比较线.Y1)-secondLineSlopeY*(X1-比较线.X1))/(-secondLineSlopeX*firstLineSlopeY+firstLineSlopeX*secondLineSlopeY);

如果(s>=0&&s=0&&t有两件事需要检查:

  • 闭合多边形由点的循环序列组成
    • 如果此序列中存在同一点不止一次,则该点不是自交多边形
    • 请注意,第一个点和最后一个点可以相同(多边形表示不同),在这种情况下,该点必须存在两次以上的棕褐色
  • 检查多边形的所有非相邻线是否相交
    • 相邻线路不共享任何点
    • 如果有交集,则多边形是自交的

  • 您当前的暴力算法是O(n^2)。对于两个70000线多边形,这几乎是100亿次操作的一个因素,更不用说700000个其他多边形了。显然,仅仅代码优化是不够的,所以您需要某种算法优化来降低O(n^2)没有过分复杂

    O(n^2)来自蛮力算法中的嵌套循环,每个循环都以
    n
    为边界,使其成为O(n*n)。改进这一点的最简单方法是找到某种方法来减少内部循环,使其不受
    n
    的约束或依赖。因此,我们需要找到某种方法对内部行列表进行排序或重新排序,以检查外部行,从而只需扫描完整列表的一部分

    我所采用的方法利用了这样一个事实,即如果两条线段相交,那么它们的X值范围必须相互重叠。请注意,这并不意味着它们相交,但如果它们的X范围不重叠,那么它们就不能相交,因此无需相互检查。(Y值范围也是如此,但一次只能利用一个维度)

    这种方法的优点是,这些X范围可用于对直线的端点进行排序,而这些端点又可作为检查直线相交的起点和终点

    因此,我们具体要做的是定义一个自定义类(
    endpointEntry
    ),它表示直线两点的高X值或低X值。这些端点都放在相同的列表结构中,然后根据它们的X值进行排序

    然后我们实现了一个外循环,在这个外循环中,我们扫描整个列表,就像蛮力算法一样。但是,我们的内循环有很大的不同。我们不是重新扫描整个列表以检查交叉点,而是从外循环的线和端点的高X值端点开始向下扫描排序的端点列表当我们通过同一条线的低X值端点下方时,它就会消失。这样,我们只检查X值范围与外循环线重叠的线

    好的,下面是一个c#类演示我的方法:

    class CheckPolygon2
    {
        // internal supporting classes
        class endpointEntry
        {
            public double XValue;
            public bool isHi;
            public Line2D line;
            public double hi;
            public double lo;
            public endpointEntry fLink;
            public endpointEntry bLink;
        }
        class endpointSorter : IComparer<endpointEntry>
        {
            public int Compare(endpointEntry c1, endpointEntry c2)
            {
                // sort values on XValue, descending
                if (c1.XValue > c2.XValue) { return -1; }
                else if (c1.XValue < c2.XValue) { return 1; }
                else // must be equal, make sure hi's sort before lo's
                    if (c1.isHi && !c2.isHi) { return -1; }
                    else if (!c1.isHi && c2.isHi) { return 1; }
                    else { return 0; }
            }
        }
    
        public bool CheckForCrossing(List<Line2D> lines)
        {
            List<endpointEntry> pts = new List<endpointEntry>(2 * lines.Count);
    
            // Make endpoint objects from the lines so that we can sort all of the
            // lines endpoints.
            foreach (Line2D lin in lines)
            {
                // make the endpoint objects for this line
                endpointEntry hi, lo;
                if (lin.P1.X < lin.P2.X)
                {
                    hi = new endpointEntry() { XValue = lin.P2.X, isHi = true, line = lin, hi = lin.P2.X, lo = lin.P1.X };
                    lo = new endpointEntry() { XValue = lin.P1.X, isHi = false, line = lin, hi = lin.P1.X, lo = lin.P2.X };
                }
                else
                {
                    hi = new endpointEntry() { XValue = lin.P1.X, isHi = true, line = lin, hi = lin.P1.X, lo = lin.P2.X };
                    lo = new endpointEntry() { XValue = lin.P2.X, isHi = false, line = lin, hi = lin.P2.X, lo = lin.P1.X };
                }
                // add them to the sort-list
                pts.Add(hi);
                pts.Add(lo);
            }
    
            // sort the list
            pts.Sort(new endpointSorter());
    
            // sort the endpoint forward and backward links
            endpointEntry prev = null;
            foreach (endpointEntry pt in pts)
            {
                if (prev != null)
                {
                    pt.bLink = prev;
                    prev.fLink = pt;
                }
                prev = pt;
            }
    
            // NOW, we are ready to look for intersecting lines
            foreach (endpointEntry pt in pts)
            {
                // for every Hi endpoint ...
                if (pt.isHi)
                {
                    // check every other line whose X-range is either wholly 
                    // contained within our own, or that overlaps the high 
                    // part of ours.  The other two cases of overlap (overlaps 
                    // our low end, or wholly contains us) is covered by hi 
                    // points above that scan down to check us.
    
                    // scan down for each lo-endpoint below us checking each's 
                    // line for intersection until we pass our own lo-X value
                    for (endpointEntry pLo = pt.fLink; (pLo != null) && (pLo.XValue >= pt.lo); pLo = pLo.fLink)
                    {
                        // is this a lo-endpoint?
                        if (!pLo.isHi)
                        {
                            // check its line for intersection
                            if (pt.line.intersectsLine(pLo.line))
                                return true;
                        }
                    }
                }
            }
    
            return false;
        }
    }
    
    打破这一点,旧式的
    for
    循环说明符有三个部分:初始化、条件和增量-减量。初始化表达式
    endpointEntry pLo=pt.fLink;
    使用列表中当前点的前向链接初始化
    pLo
    。即列表中的下一个点,降序排序顺序

    然后执行内部循环的主体。然后应用增量-减量
    pLo=pLo.fLink
    ,它只需使用前向链接(
    pLo.fLink
    )将内部循环的当前点(
    pLo
    )设置为下一个较低的点,从而推进循环

    最后,它在测试循环条件
    (pLo!=null)和&(pLo.XValue>=pt.lo)
    后循环,只要新点不是null(这意味着我们在列表的末尾)只要新点的
    XValue
    仍然大于或等于外环当前点的低X值。第二个条件确保
    class CheckPolygon2
    {
        // internal supporting classes
        class endpointEntry
        {
            public double XValue;
            public bool isHi;
            public Line2D line;
            public double hi;
            public double lo;
            public endpointEntry fLink;
            public endpointEntry bLink;
        }
        class endpointSorter : IComparer<endpointEntry>
        {
            public int Compare(endpointEntry c1, endpointEntry c2)
            {
                // sort values on XValue, descending
                if (c1.XValue > c2.XValue) { return -1; }
                else if (c1.XValue < c2.XValue) { return 1; }
                else // must be equal, make sure hi's sort before lo's
                    if (c1.isHi && !c2.isHi) { return -1; }
                    else if (!c1.isHi && c2.isHi) { return 1; }
                    else { return 0; }
            }
        }
    
        public bool CheckForCrossing(List<Line2D> lines)
        {
            List<endpointEntry> pts = new List<endpointEntry>(2 * lines.Count);
    
            // Make endpoint objects from the lines so that we can sort all of the
            // lines endpoints.
            foreach (Line2D lin in lines)
            {
                // make the endpoint objects for this line
                endpointEntry hi, lo;
                if (lin.P1.X < lin.P2.X)
                {
                    hi = new endpointEntry() { XValue = lin.P2.X, isHi = true, line = lin, hi = lin.P2.X, lo = lin.P1.X };
                    lo = new endpointEntry() { XValue = lin.P1.X, isHi = false, line = lin, hi = lin.P1.X, lo = lin.P2.X };
                }
                else
                {
                    hi = new endpointEntry() { XValue = lin.P1.X, isHi = true, line = lin, hi = lin.P1.X, lo = lin.P2.X };
                    lo = new endpointEntry() { XValue = lin.P2.X, isHi = false, line = lin, hi = lin.P2.X, lo = lin.P1.X };
                }
                // add them to the sort-list
                pts.Add(hi);
                pts.Add(lo);
            }
    
            // sort the list
            pts.Sort(new endpointSorter());
    
            // sort the endpoint forward and backward links
            endpointEntry prev = null;
            foreach (endpointEntry pt in pts)
            {
                if (prev != null)
                {
                    pt.bLink = prev;
                    prev.fLink = pt;
                }
                prev = pt;
            }
    
            // NOW, we are ready to look for intersecting lines
            foreach (endpointEntry pt in pts)
            {
                // for every Hi endpoint ...
                if (pt.isHi)
                {
                    // check every other line whose X-range is either wholly 
                    // contained within our own, or that overlaps the high 
                    // part of ours.  The other two cases of overlap (overlaps 
                    // our low end, or wholly contains us) is covered by hi 
                    // points above that scan down to check us.
    
                    // scan down for each lo-endpoint below us checking each's 
                    // line for intersection until we pass our own lo-X value
                    for (endpointEntry pLo = pt.fLink; (pLo != null) && (pLo.XValue >= pt.lo); pLo = pLo.fLink)
                    {
                        // is this a lo-endpoint?
                        if (!pLo.isHi)
                        {
                            // check its line for intersection
                            if (pt.line.intersectsLine(pLo.line))
                                return true;
                        }
                    }
                }
            }
    
            return false;
        }
    }
    
    for (endpointEntry pLo = pt.fLink; (pLo != null) && (pLo.XValue >= pt.lo); pLo = pLo.fLink)
    
    int count = lines.Count();
    for (int l1idx = 0;       l1idx < count-1; l1idx++) 
    for (int l2idx = l1idx+1; l2idx < count;   l2idx++)
    {
      Line2D g = lines[l1idx];
      Line2D h = lines[l2idx];
      if (g.intersectsLine(h))
      {
        return false;
      }
    }