//------------------------------------------------------------
// $Id: searchNextSpcDDA.cc,v 1.4.2.1 2000/06/14 15:00:10 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 
// 	次空間探索用
//	いろいろ紆余曲折があったができてみればなんのことはない。
//	DDA ユニットの独立性の高いものということである。
//	1998年1月27日(火)
//	Copyright (C) 1997--1998 YAMAUCHI Hitoshi 山内 斉
//
//    YorN moveRayToNextCalcSubspace(RayClass *pRay);
//	pRay はこの関数が終了する時には次に交差判定を行う空間にいる。
//	返り値 : 次の交差判定空間が定義空間外であれば NO
//		 定義空間内であれば YES を返す
//------------------------------------------------------------
#include "mpi2.h"
#include "mpi2exit.h"
#include "searchNextSpcDDA.h"

//------------------------------------------------------------
// local functions
//------------------------------------------------------------
// レイの進行方向を XPLUS, XMINUS,.. の形で得る(sub. calcDDA)
// その方向に行けるかどうかは不明(定義空間内かどうかのテストは行わない。)
//------------------------------
inline static DIR_3D getDirection(const DDAInfoClass *const pDInfo, 
				  int goingDirection)  
{
    DIR_3D dir = DIR_ILLEGAL;

    switch(goingDirection)
    {
    case Vector3::X:
	if(pDInfo->getDDAVec().get(Vector3::X) < 0.0)
	{
	    dir = DIR_XMINUS;
	}else
	{
	    dir = DIR_XPLUS;
	}
	break;
	
    case Vector3::Y:	
	if(pDInfo->getDDAVec().get(Vector3::Y) < 0.0)
	{
	    dir = DIR_YMINUS;
	}else
	{
	    dir = DIR_YPLUS;
	}
	break;
	
    case Vector3::Z:
	if(pDInfo->getDDAVec().get(Vector3::Z) < 0.0)
	{
	    dir = DIR_ZMINUS;
	}else
	{
	    dir = DIR_ZPLUS;
	}
	break;
	
    default:
	cerr << "Error!: at getOnlyDirection illegal goingdir( = "
	    << goingDirection << ")" << endl;
	commMpi2_exit(1);
	break;
    }
    return(dir);
}
    
// IntVec3 -> Vector3(using in calcRayTrDD.cc, prepareShading.cc)
static inline Vector3 iv2v(const IntVec3& iv)
{
    return(Vector3(double(iv.get(IntVec3::X)),
		   double(iv.get(IntVec3::Y)),	   
		   double(iv.get(IntVec3::Z))));
}

// next space 
inline IntVec3 getNextSpcPos(const IntVec3& nowSpcpos, DIR_3D nextDir)
{
    int x = nowSpcpos.get(IntVec3::X);
    int y = nowSpcpos.get(IntVec3::Y);
    int z = nowSpcpos.get(IntVec3::Z);
    switch(nextDir)
    {
    case DIR_XPLUS:	
	x++;	break;
    case DIR_XMINUS:	
	x--;	break;
    case DIR_YPLUS:
	y++;	break;
    case DIR_YMINUS:
	y--;	break;
    case DIR_ZPLUS:	
	z++;	break;
    case DIR_ZMINUS:	
	z--;	break;
    default:
	cerr << "Error! : at getNextSpcPos Illegal dir." << endl;
	commMpi2_exit(1);
	break;
    }
    return(IntVec3(x, y, z));
}

//------------------------------
// doubleの符号を double で返す (sub. of calcDDA)
//------------------------------
inline static double dSignD(double x) 
{
    if(x < 0.0)
    {
	return(-1.0);
    }else if(x > 0.0)
    {
	return(1.0);
    }else 
    {
	return(0.0);
    }
}

