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