172                                                    std::function<T(V, V)> convert)
 
  174    logging::info(
"Reading file %s", filename.c_str());
 
  178    auto min_value = std::numeric_limits<V>::max();
 
  179    auto max_value = std::numeric_limits<V>::min();
 
  181    logging::debug(
"Reading a raster where T = %s, V = %s",
 
  184    logging::debug(
"Raster type V has limits %ld, %ld",
 
  185                   std::numeric_limits<V>::min(),
 
  186                   std::numeric_limits<V>::max());
 
  187    const GridBase grid_info = read_header(tif, gtif);
 
  189    uint32_t tile_length;
 
  190    TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
 
  191    TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_length);
 
  194    TIFFGetField(tif, TIFFTAG_GDAL_NODATA, &count, &
data);
 
  195    logging::check_fatal(0 == count, 
"NODATA value is not set in input");
 
  196    logging::debug(
"NODATA value is '%s'", 
static_cast<char*
>(
data));
 
  197    const auto nodata_orig = stoi(
string(
static_cast<char*
>(
data)));
 
  198    logging::debug(
"NODATA value is originally parsed as %d", nodata_orig);
 
  199    const auto nodata_input = 
static_cast<V
>(stoi(
string(
static_cast<char*
>(
data))));
 
  200    logging::debug(
"NODATA value is parsed as %d", nodata_input);
 
  204    logging::note(
"Coordinates before reading are (%d, %d => %f, %f)",
 
  205                  std::get<0>(*coordinates),
 
  206                  std::get<1>(*coordinates),
 
  207                  std::get<0>(*coordinates) + std::get<2>(*coordinates) / 1000.0,
 
  208                  std::get<1>(*coordinates) + std::get<3>(*coordinates) / 1000.0);
 
  209    auto min_column = max(
static_cast<FullIdx
>(0),
 
  210                          static_cast<FullIdx
>(std::get<1>(*coordinates) - 
static_cast<FullIdx
>(MAX_COLUMNS) / 
static_cast<FullIdx
>(2)));
 
  211    if (min_column + MAX_COLUMNS >= actual_columns)
 
  213      min_column = max(
static_cast<FullIdx
>(0), actual_columns - MAX_COLUMNS);
 
  216    const auto tile_column = tile_width * 
static_cast<FullIdx
>(min_column / tile_width);
 
  217    const auto max_column = 
static_cast<FullIdx
>(min(min_column + MAX_COLUMNS - 1, actual_columns));
 
  219    logging::check_fatal(min_column < 0, 
"Column can't be less than 0");
 
  220    logging::check_fatal(max_column - min_column > MAX_COLUMNS, 
"Can't have more than %d columns", MAX_COLUMNS);
 
  221    logging::check_fatal(max_column > actual_columns, 
"Can't have more than actual %d columns", actual_columns);
 
  223    auto min_row = max(
static_cast<FullIdx
>(0),
 
  224                       static_cast<FullIdx
>(std::get<0>(*coordinates) - 
static_cast<FullIdx
>(MAX_ROWS) / 
static_cast<FullIdx
>(2)));
 
  225    if (min_row + MAX_COLUMNS >= actual_rows)
 
  227      min_row = max(
static_cast<FullIdx
>(0), actual_rows - MAX_ROWS);
 
  229    const auto tile_row = tile_width * 
static_cast<FullIdx
>(min_row / tile_width);
 
  230    const auto max_row = 
