/*
 * @file	AXMIspAwbAlgorithm.cpp
 * @brief	AWB Package
 *
 * @par		言語
 *			C++
 */

#include "../AXMCommon/AXMCommonConfig.hpp"

#include "AXMIspAwb.hpp"
#include "AXMIspAwbCommon.hpp"
#include "AXMIspAwbSettings.hpp"
#include "AXMIspAwbAlgorithm.hpp"
#include "AXHRegAddr.hpp"

#ifndef DISABLE_AWB_CONV_LOG
//  収束制御ログ出力有効時定義
#include "AXHSpecAwbStruct.hpp"

const SHORT ConvLogMax = 300;

struct st_conv_log {
  ST_COL_POINT  CenterPnt[ConvLogMax];
  USHORT        WB_rGain[ConvLogMax];
  USHORT        WB_bGain[ConvLogMax];
  USHORT        WBTgt_rGain[ConvLogMax];
  USHORT        WBTgt_bGain[ConvLogMax];
  SHORT         WBcnt[ConvLogMax];
  UCHAR         StableJudge[ConvLogMax];
};

st_conv_log   g_ConvLog;
static SHORT  g_ConvLogCnt;
#endif  //  DISABLE_AWB_CONV_LOG

extern ST_AWB_STATUS g_AwbStatus;


//
//	3Aデータ格納用クラス
//		CAL_COLOR
//

//
//	Constructor (Destructor : 未定義)
//
CAL_COLOR :: CAL_COLOR()
{
	for(INT i = 0; i < AWB_OPD_V_Div_Max; i++)
	{
		for(INT j = 0; j < AWB_OPD_H_Div_Max; j++)
		{
			for(INT k = 0; k < AWBColor_Max; k++)
			{
				Data[i][j][k] = 0;
			}
		}
	}
}


//
//	色データ格納用クラス
//		CAL_RG_BG
//

//
//	Constructor (Destructor : 未定義)
//
CAL_RG_BG :: CAL_RG_BG()
{
	for(INT i = 0; i < AWB_OPD_V_Div_Max; i++)
	{
		for(INT j = 0; j < AWB_OPD_H_Div_Max; j++)
		{
			Rg     [i][j] = 0;
			Bg     [i][j] = 0;
			Enabled[i][j] = False;
		}
	}
}
CAL_RG_BG :: CAL_RG_BG(SHORT init_Rg, SHORT init_Bg)
{
	for(INT i = 0; i < AWB_OPD_V_Div_Max; i++)
	{
		for(INT j = 0; j < AWB_OPD_H_Div_Max; j++)
		{
			Rg[i][j] = init_Rg;
			Bg[i][j] = init_Bg;
			Enabled[i][j] = False;
		}
	}
}


//
//	受信計算用積算データ格納用クラス
//		INT_RG_BG
//

//
//	Constructor
//
INT_RG_BG :: INT_RG_BG()
{
	bgIntData = 0;
	bgIntCnt = 0;
	rgIntData = 0;
	rgIntCnt = 0;
}


//
//	重心座標格納用クラス
//		ConterPoint
//

//
//	Constructor (Destructor : 未定義)
//
CenterPoint :: CenterPoint()
{
	for(INT i = 0; i < AWB_StableTerm_Max; i++)
	{
		Data[i].bg = 0;
		Data[i].rg = 0;
	}
}

//
//	重心座標追加
//
AWB_ER CenterPoint :: addData(SHORT bg, SHORT rg)
{
	AWB_ER	ret = AWB_E_OK;

	// 重心座標バックアップ
	for(INT i = AWB_StableTerm_Max - 1; 0 < i; i--)
	{
		Data[i] = Data[i - 1];
	}
	Data[0].bg = bg;
	Data[0].rg = rg;

	return ret;
}


//
//	演算データ格納用クラス
//		CAL_DATA
//

//
//	Constructor (Destructor : 未定義)
//
CAL_DATA :: CAL_DATA()
{
  BrightData = AWB_Bright_Init;         //  明るさデータ
  LightSource = AWBLightSource_None;    //  光源判定結果(未定義)
  OPDTrust = AWBOPDTrustJudge_High;     //  OPD信頼性判定結果
  StableJudge = False;                  //  安定判定
  WBRdiff = 0;                          //  収束制御用変化量(Rゲイン)
  WBBdiff = 0;                          //  収束制御用変化量(Bゲイン)
  WBcnt = 0;                            //  収束制御用カウンタ
  for(INT i = 0; i < AWB_ColorMatrixMax; i++) {
	MatrixDiff_CC22[i] = 0;             //  収束制御用変化量(Cbクロマゲイン)
	MatrixDiff_CC23[i] = 0;             //  収束制御用変化量(Cbマトリックスゲイン)
	MatrixDiff_CC33[i] = 0;             //  収束制御用変化量(Crクロマゲイン)
	MatrixDiff_CC32[i] = 0;             //  収束制御用変化量(Crマトリックスゲイン)
  }
}

//
//	マトリックスデータ設定
//
AWB_ER CAL_DATA :: setMatrix(UCHAR index, ColorMatrix setMatrix)
{
	AWB_ER	ret = AWB_E_OK;

	if(index < AWB_ColorMatrixMax)
	{
		Matrix[index] = setMatrix;		//	マトリックス係数(設定値代入)
	}
	else
	{
		ret = AWB_E_ER;
	}

	return ret;
}


//
//  エリア判定枠座標格納クラス
//    JudgeAreaFrame
//

//
//  Constructor(Destructor : 未定義)
//
JudgeAreaFrame :: JudgeAreaFrame()
{
  x_min = y_min = AWB_SHORT_MAX;
  x_max = y_max = AWB_SHORT_MIN;
}


//
//	色データ計算処理クラス
//		AXMIspAwbAlgorithmColorData
//

//
//	色データ計算処理
//
AWB_ER	AXMIspAwbAlgorithmColorData :: Exec(AXMIspAwbSettings& AWBSettings, UCHAR *p_img, CAL_COLOR& ImageData, CAL_RG_BG& ColorData)
{
	AWB_ER		ret = AWB_E_OK;
	USHORT	col_g;

	if((p_img == 0x00000000) || ((((ULONG)p_img) % 2) == 1))
	{
		return AWB_E_IMAGE_ADDR;
	}

	for(INT i = 0; i < AWBSettings.OPDSet.VDiv; i++)
	{
		// 今回のハードでは形式がベイヤー配列1セットずつ配列に入る
		// ベイヤー配列（R/Gr/Gb/B）取得
		for(INT j = 0; j < AWBSettings.OPDSet.HDiv; j++)
		{
			getColorData(p_img, i, j, AWBColor_IDX_R, ImageData);
			p_img += 8;
		}
		

		// R/G, B/G 取得
		for(INT j = 0; j < AWBSettings.OPDSet.HDiv; j++)
		{
			col_g = (ImageData.Data[i][j][AWBColor_IDX_Gr] + ImageData.Data[i][j][AWBColor_IDX_Gb]) >> 1;
			if(0 < col_g)
			{
				//	R/G = (R << 8) / G : 整数化のため、Rデータのかさ上げ
				ColorData.Rg     [i][j] = (SHORT)(((LONG)ImageData.Data[i][j][AWBColor_IDX_R] << AWB_Rg_Bg_Cal_Sft) / (LONG)col_g);
				//	B/G = (B << 8) / G : 整数化のため、Bデータのかさ上げ
				ColorData.Bg     [i][j] = (SHORT)(((LONG)ImageData.Data[i][j][AWBColor_IDX_B] << AWB_Rg_Bg_Cal_Sft) / (LONG)col_g);
				ColorData.Enabled[i][j] = True;
			}
			else
			{
				ColorData.Rg     [i][j] = 0;
				ColorData.Bg     [i][j] = 0;
				ColorData.Enabled[i][j] = False;
				ret = AWB_E_COLOR_DATA;
			}
		}
	}

	return ret;
}

//
//	色データパターン取得（二色ピッチ）
//		*p_img    : アドレス
//		x         : 垂直座標
//		y         : 水平座標
//		pos       : 先頭カラー番号
//		ImageData : 積算データ
//
AWB_ER	AXMIspAwbAlgorithmColorData::
		getColorData(UCHAR *p_img, INT v, INT h, INT col, CAL_COLOR& ImageData)
{
	if(p_img == 0x00000000)
	{
		return AWB_E_IMAGE_ADDR;
	}

	AWB_ER		ret = AWB_E_OK;
	// 今回のハードでは形式が通常のベイヤー配列が１セットごとに格納されている
	// ベイヤーパターン取得
	UInt32 ispReg0x04 = GetReg32(AXH_REG_ISP_CORE_BASE + 0x04);
	UInt32 bayerPattern = ispReg0x04 & 0x00000003;
	
	// ベイヤーの半分を取得（R,Gr,Gb,B中2色）
	UInt32 bayerFirstHalf = GetReg32(p_img);
	UInt32 bayerSecondHalf = GetReg32(p_img + 4);
	
	if (bayerPattern == 0) {
		// Rﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_R] = (USHORT)(bayerSecondHalf & 0x0000FFFF);
		// Grﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gr] = (USHORT)(bayerSecondHalf >> 16);
		// Gbﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gb] = (USHORT)(bayerFirstHalf & 0x0000FFFF);
		// Bﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_B] = (USHORT)(bayerFirstHalf >> 16);
		
	} else if (bayerPattern == 1) {
		// Rﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_R] = (USHORT)(bayerFirstHalf >> 16);
		// Grﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gr] = (USHORT)(bayerFirstHalf & 0x0000FFFF);
		// Gbﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gb] = (USHORT)(bayerSecondHalf >> 16);
		// Bﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_B] = (USHORT)(bayerSecondHalf & 0x0000FFFF);
		
	} else if (bayerPattern == 2) {
		// Rﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_R] = (USHORT)(bayerSecondHalf >> 16);
		// Grﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gr] = (USHORT)(bayerSecondHalf & 0x0000FFFF);
		// Gbﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gb] = (USHORT)(bayerFirstHalf >> 16);
		// Bﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_B] = (USHORT)(bayerFirstHalf & 0x0000FFFF);
		
	} else {	// bayerPattern == 3
		// Rﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_R] = (USHORT)(bayerFirstHalf & 0x0000FFFF);
		// Grﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gr] = (USHORT)(bayerFirstHalf >> 16);
		// Gbﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_Gb] = (USHORT)(bayerSecondHalf & 0x0000FFFF);
		// Bﾃﾞｰﾀ取得
		ImageData.Data[v][h][AWBColor_IDX_B] = (USHORT)(bayerSecondHalf >> 16);
		
	}
	
#if defined(IMX412) || defined(IMX415)
	// IMX412,IMX415の場合はさらに2bit右シフト
	// Rﾃﾞｰﾀ
	ImageData.Data[v][h][AWBColor_IDX_R] >>= 2;
	// Grﾃﾞｰﾀ
	ImageData.Data[v][h][AWBColor_IDX_Gr] >>= 2;
	// Gbﾃﾞｰﾀ
	ImageData.Data[v][h][AWBColor_IDX_Gb] >>= 2;
	// Bﾃﾞｰﾀ
	ImageData.Data[v][h][AWBColor_IDX_B] >>= 2;
#endif
	
	return ret;
}

//
//	OPDマスク処理クラス
//		AXMIspAwbAlgorithmOPDMaskedColorData
//

//
//	OPDマスク処理
//		マスクされた座標の色データを除外する
//		（色データを0に置き換える）
//
AWB_ER	AXMIspAwbAlgorithmOPDMaskedColorData :: Exec(AXMIspAwbSettings& AWBSettings, CAL_RG_BG& ColorData)
{
	AWB_ER		ret = AWB_E_OK;
	INT		i;

	//	マスク指定された座標の色データを0で置換する
	for(i = 0; i < AWB_OPDMaskSetMax; i++)
	{
		if((0 <= AWBSettings.OPDMask.Pnt[i].v) && (0 <= AWBSettings.OPDMask.Pnt[i].h))
		{
			SHORT	vData = AWBSettings.OPDMask.Pnt[i].v;
			SHORT	hData = AWBSettings.OPDMask.Pnt[i].h;

			//	除外データ設定
			ColorData.Rg     [vData][hData] = AWB_ColorDataException;
			ColorData.Bg     [vData][hData] = AWB_ColorDataException;
			ColorData.Enabled[vData][hData] = False;
		}
	}

	return ret;
}


//
//	判定用光源格納用クラス
//		AXMIspAwbAlgorithmJudgedLightSource
//

//
//	Constructor
//
AXMIspAwbAlgorithmJudgedLightSource :: AXMIspAwbAlgorithmJudgedLightSource()
{
  Mode = ATWMode_None;                  //  ATWモード該当なし
  Num = AWB_LightSourceNum_None;        //  光源枠数初期化
};
AXMIspAwbAlgorithmJudgedLightSource :: AXMIspAwbAlgorithmJudgedLightSource(AXMIspAwbSettings& AWBSettings)
{
  resetJudgedLightSourceData(AWBSettings);
}

void AXMIspAwbAlgorithmJudgedLightSource :: resetJudgedLightSourceData(AXMIspAwbSettings& AWBSettings)
{
  Num = AWB_LightSourceNum_None;        //  光源枠数初期化

  //  光源枠設定
  switch(AWBSettings.AWB_Mode)
  {
    case AWBMode_ATWMode:               //  0. ATWモード
      Mode = ATWMode_StandardMode;              //  標準モード
      //  1.白熱灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_A      );
      //  2.白色蛍光灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_CWF    );
      //  3.昼白色蛍光灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayWF  );
      //  4.昼光
      setLightSourceData(AWBSettings, AWBLightSource_Idx_3, AWBLightSource_Day    );
      //  5.曇天
      setLightSourceData(AWBSettings, AWBLightSource_Idx_4, AWBLightSource_Cloudy );
      //  6.水銀灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_5, AWBLightSource_Merculy);
      Num = AWB_LightSourceNum_ATWStandardMode;                     //  光源数 : 6
      break;
    case AWBMode_ATWSceaneMode:       //  1. ATWシーンモード
      switch(AWBSettings.ATW_SceaneMode)
      {
        case ATWSceaneMode_IndoorMode:                      //  0. 屋内モード
          Mode = ATWMode_SceaneIndoorMode;                          //  シーンモード : 屋内モード
          //  1.白熱灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_A    );
          //  2.白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_CWF  );
          //  3.昼白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayWF);
          //  4.昼光色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_3, AWBLightSource_DayF );
          Num = AWB_LightSourceNum_ATWSceaneIndoorMode;             //  光源数 : 4
          break;
        case ATWSceaneMode_IndoorCWFMode:                   //  1. 屋内蛍光灯モード
          Mode = ATWMode_SceaneIndoorCWFMode;                       //  シーンモード : 屋内蛍光灯モード
          //  1.電球色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_EBulbF);
          //  2.白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_CWF   );
          //  3.昼白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayWF );
          //  4.昼光色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_3, AWBLightSource_DayF  );
          Num = AWB_LightSourceNum_ATWSceaneIndoorCWFMode;          //  光源数 : 4
          break;
        case ATWSceaneMode_IndoorAMode:                     //  2. 屋内暖色系モード
          Mode = ATWMode_SceaneIndoorAMode;                         //  シーンモード : 屋内暖色系モード
          //  1.白熱灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_A);
          Num = AWB_LightSourceNum_ATWSceaneIndoorAMode;            //  光源数 : 1
          break;
        case ATWSceaneMode_OutdoorMode:                     //  3. 屋外モード
        case ATWSceaneMode_OutdoorAsphaltMode:              //  4. 屋外アスファルトモード
          Mode = ATWMode_SceaneOutdoorMode;                         //  シーンモード : 屋外モード
          //  1.ナトリウムランプ
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_NaLamp );
          //  2.白熱灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_A      );
          //  3.白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_CWF    );
          //  4.昼白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_3, AWBLightSource_DayWF  );
          //  5.昼光
          setLightSourceData(AWBSettings, AWBLightSource_Idx_4, AWBLightSource_Day    );
          //  6.曇天
          setLightSourceData(AWBSettings, AWBLightSource_Idx_5, AWBLightSource_Cloudy );
          //  7.水銀灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_6, AWBLightSource_Merculy);
          Num = AWB_LightSourceNum_ATWSceaneOutdoorMode;            //  光源数 : 7
          break;
        case ATWSceaneMode_LEDMode:                         //  5. LED照明モード
          Mode = ATWMode_SceaneLEDMode;                             //  シーンモード : LEDモード
          //  1.電球色LED
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_EBulbLED);
          //  2.白色LED
          setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_WhiteLED);
          //  3.昼光色LED
          setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayLED  );
          Num = AWB_LightSourceNum_ATWSceaneLEDMode;                //  光源数 : 3
          break;
        case ATWSceaneMode_ColorRollingMode:                //  6.カラーローリングモード
          Mode = ATWMode_SceaneColorRollingMode;                    //  シーンモード : ローリングモード
          //  1.カラーローリング検知時白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_CWFRolling);
          //  2.カラーローリング検知時昼白色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_DayWFRolling);
          //  3.カラーローリング検知時昼光色蛍光灯
          setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayFRolling  );
          Num = AWB_LightSourceNum_ATWSceaneColorRollingMode;       //  光源数 : 3
          break;
        default:
          Mode = ATWMode_None;
          Num = AWB_LightSourceNum_None;                    //  光源数 : 0
          //  何もしない
          break;
      }
      break;
    case AWBMode_OnePushMode:           //  4.全引込みモード
      Mode = ATWMode_None;
      //  ATWモードの光源枠を設定する
      //  1.白熱灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_0, AWBLightSource_A      );
      //  2.白色蛍光灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_1, AWBLightSource_CWF    );
      //  3.昼白色蛍光灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_2, AWBLightSource_DayWF  );
      //  4.昼光
      setLightSourceData(AWBSettings, AWBLightSource_Idx_3, AWBLightSource_Day    );
      //  5.曇天
      setLightSourceData(AWBSettings, AWBLightSource_Idx_4, AWBLightSource_Cloudy );
      //  6.水銀灯
      setLightSourceData(AWBSettings, AWBLightSource_Idx_5, AWBLightSource_Merculy);
      if(AWBSettings.OnePush.Range == AWBOnePushRange_ATW) {
        //  光源範囲がATW光源枠標準のときは、光源数とする
        Num = AWB_LightSourceNum_OnePushMode;             //  光源数 : 6
      }
      else {
        //  光源範囲が全範囲のときは、光源数 + 1 とする
        Num = AWB_LightSourceNum_OnePushMode + 1;           //  光源数 : 7
      }
      break;
    case AWBMode_TempManuMode:          //  2. 色温度指定マニュアルモード
    case AWBMode_LightManuMode:         //  3. 照明指定マニュアルモード
    case AWBMode_GainManuMode:          //  5. ゲイン指定マニュアルモード
    case AWBMode_HoldMode:              //  6. ホールドモード
    default:
      Mode = ATWMode_None;
      Num = AWB_LightSourceNum_None;                        //  光源数 : 0
      //  何もしない
      break;
  }
}

//	判定用光源格納
AWB_ER	AXMIspAwbAlgorithmJudgedLightSource :: setLightSourceData(AXMIspAwbSettings& AWBSettings, AWBLightSourceIdx index, AWBLightSource num)
{
  //  光源枠座標コピー
  if(((num != AWBLightSource_None       )  &&
      (num <  AWBLightSource_Rolling_Max)) &&
     (index < AWBLightSource_Idx_Max     )) {
    AWBLightDefault idx = AWBLightDefault_None;
    //  光源枠IDコピー
    Area[index].ID = num;
    //  光源枠座標コピー
    for(INT i = 0; i < AWB_LightSourcePnt; i++) {
      Area[index].CPnt[i] = AWBSettings.LightSource.Area[num].CPnt[i];
    }
    //  判定対象区間決定
    AreaFrm[index].x_min = AreaFrm[index].y_min = AWB_SHORT_MAX;
    AreaFrm[index].x_max = AreaFrm[index].y_max = AWB_SHORT_MIN;
    for(INT i = 0; i < AWB_LightSourcePnt; i++) {
      if(Area[index].CPnt[i].bg < AreaFrm[index].x_min) {
        AreaFrm[index].x_min = Area[index].CPnt[i].bg;
      }
      if(AreaFrm[index].x_max < Area[index].CPnt[i].bg) {
        AreaFrm[index].x_max = Area[index].CPnt[i].bg;
      }
      if(Area[index].CPnt[i].rg < AreaFrm[index].y_min) {
        AreaFrm[index].y_min = Area[index].CPnt[i].rg;
      }
      if(AreaFrm[index].y_max < Area[index].CPnt[i].rg) {
        AreaFrm[index].y_max = Area[index].CPnt[i].rg;
      }
    }
    //  デフォルト座標番号取得
    idx = LightSourceToLightDefault(num);
    if((idx != AWBLightDefault_None) && (idx != AWBLightDefault_Max)) {
      //  デフォルト座標コピー
      Default[index].bg = AWBSettings.LightDefault.CPnt[idx].bg;
      Default[index].rg = AWBSettings.LightDefault.CPnt[idx].rg;
    }
  }
  else {
    return AWB_E_ER;
  }
  return AWB_E_OK;
}

//  光源枠番号からデフォルト座標番号に変換
AWBLightDefault AXMIspAwbAlgorithmJudgedLightSource :: LightSourceToLightDefault(AWBLightSource LightSource)
{
  AWBLightDefault idx;

  switch(LightSource)
  {
    case AWBLightSource_A:              //   0.白熱灯
      idx = AWBLightDefault_3200K;                          //  10.黒体放射3200Kポイント
      break;
    case AWBLightSource_EBulbF:         //   1.電球色蛍光灯
      idx = AWBLightDefault_EBulbF;                         //   6.電球色蛍光灯デフォルト座標
      break;
    case AWBLightSource_CWF:            //   2.白色蛍光灯
    case AWBLightSource_CWFRolling:     //  12.白色蛍光灯(ローリング時)
      idx = AWBLightDefault_CWF;                            //   1.白色蛍光灯デフォルト座標
      break;
    case AWBLightSource_DayWF:          //   3.昼白色蛍光灯
    case AWBLightSource_DayWFRolling:   //  13.昼白色蛍光灯(ローリング時)
      idx = AWBLightDefault_DayWF;                          //   2.昼白色蛍光灯デフォルト座標
      break;
    case AWBLightSource_DayF:           //   4.昼光色蛍光灯
    case AWBLightSource_DayFRolling:    //  14.昼光色蛍光灯(ローリング時)
      idx = AWBLightDefault_DayF;                           //   3.昼光色蛍光灯デフォルト座標
      break;
    case AWBLightSource_Day:            //   5.昼光
      idx = AWBLightDefault_5800K;                          //  13.黒体放射5800Kポイント
      break;
    case AWBLightSource_Cloudy:         //   6.曇天
      idx = AWBLightDefault_7000K;                          //  14.黒体放射7000Kポイント
      break;
    case AWBLightSource_Merculy:        //   7.水銀灯
      idx = AWBLightDefault_Merculy;                        //   4.水銀灯デフォルト座標
      break;
    case AWBLightSource_NaLamp:         //   8.高圧ナトリウムランプ
      idx = AWBLightDefault_NaLamp;                         //   5.高圧ナトリウムランプデフォルト座標
      break;
    case AWBLightSource_EBulbLED:       //   9.電球色LED
      idx = AWBLightDefault_EBulbLED;                       //   6.電球色LEDデフォルト座標
      break;
    case AWBLightSource_WhiteLED:       //  10.白色LED
      idx = AWBLightDefault_WhiteLED;                       //   7.白色LEDデフォルト座標
      break;
    case AWBLightSource_DayLED:         //  11.昼光色LED
      idx = AWBLightDefault_DayLED;                         //   8.昼光色LEDデフォルト座標
      break;
    case AWBLightSource_None:
    case AWBLightSource_Rolling_Max:
    default:
      idx = AWBLightDefault_None;
      break;
  }
  return(idx);
}