//------------------------------------------------------------
// protected functions
//------------------------------------------------------------
// check initialize parameter
//------------------------------
void searchNextSpcDDA::
exitIfIllegalParam(double cellLength, 
		   const int *pSpcIdxMin, const int *pSpcIdxMax, 
		   int   rayPropSkipMethod, int networkType)
{
    const char *pMes = 
	"Error! : searchNextSpcDDA::exitIfIllegalParam : ";
    if(cellLength <= 0.0)
    {
	cerr << pMes << "illegal cellLength (" << cellLength << ")" << endl;
	commMpi2_exit(1);
    }
    if((pSpcIdxMin == NULL) || (pSpcIdxMax == NULL))
    {
	cerr << pMes << "spc index is (null)." << endl;
	commMpi2_exit(1);
    }else
    {
	for(int i = 0; i < 3; i++)
	{
	    // 部分空間 index は常に >= 0, ただし minidx = maxidx の場合あり
	    if((pSpcIdxMin[i] < 0) || (pSpcIdxMax[i] < 0) || 
	       (pSpcIdxMin[i] > pSpcIdxMax[i]))
	    {
		cerr << pMes << "illegal spc index. spcMin[" << i << "] = " 
		    << pSpcIdxMin[i] << ", spcMax[" << pSpcIdxMax[i] <<
			"]" << endl;
		commMpi2_exit(1);		
	    }
	}
    }
    if((rayPropSkipMethod == NoSkip_rayprop)	 ||
       (rayPropSkipMethod == SobokuSkip_rayprop) ||
       (rayPropSkipMethod == ProximityClouds_rayprop)) //tokunaga changed
    {
	// OK! : no skip と 素朴な skip はサポート
    }else
    {
	cerr << pMes << "illegal skip method.(" << rayPropSkipMethod <<
	    ")" << endl;
	commMpi2_exit(1);		
    }

    if(networkType == Torus_network)
    {
	cerr << pMes << "NIN : Not implemented for Torus net." << endl;
	commMpi2_exit(1);		
    }
    else if(networkType == MultiStage_network)
    {    
	// OK! : multistage はサポート
    }else
    {
	cerr << pMes << "illegal network type = " << networkType << endl;
	commMpi2_exit(1);		
    }
}