static_cast<FullIdx
>(min(min_row + MAX_ROWS - 1, actual_rows));
 
  232    logging::check_fatal(min_row < 0, 
"Row can't be less than 0 but is %d", min_row);
 
  233    logging::check_fatal(max_row - min_row > MAX_ROWS, 
"Can't have more than %d rows but have %d", MAX_ROWS, max_row - min_row);
 
  234    logging::check_fatal(max_row > actual_rows, 
"Can't have more than actual %d rows", actual_rows);
 
  236    T nodata_value = convert(nodata_input, nodata_input);
 
  237    logging::check_fatal(
 
  238      convert(nodata_input, nodata_input) != nodata_value,
 
  239      "Expected nodata value to be returned from convert()");
 
  240    vector<T> values(
static_cast<size_t>(MAX_ROWS) * MAX_COLUMNS, nodata_value);
 
  241    logging::verbose(
"%s: malloc start", filename.c_str());
 
  242    int bps = std::numeric_limits<V>::digits + (1 * std::numeric_limits<V>::is_signed);
 
  244    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps_file);
 
  245    logging::check_fatal(bps != bps_file,
 
  246                         "Raster %s type is not expected type (%d bits instead of %d)",
 
  251    int bps_int16_t = std::numeric_limits<int16_t>::digits + (1 * std::numeric_limits<int16_t>::is_signed);
 
  252    logging::debug(
"Size of pointer to int is %ld vs %ld", 
sizeof(int16_t*), 
sizeof(V*));
 
  253    logging::debug(
"Raster %s calculated bps for type V is %ld; tif says bps is %ld; int16_t is %ld",
 
  259    const auto tile_size = TIFFTileSize(tif);
 
  260    logging::debug(
"Tile size for reading %s is %ld", filename.c_str(), tile_size);
 
  261    const auto buf = _TIFFmalloc(tile_size);
 
  262    logging::verbose(
"%s: read start", filename.c_str());
 
  263    const tsample_t smp{};
 
  264    logging::debug(
"Want to clip grid to (%d, %d) => (%d, %d) for a %dx%d raster",
 
  271    for (
auto h = tile_row; h <= max_row; h += tile_length)
 
  273      for (
auto w = tile_column; w <= max_column; w += tile_width)
 
  275        TIFFReadTile(tif, buf, 
static_cast<uint32_t
>(w), 
static_cast<uint32_t
>(h), 0, smp);
 
  278          (y < static_cast<FullIdx>(tile_length)) && (y + h <= max_row);
 
  282          const auto y_row = 
static_cast<HashSize
>((h - min_row) + y);
 
  283          const auto actual_row = (max_row - min_row) - y_row;
 
  284          if (actual_row >= 0 && actual_row < MAX_ROWS)
 
  288              (x < static_cast<FullIdx>(tile_width)) && (x + w <= max_column);
 
  291              const auto offset = y * tile_width + x;
 
  292              const auto actual_column = ((w - min_column) + x);
 
  293              if (actual_column >= 0 && actual_column < MAX_ROWS)
 
  295                const auto cur_hash = actual_row * MAX_COLUMNS + actual_column;
 
  296                auto cur = *(
static_cast<V*
>(buf) + offset);
 
  298                min_value = min(cur, min_value);
 
  299                max_value = max(cur, max_value);
 
  303                values.at(cur_hash) = convert(cur, nodata_input);
 
  331    logging::verbose(
"%s: read end", filename.c_str());
 
  333    logging::verbose(
"%s: free end", filename.c_str());
 
  334    const auto new_xll = grid_info.
xllcorner() + (
static_cast<MathSize
>(min_column) * grid_info.
cellSize());
 
  335    const auto new_yll = grid_info.
yllcorner()
 
  336                       + (
static_cast<MathSize
>(actual_rows) - 
static_cast<MathSize
>(max_row))
 
  339    logging::check_fatal(new_yll < grid_info.
yllcorner(),
 
  340                         "New yllcorner is outside original grid");
 
  342    logging::verbose(
"Translated lower left is (%f, %f) from (%f, %f)",
 
  347    const auto num_rows = max_row - min_row + 1;
 
  348    const auto num_columns = max_column - min_column + 1;
 
  356                                         new_xll + (
static_cast<MathSize
>(num_columns) + 1) * grid_info.
cellSize(),
 
  357                                         new_yll + (
static_cast<MathSize
>(num_rows) + 1) * grid_info.
cellSize(),
 
  358                                         string(grid_info.
proj4()),
 
  360    auto new_location = result->findCoordinates(point, 
false);
 
  362    logging::check_fatal(
nullptr == new_location, 
"Invalid location after reading");
 
  364    logging::note(
"Coordinates are (%d, %d => %f, %f)",
 
  365                  std::get<0>(*new_location),
 
  366                  std::get<1>(*new_location),
 
  367                  std::get<0>(*new_location) + std::get<2>(*new_location) / 1000.0,
 
  368                  std::get<1>(*new_location) + std::get<3>(*new_location) / 1000.0);
 
  370    logging::note(
"Values for %s range from %d to %d",