//
//	光源枠判定処理クラス
//		AXMIspAlgorithmLightSourceJudgedColorData
//

//
//	光源枠判定処理
//		光源枠から外れるデータを除外する
//		(色データを0に置き換える)
//
AWB_ER	AXMIspAwbAlgorithmLightSourceJudgedColorData :: Exec(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER  ret = AWB_E_OK;
  INT     m = 0;
  UCHAR   mask = 0x01;

  AXMIspAwbAlgorithmCalibrationLibrary  CalLib;
  ColPoint  CPnt;

  //	光源枠判定結果初期化
  for(INT i = 0; i < AWBSettings.OPDSet.VDiv; i++)
  {
    for(INT j = 0; j < AWBSettings.OPDSet.HDiv; j++)
    {
      CalData.LightSourceArea[i][j] = 0x00;
    }
  }

  //  光源枠判定
  while(m < JudgeLightSource.Num)
  {
    //  光源枠判定
    for(INT i = 0; i < AWBSettings.OPDSet.VDiv; i++)    //  垂直軸(y : R/G)
    {
      for(INT j = 0; j < AWBSettings.OPDSet.HDiv; j++)  //  水平軸(x : B/G)
      {
        if(CalData.LightSourceArea[i][j] == 0)
        {
          CPnt.bg = CalData.ColorData.Bg[i][j];
          CPnt.rg = CalData.ColorData.Rg[i][j];
          if((JudgeLightSource.AreaFrm[m].x_min <= CPnt.bg) && (CPnt.bg <= JudgeLightSource.AreaFrm[m].x_max) &&
             (JudgeLightSource.AreaFrm[m].y_min <= CPnt.rg) && (CPnt.rg <= JudgeLightSource.AreaFrm[m].y_max)) {
            Judge result = CalLib.JudgeArea(JudgeLightSource.AreaFrm[m], CPnt, JudgeLightSource.Area[m]);
            if(result == Judge_True) {
              //  枠内判定
              CalData.LightSourceArea[i][j] |= mask;
            }
          }
        }
      }
    }
    mask <<= 0x01;
    m++;
  }
  return ret;
}


//
//	重み付け処理クラス
//		AXMIspAwbAlgorithmWeightedColorData
//

//
//	重み付け処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: Exec(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER		ret = AWB_E_OK;

	//	OPD積算処理
	ret |= ProcOPDArea(AWBSettings, CalData, JudgeLightSource);
	//	OPD重み付け処理
	ret |= ProcOPDWeight(AWBSettings, CalData, JudgeLightSource);
	//	光源枠重み計算
	ret |= CalcLightSourceWeight(AWBSettings, CalData.BrightData, JudgeLightSource);
	//	光源枠重み付け処理
	ret |= ProcLightSource(AWBSettings, CalData, JudgeLightSource);

	return ret;
}

//
//	OPD積算処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: ProcOPDArea(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER	ret = AWB_E_OK;
	USHORT	x_st = 0, x_en = 0, y_st = 0, y_en = 0;

	//	重み付け積算領域初期化
	for(INT i = 0; i < AWB_OPDArea_Idx_Max; i++)
	{
		for(INT j = 0; j < AWB_WeightLightSourceMax; j++)
		{
			CalData.IntData[i][j].bgIntData = 0;
			CalData.IntData[i][j].bgIntCnt = 0;
			CalData.IntData[i][j].rgIntData = 0;
			CalData.IntData[i][j].rgIntCnt = 0;
		}
	}

	for(INT m = 0; m < AWB_OPDArea_Idx_Max; m++)
	{
		//	OPDエリア開始-終了座標決定
		GetOPDAreaPoint(m, AWBSettings, x_st, x_en, y_st, y_en);
		//	重み付け積算データ作成
		for(USHORT i = y_st; i < y_en; i++)					// i : 垂直座標
		{
			for(USHORT j = x_st; j < x_en; j++)				// j : 水平座標
			{
				if(CalData.ColorData.Enabled[i][j] == True)
				{
					//	有効データのみ加算
					if(CalData.LightSourceArea[i][j] != 0)
					{
						//	光源枠あり
						UCHAR	mask = 0x01;
						for(INT k = 0; k < JudgeLightSource.Num; k++)
						{
							if((CalData.LightSourceArea[i][j] & mask) == mask)
							{
								//	光源枠あり
								CalData.IntData[m][k].bgIntData += CalData.ColorData.Bg[i][j];
								CalData.IntData[m][k].bgIntCnt++;
								CalData.IntData[m][k].rgIntData += CalData.ColorData.Rg[i][j];
								CalData.IntData[m][k].rgIntCnt++;
							}
							mask <<= 1;
						}
					}
					else
					{
						//	光源枠なし
						CalData.IntData[m][AWB_WeightLightSourceMax - 1].bgIntData += CalData.ColorData.Bg[i][j];
						CalData.IntData[m][AWB_WeightLightSourceMax - 1].bgIntCnt++;
						CalData.IntData[m][AWB_WeightLightSourceMax - 1].rgIntData += CalData.ColorData.Rg[i][j];
						CalData.IntData[m][AWB_WeightLightSourceMax - 1].rgIntCnt++;
						//	光源枠のないデータも無効データとする
						CalData.ColorData.Enabled[i][j] = False;
					}
				}
			}
		}
	}

	return ret;
}

//
//	OPDエリア座標を取得
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: GetOPDAreaPoint(INT index, AXMIspAwbSettings& AWBSettings, USHORT& x_st, USHORT& x_en, USHORT& y_st, USHORT& y_en)
{
  AWB_ER ret = AWB_E_OK;

  switch(index)
  {
    case (INT)AWB_OPDArea_Idx_0:        //  OPDエリア0
      x_st = 0;
      x_en = AWBSettings.OPDSet.HDiv;
      y_st = 0;
      y_en = AWBSettings.OPDWeight.V1;
      break;
    case (INT)AWB_OPDArea_Idx_1:        //  OPDエリア1
      x_st = 0;
      x_en = AWBSettings.OPDWeight.H2;
      y_st = AWBSettings.OPDWeight.V1;
      y_en = AWBSettings.OPDWeight.V4;
      break;
    case (INT)AWB_OPDArea_Idx_2:        //  OPDエリア2
      x_st = AWBSettings.OPDWeight.H2;
      x_en = AWBSettings.OPDWeight.H3;
      y_st = AWBSettings.OPDWeight.V1;
      y_en = AWBSettings.OPDWeight.V4;
      break;
    case (INT)AWB_OPDArea_Idx_3:        //  OPDエリア3
      x_st = AWBSettings.OPDWeight.H3;
      x_en = AWBSettings.OPDSet.HDiv;
      y_st = AWBSettings.OPDWeight.V1;
      y_en = AWBSettings.OPDWeight.V4;
      break;
    case (INT)AWB_OPDArea_Idx_4:        //  OPDエリア4
      x_st = 0;
      x_en = AWBSettings.OPDSet.HDiv;
      y_st = AWBSettings.OPDWeight.V4;
      y_en = AWBSettings.OPDSet.VDiv;
      break;
    default:
      ret = AWB_E_ER;
      break;
  }

  return ret;
}

//
//	OPD重み付け処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: ProcOPDWeight(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER	ret = AWB_E_OK;

	// エリア0重み付け
	ret |= OPDAreaMask(AWB_OPDArea_Idx_0, AWBSettings.OPDWeight.WeightMode[0], CalData, JudgeLightSource);
	// エリア1重み付け
	ret |= OPDAreaMask(AWB_OPDArea_Idx_1, AWBSettings.OPDWeight.WeightMode[1], CalData,	JudgeLightSource);
	// エリア2重み付け
	ret |= OPDAreaMask(AWB_OPDArea_Idx_2, AWBSettings.OPDWeight.WeightMode[2], CalData, JudgeLightSource);
	// エリア3重み付け
	ret |= OPDAreaMask(AWB_OPDArea_Idx_3, AWBSettings.OPDWeight.WeightMode[3], CalData, JudgeLightSource);
	// エリア4 重み付け
	ret |= OPDAreaMask(AWB_OPDArea_Idx_4, AWBSettings.OPDWeight.WeightMode[4], CalData, JudgeLightSource);

	return ret;
}

//
//	OPD枠重み付け処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData
	 :: OPDAreaMask(AWB_OPDArea index, AWBWeightMode WeightMode, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER		ret = AWB_E_OK;

	if(index < AWB_OPDArea_Idx_Max)
	{
		switch(WeightMode)
		{
			case AWBWeightMode_0:							//	重み 0
				//	重み0につき、積算データクリア
				for(INT k = 0; k < AWB_WeightLightSourceMax; k++)
				{
					CalData.IntData[index][k].bgIntData = 0;
					CalData.IntData[index][k].bgIntCnt = 0;
					CalData.IntData[index][k].rgIntData = 0;
					CalData.IntData[index][k].rgIntCnt = 0;
				}
				break;
			case AWBWeightMode_1_16:						// 重み 1/16(4ビット右シフト)
				for(INT k = 0; k < AWB_WeightLightSourceMax; k++)
				{
					CalData.IntData[index][k].bgIntData >>= 4;
					CalData.IntData[index][k].bgIntCnt >>= 4;
					CalData.IntData[index][k].rgIntData >>= 4;
					CalData.IntData[index][k].rgIntCnt >>= 4;
				}
				break;
			case AWBWeightMode_1_4:							// 重み 1/4(2ビット右シフト)
				for(INT k = 0; k < AWB_WeightLightSourceMax; k++)
				{
					CalData.IntData[index][k].bgIntData >>= 2;
					CalData.IntData[index][k].bgIntCnt >>= 2;
					CalData.IntData[index][k].rgIntData >>= 2;
					CalData.IntData[index][k].rgIntCnt >>= 2;
				}
				break;
			case AWBWeightMode_1:							// 重み 1
				// 何もしない
				break;
			default:
				ret = AWB_E_OPD_WEIGHT;
				break;
		}
	}
	else
	{
		ret = AWB_E_OPD_WEIGHT;
	}

	return ret;
}

//
//	光源枠重み計算処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: CalcLightSourceWeight(AXMIspAwbSettings& AWBSettings, USHORT BrightData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER  ret = AWB_E_OK;

  for(INT m = 0; m < JudgeLightSource.Num; m++) {
    INT num = AWBLightSource_None;
    if(JudgeLightSource.Area[m].ID < AWBLightSource_Max) {
      num = JudgeLightSource.Area[m].ID;
    }
    else if(JudgeLightSource.Area[m].ID < AWBLightSource_Rolling_Max) {
      num = JudgeLightSource.Area[m].ID - AWBLightSource_Max + AWBLightSource_CWF;
    }
    if((AWBLightSource_None < num) && (num < AWBLightSource_Max)) {
      if(BrightData < AWBSettings.LightSourceWeight.Weight[num].LimitL) {
        //  下限未満時処理
        JudgeLightSource.Area[m].Weight = AWBSettings.LightSourceWeight.Weight[num].WeightL;
      }
      else if(AWBSettings.LightSourceWeight.Weight[num].LimitH < BrightData) {
        //  上限超過時処理
        JudgeLightSource.Area[m].Weight = AWBSettings.LightSourceWeight.Weight[num].WeightH;
      }
      else {
        LONG  SubLimit;
        //  演算対象区間時処理
        USHORT w1 = (USHORT)AWBSettings.LightSourceWeight.Weight[num].WeightL;
        USHORT w2 = (USHORT)AWBSettings.LightSourceWeight.Weight[num].WeightH;
        USHORT l1 = AWBSettings.LightSourceWeight.Weight[num].LimitL;
        USHORT l2 = AWBSettings.LightSourceWeight.Weight[num].LimitH;
        SubLimit = l2 - l1;
        if(SubLimit == 0) {
          JudgeLightSource.Area[m].Weight = AWBSettings.LightSourceWeight.Weight[num].LimitL;
        }
        else {
          JudgeLightSource.Area[m].Weight = (USHORT)((LONG)(BrightData - l1) * (LONG)(w2 - w1) / SubLimit + w1);
        }
      }
    }
    else {
      JudgeLightSource.Area[m].Weight = 0;
      ret = AWB_E_WEIGHT;               //  光源枠設定異常
    }
  }
  return ret;
}

