Created
June 14, 2011 13:47
-
-
Save erussell/1024927 to your computer and use it in GitHub Desktop.
C# Class for polygonizing a binary raster
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using ESRI.ArcGIS.DataSourcesRaster; | |
using ESRI.ArcGIS.Geodatabase; | |
using ESRI.ArcGIS.Geometry; | |
internal enum CurveDirection { RIGHT, UP, LEFT, DOWN }; | |
public sealed class BoundingCurve | |
{ | |
private int m_Width; | |
private int m_Height; | |
private bool[,] m_IsFilled; | |
private bool[,] m_CellVisited; | |
public BoundingCurve (bool[,] grid) { | |
m_IsFilled = grid; | |
m_Width = grid.GetLength(0); | |
m_Height = grid.GetLength(1); | |
m_CellVisited = new bool[m_Width, m_Height]; | |
m_CellVisited.Initialize(); | |
} | |
public List<List<System.Drawing.Point>> GetBoundaryAsList () { | |
List<List<System.Drawing.Point>> result = new List<List<System.Drawing.Point>>(); | |
for (int x = 0; x <= m_Width; x += 1) { | |
for (int y = 0; y <= m_Height; y += 1) { | |
if ((!CellVisited(x, y)) && IsFilled(x, y) && (!IsFilled(x - 1, y))) { | |
result.Add(GetCurve(x, y)); | |
} | |
} | |
} | |
return result; | |
} | |
public IPolygon GetBoundaryAsPolygon (IRasterProps props) { | |
double left = props.Extent.XMin; | |
double top = props.Extent.YMax; | |
IPnt cellSize = props.MeanCellSize(); | |
PolygonClass result = new PolygonClass(); | |
object missing = Type.Missing; | |
for (int x = 0; x <= m_Width; x += 1) { | |
for (int y = 0; y <= m_Height; y += 1) { | |
if ((!CellVisited(x, y)) && IsFilled(x, y) && (!IsFilled(x - 1, y))) { | |
List<System.Drawing.Point> bmRing = GetCurve(x, y); | |
RingClass ring = new RingClass(); | |
foreach (System.Drawing.Point bmPt in bmRing) { | |
PointClass point = new PointClass(); | |
point.PutCoords(left + bmPt.X * cellSize.X, | |
top - bmPt.Y * cellSize.Y); | |
ring.AddPoint(point, ref missing, ref missing); | |
} | |
result.AddGeometry(ring, ref missing, ref missing); | |
} | |
} | |
} | |
return result; | |
} | |
private bool IsFilled (int x, int y) { | |
if ((x < 0) || (y < 0) || (x >= m_Width) || (y >= m_Height)) { | |
return false; | |
} else { | |
return m_IsFilled[x, y]; | |
} | |
} | |
private bool CellVisited (int x, int y) { | |
if ((x < 0) || (y < 0) || (x >= m_Width) || (y >= m_Height)) { | |
return false; | |
} else { | |
return m_CellVisited[x, y]; | |
} | |
} | |
private void MarkVisited (int x, int y) { | |
if ((x >= 0) && (x < m_Width) && (y >= 0) && (y < m_Height)) { | |
m_CellVisited[x, y] = true; | |
} | |
} | |
private List<System.Drawing.Point> GetCurve (int startX, int startY) { | |
MarkVisited(startX, startY); | |
List<System.Drawing.Point> result = new List<System.Drawing.Point>(); | |
result.Add(new System.Drawing.Point(startX, startY)); | |
int x = startX; | |
int y = startY + 1; | |
CurveDirection direction = CurveDirection.UP; | |
while ((x != startX) || (y != startY)) { | |
CurveDirection newDirection = direction; | |
switch (direction) { | |
case CurveDirection.UP: | |
if (IsFilled(x - 1, y) && IsFilled(x, y)) { | |
newDirection = CurveDirection.LEFT; | |
MarkVisited(x - 1, y); | |
} else if (IsFilled(x, y)) { | |
newDirection = CurveDirection.UP; | |
MarkVisited(x, y); | |
} else { | |
newDirection = CurveDirection.RIGHT; | |
} | |
break; | |
case CurveDirection.RIGHT: | |
if (IsFilled(x, y) && IsFilled(x, y - 1)) { | |
newDirection = CurveDirection.UP; | |
MarkVisited(x, y); | |
} else if (IsFilled(x, y - 1)) { | |
newDirection = CurveDirection.RIGHT; | |
MarkVisited(x, y - 1); | |
} else { | |
newDirection = CurveDirection.DOWN; | |
} | |
break; | |
case CurveDirection.DOWN: | |
if (IsFilled(x, y - 1) && IsFilled(x - 1, y - 1)) { | |
newDirection = CurveDirection.RIGHT; | |
MarkVisited(x, y - 1); | |
} else if (IsFilled(x - 1, y - 1)) { | |
newDirection = CurveDirection.DOWN; | |
if ((x < 2) || IsFilled(x - 2, y - 1)) | |
MarkVisited(x - 1, y - 1); | |
} else { | |
newDirection = CurveDirection.LEFT; | |
} | |
break; | |
case CurveDirection.LEFT: | |
if (IsFilled(x - 1, y - 1) && IsFilled(x - 1, y)) { | |
newDirection = CurveDirection.DOWN; | |
if ((x < 2) || IsFilled(x - 2, y - 1)) | |
MarkVisited(x - 1, y - 1); | |
} else if (IsFilled(x - 1, y)) { | |
newDirection = CurveDirection.LEFT; | |
MarkVisited(x - 1, y); | |
} else { | |
newDirection = CurveDirection.UP; | |
MarkVisited(x, y); | |
} | |
break; | |
default: | |
throw (new Exception("this shouldn't happen")); | |
} | |
result.Add(new System.Drawing.Point(x, y)); | |
switch (newDirection) { | |
case CurveDirection.UP: | |
y += 1; | |
break; | |
case CurveDirection.RIGHT: | |
x += 1; | |
break; | |
case CurveDirection.DOWN: | |
y -= 1; | |
break; | |
case CurveDirection.LEFT: | |
x -= 1; | |
break; | |
} | |
direction = newDirection; | |
} | |
// Be absolutely sure the curve is closed | |
if (!result[0].Equals(result[result.Count - 1])) { | |
result.Add(new System.Drawing.Point(startX, startY)); | |
} | |
result.Reverse(); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment