/** Inform all registered MeasureToolListeners of a new distance. */
  private void reportDistance(boolean finalDistance) {
    if (dragStartPos == null || dragCurrentPos == null) return;

    final double dx = dragCurrentPos.x - dragStartPos.x;
    final double dy = dragCurrentPos.y - dragStartPos.y;
    final double d = Math.sqrt(dx * dx + dy * dy);
    final double angle = Math.atan2(dy, dx);

    Iterator iterator = this.listeners.iterator();
    while (iterator.hasNext()) {
      MeasureToolListener listener = (MeasureToolListener) iterator.next();
      if (finalDistance) listener.newDistance(d, angle, this.mapComponent);
      else listener.distanceChanged(d, angle, this.mapComponent);
    }
  }
 public GeoObject operate(GeoGrid geoGrid) {
   float[] minMax = geoGrid.getMinMax();
   final double firstContourLevel = Math.ceil(minMax[0] / interval) * interval;
   return operate(geoGrid, firstContourLevel);
 }
  private boolean contourCell(
      boolean forward,
      float[][] grid,
      int[] cellXY,
      double level,
      double west,
      double north,
      double cellSize,
      double[] pt) {

    final int col = cellXY[0];
    final int row = cellXY[1];

    // test if this cell has been visited before
    if (this.flags[row][col] == true) {
      return false;
    }

    // mark this cell as being visited
    this.flags[row][col] = true;

    // extract the four values of the cell
    float v0 = grid[row + 1][col]; // lower left
    if (Float.isNaN(v0)) {
      return false;
    }
    float v1 = grid[row + 1][col + 1]; // lower right
    if (Float.isNaN(v1)) {
      return false;
    }
    float v2 = grid[row][col]; // upper left
    if (Float.isNaN(v2)) {
      return false;
    }
    float v3 = grid[row][col + 1]; // upper right
    if (Float.isNaN(v3)) {
      return false;
    }

    if (this.treatDegreeJump) {

      float v0d = v0 - 180;
      float v1d = v1 - 180;
      float v2d = v2 - 180;
      float v3d = v3 - 180;

      final boolean adjustCell =
          (v0d > 0 && v1d < 0 && v0d - v1d > 90)
              || (v0d < 0 && v1d > 0 && v1d - v0d > 90)
              || (v0d > 0 && v2d < 0 && v0d - v2d > 90)
              || (v0d < 0 && v2d > 0 && v2d - v0d > 90)
              || (v0d > 0 && v3d < 0 && v0d - v3d > 90)
              || (v0d < 0 && v3d > 0 && v3d - v0d > 90)
              || (v1d > 0 && v2d < 0 && v1d - v2d > 90)
              || (v1d < 0 && v2d > 0 && v2d - v1d > 90)
              || (v1d > 0 && v3d < 0 && v1d - v3d > 90)
              || (v1d < 0 && v3d > 0 && v3d - v1d > 90)
              || (v2d > 0 && v3d < 0 && v2d - v3d > 90)
              || (v2d < 0 && v3d > 0 && v3d - v2d > 90);

      if (adjustCell) {
        if (v0 > 180) {
          v0 -= 360;
        }
        if (v1 > 180) {
          v1 -= 360;
        }
        if (v2 > 180) {
          v2 -= 360;
        }
        if (v3 > 180) {
          v3 -= 360;
        }
      }
    }

    if (!forward) {
      v0 = -v0;
      v1 = -v1;
      v2 = -v2;
      v3 = -v3;
      level = -level;
    }

    int code = 0;
    if (v0 > level) {
      code ^= 1;
    }
    if (v1 > level) {
      code ^= 2;
    }
    if (v2 > level) {
      code ^= 4;
    }
    if (v3 > level) {
      code ^= 8;
    }
    if (code == 0 || code == 15) {
      return false;
    }

    switch (code) {
      case 1: // enter bottom edge, exit left edge
        pt[0] = west + col * cellSize;
        pt[1] = (north - row * cellSize) - interpol(level, v2, v0) * cellSize;
        cellXY[0]--;
        break;

      case 2: // enter right edge, exit bottom edge
        pt[0] = (west + col * cellSize) + interpol(level, v0, v1) * cellSize;
        pt[1] = (north - row * cellSize) - cellSize;
        cellXY[1]++;
        break;

      case 3: // enter right edge, exit left edge
        pt[0] = west + col * cellSize;
        pt[1] = (north - row * cellSize) - interpol(level, v2, v0) * cellSize;
        cellXY[0]--;
        break;

      case 4: // enter left edge, exit top edge
        pt[0] = (west + col * cellSize) + interpol(level, v2, v3) * cellSize;
        pt[1] = north - row * cellSize;
        cellXY[1]--;
        break;

      case 5: // enter bottom edge, exit top edge
        pt[0] = (west + col * cellSize) + interpol(level, v2, v3) * cellSize;
        pt[1] = north - row * cellSize;
        cellXY[1]--;
        break;

      case 6: // saddle point
        final double topDif = north - pt[1] - row * cellSize;

        // distinguish between lines entering from the left and from the right
        if (Math.abs(west + col * cellSize - pt[0])
            < 0.5 * cellSize) { // line is entering from left
          // compute the intersection point on right edge of cell
          final double rightY = interpol(level, v3, v1) * cellSize;
          if (rightY > topDif) {
            // line is entering from left and leaving on top edge: case 4
            pt[0] = (west + col * cellSize) + interpol(level, v2, v3) * cellSize;
            pt[1] = north - row * cellSize;
            cellXY[1]--;
          } else {
            // line is entering from left and leaving on bottom edge: case 14
            pt[0] = (west + col * cellSize) + interpol(level, v0, v1) * cellSize;
            pt[1] = (north - row * cellSize) - cellSize;
            cellXY[1]++;
          }
        } else { // line is entering from right
          // compute the intersection point on left edge of cell
          final double leftY = interpol(level, v2, v0) * cellSize;
          if (leftY > topDif) {
            // line is entering from right and leaving on top edge: case 7
            pt[0] = (west + col * cellSize) + interpol(level, v2, v3) * cellSize;
            pt[1] = north - row * cellSize;
            cellXY[1]--;
          } else {
            // line is entering from right and leaving on bottom edge: case 2
            pt[0] = (west + col * cellSize) + interpol(level, v0, v1) * cellSize;
            pt[1] = (north - row * cellSize) - cellSize;
            cellXY[1]++;
          }
        }
        break;

      case 7: // enter right edge, exit top edge
        pt[0] = (west + col * cellSize) + interpol(level, v2, v3) * cellSize;
        pt[1] = north - row * cellSize;
        cellXY[1]--;
        break;

      case 8: // enter top edge, exit right edge
        pt[0] = (west + cellXY[0] * cellSize) + cellSize;
        pt[1] = (north - cellXY[1] * cellSize) - interpol(level, v3, v1) * cellSize;
        cellXY[0]++;
        break;

      case 9: // saddle point
        final double rightDif = pt[0] - west - col * cellSize;

        // distinguish between lines entering from the bottom and from the top
        if (Math.abs(north - row * cellSize - pt[1])
            < 0.5 * cellSize) { // line is entering from top
          // compute the intersection point on bottom edge of cell
          double bottomX = interpol(level, v0, v1) * cellSize;
          if (bottomX > rightDif) {
            // line is entering from top and leaving on left edge: case 11
            pt[0] = west + col * cellSize;
            pt[1] = (north - row * cellSize) - interpol(level, v2, v0) * cellSize;
            cellXY[0]--;
          } else {
            // line is entering from top and leaving on right edge: case 8
            pt[0] = (west + col * cellSize) + cellSize;
            pt[1] = (north - row * cellSize) - interpol(level, v3, v1) * cellSize;
            cellXY[0]++;
          }
        } else { // line is entering from bottom
          // compute the intersection point on top edge of cell
          double topX = interpol(level, v2, v3) * cellSize;
          if (topX > rightDif) {
            // line is entering from bottom and leaving on left edge: case 1
            pt[0] = west + col * cellSize;
            pt[1] = (north - row * cellSize) - interpol(level, v2, v0) * cellSize;
            cellXY[0]--;
          } else {
            // line is entering from bottom and leaving on right edge: case 13
            pt[0] = (west + col * cellSize) + cellSize;
            pt[1] = (north - row * cellSize) - interpol(level, v3, v1) * cellSize;
            cellXY[0]++;
          }
        }
        break;

      case 10: // enter top edge, exit bottom edge
        pt[0] = (west + col * cellSize) + interpol(level, v0, v1) * cellSize;
        pt[1] = (north - row * cellSize) - cellSize;
        cellXY[1]++;
        break;

      case 11: // enter top edge, exit left edge
        pt[0] = west + col * cellSize;
        pt[1] = (north - row * cellSize) - interpol(level, v2, v0) * cellSize;
        cellXY[0]--;
        break;

      case 12: // enter left edge, exit right edge
        pt[0] = (west + col * cellSize) + cellSize;
        pt[1] = (north - row * cellSize) - interpol(level, v3, v1) * cellSize;
        cellXY[0]++;
        break;

      case 13: // enter bottom edge, exit right edge
        pt[0] = (west + col * cellSize) + cellSize;
        pt[1] = (north - row * cellSize) - interpol(level, v3, v1) * cellSize;
        cellXY[0]++;
        break;

      case 14: // enter left edge, exit bottom edge
        pt[0] = (west + col * cellSize) + interpol(level, v0, v1) * cellSize;
        pt[1] = (north - row * cellSize) - cellSize;
        cellXY[1]++;
        break;
    }
    return true;
  }