/**
   * 輪郭線抽出関数の実体です。
   *
   * @param i_raster
   * @param i_l
   * @param i_t
   * @param i_r
   * @param i_b
   * @param i_th
   * @param i_entry_x
   * @param i_entry_y
   * @param o_coord
   * @return
   * @throws NyARException
   */
  private boolean impl_getContour(
      INyARRaster i_raster,
      int i_l,
      int i_t,
      int i_r,
      int i_b,
      int i_th,
      int i_entry_x,
      int i_entry_y,
      NyARIntCoordinates o_coord)
      throws NyARException {
    assert (i_t <= i_entry_x);
    NyARIntPoint2d[] coord = o_coord.items;
    final int[] xdir = _getContour_xdir; // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
    final int[] ydir = _getContour_ydir; // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};

    final int[] buf = (int[]) i_raster.getBuffer();
    final int width = i_raster.getWidth();
    // クリップ領域の上端に接しているポイントを得る。

    int max_coord = o_coord.items.length;
    int coord_num = 1;
    coord[0].x = i_entry_x;
    coord[0].y = i_entry_y;
    int dir = 5;

    int c = i_entry_x;
    int r = i_entry_y;
    for (; ; ) {
      dir = (dir + 5) % 8; // dirの正規化
      // ここは頑張ればもっと最適化できると思うよ。
      // 4隅以外の境界接地の場合に、境界チェックを省略するとかね。
      if (c > i_l && c < i_r && r > i_t && r < i_b) {
        for (; ; ) { // gotoのエミュレート用のfor文
          // 境界に接していないとき(暗点判定)
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }
          dir++;
          if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) {
            break;
          }

          // 8方向全て調べたけどラベルが無いよ?
          throw new NyARException();
        }
      } else {
        // 境界に接しているとき
        int i;
        for (i = 0; i < 8; i++) {
          final int x = c + xdir[dir];
          final int y = r + ydir[dir];
          // 境界チェック
          if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) {
            if (buf[(y) * width + (x)] <= i_th) {
              break;
            }
          }
          dir++; // 倍長テーブルを参照するので問題なし
        }
        if (i == 8) {
          // 8方向全て調べたけどラベルが無いよ?
          throw new NyARException(); // return(-1);
        }
      }

      // xcoordとycoordをc,rにも保存
      c = c + xdir[dir];
      r = r + ydir[dir];
      coord[coord_num].x = c;
      coord[coord_num].y = r;
      // 終了条件判定
      if (c == i_entry_x && r == i_entry_y) {
        // 開始点と同じピクセルに到達したら、終点の可能性がある。
        coord_num++;
        // 末端のチェック
        if (coord_num == max_coord) {
          // 輪郭bufが末端に達した
          return false;
        }
        // 末端候補の次のピクセルを調べる
        dir = (dir + 5) % 8; // dirの正規化
        int i;
        for (i = 0; i < 8; i++) {
          final int x = c + xdir[dir];
          final int y = r + ydir[dir];
          // 境界チェック
          if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) {
            if (buf[(y) * width + (x)] <= i_th) {
              break;
            }
          }
          dir++; // 倍長テーブルを参照するので問題なし
        }
        if (i == 8) {
          // 8方向全て調べたけどラベルが無いよ?
          throw new NyARException();
        }
        // 得たピクセルが、[1]と同じならば、末端である。
        c = c + xdir[dir];
        r = r + ydir[dir];
        if (coord[1].x == c && coord[1].y == r) {
          // 終点に達している。
          o_coord.length = coord_num;
          break;
        } else {
          // 終点ではない。
          coord[coord_num].x = c;
          coord[coord_num].y = r;
        }
      }
      coord_num++;
      // 末端のチェック
      if (coord_num == max_coord) {
        // 輪郭が末端に達した
        return false;
      }
    }
    return true;
  }
  public boolean getContour(
      int i_l,
      int i_t,
      int i_r,
      int i_b,
      int i_entry_x,
      int i_entry_y,
      int i_th,
      NyARIntCoordinates o_coord)
      throws NyARException {
    assert (i_t <= i_entry_x);
    INyARGsPixelDriver reader = this._ref_raster.getGsPixelDriver();
    final int[] xdir = _getContour_xdir; // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
    final int[] ydir = _getContour_ydir; // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
    // クリップ領域の上端に接しているポイントを得る。
    NyARIntPoint2d[] coord = o_coord.items;
    int max_coord = o_coord.items.length;
    coord[0].x = i_entry_x;
    coord[0].y = i_entry_y;
    int coord_num = 1;
    int dir = 5;

    int c = i_entry_x;
    int r = i_entry_y;
    for (; ; ) {
      dir = (dir + 5) % 8; // dirの正規化
      // 境界に接しているとき
      int i;
      for (i = 0; i < 8; i++) {
        final int x = c + xdir[dir];
        final int y = r + ydir[dir];
        // 境界チェック
        if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) {
          if (reader.getPixel(x, y) <= i_th) {
            break;
          }
        }
        dir++; // 倍長テーブルを参照するので問題なし
      }
      if (i == 8) {
        // 8方向全て調べたけどラベルが無いよ?
        throw new NyARException(); // return(-1);
      }
      // xcoordとycoordをc,rにも保存
      c = c + xdir[dir];
      r = r + ydir[dir];
      coord[coord_num].x = c;
      coord[coord_num].y = r;
      // 終了条件判定
      if (c == i_entry_x && r == i_entry_y) {
        // 開始点と同じピクセルに到達したら、終点の可能性がある。
        coord_num++;
        // 末端のチェック
        if (coord_num == max_coord) {
          // 輪郭bufが末端に達した
          return false;
        }
        // 末端候補の次のピクセルを調べる
        dir = (dir + 5) % 8; // dirの正規化
        for (i = 0; i < 8; i++) {
          final int x = c + xdir[dir];
          final int y = r + ydir[dir];
          // 境界チェック
          if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) {
            if (reader.getPixel(x, y) <= i_th) {
              break;
            }
          }
          dir++; // 倍長テーブルを参照するので問題なし
        }
        if (i == 8) {
          // 8方向全て調べたけどラベルが無いよ?
          throw new NyARException();
        }
        // 得たピクセルが、[1]と同じならば、末端である。
        c = c + xdir[dir];
        r = r + ydir[dir];
        if (coord[1].x == c && coord[1].y == r) {
          // 終点に達している。
          o_coord.length = coord_num;
          break;
        } else {
          // 終点ではない。
          coord[coord_num].x = c;
          coord[coord_num].y = r;
        }
      }
      coord_num++;
      // 末端のチェック
      if (coord_num == max_coord) {
        // 輪郭が末端に達した
        return false;
      }
    }
    return true;
  }