<commit_before>goog.provide('ol.reproj.Tile');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.Tile');
goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.proj');
goog.require('ol.reproj');
goog.require('ol.reproj.Triangulation');



/**
 * @constructor
 * @extends {ol.Tile}
 * @param {ol.proj.Projection} sourceProj
 * @param {ol.tilegrid.TileGrid} sourceTileGrid
 * @param {ol.proj.Projection} targetProj
 * @param {ol.tilegrid.TileGrid} targetTileGrid
 * @param {number} z
 * @param {number} x
 * @param {number} y
 * @param {number} pixelRatio
 * @param {function(number, number, number, number) : ol.Tile} getTileFunction
 * @param {boolean=} opt_renderEdges
 */
ol.reproj.Tile = function(sourceProj, sourceTileGrid,
    targetProj, targetTileGrid, z, x, y, pixelRatio, getTileFunction,
    opt_renderEdges) {
  goog.base(this, [z, x, y], ol.TileState.IDLE);

  /**
   * @private
   * @type {boolean}
   */
  this.renderEdges_ = goog.isDef(opt_renderEdges) ? opt_renderEdges : false;

  /**
   * @private
   * @type {HTMLCanvasElement}
   */
  this.canvas_ = null;

  /**
   * @private
   * @type {Object.<number, HTMLCanvasElement>}
   */
  this.canvasByContext_ = {};

  /**
   * @private
   * @type {ol.tilegrid.TileGrid}
   */
  this.sourceTileGrid_ = sourceTileGrid;

  /**
   * @private
   * @type {ol.tilegrid.TileGrid}
   */
  this.targetTileGrid_ = targetTileGrid;

  /**
   * @private
   * @type {!Array.<ol.Tile>}
   */
  this.srcTiles_ = [];

  /**
   * @private
   * @type {Array.<goog.events.Key>}
   */
  this.sourcesListenerKeys_ = null;

  /**
   * @private
   * @type {number}
   */
  this.srcZ_ = 0;

  var targetExtent = targetTileGrid.getTileCoordExtent(this.getTileCoord());
  var maxTargetExtent = this.targetTileGrid_.getExtent();
  var maxSourceExtent = this.sourceTileGrid_.getExtent();

  var limitedTargetExtent = goog.isNull(maxTargetExtent) ?
      targetExtent : ol.extent.getIntersection(targetExtent, maxTargetExtent);

  if (ol.extent.getArea(limitedTargetExtent) === 0) {
    // Tile is completely outside range -> EMPTY
    // TODO: is it actually correct that the source even creates the tile ?
    this.state = ol.TileState.EMPTY;
    return;
  }

  var targetResolution = targetTileGrid.getResolution(z);

  var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJ_ERROR_THRESHOLD;

  // in source units
  var errorThreshold = targetResolution * errorThresholdInPixels *
      targetProj.getMetersPerUnit() / sourceProj.getMetersPerUnit();

  /**
   * @private
   * @type {!ol.reproj.Triangulation}
   */
  this.triangulation_ = new ol.reproj.Triangulation(
      sourceProj, targetProj, limitedTargetExtent, maxSourceExtent,
      errorThreshold);

  if (this.triangulation_.getTriangles().length === 0) {
    // no valid triangles -> EMPTY
    this.state = ol.TileState.EMPTY;
    return;
  }

  var targetCenter = ol.extent.getCenter(limitedTargetExtent);
  var sourceResolution = ol.reproj.calculateSourceResolution(
      sourceProj, targetProj, targetCenter, targetResolution);

  if (!goog.math.isFiniteNumber(sourceResolution) || sourceResolution <= 0) {
    // invalid sourceResolution -> EMPTY
    // probably edges of the projections when no extent is defined
    this.state = ol.TileState.EMPTY;
    return;
  }

  this.srcZ_ = sourceTileGrid.getZForResolution(sourceResolution);
  var srcExtent = this.triangulation_.calculateSourceExtent();

  var sourceProjExtent = sourceProj.getExtent();
  if (!sourceProj.isGlobal() && sourceProjExtent) {
    srcExtent = ol.extent.getIntersection(srcExtent, sourceProjExtent);
  }

  if (!goog.isNull(maxSourceExtent) &&
      !ol.extent.intersects(maxSourceExtent, srcExtent)) {
    this.state = ol.TileState.EMPTY;
  } else {
    var srcRange = sourceTileGrid.getTileRangeForExtentAndZ(
        srcExtent, this.srcZ_);

    var xRange;
    var srcFullRange = sourceTileGrid.getFullTileRange(this.srcZ_);
    if (!goog.isNull(srcFullRange)) {
      srcRange.minY = Math.max(srcRange.minY, srcFullRange.minY);
      srcRange.maxY = Math.min(srcRange.maxY, srcFullRange.maxY);

      if (srcRange.minX > srcRange.maxX) {
        xRange = goog.array.concat(
            goog.array.range(srcRange.minX, srcFullRange.maxX + 1),
            goog.array.range(srcFullRange.minX, srcRange.maxX + 1)
            );
      } else {
        xRange = goog.array.range(
            Math.max(srcRange.minX, srcFullRange.minX),
            Math.min(srcRange.maxX, srcFullRange.maxX) + 1
            );
      }
    } else {
      xRange = goog.array.range(srcRange.minX, srcRange.maxX + 1);
    }

    var tilesRequired = xRange.length * srcRange.getHeight();
    goog.asserts.assert(tilesRequired < ol.RASTER_REPROJ_MAX_SOURCE_TILES,
        'reasonable number of tiles is required');

    if (tilesRequired > ol.RASTER_REPROJ_MAX_SOURCE_TILES) {
      this.state = ol.TileState.ERROR;
      return;
    }
    goog.array.forEach(xRange, function(srcX, i, arr) {
      for (var srcY = srcRange.minY; srcY <= srcRange.maxY; srcY++) {
        var tile = getTileFunction(this.srcZ_, srcX, srcY, pixelRatio);
        if (tile) {
          this.srcTiles_.push(tile);
        }<commit_msg>Better handling of tilegrids without extent during reprojection<commit_after>goog.provide('ol.reproj.Tile');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.Tile');
goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.proj');
goog.require('ol.reproj');
goog.require('ol.reproj.Triangulation');



/**
 * @constructor
 * @extends {ol.Tile}
 * @param {ol.proj.Projection} sourceProj
 * @param {ol.tilegrid.TileGrid} sourceTileGrid
 * @param {ol.proj.Projection} targetProj
 * @param {ol.tilegrid.TileGrid} targetTileGrid
 * @param {number} z
 * @param {number} x
 * @param {number} y
 * @param {number} pixelRatio
 * @param {function(number, number, number, number) : ol.Tile} getTileFunction
 * @param {boolean=} opt_renderEdges
 */
ol.reproj.Tile = function(sourceProj, sourceTileGrid,
    targetProj, targetTileGrid, z, x, y, pixelRatio, getTileFunction,
    opt_renderEdges) {
  goog.base(this, [z, x, y], ol.TileState.IDLE);

  /**
   * @private
   * @type {boolean}
   */
  this.renderEdges_ = goog.isDef(opt_renderEdges) ? opt_renderEdges : false;

  /**
   * @private
   * @type {HTMLCanvasElement}
   */
  this.canvas_ = null;

  /**
   * @private
   * @type {Object.<number, HTMLCanvasElement>}
   */
  this.canvasByContext_ = {};

  /**
   * @private
   * @type {ol.tilegrid.TileGrid}
   */
  this.sourceTileGrid_ = sourceTileGrid;

  /**
   * @private
   * @type {ol.tilegrid.TileGrid}
   */
  this.targetTileGrid_ = targetTileGrid;

  /**
   * @private
   * @type {!Array.<ol.Tile>}
   */
  this.srcTiles_ = [];

  /**
   * @private
   * @type {Array.<goog.events.Key>}
   */
  this.sourcesListenerKeys_ = null;

  /**
   * @private
   * @type {number}
   */
  this.srcZ_ = 0;

  var targetExtent = targetTileGrid.getTileCoordExtent(this.getTileCoord());
  var maxTargetExtent = this.targetTileGrid_.getExtent();
  var maxSourceExtent = this.sourceTileGrid_.getExtent();

  var limitedTargetExtent = goog.isNull(maxTargetExtent) ?
      targetExtent : ol.extent.getIntersection(targetExtent, maxTargetExtent);

  if (ol.extent.getArea(limitedTargetExtent) === 0) {
    // Tile is completely outside range -> EMPTY
    // TODO: is it actually correct that the source even creates the tile ?
    this.state = ol.TileState.EMPTY;
    return;
  }

  if (!sourceProj.isGlobal()) {
    var sourceProjExtent = sourceProj.getExtent();
    if (!goog.isNull(sourceProjExtent)) {
      if (goog.isNull(maxSourceExtent)) {
        maxSourceExtent = sourceProjExtent;
      } else {
        maxSourceExtent = ol.extent.getIntersection(
            maxSourceExtent, sourceProjExtent);
      }
    }
  }

  var targetResolution = targetTileGrid.getResolution(z);

  var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJ_ERROR_THRESHOLD;

  // in source units
  var errorThreshold = targetResolution * errorThresholdInPixels *
      targetProj.getMetersPerUnit() / sourceProj.getMetersPerUnit();

  /**
   * @private
   * @type {!ol.reproj.Triangulation}
   */
  this.triangulation_ = new ol.reproj.Triangulation(
      sourceProj, targetProj, limitedTargetExtent, maxSourceExtent,
      errorThreshold);

  if (this.triangulation_.getTriangles().length === 0) {
    // no valid triangles -> EMPTY
    this.state = ol.TileState.EMPTY;
    return;
  }

  var targetCenter = ol.extent.getCenter(limitedTargetExtent);
  var sourceResolution = ol.reproj.calculateSourceResolution(
      sourceProj, targetProj, targetCenter, targetResolution);

  if (!goog.math.isFiniteNumber(sourceResolution) || sourceResolution <= 0) {
    // invalid sourceResolution -> EMPTY
    // probably edges of the projections when no extent is defined
    this.state = ol.TileState.EMPTY;
    return;
  }

  this.srcZ_ = sourceTileGrid.getZForResolution(sourceResolution);
  var srcExtent = this.triangulation_.calculateSourceExtent();

  if (!goog.isNull(maxSourceExtent) &&
      !ol.extent.intersects(maxSourceExtent, srcExtent)) {
    this.state = ol.TileState.EMPTY;
  } else {
    var srcRange = sourceTileGrid.getTileRangeForExtentAndZ(
        srcExtent, this.srcZ_);

    var xRange;
    var srcFullRange = sourceTileGrid.getFullTileRange(this.srcZ_);
    if (!goog.isNull(srcFullRange)) {
      srcRange.minY = Math.max(srcRange.minY, srcFullRange.minY);
      srcRange.maxY = Math.min(srcRange.maxY, srcFullRange.maxY);

      if (srcRange.minX > srcRange.maxX) {
        xRange = goog.array.concat(
            goog.array.range(srcRange.minX, srcFullRange.maxX + 1),
            goog.array.range(srcFullRange.minX, srcRange.maxX + 1)
            );
      } else {
        xRange = goog.array.range(
            Math.max(srcRange.minX, srcFullRange.minX),
            Math.min(srcRange.maxX, srcFullRange.maxX) + 1
            );
      }
    } else {
      xRange = goog.array.range(srcRange.minX, srcRange.maxX + 1);
    }

    var tilesRequired = xRange.length * srcRange.getHeight();
    if (!goog.asserts.assert(tilesRequired < ol.RASTER_REPROJ_MAX_SOURCE_TILES,
        'reasonable number of tiles is required')) {
      this.state = ol.TileState.ERROR;
      return;
    }
    goog.array.forEach(xRange, function(srcX, i, arr) {
      for (var srcY = srcRange.minY; srcY <= srcRange.maxY; srcY++) {
        var tile = getTileFunction(this.srcZ_, srcX, srcY, pixelRatio);
        if (tile) {
          this.srcTiles_.push(tile);
        }
{'fraction_non_alphanumeric': 0.13558231455096975, 'fraction_numerical': 0.001470723412078316, 'mean_word_length': 3.3800322061191626, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4473607', 'n_tokens_mistral': 3821, 'n_tokens_neox': 3680, 'n_words': 640}