| 83 | |
| 84 | template <typename T> |
| 85 | Utils::StatusWithReason Raster<T>::expand(int newWidth, int newHeight, int xshift, int yshift) |
| 86 | { |
| 87 | if (newWidth < width()) |
| 88 | return { -1, "Expanded grid must have width at least as large as existing grid." }; |
| 89 | if (newHeight < height()) |
| 90 | return { -1, "Expanded grid must have height at least as large as existing grid." }; |
| 91 | if (width() + xshift > newWidth || height() + yshift > newHeight) |
| 92 | return { -1, "Can't shift existing grid outside of new grid during expansion." }; |
| 93 | if (newWidth == width() && newHeight == height()) |
| 94 | return true; |
| 95 | |
| 96 | m_limits.xOrigin -= xshift * edgeLength(); |
| 97 | m_limits.yOrigin -= yshift * edgeLength(); |
| 98 | |
| 99 | // Raster works upside down from cartesian X/Y |
| 100 | yshift = newHeight - (height() + yshift); |
| 101 | |
| 102 | auto dstIndex = [newWidth, xshift, yshift](size_t i, size_t j) |
| 103 | { |
| 104 | return ((yshift + j) * newWidth) + i + xshift; |
| 105 | }; |
| 106 | |
| 107 | // Note: that i, j are internal to the raster and start at the top left and |
| 108 | // move across and down. |
| 109 | DataVec& src = m_data; |
| 110 | DataVec dst((size_t)newWidth * newHeight, m_initializer); |
| 111 | for (int j = 0; j < height(); ++j) |
| 112 | { |
| 113 | size_t srcPos = index(0, j); |
| 114 | size_t dstPos = dstIndex(0, j); |
| 115 | std::copy(src.begin() + srcPos, src.begin() + srcPos + width(), |
| 116 | dst.begin() + dstPos); |
| 117 | } |
| 118 | m_data = std::move(dst); |
| 119 | m_limits.width = newWidth; |
| 120 | m_limits.height = newHeight; |
| 121 | return true; |
| 122 | } |
| 123 | |
| 124 | // Instantiate Raster<double> |
| 125 | template class Raster<double>; |