/**
   * do a dilation operation
   *
   * @param original Original region
   * @param r Radius of a circle used for dilation operation
   * @param search HashSet of search area
   * @return Dilated region
   */
  public static Region doDilationOperation(Region original, int r, HashSet<Integer> search) {
    Region region = new Region();

    /*
     * Create a relative distance list of a radius 'r' circle
     */
    ArrayList<Point> rdlist = new ArrayList<Point>();
    for (int x = -r; x <= r; x++) {
      for (int y = -r; y <= r; y++) {
        if (x * x + y * y <= r * r) {
          rdlist.add(new Point(x, y));
        }
      }
    }

    /*
     * Set search area if 'search' is empty
     */
    if (search == null || search.isEmpty()) {
      search = new HashSet<Integer>();

      int x_from = Math.max(original.left - r, 0);
      int x_to = Math.min(original.right + r, canvas_width - 1);
      int y_from = Math.max(original.top - r, 0);
      int y_to = Math.min(original.bottom + r, canvas_height - 1);
      for (int x = x_from; x <= x_to; x++) {
        for (int y = y_from; y <= y_to; y++) {
          search.add(ID(x, y));
        }
      }
    }

    /*
     * Dilation operation
     */
    for (int id : search) {
      Point pos = XY(id);
      boolean flag = false;

      // check if there is a region pixel around (x, y)
      for (Point p : rdlist) {
        if (original.contains(pos.x + p.x, pos.y + p.y)) {
          flag = true;
          break;
        }
      }

      // point (x, y) is added by dilation operation
      if (flag) {
        region.addPixel(pos.x, pos.y);
      }
    }

    return region;
  }
  public Region() throws IllegalStateException {
    if (canvas_width < 0 || canvas_height < 0) {
      throw new IllegalStateException("The canvas size has not been set appropriately.");
    }

    // initialize position values
    this.left = canvas_width + 1;
    this.top = canvas_height + 1;
    this.right = -1;
    this.bottom = -1;

    this.image = null;
    this.color =
        ColorConverter.RGB.rgb(
            (int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
  }