text: /**
   * @module ol/geom/flat/closest
   */
  import {lerp, squaredDistance as squaredDx} from '../../math.js';
  
  
  /**
   * Returns the point on the 2D line segment flatCoordinates[offset1] to
   * flatCoordinates[offset2] that is closest to the point (x, y).  Extra
   * dimensions are linearly interpolated.
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset1 Offset 1.
   * @param {number} offset2 Offset 2.
   * @param {number} stride Stride.
   * @param {number} x X.
   * @param {number} y Y.
   * @param {Array.<number>} closestPoint Closest point.
   */
  function assignClosest(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
    var x1 = flatCoordinates[offset1];
    var y1 = flatCoordinates[offset1 + 1];
    var dx = flatCoordinates[offset2] - x1;
    var dy = flatCoordinates[offset2 + 1] - y1;
    var offset;
    if (dx === 0 && dy === 0) {
      offset = offset1;
    } else {
      var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
      if (t > 1) {
        offset = offset2;
      } else if (t > 0) {
        for (var i = 0; i < stride; ++i) {
          closestPoint[i] = lerp(flatCoordinates[offset1 + i],
            flatCoordinates[offset2 + i], t);
        }
        closestPoint.length = stride;
        return;
      } else {
        offset = offset1;
      }
    }
    for (var i$1 = 0; i$1 < stride; ++i$1) {
      closestPoint[i$1] = flatCoordinates[offset + i$1];
    }
    closestPoint.length = stride;
  }
  
  
  /**
   * Return the squared of the largest distance between any pair of consecutive
   * coordinates.
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @param {number} max Max squared delta.
   * @return {number} Max squared delta.
   */
  export function maxSquaredDelta(flatCoordinates, offset, end, stride, max) {
    var x1 = flatCoordinates[offset];
    var y1 = flatCoordinates[offset + 1];
    for (offset += stride; offset < end; offset += stride) {
      var x2 = flatCoordinates[offset];
      var y2 = flatCoordinates[offset + 1];
      var squaredDelta = squaredDx(x1, y1, x2, y2);
      if (squaredDelta > max) {
        max = squaredDelta;
      }
      x1 = x2;
      y1 = y2;
    }
    return max;
  }
  
  
  /**
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array.<number>} ends Ends.
   * @param {number} stride Stride.
   * @param {number} max Max squared delta.
   * @return {number} Max squared delta.
   */
  export function arrayMaxSquaredDelta(flatCoordinates, offset, ends, stride, max) {
    for (var i = 0, ii = ends.length; i < ii; ++i) {
      var end = ends[i];
      max = maxSquaredDelta(
        flatCoordinates, offset, end, stride, max);
      offset = end;
    }
    return max;
  }
  
  
  /**
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array.<Array.<number>>} endss Endss.
   * @param {number} stride Stride.
   * @param {number} max Max squared delta.
   * @return {number} Max squared delta.
   */
  export function multiArrayMaxSquaredDelta(flatCoordinates, offset, endss, stride, max) {
    for (var i = 0, ii = endss.length; i < ii; ++i) {
      var ends = endss[i];
      max = arrayMaxSquaredDelta(
        flatCoordinates, offset, ends, stride, max);
      offset = ends[ends.length - 1];
    }
    return max;
  }
  
  
  /**
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @param {number} maxDelta Max delta.
   * @param {boolean} isRing Is ring.
   * @param {number} x X.
   * @param {number} y Y.
   * @param {Array.<number>} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @param {Array.<number>=} opt_tmpPoint Temporary point object.
   * @return {number} Minimum squared distance.
   */
  export function assignClosestPoint(flatCoordinates, offset, end,
    stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
    opt_tmpPoint) {
    if (offset == end) {
      return minSquaredDistance;
    }
    var i, squaredDistance;
    if (maxDelta === 0) {
      // All points are identical, so just test the first point.
      squaredDistance = squaredDx(
        x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);
      if (squaredDistance < minSquaredDistance) {
        for (i = 0; i < stride; ++i) {
          closestPoint[i] = flatCoordinates[offset + i];
        }
        closestPoint.length = stride;
        return squaredDistance;
      } else {
        return minSquaredDistance;
      }
    }
    var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
    var index = offset + stride;
    while (index < end) {
      assignClosest(
        flatCoordinates, index - stride, index, stride, x, y, tmpPoint);
      squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);
      if (squaredDistance < minSquaredDistance) {
        minSquaredDistance = squaredDistance;
        for (i = 0; i < stride; ++i) {
          closestPoint[i] = tmpPoint[i];
        }
        closestPoint.length = stride;
        index += stride;
      } else {
        // Skip ahead multiple points, because we know that all the skipped
        // points cannot be any closer than the closest point we have found so
        // far.  We know this because we know how close the current point is, how
        // close the closest point we have found so far is, and the maximum
        // distance between consecutive points.  For example, if we're currently
        // at distance 10, the best we've found so far is 3, and that the maximum
        // distance between consecutive points is 2, then we'll need to skip at
        // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of
        // finding a closer point.  We use Math.max(..., 1) to ensure that we
        // always advance at least one point, to avoid an infinite loop.
        index += stride * Math.max(
          ((Math.sqrt(squaredDistance) -
              Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);
      }
    }
    if (isRing) {
      // Check the closing segment.
      assignClosest(
        flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);
      squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);
      if (squaredDistance < minSquaredDistance) {
        minSquaredDistance = squaredDistance;
        for (i = 0; i < stride; ++i) {
          closestPoint[i] = tmpPoint[i];
        }
        closestPoint.length = stride;
      }
    }
    return minSquaredDistance;
  }
  
  
  /**
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array.<number>} ends Ends.
   * @param {number} stride Stride.
   * @param {number} maxDelta Max delta.
   * @param {boolean} isRing Is ring.
   * @param {number} x X.
   * @param {number} y Y.
   * @param {Array.<number>} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @param {Array.<number>=} opt_tmpPoint Temporary point object.
   * @return {number} Minimum squared distance.
   */
  export function assignClosestArrayPoint(flatCoordinates, offset, ends,
    stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
    opt_tmpPoint) {
    var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
    for (var i = 0, ii = ends.length; i < ii; ++i) {
      var end = ends[i];
      minSquaredDistance = assignClosestPoint(
        flatCoordinates, offset, end, stride,
        maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
      offset = end;
    }
    return minSquaredDistance;
  }
  
  
  /**
   * @param {Array.<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array.<Array.<number>>} endss Endss.
   * @param {number} stride Stride.
   * @param {number} maxDelta Max delta.
   * @param {boolean} isRing Is ring.
   * @param {number} x X.
   * @param {number} y Y.
   * @param {Array.<number>} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @param {Array.<number>=} opt_tmpPoint Temporary point object.
   * @return {number} Minimum squared distance.
   */
  export function assignClosestMultiArrayPoint(flatCoordinates, offset,
    endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
    opt_tmpPoint) {
    var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
    for (var i = 0, ii = endss.length; i < ii; ++i) {
      var ends = endss[i];
      minSquaredDistance = assignClosestArrayPoint(
        flatCoordinates, offset, ends, stride,
        maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
      offset = ends[ends.length - 1];
    }
    return minSquaredDistance;
  }
  
  //# sourceMappingURL=closest.js.map