//------------------------------
// 次空間探索を行う
//	次空間探索を行い、次空間の方向を返す
//	しかし、次空間の方向がまだ定義空間内部かどうかは不明
//------------------------------
DIR_3D searchNextSpcDDA::
getDirByDDA(DDAInfoClass *pDInfo)
{
    // この関数をテストするために member へのアクセスはここだけにする
    // optimizer of compiler will be delete this code
    const double CellLen	= this->mCellLength;
    const double CellHalf 	= this->mCellHalf;

    // DDA info is already initialized
    assert(pDInfo->isDDAinited() == YES);

    int travAxis = pDInfo->getTravAxis(); // トラバース方向軸    
    
    int OtherAxis1 = (travAxis + 1) % 3; // 進行軸以外軸 1
    int OtherAxis2 = (travAxis + 2) % 3; // 進行軸以外軸 2
    
    // 進行軸以外の軸方向にも進むか 相対位置を移動させてみる
    const Vector3 relaPos(pDInfo->getRelativePos());
    const Vector3 DDAVec(pDInfo->getDDAVec());
    
    // 相対位置計算
    double t1 = relaPos.get(OtherAxis1) + DDAVec.get(OtherAxis1); 
    double t2 = relaPos.get(OtherAxis2) + DDAVec.get(OtherAxis2); 
    
    // 移動した後の相対位置の絶対値
    const double absT1 = fabs(t1);
    const double absT2 = fabs(t2);
    
    if((absT1 <= CellHalf) && (absT2 <= CellHalf)) // どちらにも進まない
    {
	pDInfo->changeRelativePos(t1, OtherAxis1, t2, OtherAxis2);
	DIR_3D dir = getDirection(pDInfo, travAxis);
	pDInfo->setGoingDir(dir);
	return(dir);		//----- 進行軸方向へ;
    }
    
    // 進行方向以外のベクトルの符号
    const double axis1_sign = dSignD((pDInfo->getDDAVec()).get(OtherAxis1));
    const double axis2_sign = dSignD((pDInfo->getDDAVec()).get(OtherAxis2));
    
    if((absT1 > CellHalf) && (absT2 <= CellHalf)) // 1の方向に進む
    {
	double rpos = relaPos.get(OtherAxis1) - axis1_sign * CellLen;
	pDInfo->changeRelativePos(rpos,                    OtherAxis1, 
				relaPos.get(OtherAxis2), OtherAxis2);
	DIR_3D dir = getDirection(pDInfo, OtherAxis1);	
	pDInfo->setGoingDir(dir);
	return(dir);		//----- 1軸方向へ;
    }

    if((absT1 <= CellHalf) && (absT2 > CellHalf)) // 2の方向に進む
    {
	double rpos = relaPos.get(OtherAxis2) - axis2_sign * CellLen;
	pDInfo->changeRelativePos(relaPos.get(OtherAxis1), OtherAxis1,
				rpos,                    OtherAxis2);
	DIR_3D dir = getDirection(pDInfo, OtherAxis2);
	pDInfo->setGoingDir(dir);
	return(dir);		//----- 2軸方向へ;
    }
    
    //--------------------------------------------------
    // それ以外(1,2方向しかし、1,2どちらかへ進む) 
    //--------------------------------------------------
    const double param_s1
        = (axis2_sign * (pDInfo->getDDAVec()).get(OtherAxis2))
            * (CellHalf - (axis1_sign * relaPos.get(OtherAxis1)));
    const double param_s2
        = (axis1_sign * (pDInfo->getDDAVec()).get(OtherAxis1))
            * (CellHalf - (axis2_sign * relaPos.get(OtherAxis2)));
    
    if(param_s1 < param_s2)
    {
        double rpos = relaPos.get(OtherAxis1) - axis1_sign * CellLen;
        pDInfo->changeRelativePos(rpos,                    OtherAxis1,
                                relaPos.get(OtherAxis2), OtherAxis2);
	DIR_3D dir = getDirection(pDInfo, OtherAxis1);
	pDInfo->setGoingDir(dir);
	return(dir);		//----- 1軸方向へ;
    }else
    {
        double rpos = relaPos.get(OtherAxis2) - axis2_sign * CellLen;
        pDInfo->changeRelativePos(relaPos.get(OtherAxis1), OtherAxis1,
				 rpos,                    OtherAxis2);
	DIR_3D dir = getDirection(pDInfo, OtherAxis2);
	pDInfo->setGoingDir(dir);
	return(dir);		//----- 2軸方向へ;
    }
}

//--------------------------------------------------------------
// 進行軸とDDA用VectorをpDInfoにセット(sub. of initializeDDA)
//--------------------------------------------------------------
void searchNextSpcDDA::
setTraverseAxisNVector(DDAInfoClass* pDInfo, const Vector3& rayDir)
{
    // access to member variable at here only
    const double cellLen = this->mCellLength;

    double dAbsmax;		/* ベクトルの大きさ(初期値x) */
    double dy, dz;		/* ベクトルの大きさ          */
    int SinkouJiku;		// トラバース方向軸
    
    // ベクトルの絶対値最大の要素を求める
    dAbsmax = fabs(rayDir.get(Vector3::X));
    dy      = fabs(rayDir.get(Vector3::Y));
    dz      = fabs(rayDir.get(Vector3::Z));
    SinkouJiku = Vector3::X;

    if(dAbsmax < dy){
	dAbsmax = dy;
	SinkouJiku = Vector3::Y;
    }
    if(dAbsmax < dz){
	dAbsmax = dz;
	SinkouJiku = Vector3::Z;
    }
    pDInfo->setTravAxis(SinkouJiku); // 進行軸をセットし、

    //----- DDA用のベクトルをセットする
    pDInfo->setDDAVec(rayDir * (cellLen / dAbsmax));
}


