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
时,遍历就完成了 // 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;
}