Interface for a transformable grid
I am working on an XNA project, and since procedural generation is likely to be used, I wanted to eventually create a helper class to work with data to facilitate that.
Design Goal:
Originally, I wanted to generate and modify a heightmap in a simple but efficient manner. The most straightforward approach to handle this would be a with a float[,]
.
Right now, I have a Grid<T>
which simply holds the data in a more convenient manner, but I want to introduce a way to transform it somehow - slicing, rotations, etc. The ability to add and multiply different heightmaps together would be beneficial as well.
My Code:
Knowing that C# is optimized for single-dimensional arrays, I decided to make a simple wrapper class that contains an internal jagged array, but have it look and behave like a 2-dimensional array.
I first made it into an interface because doing so allows me to implement it however I want, which allows for future optimizations which won't break any dependent code:
// Presents itself as a simplified 2-dimensional array
public interface IGrid<T> : IEnumerable<T>, IEnumerable
{
Point Size { get; }
T this[int x, int y] { get; set; }
}
And the current (simplified) implementation is:
// Functions as a jagged array under the hood
public class Grid<T> : IGrid<T>
{
private readonly T[][] _values;
// Implement IGrid<T>
public Point Size { get; private set; }
public T this[int x, int y]
{
get { return _values[y][x]; }
set { _values[y][x] = value; }
}
// Constructor
public Grid(int x, int y)
{
Size = new Point(x, y);
_values = new T[y][];
for (int i = 0; i < y; i++)
_values[i] = new T[x];
}
// Provide IEnumerator, override ToString(), etc...
}
My approach for the transformation bits is similar:
public interface ITransformable<T>
{
T Slice(int x, int y, int width, int height);
T Slice(Rectangle value);
T Transpose();
T Flip(bool horizontal, bool vertical);
T Rotate(bool clockwise);
}
And here is where I am stumbling. I'm not actually sure what I want to do with it!
- Attach it to
IGrid<T>
. It's no longer about simply storing the data, but transforming it as well. - Attach it to
Grid<T>
. The fact that a grid can transform the data is an implementation detail. - Create a derived class
Mesh<T>
which does everythingGrid<T>
does, but also implementsITransformable<T>
. - Create a derived class
Mesh<T>
, but removeITransformable<T>
and move its methods into this class.
Thoughts:
Since generic types do not support operator overloading (+, -, /, *), it means that if I want a Heightmap
to support addition in the form of Heightmap m = a + b
, it would need a specific implementation, such as public class Heightmap : Mesh<float>
, which then supplies the implementation of the operators.
Based on that, my entire class chain might resemeble:
public interface IGrid<T> { ... }
public interface IMesh<T> : IGrid<T> { ... }
public class Grid<T> : IGrid<T> { ... }
public class Mesh<T> : Grid<T>, IMesh<T> { ... }
public class Heightmap : Mesh<float> { ... }
- 411
- 4
- 9