//
//	光源枠重み付け処理
//
AWB_ER	AXMIspAwbAlgorithmWeightedColorData :: ProcLightSource(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER		ret = AWB_E_OK;

	for(INT i = 0; i < AWB_OPDArea_Idx_Max; i++)			//	i : OPD枠重み付けエリア
	{
		//	光源枠内のデータに対してのみ、光源枠の重み付けを行う
		for(INT j = 0; j < AWBLightSource_Idx_Max; j++)		//	j : 光源枠
		{
			CalData.IntData[i][j].bgIntData *= JudgeLightSource.Area[j].Weight;
			CalData.IntData[i][j].bgIntCnt *= JudgeLightSource.Area[j].Weight;
			CalData.IntData[i][j].rgIntData *= JudgeLightSource.Area[j].Weight;
			CalData.IntData[i][j].rgIntCnt *= JudgeLightSource.Area[j].Weight;
		}
	}

	return ret;
}


//
//	重心計算処理クラス
//		AXMIspAwbAlgorithmBalanceCenterData
//

//
//	重心計算処理
//
AWB_ER	AXMIspAwbAlgorithmBalanceCenterData :: Exec(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER		ret = AWB_E_OK;
	LONG	sum_bg = 0;					//	重心座標計算対象B/G軸積算
	LONG	sum_rg = 0;					//	重心座標計算対象R/G軸積算
	LONG	num_bg = 0;					//	重心座標計算対象B/G点数
	LONG	num_rg = 0;					//	重心座標計算対象R/G点数

	for(INT i = 0; i < AWB_OPDArea_Idx_Max; i++)
	{
	  //  光源枠内にないのもは重心計算から除外する
	  //    AWB_WeightLightSourceMaxでは(光源枠数) + 1になるので、
	  //    演算に使用する光源枠数を使用する
		for(INT j = 0; j < JudgeLightSource.Num; j++)
		{
			if(0 < CalData.IntData[i][j].bgIntCnt)
			{
				sum_bg += CalData.IntData[i][j].bgIntData;
				num_bg += CalData.IntData[i][j].bgIntCnt;
			}
			if(0 < CalData.IntData[i][j].rgIntCnt)
			{
				sum_rg += CalData.IntData[i][j].rgIntData;
				num_rg += CalData.IntData[i][j].rgIntCnt;
			}
		}
	}

	//	B/G軸座標算出
	if((0 < num_bg) && (0 < num_rg))
	{
		//	重心決定
		CalData.CenterPnt.addData((USHORT)(sum_bg / num_bg), (USHORT)(sum_rg / num_rg));
	}
	else
	{
		ret = AWB_E_BALANCE_CENTER;
	}

	return ret;
}

//
//	重心計算処理(ワンプッシュモード)
//
AWB_ER	AXMIspAwbAlgorithmBalanceCenterData :: ExecAdjustMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER  ret = AWB_E_OK;
  LONG    sum_bg = 0;                   //  重心座標計算対象B/G軸積算
  LONG    sum_rg = 0;                   //  重心座標計算対象R/G軸積算
  LONG    num_bg = 0;                   //  重心座標計算対象B/G点数
  LONG    num_rg = 0;                   //  重心座標計算対象R/G点数

  //  全データを加算して重心データを算出する
  for(INT i = 0; i < AWBSettings.OPDSet.VDiv; i++) {
    for(INT j = 0; j < AWBSettings.OPDSet.HDiv; j++) {
      if(CalData.ColorData.Enabled[i][j] == True) {
        sum_bg += CalData.ColorData.Bg[i][j];
        num_bg++;
        sum_rg += CalData.ColorData.Rg[i][j];
        num_rg++;
      }
    }
  }

  //  B/G軸座標算出
  if((0 < num_bg) && (0 < num_rg)) {
    //  重心決定
    CalData.CenterPnt.addData((USHORT)(sum_bg / num_bg), (USHORT)(sum_rg / num_rg));
  }
  else {
    ret = AWB_E_BALANCE_CENTER;
  }

  return ret;
}


//
//	調整/収束制御処理クラス
//		AXMIspAwbAlgorithmAWBTarget
//
//		OPD信頼性判定処理
//		Mg-G方向調整処理
//		オフセット調整処理
//		安定性/差異評価処理
//		マトリックス調整処理
//		収束変位量計算処理
//

//
//	調整/収束制御処理(ATWモード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget ::
                    ExecATWMode(AXMIspAwbSettings& AWBSettings, CAL_DATA &CalData,
                                        AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER	ret = AWB_E_OK;

  //  OPD信頼性判定処理
  ret |= ProcOPDTrust(AWBSettings, CalData, JudgeLightSource);

  //	OPD信頼性判定以後処理選択
  switch(CalData.OPDTrust)
  {
    case AWBOPDTrustJudge_High:                             //  高信頼性判定
      //  光源枠判定処理
      ProcLightSource(CalData, JudgeLightSource);
      if((AWBSettings.AWB_Mode       == ::AWBMode_ATWSceaneMode         ) &&
         (AWBSettings.ATW_SceaneMode == ::ATWSceaneMode_ColorRollingMode)) {
        //  Mg-G方向調整処理(カラーローリングモード時、演算不要)
        //  オフセット調整処理
        ret |= ProcOffset(AWBSettings, CalData);
        //  安定性/差異評価処理(カラーローリングモード時、演算不要)
        //    ->重心をここでターゲットにセットし、ゲイン計算のために安定完了フラグを設定する)
        CalData.Tgt = CalData.CenterPnt.Data[0];
        CalData.StableJudge = ::AWB_StableComp;
        g_AwbStatus.Sts_Convergence = AWBStauts_Stable;   //  AWB状態出力:安定中
        //  WB/マトリックス決定処理
        ret |= ProcMatrix(AWBSettings, CalData);
        //  収束変位量計算(カラーローリングモード時、演算不要)
        //    ->最終目標値をここでターゲットにセットする
        CalData.WBTarget = CalData.WB;
        for(INT i = 0; i < AWB_ColorMatrixMax; i++) {
          CalData.MatrixTarget[i] = CalData.Matrix[i];
        }
      }
      else {
        //  Mg-G方向調整処理
        ret |= ProcMgGDirect(AWBSettings, CalData, JudgeLightSource);
        //  オフセット調整処理
        ret |= ProcOffset(AWBSettings, CalData);
        //  安定性/差異評価処理
        ret |= ProcStable(AWBSettings, CalData);
        //  WB/マトリックス決定処理
        ret |= ProcMatrix(AWBSettings, CalData);
        //  収束変位量計算
        ret |= ProcConvergence(AXMIspAwb::STATE_ATWMode, AWBSettings, CalData);
      }
      break;
    case AWBOPDTrustJudge_Low_Default:                      //  低信頼性判定 : デフォルト選択
      //  光源枠判定処理
      ProcLightSource(CalData, JudgeLightSource);
      //  光源が確定していれば、重心座標を光源デフォルト座標に置き換える
      {
        AWBLightDefault idx = JudgeLightSource.LightSourceToLightDefault(CalData.LightSource);
        if(idx != AWBLightDefault_None) {
          CalData.CenterPnt.Data[0] = AWBSettings.LightDefault.CPnt[idx];
        }
      }
      //  オフセット調整処理
      ret |= ProcOffset(AWBSettings, CalData);
      //  安定性/差異評価処理
      ret |= ProcStable(AWBSettings, CalData);
      //  WB/マトリックス決定処理
      ret |= ProcMatrix(AWBSettings, CalData);
      //  収束変位量計算
      ret |= ProcConvergence(AXMIspAwb::STATE_ATWMode, AWBSettings, CalData);
      break;
    case AWBOPDTrustJudge_Low_Hold:                         //  低信頼性判定 : ホールド選択
    default:
      break;
  }

  return ret;
}

//
//  調整/収束制御処理(OnePushモード)
//
AWB_ER  AXMIspAwbAlgorithmAWBTarget :: ExecOnePushMode(
    AXMIspAwbSettings &AWBSettings,
    CAL_DATA &CalData,
	AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource
    )
{
  AWB_ER  ret = AWB_E_OK;

  //  光源枠判定処理
  ProcLightSource(CalData, JudgeLightSource);
  //  目標ゲイン算出のための演算データを格納
  CalData.Tgt.bg = CalData.CenterPnt.Data[0].bg;
  CalData.Tgt.rg = CalData.CenterPnt.Data[0].rg;
  //  WB/マトリックス決定処理
  ret |= ProcMatrix(AWBSettings, CalData);
  //  収束変位量計算
  ret |= ProcConvergence(AXMIspAwb::STATE_OnePush, AWBSettings, CalData);

  return ret;
}

//
//  Matrix係数演算処理
//
ColorMatrix AXMIspAwbAlgorithmAWBTarget :: CalcMatrix(INT index, AWBLightSource LightSource, AXMIspAwbSettings& AWBSettings)
{
  ColorMatrix Matrix;

  if(LightSource != AWBLightSource_None)
  {
    //  Cbクロマゲイン
    Matrix.CC22 = (USHORT)(((INT)AWBSettings.ColorMatrix.Matrix[index].CC22 *
        (INT)AWBSettings.AdjustMatrix.Matrix[LightSource].AJCF11) >> AWB_Matrix_Sft);
    //  Cbマトリックスゲイン
    Matrix.CC23 = (USHORT)(((INT)AWBSettings.ColorMatrix.Matrix[index].CC23 *
        (INT)AWBSettings.AdjustMatrix.Matrix[LightSource].AJCF12) >> AWB_Matrix_Sft);
    //  Crクロマゲイン
    Matrix.CC33 = (USHORT)(((INT)AWBSettings.ColorMatrix.Matrix[index].CC33 *
        (INT)AWBSettings.AdjustMatrix.Matrix[LightSource].AJCF22) >> AWB_Matrix_Sft);
    //  Crマトリックスゲイン
    Matrix.CC32 = (USHORT)(((INT)AWBSettings.ColorMatrix.Matrix[index].CC32 *
        (INT)AWBSettings.AdjustMatrix.Matrix[LightSource].AJCF21) >> AWB_Matrix_Sft);
  }
  else
  {
    //  Cbクロマゲイン
    Matrix.CC22 = AWBSettings.ColorMatrix.Matrix[index].CC22;
    //  Cbマトリックスゲイン
    Matrix.CC23 = AWBSettings.ColorMatrix.Matrix[index].CC23;
    //  Crクロマゲイン
    Matrix.CC33 = AWBSettings.ColorMatrix.Matrix[index].CC33;
    //  Crマトリックスゲイン
    Matrix.CC32 = AWBSettings.ColorMatrix.Matrix[index].CC32;
  }
  return Matrix;
}

//
//	OPD信頼性処理
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcOPDTrust(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
	AWB_ER		ret = AWB_E_OK;
	INT		i, j;
	INT		cnt = 0;

	//	信頼性判定
	for(i = 0; i < AWBSettings.OPDSet.VDiv; i++)
	{
		for(j = 0; j < AWBSettings.OPDSet.HDiv; j++)
		{
			if(CalData.ColorData.Enabled[i][j] == True)
			{
				cnt++;
				if(AWBSettings.OPDTrust.TH <= cnt)
				{
					//	判定終了 : 高信頼性判定
					CalData.OPDTrust = AWBOPDTrustJudge_High;
					g_AwbStatus.TrustJudge = AWBOPDTrustJudge_High;             //  AWB状態出力:高信頼性判定
					return ret;
				}
			}
		}
	}

	//	低信頼性判定時処理
	switch(AWBSettings.OPDTrust.Sel)
	{
		case AWBLowTrust_Hold:			//	ホールド選択
			//	前回値をコピー
			CalData.OPDTrust = AWBOPDTrustJudge_Low_Hold;
			CalData.CenterPnt.Data[0] = CalData.CenterPnt.Data[1];
			break;
		case AWBLowTrust_Default:		//	デフォルト選択
			//	光源デフォルト座標をコピー
			CalData.OPDTrust = AWBOPDTrustJudge_Low_Default;
			if(0 < cnt)
			{
				LONG	min = 0xFFFF;
				LONG	cal;
				INT		index = 0;

				for(i = 0; i < JudgeLightSource.Num; i++)
				{
					//	モードごとに使用する光源からの距離を算出
					LONG	x = CalData.CenterPnt.Data[0].bg - JudgeLightSource.Default[i].bg;
					LONG	y = CalData.CenterPnt.Data[0].rg - JudgeLightSource.Default[i].rg;
					cal = x * x + y * y;
					if(cal < min)
					{
						//	最短距離判定
						index = i;
						min = cal;
					}
				}
				//	最短距離の光源座標を重心として代入
				CalData.CenterPnt.Data[0] = JudgeLightSource.Default[index];
			}
			else
			{
				AWBLightDefault LightDefault = JudgeLightSource.LightSourceToLightDefault(AWBSettings.OPDTrust.Zero);
				if((LightDefault != AWBLightDefault_None) && (LightDefault != AWBLightDefault_Max)) {
					CalData.CenterPnt.Data[0] = AWBSettings.LightDefault.CPnt[LightDefault];
				}
				else {
					ret = AWB_E_OPD_TRUST;
				}
			}
			break;
		default:
			ret = AWB_E_OPD_TRUST;
			//	何もしない
			break;
	}
	g_AwbStatus.TrustJudge = AWBOPDTrustJudge_Low_Hold;     //  AWB状態出力:低信頼性判定

	return ret;
}

//
//  光源判定処理
//
void AXMIspAwbAlgorithmAWBTarget :: ProcLightSource(CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  CalData.LightSource = AWBLightSource_None;                //  光源枠判定結果初期化
  for(INT m = 0; m < JudgeLightSource.Num; m++)
  {
    //  判定除外区間決定
    JudgeAreaFrame  AreaFrm;
    AreaFrm = ProcMgGDirect_getJudgeAreaFrame(m, JudgeLightSource);

    AXMIspAwbAlgorithmCalibrationLibrary  CalLib;
    Judge result = CalLib.JudgeArea(AreaFrm, CalData.CenterPnt.Data[0], JudgeLightSource.Area[m]);
    if(result == Judge_True)
    {
      //  枠内判定
      CalData.LightSource = JudgeLightSource.Area[m].ID;
    }
  }
  g_AwbStatus.LightSource = CalData.LightSource;            //  AWB状態出力
}

//
//	Mg-G方向調整
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER    ret = AWB_E_OK;
  ColPoint  ColPnt;

  //  Mg方向調整
  //  モード別処理
  switch(JudgeLightSource.Mode)
  {
    case ATWMode_StandardMode:          //  ATW標準モード
      ret = ProcMgGDirect_StandardMode(AWBSettings, CalData, JudgeLightSource);
      break;
    case ATWMode_SceaneIndoorMode:      //  シーンモード : 屋内モード
      ret = ProcMgGDirect_SceaneIndoorMode(AWBSettings, CalData, JudgeLightSource);
      break;
    case ATWMode_SceaneIndoorCWFMode:   //  シーンモード : 屋内蛍光灯モード
    case ATWMode_SceaneColorRollingMode://  シーンモード : カラーローリングモード
#ifndef DISABLE_MG_G_ADJ_FLU_FRAME      //  2015/2/18：蛍光灯枠判定時は、調整演算を行わない
      ret = ProcMgGDirect_SceaneIndoorCWFMode(AWBSettings, CalData, JudgeLightSource);
#endif  //  DISABLE_MG_G_ADJ_FLU_FRAME
      break;
    case ATWMode_SceaneIndoorAMode:     //  シーンモード : 屋内暖色系モード
      //  高色温度側領域調整
      //  黒体放射 1800K-3200K間で調整済みB/G座標算出
      CalData.CenterPnt.Data[0].bg = CalcMgGDirectLowColTemp(AWBSettings, AWBLightDefault_1800K, AWBLightDefault_3200K, CalData.CenterPnt.Data[0].rg);
      break;
    case ATWMode_SceaneOutdoorMode:     //  シーンモード : 屋外モード
      ret = ProcMgGDirect_SceaneOutdoorMode(AWBSettings, CalData, JudgeLightSource);
      break;
    case ATWMode_SceaneLEDMode:         //  シーンモード : LED照明モード
      ret = ProcMgGDirect_LEDMode(AWBSettings, CalData, JudgeLightSource);
      break;
    default:
      ret = AWB_E_MGG_DIRECT;
      break;
  }

  return ret;
}

//
//	Mg-G方向調整(除外区間決定)
//
JudgeAreaFrame AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_getJudgeAreaFrame(INT index, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  JudgeAreaFrame  AreaFrm;

  //  判定除外区間決定
  for(INT i = 0; i < AWB_LightSourcePnt; i++) {
    if(JudgeLightSource.Area[index].CPnt[i].bg < AreaFrm.x_min) {
      AreaFrm.x_min =JudgeLightSource.Area[index].CPnt[i].bg;
    }
    if(AreaFrm.x_max < JudgeLightSource.Area[index].CPnt[i].bg) {
      AreaFrm.x_max = JudgeLightSource.Area[index].CPnt[i].bg;
    }
    if(JudgeLightSource.Area[index].CPnt[i].rg < AreaFrm.y_min) {
      AreaFrm.y_min = JudgeLightSource.Area[index].CPnt[i].rg;
    }
    if(AreaFrm.y_max < JudgeLightSource.Area[index].CPnt[i].rg) {
      AreaFrm.y_max = JudgeLightSource.Area[index].CPnt[i].rg;
    }
  }

  return AreaFrm;
}

//
//	Mg-G方向調整(ATW標準モード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_StandardMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER  ret = AWB_E_OK;

  //  ATW標準モード 光源別処理
  switch(CalData.LightSource) {
    case AWBLightSource_A:              //	白熱灯
      //  低色温度側領域調整
      //  黒体放射 1800K-3200K間で調整済みB/G座標算出
      CalData.CenterPnt.Data[0].bg = CalcMgGDirectLowColTemp(AWBSettings, AWBLightDefault_1800K, AWBLightDefault_3200K, CalData.CenterPnt.Data[0].rg);
      break;
    case AWBLightSource_CWF:            //	白色蛍光灯
    case AWBLightSource_DayWF:          //	昼白色蛍光灯
#ifndef DISABLE_MG_G_ADJ_FLU_FRAME      //  2015/2/18：蛍光灯枠判定時は、調整演算を行わない
      //  蛍光灯領域調整
      //  白色蛍光灯-昼白色蛍光灯間で調整済み座標算出
      CalData.CenterPnt.Data[0] = CalcMgGDirectF(AWBSettings, AWBLightDefault_CWF, AWBLightDefault_DayWF, CalData.CenterPnt.Data[0]);
#endif  //  DISABLE_MG_G_ADJ_FLU_FRAME
      break;
    case AWBLightSource_Day:            //	昼光
    case AWBLightSource_Cloudy:         //	曇天
      //  高色温度側領域調整
      if(CalData.CenterPnt.Data[0].bg <= AWBSettings.LightDefault.CPnt[AWBLightDefault_7000K].bg) {
        //  黒体放射 5800K-7000K間で調整済みR/G座標算出
        CalData.CenterPnt.Data[0].rg = CalcMgGDirectHighColTemp(AWBSettings, AWBLightDefault_5800K, AWBLightDefault_7000K, CalData.CenterPnt.Data[0].bg);
      }
      else {
        //  黒体放射 7000K-10000K間で調整済みR/G座標算出
        CalData.CenterPnt.Data[0].rg = CalcMgGDirectHighColTemp(AWBSettings, AWBLightDefault_7000K, AWBLightDefault_10000K, CalData.CenterPnt.Data[0].bg);
      }
      break;
    case AWBLightSource_Merculy:        //	水銀灯
      //  そのままの座標とする
      break;
    default:
      ret = AWB_E_MGG_DIRECT_STD;
      break;
  }

  return ret;
}

//
//	Mg-G方向調整(シーンモード:屋内モード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_SceaneIndoorMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER    ret = AWB_E_OK;
  ColPoint  ColPnt;

  //  シーンモード:屋内モード 光源別処理
  switch(CalData.LightSource) {
    case AWBLightSource_A:              //  白熱灯
      //  高色温度側領域調整
      //  黒体放射 1800K-3200K間で調整済みB/G座標算出
      CalData.CenterPnt.Data[0].bg = CalcMgGDirectLowColTemp(AWBSettings, AWBLightDefault_1800K, AWBLightDefault_3200K, CalData.CenterPnt.Data[0].rg);
      break;
    case AWBLightSource_CWF:            //  白色蛍光灯
    case AWBLightSource_DayWF:          //  昼白色蛍光灯
    case AWBLightSource_DayF:           //  昼光色蛍光灯
#ifndef DISABLE_MG_G_ADJ_FLU_FRAME      //  2015/2/18：蛍光灯枠判定時は、調整演算を行わない
      //  蛍光灯領域調整
      //  (白色蛍光灯)-昼白色蛍光灯間で調整済み座標算出
      ColPnt = CalcMgGDirectF(AWBSettings, AWBLightDefault_CWF, AWBLightDefault_DayWF, CalData.CenterPnt.Data[0]);
      if(AWBSettings.LightDefault.CPnt[AWBLightDefault_DayWF].bg <= ColPnt.bg) {
        //  昼白色蛍光灯座標よりも高色温度側にあるとき
        //  昼白色蛍光灯-昼光色蛍光灯間で調整済み座標を算出
        CalData.CenterPnt.Data[0] = CalcMgGDirectF(AWBSettings, AWBLightDefault_DayWF, AWBLightDefault_DayF, CalData.CenterPnt.Data[0]);
      }
      else {
        CalData.CenterPnt.Data[0] = ColPnt;
      }
#endif  //  DISABLE_MG_G_ADJ_FLU_FRAME
      break;
    default:
      ret = AWB_E_MGG_DIRECT_INDOOR;
      break;
  }

  return ret;
}

//
//	Mg-G方向調整(シーンモード:屋内蛍光灯モード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_SceaneIndoorCWFMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER    ret = AWB_E_OK;
  ColPoint  ColPnt;

#ifndef DISABLE_MG_G_ADJ_FLU_FRAME      //  2015/2/18：蛍光灯枠判定時は、調整演算を行わない
  //  蛍光灯領域調整
  //  電球色蛍光灯-白色蛍光灯間で調整済み座標算出
  ColPnt = CalcMgGDirectF(AWBSettings, AWBLightDefault_EBulbF, AWBLightDefault_CWF, CalData.CenterPnt.Data[0]);
  if(AWBSettings.LightDefault.CPnt[AWBLightDefault_CWF].bg <= ColPnt.bg) {
    //  白色蛍光灯座標よりも高色温度側にあるとき
    //  白色蛍光灯-昼白色蛍光灯間で調整済み座標を算出
    ColPnt = CalcMgGDirectF(AWBSettings, AWBLightDefault_CWF, AWBLightDefault_DayWF, CalData.CenterPnt.Data[0]);
    if(AWBSettings.LightDefault.CPnt[AWBLightDefault_DayWF].bg <= ColPnt.bg) {
      //  昼白色蛍光灯座標よりも高色温度側にあるとき
      //  昼白色蛍光灯-昼光色蛍光灯間で調整済み座標を算出
      CalData.CenterPnt.Data[0] = CalcMgGDirectF(AWBSettings, AWBLightDefault_DayWF, AWBLightDefault_DayF, CalData.CenterPnt.Data[0]);
    }
    else {
      CalData.CenterPnt.Data[0] = ColPnt;
    }
  }
  else {
    CalData.CenterPnt.Data[0] = ColPnt;
  }
#endif  //  DISABLE_MG_G_ADJ_FLU_FRAME

  return ret;
}

