Shinya Kitaoka 120a6e
#include <cmath>      // sqrt() sin() cos()</cmath>
Shinya Kitaoka 120a6e
#include <vector>     // std::vector</vector>
Shinya Kitaoka 120a6e
#include <stdexcept>  // std::domain_error()</stdexcept>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
bool inside_polygon_(double radius, int odd_diameter, double xp, double yp,
Shinya Kitaoka 120a6e
                     int polygon_num, double degree) {
Shinya Kitaoka 120a6e
  double radian = degree * (M_PI / 180), add_radian = 2.0 * M_PI / polygon_num,
Shinya Kitaoka 120a6e
         x1 = 0, y1 = 0, x2, y2, xa = -odd_diameter, xb = -odd_diameter;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int ii = 0; ii <= polygon_num;
Shinya Kitaoka 120a6e
       ++ii, radian += add_radian, x1 = x2, y1 = y2) {
Shinya Kitaoka 120a6e
    /* (x2,y2)は(0,0)を原点とした正多角形の各頂点 */
Shinya Kitaoka 120a6e
    /* 注意:参照の図形と 計算結果の図形は左右反転する。
Shinya Kitaoka 120a6e
            そのため結果画像は左からCW回転となってしまう。
Shinya Kitaoka 120a6e
            数学的開始点(右)及び回転方向(CCW)とするため、
Shinya Kitaoka 120a6e
            内部で上下左右反転する。
Shinya Kitaoka 120a6e
    */
Shinya Kitaoka 120a6e
    x2 = -radius * cos(radian);
Shinya Kitaoka 120a6e
    y2 = -radius * sin(radian);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /* 線分をみるので、loop次へ */
Shinya Kitaoka 120a6e
    if (ii <= 0) {
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /* ypのy scanline上で交差
Shinya Kitaoka 120a6e
    ((y2==y1==yp)の場合も)しない線分なら次へ */
Shinya Kitaoka 120a6e
    if (!(((y1 <= yp) && (yp <= y2)) || ((y2 <= yp) && (yp <= y1)))) {
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /* 水平線分上 */
Shinya Kitaoka 120a6e
    if (y2 == y1) {
Shinya Kitaoka 120a6e
      if (((x1 <= xp) && (xp <= x2)) || ((x2 <= xp) && (xp <= x1))) {
Shinya Kitaoka 120a6e
        return true;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
      } /* 水平範囲外 */
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /* 初めの交差 */
Shinya Kitaoka 120a6e
    if (xa == -odd_diameter) {
Shinya Kitaoka 120a6e
      /* (x2 - x1)/(y2 - y1)=(xa - x1)/(yp - y1);
Shinya Kitaoka 120a6e
(xa - x1)=(yp - y1)*(x2 - x1)/(y2 - y1); */
Shinya Kitaoka 120a6e
      xa = (yp - y1) * (x2 - x1) / (y2 - y1) + x1;
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
        /* 2番目の交差 */
Shinya Kitaoka 120a6e
        if (xb == -odd_diameter) {
Shinya Kitaoka 120a6e
      xb = (yp - y1) * (x2 - x1) / (y2 - y1) + x1;
Shinya Kitaoka 120a6e
      if (((xa <= xp) && (xp <= xb)) || ((xb <= xp) && (xp <= xa))) {
Shinya Kitaoka 120a6e
        return true;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
      } /* 水平範囲外 */
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
/* 円錐型(1==curve)に減衰分布する2次元配列を生成する */
Shinya Kitaoka 120a6e
// bool attenuation_distribution_(
Toshihiro Shimizu 890ddd
void attenuation_distribution_(
Shinya Kitaoka 120a6e
    std::vector<std::vector<double>> &lens_matrix,</std::vector<double>
Shinya Kitaoka 120a6e
    std::vector<int> &lens_offsets, std::vector<double *=""> &lens_starts,</double></int>
Shinya Kitaoka 120a6e
    std::vector<int> &lens_sizes, int &odd_diameter,</int>
Shinya Kitaoka 120a6e
    const double radius /* =1.01 円半径(Pixel単位)1より大きい値 */
Shinya Kitaoka 120a6e
    ,
Shinya Kitaoka 120a6e
    const double curve /* =1. 0:無 0<.<1.0:減 1.0:リニア 1.0<:増 */
Shinya Kitaoka 120a6e
    ,
Shinya Kitaoka 120a6e
    const int polygon_num /* =2  2:円 3<=:円内接多角形(中心右始) */
Shinya Kitaoka 120a6e
    ,
Shinya Kitaoka 120a6e
    const double degree /* =0. 多角形開始角度(傾き)(反時計回り) */
Shinya Kitaoka 120a6e
    ) {
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
  double radius
Shinya Kitaoka 120a6e
          影響の半径
Shinya Kitaoka 120a6e
          1より大きい浮動小数値
Shinya Kitaoka 120a6e
          diameterはこの値から自動設定する
Shinya Kitaoka 120a6e
  double curve
Shinya Kitaoka 120a6e
          中心から周辺への下り具合(デフォルトは1)
Shinya Kitaoka 120a6e
          光り拡散の強弱
Shinya Kitaoka 120a6e
          zeroでない浮動小数値
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
  lens_offsetsとlens_sizesで影響範囲を表わすmatrixを表わす
Shinya Kitaoka 120a6e
  radiusは影響円の半径
Shinya Kitaoka 120a6e
  matrix(縦横)サイズ(lens_offsets.size())は
Shinya Kitaoka 120a6e
          円(radius)が入る最小整数値でかつ、
Shinya Kitaoka 120a6e
          1以上の奇数(1,3,5,...)値
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  影響は上下反転、左右反転するので注意、以下説明図
Shinya Kitaoka 120a6e
  y
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ^
Shinya Kitaoka 120a6e
  |	        |\
Shinya Kitaoka 120a6e
  |	        |   \
Shinya Kitaoka 120a6e
  |	        |  *   >
Shinya Kitaoka 120a6e
  |	|\      |   /
Shinya Kitaoka 120a6e
  |	|   \   |/
Shinya Kitaoka 120a6e
  |	|  *   >P
Shinya Kitaoka 120a6e
  |	|   /   |\
Shinya Kitaoka 120a6e
  |	|/      |   \
Shinya Kitaoka 120a6e
  |	        |  *   >
Shinya Kitaoka 120a6e
  |	        |   /
Shinya Kitaoka 120a6e
  |	        |/
Shinya Kitaoka 120a6e
--+--------------------------------------> x
Shinya Kitaoka 120a6e
  y
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ^
Shinya Kitaoka 120a6e
  |	   -----------
Shinya Kitaoka 120a6e
  |	    \   *   /
Shinya Kitaoka 120a6e
  |	      \   /
Shinya Kitaoka 120a6e
  |     ----------P----------
Shinya Kitaoka 120a6e
  |      \   *   / \   *   /
Shinya Kitaoka 120a6e
  |	 \   /     \   /
Shinya Kitaoka 120a6e
  |	   v         v
Shinya Kitaoka 120a6e
--+--------------------------------------> x
Shinya Kitaoka 120a6e
  |   P       : Target pixel
Shinya Kitaoka 120a6e
  |   <,/,\,| : 影響範囲
Shinya Kitaoka 120a6e
  |   *       : 描画の結果
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  /* --- 散光の力がゼロだと画像に対する変化はない ----- */
Shinya Kitaoka 120a6e
  if (0.0 == curve) {
Shinya Kitaoka 120a6e
    // return false;
Shinya Kitaoka 120a6e
    throw std::domain_error("curve is zero");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* --- 直径は、半径(radius)の2倍より大きい整数値 ---- */
Shinya Kitaoka 120a6e
  odd_diameter = static_cast<int>(ceil(radius * 2.0));</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* --- 直径が1Pixel以下は画像に対する変化はない ----- */
Shinya Kitaoka 120a6e
  if (odd_diameter <= 1) {
Shinya Kitaoka 120a6e
    // return false;
Shinya Kitaoka 120a6e
    throw std::domain_error("diameter is equal less than 1");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* --- 中心pixelが必要なので、奇数(1,3,5...)にする -- */
Shinya Kitaoka 120a6e
  if (0 == (odd_diameter % 2)) {
Shinya Kitaoka 120a6e
    ++odd_diameter;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* --- Memory確保or再利用 --------------------------- */
Shinya Kitaoka 120a6e
  lens_matrix.resize(odd_diameter);
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < odd_diameter; ++yy) {
Shinya Kitaoka 120a6e
    lens_matrix.at(yy).resize(odd_diameter);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  lens_offsets.resize(odd_diameter);
Shinya Kitaoka 120a6e
  lens_starts.resize(odd_diameter);
Shinya Kitaoka 120a6e
  lens_sizes.resize(odd_diameter);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* ---  1.円のレンズmatrix生成
Shinya Kitaoka 120a6e
          2.scanlineスタート位置とスタートポインタのセット
Shinya Kitaoka 120a6e
          3.scanlineサイズのセット -------------------- */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* --- scanlineスタート位置とscanlineサイズ生成 --- */
Shinya Kitaoka 120a6e
  double yp = 0.5 - (odd_diameter / 2.0); /* matrix中心からのy距離 */
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < odd_diameter; ++yy, yp += 1.0) {
Shinya Kitaoka 120a6e
    lens_offsets.at(yy) = -1;               /* 初期値 */
Shinya Kitaoka 120a6e
    lens_starts.at(yy)  = 0;                /* 初期値 */
Shinya Kitaoka 120a6e
    lens_sizes.at(yy)   = -1;               /* 初期値 */
Shinya Kitaoka 120a6e
    double xp = 0.5 - (odd_diameter / 2.0); /* matrix中心からのx距離 */
Shinya Kitaoka 120a6e
    for (int xx = 0; xx < odd_diameter; ++xx, xp += 1.0) {
Shinya Kitaoka 120a6e
      const double length = sqrt(xp * xp + yp * yp);
Shinya Kitaoka 120a6e
      if ((length <= radius) &&
Shinya Kitaoka 120a6e
          ((polygon_num < 3) ||
Shinya Kitaoka 120a6e
           inside_polygon_(radius, odd_diameter, xp, yp, polygon_num,
Shinya Kitaoka 120a6e
                           degree))) { /* 影響内 */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 1.円のレンズmatrix生成 */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 中心が1で外郭が0その間をリニアに */
Shinya Kitaoka 120a6e
        double val = 1.0 - (length / radius);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 光の減衰の様子をGamma曲線で指定する */
Shinya Kitaoka 120a6e
        /* 0<.<1.0:光減 1.0:リニア 1.0<:光増 */
Shinya Kitaoka 120a6e
        val = pow(val, 1.0 / curve);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 影響内は値を設定 */
Shinya Kitaoka 120a6e
        lens_matrix.at(yy).at(xx) = val;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 2.scanlineスタート位置(ポインタ)のセット */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (lens_offsets.at(yy) < 0) {
Shinya Kitaoka 120a6e
          /* 半径内に入った瞬間その位置を記録 */
Shinya Kitaoka 120a6e
          lens_offsets.at(yy) = xx;
Shinya Kitaoka 120a6e
          lens_starts.at(yy)  = &lens_matrix.at(yy).at(xx);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else { /* 影響外 */
Shinya Kitaoka 120a6e
        /* 1.円のレンズmatrix生成 */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 影響外はゼロ */
Shinya Kitaoka 120a6e
        lens_matrix.at(yy).at(xx) = 0.0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /* 3.scalineサイズのセット */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if ((0 <= lens_offsets.at(yy)) && (lens_sizes.at(yy) < 0)) {
Shinya Kitaoka 120a6e
          /* 半径内を出た瞬間そこまでのサイズを記録 */
Shinya Kitaoka 120a6e
          lens_sizes.at(yy) = xx - lens_offsets.at(yy);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    /* scanlineの最後までが半径内のとき */
Shinya Kitaoka 120a6e
    if ((0 <= lens_offsets.at(yy)) && (lens_sizes.at(yy) < 0)) {
Shinya Kitaoka 120a6e
      lens_sizes.at(yy) = odd_diameter - lens_offsets.at(yy);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /* matrixの値を正規化 */
Shinya Kitaoka 120a6e
  double total = 0.0;
Shinya Kitaoka 120a6e
  for (unsigned int yy = 0; yy < lens_matrix.size(); ++yy) {
Shinya Kitaoka 120a6e
    for (unsigned int xx = 0; xx < lens_matrix.at(yy).size(); ++xx) {
Shinya Kitaoka 120a6e
      total += lens_matrix.at(yy).at(xx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (unsigned int yy = 0; yy < lens_matrix.size(); ++yy) {
Shinya Kitaoka 120a6e
    for (unsigned int xx = 0; xx < lens_matrix.at(yy).size(); ++xx) {
Shinya Kitaoka 120a6e
      lens_matrix.at(yy).at(xx) /= total;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}