//------------------------------
// 次空間へ移動できるかをテストする。定義空間内なら yes 
// 	IN : pSpcPos に元の位置を入れてが関数を呼ぶ。
//	IN : dir 移動方向
// テストのみ副作用なし
//------------------------------
YorN searchNextSpcDDA::
testCanGo(IntVec3* pSpcPos, DIR_3D dir) const
{
    switch(dir)
    {
    case DIR_XPLUS:
	if((pSpcPos->get(IntVec3::X) + 1) > this->mSpcIdxMax[0])
	{
	    return(NO);
	}
	break;
    case DIR_XMINUS:
	if((pSpcPos->get(IntVec3::X) - 1) <  this->mSpcIdxMin[0])
	{
	    return(NO);
	}
	break;
    case DIR_YPLUS:
	if((pSpcPos->get(IntVec3::Y) + 1) > this->mSpcIdxMax[1])
	{
	    return(NO);
	}
	break;
    case DIR_YMINUS:
	if((pSpcPos->get(IntVec3::Y) - 1) <  this->mSpcIdxMin[1])
	{
	    return(NO);
	}
	break;
    case DIR_ZPLUS:
	if((pSpcPos->get(IntVec3::Z) + 1) > this->mSpcIdxMax[2])
	{
	    return(NO);
	}
	break;
    case DIR_ZMINUS:
	if((pSpcPos->get(IntVec3::Z) - 1) <  this->mSpcIdxMin[2])
	{
	    return(NO);
	}
	break;
    default:
	cerr << "Error! : at testCanGo Illegal dir." << endl;
	commMpi2_exit(1);
	break;
    }
    return(YES);
}

//------------------------------
// 次空間へ移動する。
// 	IN OUT: pSpcPos に元の位置を入れて関数を呼ぶ。
//	IN    : dir 移動方向
// 空間を移動する
//------------------------------
void searchNextSpcDDA::
goNextSpace(IntVec3* pSpcPos, DIR_3D dir) const
{
    // forceMove で利用する場合があるのでこの assert は無効
    // assert(this->testCanGo(pSpcPos, dir) == YES);

    int x = pSpcPos->get(IntVec3::X);
    int y = pSpcPos->get(IntVec3::Y);
    int z = pSpcPos->get(IntVec3::Z);
    switch(dir)
    {
    case DIR_XPLUS:
	x++;
	break;
    case DIR_XMINUS:
	x--;
	break;
    case DIR_YPLUS:
	y++;
	break;
    case DIR_YMINUS:
	y--;
	break;
    case DIR_ZPLUS:
	z++;
	break;
    case DIR_ZMINUS:
	z--;
	break;
    default:
	cerr << "Error! : goNextSpace() : Illegal dir." << endl;
	commMpi2_exit(1);
	break;
    }
    pSpcPos->set(x, y, z);
}

//------------------------------
// 次空間を探索する
// 	calculate next subspace and set the subspace to ray
//	pDinfo, pSpcPos は変更される
// protected 関数．skip 無し
//------------------------------
YorN searchNextSpcDDA::
moveRayToNextSubspaceNoSkip(DDAInfoClass *pDinfo, 
			    const Vector3& rayPos,
			    const Vector3& rayDir,
			    IntVec3      *pSpcPos)
{
    // 1.レイが次に行く次の空間を求める
    // この関数は現在の空間位置と DDA の情報から新しい空間位置を決める
    if(pDinfo->isDDAinited() == NO)
    {
	this->initializeDDA(pDinfo, rayPos, rayDir, (*pSpcPos));
    }

    DIR_3D nextDir = this->getDirByDDA(pDinfo);   
	
    // 2.その空間が定義空間内か調べる
    YorN isNextSpaceInDefspc = this->testAndGoIfItCan(pSpcPos, nextDir);
    return(isNextSpaceInDefspc);
}


//------------------------------------------------------------
// public functions
//------------------------------------------------------------
// constructor
//------------------------------
searchNextSpcDDA::
searchNextSpcDDA(void)
{
    this->mPartVolMin.set(-1.0, -2.0, -3.0);
    this->mCellLength	= -1.0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mSpcIdxMin[i] = -1;
	this->mSpcIdxMax[i] = -1;
    }
    this->mRayPropSkipMethod	= ELSE_rayprop;
    this->mNetworkType		= ELSE_network;

    // derived variables
    this->mCellHalf	= -1.0;
}

//------------------------------
// destructor
//------------------------------
searchNextSpcDDA::
~searchNextSpcDDA(void)
{
    // void 
}


//------------------------------
// initialize
//	partVolMin は DDA を適用する空間の最小位置である．これは 
//	subspace の最小位置ではなく，空間分割される前あるいは subvolume に
//	分割される前の partvol min である。 
//	ここを原点とし、[minIdx, maxIdx] の範囲で部分空間が存在する
//	(誤って部分空間に分割した後の最小位置を入れるバグがなかなか直
//	 らなかった。1998年4月 3日(金) 今日は多田研の花見であった。
//	 3/30 に林原さんが結婚したらしい。)
//------------------------------
void searchNextSpcDDA::
initWithoutObjInSpcMap(const Vector3& partVolMin,//DDAを適用する空間の最小位置
		       double  	    cellLength,	//DDAでtraverseするセルの大きさ
		       const int   *pSpcIdxMin, //cellの最小index
		       const int   *pSpcIdxMax, //最大index
		       int     	   rayPropSkipMetod,//skip 法
		       int     	   networkType)	//ネットワーク形状
{
    exitIfIllegalParam(cellLength, pSpcIdxMin, pSpcIdxMax, 
		       rayPropSkipMetod, networkType);
    this->mPartVolMin	= partVolMin; 	 
    this->mCellLength	= cellLength;
    for(int i = 0; i < 3; i++)
    {
	this->mSpcIdxMin[i] 	= pSpcIdxMin[i];
	this->mSpcIdxMax[i]	= pSpcIdxMax[i];
    }
    this->mRayPropSkipMethod = rayPropSkipMetod;
    this->mNetworkType 	 = networkType;    
    // derived variables
    this->mCellHalf = this->mCellLength / 2.0;
}

// 空間中の物体の存在状況
void searchNextSpcDDA::
initObjInSpcMap(array3dClass < objectExistInASpaceClass >  *pObjInSpcMap) 
{
    const char *pMes = "Error! : searchNextSpcDDA::initObjInSpcMap : ";
    if((pObjInSpcMap == NULL) || (pObjInSpcMap->getTotalSize() <= 0))
    {
	cerr << pMes << "illegal object in space map." << endl;
	commMpi2_exit(1);		
    }
    this->mObjInSpcMap	= (*pObjInSpcMap);
}

//------------------------------------------------------------
// 次空間を探索する
// 	calculate next subspace and set the subspace to ray
//	ray の 空間(volume でない方) の ddainfo, space pos は更新される
// skip 無し
//------------------------------------------------------------
YorN searchNextSpcDDA::
moveRayToNextSubspaceNoSkip(Ray *pRay)
{
    DDAInfoClass ddainfo = pRay->getSpcDDAInfo();
    IntVec3      spcpos  = pRay->getSpcPos();
    YorN isSendRay = this->moveRayToNextSubspaceNoSkip(&ddainfo,
						       pRay->getPos(),
						       pRay->getDir(),
						       &spcpos);

    pRay->setSpcDDAInfo(ddainfo);
    pRay->setSpcPos(spcpos);
    return(isSendRay);
}    

//------------------------------------------------------------
// 次空間を探索する
// 	素朴な skip (もう pRay->getSpcPos() に用はなく必ず隣へ移動して
// 	みる)
//------------------------------------------------------------
YorN searchNextSpcDDA::
moveRayWithSobokuSkip(Ray *pRay)
{
    DDAInfoClass ddainfo = pRay->getSpcDDAInfo();
    IntVec3      spcpos  = pRay->getSpcPos();
    YorN isNextSpaceInDefspc = YES;

    if(ddainfo.isDDAinited() == NO)
    {
	this->initializeDDA(&ddainfo, pRay->getPos(), pRay->getDir(),
			    spcpos);
    }

    while(1)
    {
	// 次の空間を探索する
	DIR_3D nextDir = this->getDirByDDA(&ddainfo); 

	// 次の空間は定義空間内部か
	isNextSpaceInDefspc = this->testAndGoIfItCan(&spcpos, nextDir);

	if(isNextSpaceInDefspc == YES)
	{
	    int idx[3];
	    spcpos.getAsArray(idx);
	    if(this->mObjInSpcMap.get(idx).isObj() == YES)
	    {
		// 定義空間内 && 物体が存在する -> skip できない
		// isNextSpaceInDefspc == YES で loop を抜ける
		pRay->setSpcDDAInfo(ddainfo);
		pRay->setSpcPos(spcpos);
		return(YES);
		break;
	    }
	    else
	    {
		// 次空間は定義空間内 && 物体が存在しない -> 素朴 Skip
		// skip 回数を記録したい場合はここで記録する
		//  		this->incSkipSpcNum();		
		//  		this->incTravSpcNum();
	    }
	}else
	{
	    // 何も存在しないまま定義空間を外れてしまった．もう行く場所はない
	    // isNextSpaceInDefspc == NO となって loop を抜ける
	    break;
	}
    }
    pRay->setSpcDDAInfo(ddainfo);
    pRay->setSpcPos(spcpos);
    return(isNextSpaceInDefspc);
}


//------------------------------------------------------------
// volume 移動用
//	隣接空間との整合をとりつつ移動するため、volume 中を移動する場
//      合には境界において ray が正しい voxel にいない場合がある。
//------------------------------------------------------------
// ある部分空間がこの Direction Decision Unit で有効とされているか
YorN searchNextSpcDDA::
isValidASpcpos(const IntVec3& spcpos)
{
    if((this->mSpcIdxMin[0]    <= spcpos.get(IntVec3::X)) && 
       (this->mSpcIdxMin[1]    <= spcpos.get(IntVec3::Y)) &&
       (this->mSpcIdxMin[2]    <= spcpos.get(IntVec3::Z)) &&
       (spcpos.get(IntVec3::X) <= this->mSpcIdxMax[0]) && 
       (spcpos.get(IntVec3::Y) <= this->mSpcIdxMax[1]) &&
       (spcpos.get(IntVec3::Z) <= this->mSpcIdxMax[2]))
    {
	return(YES);
    }
    else
    {
	return(NO);	
    }
}

//------------------------------
// forceMoveRayToNextSpace
// 	次空間を探索し必ず次の空間に移動してしまう。
//------------------------------
void searchNextSpcDDA::
forceMoveRayToNextSpace(DDAInfoClass *pDinfo, 
			const Vector3& rayPos, const Vector3& rayDir,
			IntVec3      *pSpcPos)
{
    if(pDinfo->isDDAinited() == NO)
    {
	this->initializeDDA(pDinfo, rayPos, rayDir, (*pSpcPos));
    }
    DIR_3D nextDir = this->getDirByDDA(pDinfo);   
    this->goNextSpace(pSpcPos, nextDir);
}