//
//	Mg-G方向調整(シーンモード:屋外モード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_SceaneOutdoorMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER ret = AWB_E_OK;

  //  シーンモード:屋外モード 光源別処理
  switch(CalData.LightSource)
  {
    case AWBLightSource_Day:            //  昼光
    case AWBLightSource_Cloudy:         //  曇天
      //  高色温度側領域調整
      if(CalData.CenterPnt.Data[0].bg <= AWBSettings.LightDefault.CPnt[AWBLightDefault_7000K].bg)
      {
        //  黒体放射 5800K-7000K間で調整済みR/G座標算出
        CalData.CenterPnt.Data[0].rg = CalcMgGDirectHighColTemp(AWBSettings, AWBLightDefault_5800K, AWBLightDefault_7000K, CalData.CenterPnt.Data[0].bg);
      }
      else
      {
        //  黒体放射 7000K-10000K間で調整済みR/G座標算出
        CalData.CenterPnt.Data[0].rg = CalcMgGDirectHighColTemp(AWBSettings, AWBLightDefault_7000K, AWBLightDefault_10000K, CalData.CenterPnt.Data[0].bg);
      }
      break;
    case AWBLightSource_Merculy:        //  水銀灯
       //  そのままの座標とする
      break;
    case AWBLightSource_NaLamp:         //  ナトリウムランプ
      //  低色温度側領域調整
      //  黒体放射 1800-3200K間の傾きで水銀灯ポイントを通過する直線でR/G座標を算出
      CalData.CenterPnt.Data[0].bg = CalcMgGDirectNaLamp(AWBSettings, AWBLightDefault_1800K, AWBLightDefault_3200K, CalData.CenterPnt.Data[0].rg);
      break;
    default:
      ret = AWB_E_MGG_DIRECT_OUTDOOR;
      break;
  }

  return ret;
}

//
//	Mg-G方向調整(LED照明モード)
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMgGDirect_LEDMode(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData, AXMIspAwbAlgorithmJudgedLightSource& JudgeLightSource)
{
  AWB_ER ret = AWB_E_OK;

  //  LED照明モード 光源別処理
  switch(CalData.LightSource)
  {
    case AWBLightSource_EBulbLED:
      //  黒体放射 1800-3200K間で調整済みB/G座標を算出
      CalData.CenterPnt.Data[0].bg = CalcMgGDirectLowColTemp(AWBSettings, AWBLightDefault_1800K, AWBLightDefault_3200K, CalData.CenterPnt.Data[0].rg);
      break;
    case AWBLightSource_WhiteLED:
      //  黒体放射 4200K-5200K間で調整済み座標を算出
      CalData.CenterPnt.Data[0] = CalcMgGDirectF(AWBSettings, AWBLightDefault_4200K, AWBLightDefault_5200K, CalData.CenterPnt.Data[0]);
      break;
    case AWBLightSource_DayLED:
      //  黒体放射 5800-7000K間で調整済みR/G座標を算出
      CalData.CenterPnt.Data[0].rg = CalcMgGDirectHighColTemp(AWBSettings, AWBLightDefault_5800K, AWBLightDefault_7000K, CalData.CenterPnt.Data[0].bg);
      break;
    default:
      ret = AWB_E_MGG_DIRECT_LED;
      break;
  }

  return ret;
}

//
//	低色温度側領域調整
//
SHORT	AXMIspAwbAlgorithmAWBTarget :: CalcMgGDirectLowColTemp(AXMIspAwbSettings& AWBSettings, AWBLightDefault p1, AWBLightDefault p2, SHORT& rg)
{
  LONG	x1, x2, y1, y2;
  SHORT	bg;

  //  黒体放射 ポイント間で演算
  x1 = (LONG)AWBSettings.LightDefault.CPnt[p1].bg;
  x2 = (LONG)AWBSettings.LightDefault.CPnt[p2].bg;
  y1 = (LONG)AWBSettings.LightDefault.CPnt[p1].rg;
  y2 = (LONG)AWBSettings.LightDefault.CPnt[p2].rg;
  //  調整済みB/G座標算出
  if((y2 - y1) == 0) {
    bg = -1;
  }
  else {
    bg = (SHORT)(((x2 - x1) * (LONG)rg + x1 * y2 - x2 * y1) / (y2 - y1));
  }

  if(p1 == AWBLightDefault_1800K) {
    //  引込み範囲下限確認
    if(AWBSettings.LightRange.CPnt[AWB_LightRange_LowTemp].rg <= rg) {
      bg = AWBSettings.LightRange.CPnt[AWB_LightRange_LowTemp].bg;
      rg = AWBSettings.LightRange.CPnt[AWB_LightRange_LowTemp].rg;
    }
  }

  return bg;
}

//
//	高色温度側領域調整
//
SHORT	AXMIspAwbAlgorithmAWBTarget :: CalcMgGDirectHighColTemp(AXMIspAwbSettings& AWBSettings, AWBLightDefault p1, AWBLightDefault p2, SHORT& bg)
{
  LONG  x1, x2, y1, y2;
  SHORT rg;

  //  黒体放射ポイント間で演算
  x1 = (LONG)AWBSettings.LightDefault.CPnt[p1].bg;
  x2 = (LONG)AWBSettings.LightDefault.CPnt[p2].bg;
  y1 = (LONG)AWBSettings.LightDefault.CPnt[p1].rg;
  y2 = (LONG)AWBSettings.LightDefault.CPnt[p2].rg;
  //  調整済みR/G座標算出
  if((x2 - x1) == 0) {
    rg = -1;
  }
  else {
    rg = (SHORT)(((y2 - y1) * bg + y1 * x2 - y2 * x1) / (x2 - x1));
  }

  if(p2 == AWBLightDefault_10000K) {
    //  引込み範囲下限確認
    if(AWBSettings.LightRange.CPnt[AWB_LightRange_HighTemp].bg <= bg) {
      bg = AWBSettings.LightRange.CPnt[AWB_LightRange_HighTemp].bg;
      rg = AWBSettings.LightRange.CPnt[AWB_LightRange_HighTemp].rg;
    }
  }

  return rg;
}

//
//	蛍光灯領域調整
//
ColPoint	AXMIspAwbAlgorithmAWBTarget :: CalcMgGDirectF(AXMIspAwbSettings& AWBSettings, AWBLightDefault p1, AWBLightDefault p2, ColPoint in_data)
{
	LONG		x1, x2, y1, y2, x_sub, y_sub;
	ColPoint	out_data;

	//	白色蛍光灯-昼白色蛍光灯間で演算
	x1 = (LONG)AWBSettings.LightDefault.CPnt[p1].bg;
	x2 = (LONG)AWBSettings.LightDefault.CPnt[p2].bg;
	y1 = (LONG)AWBSettings.LightDefault.CPnt[p1].rg;
	y2 = (LONG)AWBSettings.LightDefault.CPnt[p2].rg;
	x_sub = x2 - x1;
	y_sub = y1 - y2;
	// 調整済みB/G座標算出
	out_data.bg = (SHORT)((x_sub * (x_sub * in_data.bg - y_sub * in_data.rg) - y_sub * (x1 * y2 - x2 * y1)) / (x_sub * x_sub + y_sub * y_sub));
	//	調整済みR/G座標算出
	out_data.rg = (SHORT)((y_sub * (y_sub * in_data.rg - x_sub * in_data.bg) - x_sub * (x1 * y2 - x2 * y1)) / (x_sub * x_sub + y_sub * y_sub));

	return out_data;
}

//
//	ナトリウムランプ領域調整
//
SHORT	AXMIspAwbAlgorithmAWBTarget :: CalcMgGDirectNaLamp(AXMIspAwbSettings& AWBSettings, AWBLightDefault p1, AWBLightDefault p2, SHORT rg)
{
	LONG	x1, x2, x3, y1, y2, y3;
	SHORT	bg;

	//	黒体放射 ポイント間で演算
	x1 = (LONG)AWBSettings.LightDefault.CPnt[p1].bg;
	x2 = (LONG)AWBSettings.LightDefault.CPnt[p2].bg;
	y1 = (LONG)AWBSettings.LightDefault.CPnt[p1].rg;
	y2 = (LONG)AWBSettings.LightDefault.CPnt[p2].rg;
	x3 = (LONG)AWBSettings.LightDefault.CPnt[AWBLightDefault_NaLamp].bg;
	y3 = (LONG)AWBSettings.LightDefault.CPnt[AWBLightDefault_NaLamp].rg;
	//	調整済みB/G座標算出
	if((y2 - y1) == 0)
	{
		bg = -1;
	}
	else
	{
		bg = (SHORT)(((x2 - x1) * (LONG)(rg - y3) + (y2 - y1) * x3) / (y2 - y1));
	}

	return bg;
}

//
//	オフセット調整処理
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcOffset(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData)
{
  //  オフセット調整
  if(AWBLightSource_None < CalData.LightSource) {
    if(CalData.LightSource < AWBLightSource_Max) {
      CalData.CenterPnt.Data[0].bg += AWBSettings.Offset.Pnt[CalData.LightSource].bg;
      CalData.CenterPnt.Data[0].rg += AWBSettings.Offset.Pnt[CalData.LightSource].rg;
    }
    else if(CalData.LightSource < AWBLightSource_Rolling_Max) {
      //  ローリング時(通常時のものを使用する)
      INT tmp = CalData.LightSource - AWBLightSource_Max + AWBLightSource_CWF;
      CalData.CenterPnt.Data[0].bg += AWBSettings.Offset.Pnt[tmp].bg;
      CalData.CenterPnt.Data[0].rg += AWBSettings.Offset.Pnt[tmp].rg;
    }
    else {
      //  光源枠異常
      return AWB_E_OFFSET;
    }
  }
  else
  {
    return AWB_E_OFFSET;
    //  光源枠が確定していない時は何もしない
  }

  return AWB_E_OK;
}

//
//	安定性/差異評価処理
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcStable(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData)
{
  AWB_ER  ret = AWB_E_OK;
  SHORT   minBg, minRg, maxBg, maxRg;
  LONG    StableTerm = (LONG)AWBSettings.Convergence.StableTerm;

  minBg = minRg = AWB_SHORT_MAX;
  maxBg = maxRg = AWB_SHORT_MIN;
  //  安定性確認期間での設定回数で安定確認するためには、(StableTerm + 1)にする必要がある
  for(INT i = 0; i < (StableTerm + 1); i++)
  {
    //  B/G軸 : max,min確認
    if(CalData.CenterPnt.Data[i].bg < minBg)
    {
      minBg = CalData.CenterPnt.Data[i].bg;
    }
    if(maxBg < CalData.CenterPnt.Data[i].bg)
    {
      maxBg = CalData.CenterPnt.Data[i].bg;
    }
    //  R/G軸 : max, min確認
    if(CalData.CenterPnt.Data[i].rg < minRg)
    {
      minRg = CalData.CenterPnt.Data[i].rg;
    }
    if(maxRg < CalData.CenterPnt.Data[i].rg)
    {
      maxRg = CalData.CenterPnt.Data[i].rg;
    }
  }
  //  安定性評価
  if(((maxBg - minBg) <= AWBSettings.Convergence.StableTH) &&
     ((maxRg - minRg) <= AWBSettings.Convergence.StableTH))
  {
    LONG sumBg = 0;
    LONG sumRg = 0;
    SHORT diffBg, diffRg;
    for(INT i = 0; i < StableTerm; i++)
    {
      sumBg += CalData.CenterPnt.Data[i].bg;
      sumRg += CalData.CenterPnt.Data[i].rg;
    }
    CalData.TgtTmp.bg = (SHORT)(sumBg / StableTerm);
    CalData.TgtTmp.rg = (SHORT)(sumRg / StableTerm);
    //  差異評価
    if(CalData.TgtPrev.bg <= CalData.TgtTmp.bg)
    {
      diffBg = CalData.TgtTmp.bg - CalData.TgtPrev.bg;
    }
    else
    {
      diffBg = CalData.TgtPrev.bg - CalData.TgtTmp.bg;
    }
    if(CalData.TgtPrev.rg <= CalData.TgtTmp.rg)
    {
      diffRg = CalData.TgtTmp.rg - CalData.TgtPrev.rg;
    }
    else
    {
      diffRg = CalData.TgtPrev.rg - CalData.TgtTmp.rg;
    }
    if((diffBg <= AWBSettings.Convergence.LightTH) &&
        (diffRg <= AWBSettings.Convergence.LightTH))
    {
//      CalData.TgtPrev = CalData.Tgt;
      CalData.Tgt = CalData.TgtTmp;
      //  目標値更新
      CalData.StableJudge = AWB_StableComp;
      g_AwbStatus.Sts_Convergence = AWBStatus_Convergence;  //  AWB状態出力:収束中
    }
    else
    {
      CalData.WBcnt = 0;
      //  収束制御中に不安定判定された場合には、現在値(変化点)を前回値とする
      if((CalData.StableJudge & AWB_StableComp) == AWB_StableComp) {
        CalData.WBPrev = CalData.WBTarget;
        for(INT i = 0; i < AWB_ColorMatrixMax; i++) {
          CalData.MatrixPrev[i]   = CalData.MatrixTarget[i];
        }
      }
      CalData.StableJudge = 0;
      g_AwbStatus.Sts_Convergence = AwbStatus_flact;        //  AWB状態出力:変動中
    }
  }
  else
  {
    CalData.WBcnt = 0;
    //  収束制御中に不安定判定された場合には、現在値(変化点)を前回値とする
    if((CalData.StableJudge & AWB_StableComp) == AWB_StableComp) {
      CalData.WBPrev = CalData.WBTarget;
      for(INT i = 0; i < AWB_ColorMatrixMax; i++) {
        CalData.MatrixPrev[i]   = CalData.MatrixTarget[i];
      }
    }
    CalData.StableJudge = 0;
    g_AwbStatus.Sts_Convergence = AwbStatus_flact;          //  AWB状態出力:変動中
  }
  CalData.TgtPrev = CalData.TgtTmp;

  return ret;
}

