Created
November 3, 2013 21:37
-
-
Save BrianMacIntosh/7295134 to your computer and use it in GitHub Desktop.
This class provides a mechanism to iterate through the pixels in a rasterized line. The pixels are returned in order by distance from the point 'start'. The iterator acts like a raycast, not like e.g. Bresenham's line algorithm, in that it returns every pixel intersected by the ray.
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; | |
// RasterLineIterator.cs | |
// 3 November 2013 | |
// Author: Brian MacIntosh | |
/// <summary> | |
/// A simple two-dimensional vector. Replace with any 2d vector class. | |
/// </summary> | |
class Vector2 | |
{ | |
public float X; | |
public float Y; | |
public Vector2() | |
: this(0, 0) | |
{ | |
} | |
public Vector2(float X, float Y) | |
{ | |
this.X = X; | |
this.Y = Y; | |
} | |
} | |
/// <summary> | |
/// This class provides a mechanism to iterate through the pixels in a rasterized | |
/// line. The pixels are returned in order by distance from the point 'start'. | |
/// The iterator acts like a raycast, not like e.g. Bresenham's line algorithm, | |
/// in that it returns every pixel intersected by the ray. | |
/// </summary> | |
class RasterLineIterator | |
{ | |
double nextX; | |
double nextY; | |
double incX; | |
double incY; | |
/// <summary> | |
/// Set to false when the iterator reaches the last pixel. | |
/// </summary> | |
bool notended; | |
/// <summary> | |
/// Set to false when the iterator passes the last pixel. | |
/// </summary> | |
bool valid; | |
Vector2 start; | |
Vector2 cur; | |
Vector2 dir = new Vector2(); | |
Vector2 end; | |
/// <summary> | |
/// Cached value. Negative indicates it must be recalculated. | |
/// </summary> | |
float progress; | |
/// <summary> | |
/// Construct a new iterator starting at the point 'start' and ending at the point 'end'. | |
/// </summary> | |
public RasterLineIterator(Vector2 start, Vector2 end) | |
{ | |
set(start, end); | |
} | |
/// <summary> | |
/// Reset this iterator using the specified start and end points. | |
/// </summary> | |
public void set(Vector2 start, Vector2 end) | |
{ | |
//Clamp start and end to the pixel grid | |
start.X = (int)start.X; | |
start.Y = (int)start.Y; | |
end.X = (int)end.X; | |
end.Y = (int)end.Y; | |
notended = start.X != end.X || start.Y != end.Y; | |
valid = true; | |
progress = -1; | |
this.cur = this.start = start; | |
this.end = end; | |
dir.X = Math.Sign(end.X - start.X); | |
dir.Y = Math.Sign(end.Y - start.Y); | |
if (end.X == start.X) | |
incX = 0; | |
else | |
incX = 1 / (double)Math.Abs(end.X - start.X); | |
if (end.Y == start.Y) | |
incY = 0; | |
else | |
incY = 1 / (double)Math.Abs(end.Y - start.Y); | |
nextX = incX; | |
nextY = incY; | |
} | |
/// <summary> | |
/// Advance the iterator to the next pixel. | |
/// </summary> | |
public void next() | |
{ | |
if (!notended) | |
valid = false; | |
if (dir.Y == 0) | |
{ | |
cur.X += dir.X; | |
} | |
else if (dir.X == 0) | |
{ | |
cur.Y += dir.Y; | |
} | |
else | |
{ | |
//Go to next axis cross | |
if (nextX < nextY) | |
{ | |
nextX += incX; | |
cur.X += dir.X; | |
} | |
else | |
{ | |
nextY += incY; | |
cur.Y += dir.Y; | |
} | |
} | |
//Invalidate progress calculation | |
progress = -1; | |
if (cur.X == end.X && cur.Y == end.Y) | |
{ | |
notended = false; | |
} | |
} | |
/// <summary> | |
/// Returns true if the iterator can be advanced and remain within the valid range of the line. | |
/// </summary> | |
public bool hasNext() | |
{ | |
return notended; | |
} | |
/// <summary> | |
/// Returns false if the iterator has passed the end of the line. | |
/// </summary> | |
public bool isValid() | |
{ | |
return valid; | |
} | |
/// <summary> | |
/// Returns the current location of the iterator. | |
/// </summary> | |
public Vector2 current() | |
{ | |
return cur; | |
} | |
/// <summary> | |
/// Returns a value from 0 to 1 indicating the progress of the iterator from start to end. | |
/// This value is cached for you. | |
/// </summary> | |
public float getProgress() | |
{ | |
if (progress < 0) | |
{ | |
if (start.X == end.X) | |
{ | |
if (start.Y == end.Y) | |
progress = 1; | |
else | |
progress = (cur.Y - start.Y) / (end.Y - start.Y); | |
} | |
else | |
progress = (cur.X - start.X) / (end.X - start.X); | |
} | |
return progress; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment