/// <summary> /// Try to visit all the spans. May be needed in filtering small regions. /// </summary> /// <param name="regions">an array of region values</param> /// <param name="spanRef">The span to start walking from.</param> /// <param name="dir">The direction to start walking in.</param> /// <param name="cont">A collection of regions to append to.</param> private void WalkContour(RegionId[] regions, CompactSpanReference spanRef, Direction dir, List<RegionId> cont) { Direction startDir = dir; int starti = spanRef.Index; CompactSpan ss = spans[starti]; RegionId curReg = RegionId.Null; if (ss.IsConnected(dir)) { int dx = spanRef.X + dir.GetHorizontalOffset(); int dy = spanRef.Y + dir.GetVerticalOffset(); int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref ss, dir); curReg = regions[di]; } cont.Add(curReg); int iter = 0; while (++iter < 40000) { CompactSpan s = spans[spanRef.Index]; if (IsSolidEdge(regions, ref spanRef, dir)) { //choose the edge corner RegionId r = RegionId.Null; if (s.IsConnected(dir)) { int dx = spanRef.X + dir.GetHorizontalOffset(); int dy = spanRef.Y + dir.GetVerticalOffset(); int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dir); r = regions[di]; } if (r != curReg) { curReg = r; cont.Add(curReg); } dir = dir.NextClockwise(); //rotate clockwise } else { int di = -1; int dx = spanRef.X + dir.GetHorizontalOffset(); int dy = spanRef.Y + dir.GetVerticalOffset(); if (s.IsConnected(dir)) { CompactCell dc = cells[dx + dy * width]; di = dc.StartIndex + CompactSpan.GetConnection(ref s, dir); } if (di == -1) { //shouldn't happen return; } spanRef = new CompactSpanReference(dx, dy, di); dir = dir.NextCounterClockwise(); //rotate counterclockwise } if (starti == spanRef.Index && startDir == dir) break; } //remove adjacent duplicates if (cont.Count > 1) { for (int j = 0; j < cont.Count;) { //next element int nj = (j + 1) % cont.Count; //adjacent duplicate found if (cont[j] == cont[nj]) cont.RemoveAt(j); else j++; } } }