Skip to content

Instantly share code, notes, and snippets.

@dg1an3
Last active July 3, 2018 19:35
Show Gist options
  • Save dg1an3/2af602331c10707cdfce8d557c367a29 to your computer and use it in GitHub Desktop.
Save dg1an3/2af602331c10707cdfce8d557c367a29 to your computer and use it in GitHub Desktop.
Isocurve Generation via simple marching squares
/// <summary>
///
/// </summary>
public class ComplexGeometry : List<LineSegments>
{
// stores the dictionary
Dictionary<Point, LineSegments> _segments =
new Dictionary<Point, LineSegments>();
/// <summary>
/// creates or adds a segment to the collections
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="startOffset"></param>
/// <param name="endOffset"></param>
public void CreateOrAddSegment(int x, int y, Vector startOffset, Vector endOffset)
{
Point ptMiddle = new Point(x, y);
Point startPoint = ptMiddle + startOffset;
Point endPoint = ptMiddle + endOffset;
if (_segments.ContainsKey(startPoint))
{
var pc = _segments[startPoint];
_segments.Remove(startPoint);
if (pc.First() == startPoint)
{
pc.Insert(0, endPoint);
}
else if (pc.Last() == startPoint)
{
pc.Add(endPoint);
}
if (!_segments.ContainsKey(endPoint))
_segments.Add(endPoint, pc);
}
else if (_segments.ContainsKey(endPoint))
{
var pc = _segments[endPoint];
_segments.Remove(endPoint);
if (pc.First() == endPoint)
{
pc.Insert(0, startPoint);
}
else if (pc.Last() == endPoint)
{
pc.Add(startPoint);
}
if (!_segments.ContainsKey(startPoint))
_segments.Add(startPoint, pc);
}
else
{
var pc = new LineSegments();
pc.Add(startPoint);
pc.Add(endPoint);
_segments.Add(startPoint, pc);
_segments.Add(endPoint, pc);
this.Add(pc);
}
}
}
/// <summary>
///
/// </summary>
public class LineSegments : List<Point> { }
public static class IsocurveGenerator
{
public static ComplexGeometry GenerateIsocurve(byte[,] pixels, float threshold)
{
var geometry = new ComplexGeometry();
int height = pixels.GetLength(0);
int width = pixels.GetLength(1);
byte byteThreshold = (byte)threshold;
// Y is increasing as we move down the image
// Upper is -Y
// Lower is +Y
// for (int y = -height / 2; y < height / 2 - 1; y++)
Parallel.For(-height / 2, height / 2 - 1,
y =>
{
for (int x = -width / 2; x < width / 2 - 1; x++)
{
// UL---UR Bit order:
// |/ \| (UL) (UR) (LR) (LL)
// |\ /|
// LL---LR
byte ul = pixels[y + height / 2, x + width / 2];
byte ur = pixels[y + height / 2, x + width / 2 + 1];
byte lr = pixels[y + height / 2 + 1, x + width / 2 + 1];
byte ll = pixels[y + height / 2 + 1, x + width / 2];
uint index = 0;
index |= (uint)((ul < byteThreshold) ? 0 : 1) << 3; // 1000
index |= (uint)((ur < byteThreshold) ? 0 : 1) << 2; // 0100
index |= (uint)((lr < byteThreshold) ? 0 : 1) << 1; // 0010
index |= (uint)((ll < byteThreshold) ? 0 : 1) << 0; // 0001
System.Diagnostics.Trace.Assert(index <= 0xF);
System.Diagnostics.Trace.Assert(index >= 0x0);
lock (geometry)
{
switch (index)
{
// UL---UR
// | |
// |\ |
// LL---LR
case 0x1: // 0001
case 0xE: // 1110
geometry.CreateOrAddSegment(x, y,
new Vector(-0.5, 0.0),
new Vector(0.0, 0.5));
break;
// UL---UR
// | |
// | /|
// LL---LR
case 0x2: // 0010
case 0xD: // 1101
geometry.CreateOrAddSegment(x, y,
new Vector(0.0, 0.5),
new Vector(0.5, 0.0));
break;
// UL---UR
// |___|
// | |
// LL---LR
case 0x3: // 0011
case 0xC: // 1100
geometry.CreateOrAddSegment(x, y,
new Vector(-0.5, 0.0),
new Vector(0.5, 0.0));
break;
// UL---UR
// | \|
// | |
// LL---LR
case 0x4: // 0100
case 0xB: // 1011
geometry.CreateOrAddSegment(x, y,
new Vector(0.0, -0.5),
new Vector(0.5, 0.0));
break;
// UL---UR
// | \|
// |\ |
// LL---LR
case 0x5: // 0101
case 0xA: // 1010
geometry.CreateOrAddSegment(x, y,
new Vector(0.0, -0.5),
new Vector(0.5, 0.0));
geometry.CreateOrAddSegment(x, y,
new Vector(-0.5, 0.0),
new Vector(0.0, 0.5));
break;
// UL---UR
// | | |
// | | |
// LL---LR
case 0x6: // 0110
case 0x9: // 1001
geometry.CreateOrAddSegment(x, y,
new Vector(0.0, -0.5),
new Vector(0.0, 0.5));
break;
// UL---UR
// |/ |
// | |
// LL---LR
case 0x7:
case 0x8:
geometry.CreateOrAddSegment(x, y,
new Vector(-0.5, 0.0),
new Vector(0.0, -0.5));
break;
case 0xF:
case 0x0:
default:
// all on same side - do nothing
break;
}
}
}
});
return geometry;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment