Skip to content

Instantly share code, notes, and snippets.

@erussell
Created June 14, 2011 13:47
Show Gist options
  • Save erussell/1024927 to your computer and use it in GitHub Desktop.
Save erussell/1024927 to your computer and use it in GitHub Desktop.
C# Class for polygonizing a binary raster
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