Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.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
Algorithm 获取网格的边界边-按缠绕顺序_Algorithm_Geometry_Mesh_Triangulation_Convex Polygon - Fatal编程技术网

Algorithm 获取网格的边界边-按缠绕顺序

Algorithm 获取网格的边界边-按缠绕顺序,algorithm,geometry,mesh,triangulation,convex-polygon,Algorithm,Geometry,Mesh,Triangulation,Convex Polygon,我有一个三角形网格。假设它看起来像一个凹凸不平的表面。我希望能够找到落在网格周围边界上的所有边。(忘记内部顶点) 我知道我必须找到只与一个三角形相连的边,并将所有这些边收集在一起,这就是答案。但是我想确定这些边的顶点是围绕形状顺时针排列的 我想这样做,因为我想得到一个多边形线周围的外部网格 我希望这是足够清楚的理解。在某种意义上,我正在尝试“去三角化”网格。哈如果存在这样的术语。边界边仅由网格中的单个三角形引用,因此要找到它们,需要扫描网格中的所有三角形,并使用单个引用计数获取边。通过使用哈希表

我有一个三角形网格。假设它看起来像一个凹凸不平的表面。我希望能够找到落在网格周围边界上的所有边。(忘记内部顶点)

我知道我必须找到只与一个三角形相连的边,并将所有这些边收集在一起,这就是答案。但是我想确定这些边的顶点是围绕形状顺时针排列的

我想这样做,因为我想得到一个多边形线周围的外部网格


我希望这是足够清楚的理解。在某种意义上,我正在尝试“去三角化”网格。哈如果存在这样的术语。

边界边仅由网格中的单个三角形引用,因此要找到它们,需要扫描网格中的所有三角形,并使用单个引用计数获取边。通过使用哈希表,您可以高效地(在
O(N)
)执行此操作

要将边集转换为有序多边形循环,可以使用遍历方法:

  • 拾取任何未访问的边段
    [v_start,v_next]
    ,然后将这些顶点添加到多边形循环中
  • 找到具有
    v_i=v_next
    v_j=v_next
    的未访问边段
    [v_i,v_j]
    ,并将另一个顶点(不等于
    v_next
    )添加到多边形循环中。重置
    v_next
    作为新添加的顶点,将边标记为已访问并从2继续
  • 当我们回到
    v_start
    时,遍历就完成了
  • 遍历将产生一个多边形循环,该循环可以按时钟顺序排列,也可以按逆时钟顺序排列。通过考虑以下因素,可以建立一致的排序。如果遍历导致方向错误,您只需颠倒多边形循环顶点的顺序。

    遍历代码(效率不高-需要整理,在某个时候会达到这一点)请注意:我将链中的每个段存储为2索引,而不是Darren建议的1。这纯粹是为了满足我自己的实现/渲染需求

            // okay now lets sort the segments so that they make a chain.
    
            var sorted = new List<int>();
            var visited = new Dictionary<int, bool>();
    
            var startIndex = edges[0];
            var nextIndex = edges[1];
    
            sorted.Add(startIndex);
            sorted.Add(nextIndex);
    
            visited[0] = true;
            visited[1] = true;
    
            while (nextIndex != startIndex)
            {
                for (int i = 0; i < edges.Count - 1; i += 2)
                {
                    var j = i + 1;
                    if (visited.ContainsKey(i) || visited.ContainsKey(j))
                        continue;
    
                    var iIndex = edges[i];
                    var jIndex = edges[j];
    
                    if (iIndex == nextIndex)
                    {
                        sorted.Add(nextIndex);
                        sorted.Add(jIndex);
                        nextIndex = jIndex;
                        visited[j] = true;
                        break;
                    }
                    else if (jIndex == nextIndex)
                    {
                        sorted.Add(nextIndex);
                        sorted.Add(iIndex);
                        nextIndex = iIndex;
                        visited[i] = true;
                        break;
                    }
                }
            }
    
            return sorted;
    
    //好的,现在让我们对段进行排序,使它们形成一个链。
    var sorted=新列表();
    var=newdictionary();
    var startIndex=边[0];
    var nextIndex=边[1];
    已排序。添加(startIndex);
    已排序。添加(nextIndex);
    已访问[0]=真;
    已访问[1]=正确;
    while(nextIndex!=startIndex)
    {
    对于(int i=0;i
    俗话说——让它工作——然后让它更好地工作。我注意到在我上面的示例中,它假设Edge数组中的所有边实际上都连接在一个漂亮的边框中。在现实世界中可能不是这样(正如我从我正在使用的输入文件中发现的!)事实上,我的一些输入文件实际上有许多多边形,并且都需要检测边界。我还想确定缠绕顺序是否正确。所以我也解决了这个问题。见下文。(感觉我终于有进展了!)

    私有静态列表组织页(列表边、列表位置)
    {
    var=newdictionary();
    var edgeList=新列表();
    var resultList=新列表();
    var-nextIndex=-1;
    while(resultList.Count=0)
    {
    var edge=边[k];
    访问[我]=真实;
    edgeList.Add(下一个索引);
    边列表。添加(边);
    nextIndex=边缘;
    i=0;
    }
    }
    //计算绕组顺序-然后添加到最终结果。
    var borderPoints=新列表();
    ForEach(ei=>borderPoints.Add(positions[ei]);
    var绕组=计算绕组顺序(边界点);
    如果(绕组>0)
    edgeList.Reverse();
    结果列表AddRange(edgeList);
    edgeList=新列表();
    nextIndex=-1;
    }
    返回结果列表;
    }
    /// 
    ///对于CW返回1,对于CCW返回1,对于未知返回0。
    /// 
    公共静态int计算索引顺序(IList点)
    {
    //多边形的“面积”符号是我们感兴趣的全部。
    var面积=计算总面积(点);
    如果(面积<0.0)
    返回1;
    否则,如果(面积>0.0)
    返回-1;
    返回0;//错误条件
    
        private static List<int> OrganizeEdges(List<int> edges, List<Point> positions)
        {
            var visited = new Dictionary<int, bool>();
            var edgeList = new List<int>();
            var resultList = new List<int>();
            var nextIndex = -1;
            while (resultList.Count < edges.Count)
            {
                if (nextIndex < 0)
                {
                    for (int i = 0; i < edges.Count; i += 2)
                    {
                        if (!visited.ContainsKey(i))
                        {
                            nextIndex = edges[i];
                            break;
                        }
                    }
                }
    
                for (int i = 0; i < edges.Count; i += 2)
                {
                    if (visited.ContainsKey(i))
                        continue;
    
                    int j = i + 1;
                    int k = -1;
                    if (edges[i] == nextIndex)
                        k = j;
                    else if (edges[j] == nextIndex)
                        k = i;
    
                    if (k >= 0)
                    {
                        var edge = edges[k];
                        visited[i] = true;
                        edgeList.Add(nextIndex);
                        edgeList.Add(edge);
                        nextIndex = edge;
                        i = 0;
                    }
                }
    
                // calculate winding order - then add to final result.
                var borderPoints = new List<Point>();
                edgeList.ForEach(ei => borderPoints.Add(positions[ei]));
                var winding = CalculateWindingOrder(borderPoints);
                if (winding > 0)
                    edgeList.Reverse();
    
                resultList.AddRange(edgeList);
                edgeList = new List<int>();
                nextIndex = -1;
            }
    
            return resultList;
        }
    
    
    
    
        /// <summary>
        /// returns 1 for CW, -1 for CCW, 0 for unknown.
        /// </summary>
        public static int CalculateWindingOrder(IList<Point> points)
        {
            // the sign of the 'area' of the polygon is all we are interested in.
            var area = CalculateSignedArea(points);
            if (area < 0.0)
                return 1;
            else if (area > 0.0)
                return - 1;        
            return 0; // error condition - not even verts to calculate, non-simple poly, etc.
        }
    
        public static double CalculateSignedArea(IList<Point> points)
        {
            double area = 0.0;
            for (int i = 0; i < points.Count; i++)
            {
                int j = (i + 1) % points.Count;
                area += points[i].X * points[j].Y;
                area -= points[i].Y * points[j].X;
            }
            area /= 2.0f;
    
            return area;
        }