Рукой
Если память не является очень редким ресурсом, я рассматриваю работу большими кусками.
Вот немного псевдокода.
class Chunk {
Chunk new(int size) {...}
void setPixel(int x, int y, int value) {...}
int getPixel(int x, int y) {...}
}
class Grid {
Map<int, Map<Chunk>> chunks;
Grid new(int chunkSize) {...}
void setPixel(int x, int y, int value) {
getChunk(x,y).setPixel(x % chunkSize, y % chunkSize, value);//actually the modulo could be right in Chunk::setPixel and getPixel for more safety
}
int getPixel(int x, int y) { /*along the lines of setPixel*/ }
private Chunk getChunk(int x, int y) {
x /= chunkSize;
y /= chunkSize;
Map<Chunk> row = chunks.get(y);
if (row == null) chunks.set(y, row = new Map<Chunk>());
Chunk ret = row.get(x);
if (ret == null) row.set(x, ret = new Chunk(chunkSize));
return ret;
}
}
Эта реализация довольно наивна.
Во-первых, он создает чанки в getPixel (в принципе, было бы хорошо просто вернуть 0 или около того, если чанки не были определены для этой позиции). Во-вторых, он основан на предположении, что у вас достаточно быстрая и масштабируемая реализация Map. Насколько мне известно, каждый приличный язык имеет один.
Также вам придется играть с размером куска. Для плотных растровых изображений большой размер порции хорош, для разреженных растровых изображений меньший размер порции лучше. На самом деле для очень разреженных «размер порции» равен 1, что делает «порции» самими устаревшими и сокращает структуру данных до int-карты int-карты пикселей.
С полки
Другим решением может быть просмотр некоторых графических библиотек. На самом деле они неплохо рисуют один 2D буфер в другой. Это будет означать, что вы просто выделите больший буфер и поместите оригинал в соответствующие координаты.
Как общая стратегия: при наличии «динамически растущего блока памяти» хорошей идеей будет выделить его несколько раз, когда он израсходован. Это довольно много памяти, но значительно сокращает затраты на выделение и копирование . Большинство векторных реализаций выделяют вдвое больше своего размера, когда он превышен. Поэтому, особенно если вы используете готовое решение, не расширяйте свой буфер только на 1 пиксель, потому что был запрошен только один пиксель. Выделенная память дешевая. Перераспределение, копирование и выпуск - это дорого.