//
//	WB/マトリックス決定処理
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcMatrix(AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData)
{
  INT     lp_max = 1;
  WBGain  WBTmp;
  UCHAR   mask = AWB_StableComp;

  if(((CalData.StableJudge & mask) == mask) || (AWBSettings.AWB_Mode == AWBMode_OnePushMode))
  {
    //  目標WBゲイン算出
    if((CalData.Tgt.bg != 0) && (CalData.Tgt.rg != 0))
    {
      //  WB(B) 目標値算出
      CalData.WB.BGain = (USHORT)((0x00000001l << AWB_Rg_Bg_WB_Sft) / (LONG)CalData.Tgt.bg);
      //  WB(R) 目標値算出
      CalData.WB.RGain = (USHORT)((0x00000001l << AWB_Rg_Bg_WB_Sft) / (LONG)CalData.Tgt.rg);
    }
    //  マトリックス係数算出
    if(AWBLightSource_None < CalData.LightSource) {
      AWBLightSource index;
      if(AWBSettings.ColorMatrix.Mode == True) {
        //  4象限独立モードのときは、4象限分の係数を更新するOK
        lp_max = AWB_ColorMatrixMax;
      }
      if(CalData.LightSource < AWBLightSource_Max) {                            //  通常時光源枠
        index = CalData.LightSource;
      }
      else if(CalData.LightSource < AWBLightSource_Rolling_Max) {               //  ローリング検知時光源枠
        index = (AWBLightSource)(CalData.LightSource - AWBLightSource_Max + AWBLightSource_CWF);
      }
      else {
        return AWB_E_MATRIX;            //  光源異常
      }
      for(INT i = 0; i < lp_max; i++) {
        //  マトリックス係数演算
        CalData.Matrix[i] = CalcMatrix(i, index, AWBSettings);
      }
    }
    else {
      return AWB_E_MATRIX;              //  該当する光源なし
    }
  }
  return AWB_E_OK;
}

//
//	収束変位量計算処理
//
AWB_ER	AXMIspAwbAlgorithmAWBTarget :: ProcConvergence(UCHAR state, AXMIspAwbSettings& AWBSettings, CAL_DATA& CalData)
{
  AWB_ER  ret = AWB_E_OK;
  INT     lp_max = 1;
  USHORT  speed;
  UCHAR   StableComp = False;

  //  ワンプッシュモード時のみ収束速度に引込み速度を使用
  if(state == AXMIspAwb::STATE_OnePush)
  {
    speed = AWBSettings.OnePush.Speed;
    StableComp = True;
  }
  else
  {
    speed = AWBSettings.Convergence.Speed;
    if((CalData.StableJudge & AWB_StableComp) == AWB_StableComp)
    {
      StableComp = True;
    }
  }

  //  安定期間確認
  if(StableComp == True)
  {
    if(AWBSettings.ColorMatrix.Mode == True)
    {
      //  4象限独立モードのときは、4象限分の係数を更新する
      lp_max = AWB_ColorMatrixMax;
    }
    //  WB(B)収束制御用目標値決定
    if(CalData.WBcnt == 0)
    {
      //  差分量決定(WB)
      CalData.WBBdiff = ((SHORT)CalData.WB.BGain - (SHORT)CalData.WBPrev.BGain);
      CalData.WBRdiff = ((SHORT)CalData.WB.RGain - (SHORT)CalData.WBPrev.RGain);
      //  差分量決定(カラーマトリックス)
      for(INT i = 0; i < lp_max; i++)
      {
        CalData.MatrixDiff_CC22[i] = ((SHORT)CalData.Matrix[i].CC22 - (SHORT)CalData.MatrixPrev[i].CC22);
        CalData.MatrixDiff_CC23[i] = ((SHORT)CalData.Matrix[i].CC23 - (SHORT)CalData.MatrixPrev[i].CC23);
        CalData.MatrixDiff_CC33[i] = ((SHORT)CalData.Matrix[i].CC33 - (SHORT)CalData.MatrixPrev[i].CC33);
        CalData.MatrixDiff_CC32[i] = ((SHORT)CalData.Matrix[i].CC32 - (SHORT)CalData.MatrixPrev[i].CC32);
      }
    }
    CalData.WBcnt++;
    if(speed <= CalData.WBcnt)
    {
      //  収束制御終了
      //  最終目標値セット
      CalData.WBTarget = CalData.WB;
      CalData.WBPrev = CalData.WB;
      //  収束制御用のカウンタは、OnePushモードが繰り返し動作しないように [(設定値) + 1] とする
      CalData.WBcnt = speed + 1;
      for(INT i = 0; i < AWB_ColorMatrixMax; i++)
      {
        CalData.MatrixTarget[i] = CalData.Matrix[i];
        CalData.MatrixPrev[i]   = CalData.Matrix[i];
      }
      g_AwbStatus.Sts_Convergence = AWBStauts_Stable;       //  AWB状態出力:安定中
    }
    else
    {
      if(speed != 0)
      {
        //  最終目標値が安定範囲内で変化したときのために、差分は毎回算出する
        //  差分量決定(WB)
        CalData.WBBdiff = ((SHORT)CalData.WB.BGain - (SHORT)CalData.WBPrev.BGain);
        CalData.WBRdiff = ((SHORT)CalData.WB.RGain - (SHORT)CalData.WBPrev.RGain);
        //  現在目標値算出(WB)
        CalData.WBTarget.BGain = (USHORT)((LONG)CalData.WBBdiff * (LONG)CalData.WBcnt / speed + (LONG)CalData.WBPrev.BGain);
        CalData.WBTarget.RGain = (USHORT)((LONG)CalData.WBRdiff * (LONG)CalData.WBcnt / speed + (LONG)CalData.WBPrev.RGain);
        for(INT i = 0; i < lp_max; i++)
        {
          //  差分量決定(カラーマトリックス)
          CalData.MatrixDiff_CC22[i] = ((SHORT)CalData.Matrix[i].CC22 - (SHORT)CalData.MatrixPrev[i].CC22);
          CalData.MatrixDiff_CC23[i] = ((SHORT)CalData.Matrix[i].CC23 - (SHORT)CalData.MatrixPrev[i].CC23);
          CalData.MatrixDiff_CC33[i] = ((SHORT)CalData.Matrix[i].CC33 - (SHORT)CalData.MatrixPrev[i].CC33);
          CalData.MatrixDiff_CC32[i] = ((SHORT)CalData.Matrix[i].CC32 - (SHORT)CalData.MatrixPrev[i].CC32);
          //  現在目標値算出(カラーマトリックス)
          CalData.MatrixTarget[i].CC22 = (USHORT)((LONG)CalData.MatrixDiff_CC22[i] * (LONG)CalData.WBcnt / speed + (LONG)CalData.MatrixPrev[i].CC22);
          CalData.MatrixTarget[i].CC23 = (USHORT)((LONG)CalData.MatrixDiff_CC23[i] * (LONG)CalData.WBcnt / speed + (LONG)CalData.MatrixPrev[i].CC23);
          CalData.MatrixTarget[i].CC33 = (USHORT)((LONG)CalData.MatrixDiff_CC33[i] * (LONG)CalData.WBcnt / speed + (LONG)CalData.MatrixPrev[i].CC33);
          CalData.MatrixTarget[i].CC32 = (USHORT)((LONG)CalData.MatrixDiff_CC32[i] * (LONG)CalData.WBcnt / speed + (LONG)CalData.MatrixPrev[i].CC32);
        }
        g_AwbStatus.Sts_Convergence = AWBStatus_Convergence;//  AWB状態出力:収束中
      }
      else
      {
        ret = AWB_E_CONVERGENCE;
      }
    }
  }

#if !defined(PARASOFT_CPPTEST) && !defined(DISABLE_AWB_CONV_LOG)
  //  収束制御ログ出力有効時処理
  g_ConvLog.CenterPnt[g_ConvLogCnt].Bg = CalData.CenterPnt.Data[0].bg;
  g_ConvLog.CenterPnt[g_ConvLogCnt].Rg = CalData.CenterPnt.Data[0].rg;
  g_ConvLog.WB_bGain[g_ConvLogCnt] = CalData.WB.BGain;
  g_ConvLog.WB_rGain[g_ConvLogCnt] = CalData.WB.RGain;
  g_ConvLog.WBTgt_bGain[g_ConvLogCnt] = CalData.WBTarget.BGain;
  g_ConvLog.WBTgt_rGain[g_ConvLogCnt] = CalData.WBTarget.RGain;
  g_ConvLog.WBcnt[g_ConvLogCnt] = CalData.WBcnt;
  g_ConvLog.StableJudge[g_ConvLogCnt] = CalData.StableJudge;
  g_ConvLogCnt++;
  if(ConvLogMax <= g_ConvLogCnt) {
    g_ConvLogCnt = 0;
  }
#endif  //  DISABLE_AWB_CONV_LOG

  return ret;
}


//
//	ゲイン/マトリックス設定処理クラス
//		AXMIspAwbAlgorithmCurrentControlValue
//


//
//	ゲイン/マトリックス設定処理
//
AWB_ER	AXMIspAwbAlgorithmCurrentControlValue :: Exec(CAL_DATA& CalData, ::AXMIspAwbSettings& AWBSettings)
{
  AWB_ER  ret = AWB_E_OK;

  //  WBゲイン設定(レジスタ)
  regWB.setBGain(CalData.WBTarget.BGain);
  regWB.setRGain(CalData.WBTarget.RGain);
  g_AwbStatus.WBGain.bGain = regWB.getBGain();              //  AWB状態出力
  g_AwbStatus.WBGain.rGain = regWB.getRGain();              //  AWB状態出力

  //  カラーマトリックス係数設定(レジスタ)
  regMatrix.setMode((UINT)AWBSettings.ColorMatrix.Mode);
  for(INT index = 0; index < AWB_ColorMatrixMax; index++)
  {
    //  Cbクロマゲイン設定
    regMatrix.setCbGain(index, CalData.MatrixTarget[index].CC22);
    //  Cbマトリックスゲイン
    regMatrix.setCbCrGain(index, CalData.MatrixTarget[index].CC23);
    //  Crマトリックスゲイン
    regMatrix.setCrCbGain(index, CalData.MatrixTarget[index].CC32);
    //  Crクロマゲイン設定
    regMatrix.setCrGain(index, CalData.MatrixTarget[index].CC33);
  }
	
  //  Yゲイン/Yオフセット設定
  regMatrix.setYGain(AWBSettings.ColorMatrix.CC11);
  regMatrix.setYOffset(AWBSettings.ColorMatrix.COF1);

  return ret;
}


//
//  アルゴリズム演算用共通関数クラス
//    AXMIspAwbAlgorithmCalibrationLibraty
//

//
//  枠内判定処理
//
Judge AXMIspAwbAlgorithmCalibrationLibrary :: JudgeArea(JudgeAreaFrame AreaFrm, ColPoint CPnt, AreaColorPoint Area)
{
  Judge result = Judge_False;
  LONG  tmp;

#ifdef  PARASOFT_CPPTEST
  //  高速化のために、区間内外判定は上位で行う
  //  但し、c++test実行時には、作成したテストケースの都合で区間内外判定を行う
  if((AreaFrm.x_min <= CPnt.bg) && (CPnt.bg <= AreaFrm.x_max) &&
     (AreaFrm.y_min <= CPnt.rg) && (CPnt.rg <= AreaFrm.y_max))
  {
#endif  //  PARASOFT_CPPTEST
    //  y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
    //    x : B / G
    //    y : R / G
    tmp = JudgeArea_Calculation1(CPnt, Area);
    // 光源枠上側の直線にて判定 : y座標を計算し、y座標が計算結果より小さいときは枠内の可能性あり
    if(CPnt.rg <= tmp)
    {
      //  x = (x2 - x1) / (y2 - y1) * (y - y1) + x1
      //    x : B / G
      //    y : R / G
      tmp = JudgeArea_Calculation2(CPnt, Area);
      // 光源枠の右側の直線にて判定 : x座標を計算し、x座標が計算結果より小さいときは枠内の可能性があり
      if(CPnt.bg <= tmp)
      {
        //  y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
        //    x : B / G
        //    y : R / G
        tmp = JudgeArea_Calculation3(CPnt, Area);
        // 光源枠下側の直線にて判定 : y座標を計算し、y座標が計算結果より大きいときは枠内の可能性あり
        if(tmp <= CPnt.rg)
        {
          //  x = (x2 - x1) / (y2 - y1) * (y - y1) + x1
          //    x : B / G
          //    y : R / G
          tmp = JudgeArea_Calculation4(CPnt, Area);
          // 光源枠の左側の直線にて判定 : x座標を計算し、x座標が計算結果より大きいときは枠内
          if(tmp <= CPnt.bg)
          {
            //
            result = Judge_True;
          }
        }
      }
    }
#ifdef  PARASOFT_CPPTEST
  }
#endif  //  PARASOFT_CPPTEST

  return  result;
}

//
//  枠内判定用演算処理(直線1に対する演算)
//
LONG AXMIspAwbAlgorithmCalibrationLibrary::JudgeArea_Calculation1(ColPoint CPnt, AreaColorPoint Area)
{
  LONG  nume;       //  分子(傾き計算用)
  LONG  denomi;     //  分母(傾き計算用)
  LONG  res;

  //  y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
  //    x : B / G
  //    y : R / G
  nume   = Area.CPnt[1].rg - Area.CPnt[0].rg;
  denomi = Area.CPnt[1].bg - Area.CPnt[0].bg;
  if(denomi == 0) {
    if(nume == 0) {
      res = CPnt.rg;
    }
    else {
      //  枠座標1-2間が垂直方向の直線の場合は設定異常につき、異常データとして取り扱う
      //  次に、垂直軸の上方向での判定のため、最小値(0x00000000)を設定する
      res = 0x00000000;
    }
  }
  else {
    res = CPnt.bg - Area.CPnt[0].bg;
    res = res * nume / denomi + Area.CPnt[0].rg;
  }

  return res;
}

//
//  枠内判定用演算処理(直線2に対する演算)
//
LONG AXMIspAwbAlgorithmCalibrationLibrary::JudgeArea_Calculation2(ColPoint CPnt, AreaColorPoint Area)
{
  LONG  nume;       //  分子(傾き計算用)
  LONG  denomi;     //  分母(傾き計算用)
  LONG  res;

  //  x = (x2 - x1) / (y2 - y1) * (y - y1) + x1
  //    x : B / G
  //    y : R / G
  nume   = Area.CPnt[2].bg - Area.CPnt[1].bg;
  denomi = Area.CPnt[2].rg - Area.CPnt[1].rg;
  if(denomi == 0) {
    if(nume == 0) {
      res = CPnt.bg;
    }
    else {
      //  枠座標2-3間が水平方向の直線の場合は設定異常につき、異常データとして取り扱う
      //  次に、水平軸の右方向の判定のため、最小値(0x00000000)を設定する
      res = 0x00000000;
    }
  }
  else {
    res = CPnt.rg - Area.CPnt[1].rg;
    res = res * nume / denomi + Area.CPnt[1].bg;
  }

  return res;
}

//
//  枠内判定用演算処理(直線3に対する演算)
//
LONG AXMIspAwbAlgorithmCalibrationLibrary::JudgeArea_Calculation3(ColPoint CPnt, AreaColorPoint Area)
{
  LONG  nume;       //  分子(傾き計算用)
  LONG  denomi;     //  分母(傾き計算用)
  LONG  res;

  //  y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
  //    x : B / G
  //    y : R / G
  nume   = Area.CPnt[3].rg - Area.CPnt[2].rg;
  denomi = Area.CPnt[3].bg - Area.CPnt[2].bg;
  if(denomi == 0) {
    if(nume == 0) {
      res = CPnt.rg;
    }
    else {
      //  枠座標3-4間が垂直方向の直線の場合は設定異常につき、異常データとして取り扱う
      //  次に、水平軸の左方向の判定のため、最大値(0x7FFFFFFF)を設定する
      res = 0x7FFFFFFF;
    }
  }
  else {
    res = CPnt.bg - Area.CPnt[2].bg;
    res = res * nume / denomi + Area.CPnt[2].rg;
  }

  return res;
}

//
//  枠内判定用演算処理(直線4に対する演算)
//
LONG AXMIspAwbAlgorithmCalibrationLibrary::JudgeArea_Calculation4(ColPoint CPnt, AreaColorPoint Area)
{
  LONG  nume;       //  分子(傾き計算用)
  LONG  denomi;     //  分母(傾き計算用)
  LONG  res;

  //  x = (x2 - x1) / (y2 - y1) * (y - y1) + x1
  //    x : B / G
  //    y : R / G
  nume   = Area.CPnt[0].bg - Area.CPnt[3].bg;
  denomi = Area.CPnt[0].rg - Area.CPnt[3].rg;
  if(denomi == 0) {
    if(nume == 0) {
      res = CPnt.bg;
    }
    else {
      //  枠座標4-1間が水平方向の直線の場合は設定異常につき、異常データとして取り扱う
      //  次に、水平軸の左方向の判定のため、最大値(0x7FFFFFFF)を設定する
      res = 0x7FFFFFFF;
    }
  }
  else {
    res = CPnt.rg - Area.CPnt[3].rg;
    res = res * nume / denomi + Area.CPnt[3].bg;
  }

  return res;
}


//
//  センサー分光バラつき調整クラス
//    AXMIspAwbAlgorithmSpectrumAdjust
//

//
//  取得した座標より、座標を正規化する
//
AWB_ER AXMIspAwbAlgorithmSpectrumAdjust::Init(AWB_SpectrumAdjust Mode, ColPoint CPnt, AXMIspAwbSettings& AWBSettings)
{
  AWB_ER ret = AWB_E_OK;
  //  2015/2/3:低色温度側調整ポイントを黒体放射 3200K座標から黒体放射 2800K座標に変更
  INT x1 = (INT)AWBSettings.SpectrumAdjust.LowTempPnt.bg;                       //  2800Kポイント座標
  INT x2 = (INT)AWBSettings.SpectrumAdjust.HighTempPnt.bg;                      //  5800Kポイント座標
  INT y1 = (INT)AWBSettings.SpectrumAdjust.LowTempPnt.rg;                       //  2800Kポイント座標
  INT y2 = (INT)AWBSettings.SpectrumAdjust.HighTempPnt.rg;                      //  5800Kポイント座標
  if((x1 == x2) || (y1 == y2)) {
    ret = AWB_E_SPECTRUM_ADJ;
  }
  else if(Mode == AWB_SpectrumAdjust_LTemp) {
    //  低色温度側座標正規化
    INT sub_x = CPnt.bg - x2;
    INT std_x = x1 - x2;
    INT sub_y = CPnt.rg - y2;
    INT std_y = y1 - y2;
    INT x, y;
    //  デフォルト座標
    for(SHORT i = 0; i < AWBLightDefault_Max; i++) {
      x = (AWBSettings.LightDefault.CPnt[i].bg - x2) * sub_x / std_x + x2;
      y = (AWBSettings.LightDefault.CPnt[i].rg - y2) * sub_y / std_y + y2;
      AWBSettings.LightDefault.CPnt[i].bg = x;
      AWBSettings.LightDefault.CPnt[i].rg = y;
    }
    //  光源枠座標
    for(SHORT i = 0; i < AWBLightSource_Rolling_Max; i++) {
      for(SHORT j = 0; j < AWB_LightSourcePnt; j++) {
        x = (AWBSettings.LightSource.Area[i].CPnt[j].bg - x2) * sub_x / std_x + x2;
        y = (AWBSettings.LightSource.Area[i].CPnt[j].rg - y2) * sub_y / std_y + y2;
        AWBSettings.LightSource.Area[i].CPnt[j].bg = x;
        AWBSettings.LightSource.Area[i].CPnt[j].rg = y;
      }
    }
    //  低色温度側調整ポイント(黒体放射 2800Kポイント)更新
    AWBSettings.SpectrumAdjust.LowTempPnt = CPnt;
    //  高色温度側調整ポイント(黒体放射 5800Kポイント)更新
    AWBSettings.SpectrumAdjust.HighTempPnt = AWBSettings.LightDefault.CPnt[AWBLightDefault_5800K];
  }
  else {
    //  高色温度側座標正規化
    INT sub_x = CPnt.bg - x1;
    INT std_x = x2 - x1;
    INT sub_y = CPnt.rg - y1;
    INT std_y = y2 - y1;
    INT x, y;
    //  デフォルト座標
    for(SHORT i = 0; i < AWBLightDefault_Max; i++) {
      if(i != AWBLightDefault_5800K) {                      //  5800Kポイント座標は更新しない
        x = ((INT)AWBSettings.LightDefault.CPnt[i].bg - x1) * sub_x / std_x + x1;
        y = ((INT)AWBSettings.LightDefault.CPnt[i].rg - y1) * sub_y / std_y + y1;
        AWBSettings.LightDefault.CPnt[i].bg = x;
        AWBSettings.LightDefault.CPnt[i].rg = y;
      }
    }
    //  光源枠座標
    for(SHORT i = 0; i < AWBLightSource_Rolling_Max; i++) {
      for(SHORT j = 0; j < AWB_LightSourcePnt; j++) {
        x = (AWBSettings.LightSource.Area[i].CPnt[j].bg - x1) * sub_x / std_x + x1;
        y = (AWBSettings.LightSource.Area[i].CPnt[j].rg - y1) * sub_y / std_y + y1;
        AWBSettings.LightSource.Area[i].CPnt[j].bg = x;
        AWBSettings.LightSource.Area[i].CPnt[j].rg = y;
      }
    }
    AWBSettings.LightDefault.CPnt[AWBLightDefault_5800K] = CPnt;                //  5800Kポイント座標更新
    //  低色温度側調整ポイント(黒体放射 2800Kポイント)更新
    x = (AWBSettings.SpectrumAdjust.LowTempPnt.bg - x1) * sub_x / std_x + x1;
    y = (AWBSettings.SpectrumAdjust.LowTempPnt.rg - y1) * sub_y / std_y + y1;
    AWBSettings.SpectrumAdjust.LowTempPnt.bg = x;
    AWBSettings.SpectrumAdjust.LowTempPnt.rg = y;
    //  高色温度側調整ポイント(黒体放射 5800Kポイント)更新
    AWBSettings.SpectrumAdjust.HighTempPnt = CPnt;
  }
  return ret;
}