//------------------------------
// 3DDDAのための情報の初期化 (sub. of calcDDA)
//	ray は define space 内にいることを確認してある
//	rayDir はレイの進行方向ベクトル
//	ray の持つ DDA info を更新する
//------------------------------
void searchNextSpcDDA::
initializeDDA(DDAInfoClass*  pDInfo, 
	      const Vector3& rayPos, const Vector3& rayDir,
	      const IntVec3& raySpcPos)
{
    assert(pDInfo->isDDAinited() == NO);
    assert(fabs((rayDir.getNorm()) - 1.0) < D_ERROR_RES);    
    
    // access to member variable at here only
    const double CellLen	= this->mCellLength;
    assert(this->mCellLength > 0.0);
    const Vector3& partVolMin   = this->mPartVolMin;
    
    // 進行軸の決定と進行ベクトルのset
    this->setTraverseAxisNVector(pDInfo, rayDir); 
    int shinkouJiku = pDInfo->getTravAxis(); 
    
    int OtherAxis1 = (shinkouJiku + 1) % 3; // 進行軸以外軸 1
    int OtherAxis2 = (shinkouJiku + 2) % 3; // 進行軸以外軸 2
    
    // 進行軸方向の セルの最小値
    const double PartMinShinkouJiku = partVolMin.get(shinkouJiku);	
    const Vector3 center(0.5, 0.5, 0.5); // セルの中心に位置するための偏差
    const Vector3 spcpos = iv2v(raySpcPos);
    
    // セルの３次元的中心
    const Vector3 centerOfCell = (partVolMin + CellLen * (center + spcpos));
    
    //---------------------------------------------------------------
    // 相対位置 = レイの進行軸方向の逆のセル上の平面との交差点
    // 交差点 = Define Space Min + Cell Length * spcpos
    //---------------------------------------------------------------
    double minAtCell = 0.0;
    if((rayDir.get(shinkouJiku)) > 0.0)	// 進行ベクトルは正
    {
	minAtCell = PartMinShinkouJiku + spcpos.get(shinkouJiku) * CellLen;
    }else
    {				// 負の方向ではセルの大きい方から初める
	minAtCell = PartMinShinkouJiku 
	    + (spcpos.get(shinkouJiku) + 1.0) * CellLen;
    }
    
    // 進行軸方向についての始点の位置から進行軸方向のベクトルに沿った 
    // minAtCell までの距離 = param_t * 進行軸方向のベクトル成分
    const double param_t 
	= (minAtCell - rayPos.get(shinkouJiku)) 
	    / rayDir.get(shinkouJiku);

    // この assertion は ray tracing の初期においては正しくない。とい
    // うのは視点が定義空間の外にあることがあるからである。 
    //     if(param_t > 0.0)
    //     {
    // 	cout << "initializeDDA param_t " << param_t << endl;
    // 	commMpi2_exit(1);
    //     }
    //     assert(param_t < 1e-5);	// (0 のことがあるので)
    const double relaPos1 
	= (rayPos.get(OtherAxis1) + param_t * rayDir.get(OtherAxis1)) // rayDir
	    - centerOfCell.get(OtherAxis1);		    
    
    const double relaPos2 
	= (rayPos.get(OtherAxis2) + param_t * rayDir.get(OtherAxis2)) // rayDir
	    - centerOfCell.get(OtherAxis2);
    // 上で rayDir なのは rayDir が ray の進行方向の単位ベクトルから

    //----- 3DDDAの相対値初期値(進行軸方向は無意味)
    pDInfo->changeRelativePos(relaPos1, OtherAxis1, relaPos2, OtherAxis2);

    //----- ちょっと甘い assertionしかし、初期値は自空間内とは限らない(rayTr)
    // その場合にはこの asserttion は誤りである。視点が空間の外にある
    // 場合には相対位置は cell length の 1.5 倍以内にはおさまらない。
    //----- 一番上部から45度ぎりぎりの場合には隣の端までなので、+-1.5倍
    //assert((relaPos1 <= (1.5 * CellLen)) && ((-1.5 * CellLen) <= relaPos1));
    //assert((relaPos2 <= (1.5 * CellLen)) && ((-1.5 * CellLen) <= relaPos2));
#ifndef NDEBUG
    if(!((relaPos1 <= (1.5 * CellLen)) && ((-1.5 * CellLen) <= relaPos1)))
    {
 	cerr << "relapos1 (" << relaPos1 << "), pm 1.5 celllen = " << 
 	    (-1.5 * CellLen) << endl;
	abort();
    }
    if(!((relaPos2 <= (1.5 * CellLen)) && ((-1.5 * CellLen) <= relaPos2)))
    {
 	cerr << "relapos2 (" << relaPos2 << "), pm 1.5 celllen = " << 
 	    (-1.5 * CellLen) << endl;
	abort();
    }
#endif

    pDInfo->setDDAset();		// 計算したことを記す
}



//------------------------------------------------------------
// for test 
//------------------------------------------------------------
#ifdef TEST_DDA_UNIT
void commMpi2_exit(int i)
{
    exit(i);
}

int main()
{
    searchNextSpcDDA nssDDA;

    int min[] = {  0,  0,  0, };
    int max[] = { 10, 10, 10, };
    nssDDA.init(Vector3(0.0, 0.0, 0.0),
		2.0,
		min, max, NoSkip_rayprop);
    
}
#endif

// Local Variables:
// mode :c++
// // compile-command: "g++ -g -Wall -DTEST_DDA_UNIT searchNextSpcDDA.cc Vector3.o ray.o IntVec3.o"
// End:

