//------------------------------------------------------------
// $Id: prepareShading.cc,v 1.10.2.1 2000/06/14 17:46:35 yamauchi Exp $
//------------------------------------------------------------
//	prepare shading
//	1996/9/11
//	Copyright (C) 1996--1998 YAMAUCHI Hitoshi 山内 斉
//
//	shading のための頂点輝度交換と処理(平均化など)
//------------------------------------------------------------
#include "PE.h"
#include "Option.h"
#include "mpi2communication.h"
#include "adjdir.h"
#include "mpi2_funcs.h"
#include "PEpmarray.h"

// stand alone 
#ifdef FOR_STANDALONE
// #include "StandAloneModeObjects.h"
#else

#endif

// 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))));
}

#ifdef FOR_STANDALONE
//------------------------------
// for stand alone mode 
// stand alone ではこの関数は全ての送信が終了した後(つまり受信も終了し
// ている)に呼ばれるので常に YES
// 	isPrepareStageOver()
//------------------------------
YorN PEClass::
isPrepareShadingStageOver(void)
{
    this->mIsPrepareShadingOver = YES;
    return(YES);		
}
#endif
//------------------------------
// initPrepareStage
//	Shading stage 
//------------------------------
void PEClass::
initPrepareShadingStage(void) 
{
    // このステージはこれから初める(終了していない)
    this->mIsPrepareShadingOver = NO;
    this->initBusyIdleStat();

    // 輝度頂点送受信バッファ
    this->mNIUnit.initVerIntBuff(this->mSysInfo.getSendVerIntAtOnce(), 
				 &(this->mVerIntPtrQueue));
}

//------------------------------
// その空間指標は定義空間内か
//------------------------------
inline YorN PEClass::
checkInSpc(const IntVec3 &spcpos)
{
    for(int i = 0; i < 3; i++)
    {
	if((spcpos.get(i) < (this->mSpcParam.getMinDefSpcIdx()).get(i)) ||
	   (spcpos.get(i) > (this->mSpcParam.getMaxDefSpcIdx()).get(i)))
	{
	    return(NO);
	}
    }
    return(YES);
}

/*
 * 各空間ごとに同一頂点の輝度を伝播
 * 	それぞれの空間内のみ
 */
class PolygonIDNObjAryIdx {
public:
    int mPolygonID;
    int mObjAryIdx;    
public:
    PolygonIDNObjAryIdx()
    {
	this->mPolygonID = -1;
	this->mObjAryIdx = -1;    
    }
    ~PolygonIDNObjAryIdx(){}
    PolygonIDNObjAryIdx(const PolygonIDNObjAryIdx& rhs)
    {
	this->mPolygonID = rhs.mPolygonID;
	this->mObjAryIdx = rhs.mObjAryIdx;
    }
    const PolygonIDNObjAryIdx& operator=(const PolygonIDNObjAryIdx& rhs)
    {
	if(this != &rhs)
	{
	    this->mPolygonID = rhs.mPolygonID;
	    this->mObjAryIdx = rhs.mObjAryIdx;
	}
	return(*this);
    }
    void print()
    {
	cout << "PolyID " << this->mPolygonID << ", objary index " 
	     << this->mObjAryIdx << endl;
    }
};

static int comp(const void *pAa, const void *pBb)
{
    PolygonIDNObjAryIdx *pA = (PolygonIDNObjAryIdx *)pAa;
    PolygonIDNObjAryIdx *pB = (PolygonIDNObjAryIdx *)pBb;
    
    if(pA->mPolygonID < pB->mPolygonID)
    {
	return(-1);
    }
    else if(pA->mPolygonID == pB->mPolygonID)
    {
	return(0);
    }else
    {
	return(1);	
    }
}

/*
 * ひとつの Polygon の分
 *	IMPROVEME 相互作用の形に書ければいいのだが、現在は送りて受け手
 *  @param pObjArray 	 : この PE が保持している object array
 *  @param pPIDnOAidxTab : polygonIDでsort済みの PolygonIDNObjAryIdx 配列
 *  @param startTabIdx   : PolygonIDNObjAryIdx 配列で連続した同じ
 *			   polygonIDが始まる table の index
 *  @param endTabIdx 	 : 連続の終わりindex 
 *			   連続する範囲は [startTabIdx, endTabIdx]
 */
static void aveVerIntOnePolygon(objectsArrayClass   *pObjArray,
				PolygonIDNObjAryIdx *pPIDnOAidxTab,
				const int startTabIdx, 
				const int endTabIdx)
{
    VertexIntensity senderIvc[3];
    for(int i = startTabIdx; i <= endTabIdx; i++)
    {
	const int sendOAidx = pPIDnOAidxTab[i].mObjAryIdx;
	objBaseClass *pSenderObj = pObjArray->get(sendOAidx); // 輝度送り元
	if(pSenderObj->who() == TRIANGLE_OBJ_E)	      // 三角形のみ処理
	{
	    pSenderObj->getRadVer(senderIvc);
	    for(int j = startTabIdx; j <= endTabIdx; j++)
	    {
		if(i != j)	// 自分自身でない者へ送信
		{
		    assert(pPIDnOAidxTab[i].mPolygonID == 
			   pPIDnOAidxTab[j].mPolygonID);

		    const int recvOAidx = pPIDnOAidxTab[j].mObjAryIdx;

		    // 輝度受け側
		    objBaseClass *pGetterObj = pObjArray->get(recvOAidx);
		    if(pGetterObj->who() == TRIANGLE_OBJ_E)
		    {
			// sv ... sender vertex idx
			for(int sv = 0; sv < 3; sv++)
			{
			    // addIntensityToVertex は porigonID と頂
			    // 点の位置が同一なら輝度を加える  
			    pGetterObj->addIntensityToVertex(senderIvc[sv]);
			}
		    }
		}
	    }
	}
    }
}

/*
 * ひとつの空間の分
 */
static void aveVerIntOneSpcLocal(objectsArrayClass *pObjArray)
{
    const int len = pObjArray->getLength();
    int i;

    /*
     * make { polygonID, objarray idx } array
     *	The last element is the guard. 最後はばんぺい君
     */
    // cerr << "DEBUG : sorting " << len << "\t"; cerr.flush();

    PolygonIDNObjAryIdx *pPIDnOAidxTab = new PolygonIDNObjAryIdx[len + 1];
    for(i = 0; i < len; i++) 
    {
	objBaseClass *pSenderObj = pObjArray->get(i);
	pPIDnOAidxTab[i].mPolygonID = pSenderObj->getObjectID();
	pPIDnOAidxTab[i].mObjAryIdx = i;
    }
    qsort(pPIDnOAidxTab, len, sizeof(PolygonIDNObjAryIdx), comp);
    
    /*
     * search same polygon ID
     */
    // cerr << "DEBUG : update ";cerr.flush();
    for(i = 0; i < len; i++)
    {
	if(pPIDnOAidxTab[i].mPolygonID == pPIDnOAidxTab[i + 1].mPolygonID)
	{
	    // found, counting same polygonID polygon
	    int samepidnum = 1;	// I already know [i] and [i+1] is the same.
	    while(pPIDnOAidxTab[i].mPolygonID == 
		  pPIDnOAidxTab[i + samepidnum + 1].mPolygonID)
	    {
		samepidnum++;
	    }
	    
	    // 一つの polygon 分
	    aveVerIntOnePolygon(pObjArray, pPIDnOAidxTab, i, i + samepidnum);

	    // for が i++ しているので一つ減らした分を加える
	    // 本来は飛ばしても良いが，番兵は一人しかいないので最後に
	    // 同じものが続いた場合にも大丈夫なようにする．
	    i += (samepidnum - 1); 
	}
    }
    delete [] pPIDnOAidxTab;
    // cerr << "DEBUG : done" << endl;    
}

//------------------------------------------------------------
// prepare Gouroud shading
//	shading のために頂点の輝度を交換する
//------------------------------------------------------------
void PEClass::
prepareGouroudShading(void)
{
    pm_change_area(PA_prepshade_e);
    pm_change_stat(PC_prec_intensity_e);

    // Cell 長さ、頂点の位置の許容誤差を求める
    const double cellLen   = this->mSpcParam.getCellLen();
    const double tolerance = cellLen / 64.0; // 判定基準

    // PE の持つ物体情報を空間ごとにスキャンする
    int spx, spy, spz;
    IntVec3 peid, spcpos;
    Vector3 partVolMinPos = this->mSpcParam.getPartVolumeMin();
    if(partVolMinPos != Vector3(0.0, 0.0, 0.0))
    {
	// 多分この制約はなくなったと思うが，何かあった場合のために一応警告する
	// 2000年5月21日(日)
	cerr << "Warning! : constraint as partvol min is " 
	     << "(0.0, 0.0, 0.0) may deleted. but notice." << endl;
    }
    
    for(spz = 0; spz < this->mSpcParam.getSubDivNum(); spz++)
    {
	for(spy = 0; spy < this->mSpcParam.getSubDivNum(); spy++)
	{
	    for(spx = 0; spx < this->mSpcParam.getSubDivNum(); spx++)
	    {
		// この PE が担当する空間か
		spcpos.set(spx, spy, spz);
		peid = this->mNIUnit.mpSpc2PE->getPEIDfromSpcPos(spcpos);
		if(this->mID == peid)
		{
		    // 物体数が 0 ならこの空間で送信処理を行う必要はない
		    if(this->mObjectSet.getLength(spcpos) > 0) 
		    {
			// 1.この空間内の輝度値を平均する 
			// 空間内に 1 つしか物体がなければ処理する必要はない
			if(this->mObjectSet.getLength(spcpos) > 1)
			{
			    aveVerIntOneSpcLocal(this->mObjectSet.get(spcpos));
			}
			
			// 2.この空間内の輝度を他の空間へと伝搬させる
			//   この空間の min, max を求める
			const Vector3 spmin = 
			    partVolMinPos + cellLen * iv2v(spcpos);
			const Vector3 spmax = 
			    spmin + Vector3(cellLen, cellLen, cellLen);
			
			//   空間内の物体を取り出し送信する
			objectsArrayClass *pOAry =this->mObjectSet.get(spcpos);
			this->sendVerIntOfThisSpc(pOAry, spcpos, 
						  spmin, spmax, tolerance);
		    }
		}
	    }
	}
	if(Option::getInstance()->getVerboseMode() == YES)
	{
	    cout << genHd(VERBOSEHEAD, this->getMyRank()) 
		 << " z = " << spz << endl;
	}
    }
#ifndef REDUCE_VERBOSE_INFO
    if(Option::getInstance()->getVerboseMode() == YES)
    {
	cout << genHd(VERBOSEHEAD, this->getMyRank()) << 
		"send Intensity-Vertex.. done." << endl;
    }
#endif
    // この PE の担当する物体の頂点輝度はとりあえずキューには入れた．
    // あとは送信の完了と受信の完了，そしてステージの終了待ち 
    while(this->isPrepareShadingStageOver() == NO)
    {
	// 送信バッファの flush
	this->mNIUnit.flushVerIntSendBuff();

	// 受信
	this->mNIUnit.recvVerInt();
    
	if((this->mNIUnit.isSendingVerInt() == YES) ||
	   (this->mNIUnit.isRecvingVerInt() == YES))
	{
	    // 送信中あるいは受信中
	    this->toBusy(); // host へ動作中伝達	    
	    this->mNIUnit.recvVerInt();
	}
	else
	{
	    // 送信・受信ともになくなった
	    this->toIdle(); // host へ終了伝達
	}
	this->probNgetHostCommand(); // host からの連絡待ち
	pollingSleep();
    }

#ifndef REDUCE_VERBOSE_INFO
    if(Option::getInstance()->getVerboseMode() == YES)
    {
	cout << genHd(VERBOSEHEAD, this->getMyRank()) << 
		"get all Intensity-Vertex.. done." << endl;
    }
#endif
}

//------------------------------
// 一つの空間内の輝度情報を他へ送信する。ある1つの空間の物体情報は 
// pOAry が指している。
//------------------------------
void PEClass::
sendVerIntOfThisSpc(objectsArrayClass *pOAry, const IntVec3& srcspc, 
		    const Vector3& spmin,     const Vector3& spmax,
		    const double tolerance)
{
    const int objnum = pOAry->getLength();
    int i, ver;			
    VertexIntensity retVerInts3[3];
    for(i = 0; i < objnum; i++)
    {
	objBaseClass *pObj = pOAry->get(i);

	// 送信候補になれるのは radiosity で用いることが可能な primitive
	// (現在は、三角パッチのみ)
	if(pObj->who() == TRIANGLE_OBJ_E)
	{
	    // 輝度値を取り出す．
	    pObj->getRadVer(retVerInts3);
	    for(ver = 0; ver < 3; ver++) // 三角形の頂点は3つ
	    {
		// この物体の一つの輝度値が送信すべきものかどうか判定
		// し、送信する。nonblocking 送信を行う。
		this->testOneIntNsendVerInt(retVerInts3[ver], srcspc, 
					    spmin, spmax, tolerance);
	    }
	}
    }
}

//------------------------------
// この輝度情報が送信すべきものかどうか判定し、送信する
//------------------------------
void PEClass::
testOneIntNsendVerInt(const VertexIntensity& v, const IntVec3& srcspc, 
		      const Vector3& spmin,   const Vector3& spmax,
		      const double   tolerance)
{
    VertexIntensity verint(v);	// verint は変更の可能性あり

    assert(tolerance > 0.0);
    int i;
    for(i = 0; i < 3; i++) // vector i 番目 (x, y, z)
    {
	// 頂点は空間内部
#ifndef NDEBUG
	if((spmax.get(i) - (verint.getVertex()).get(i)) < (-tolerance))
	{
	    cout << "Error! : vertex is out of range:Large"	<< endl;
	    cout << "min	" << spmin 		     	<< endl;
	    cout << "ver	" << (verint.getVertex())	<< endl;
	    cout << "max	" << spmax		     	<< endl;
	    cout << "out axis is [" << i << "], val = " 	<< 
		(spmax.get(i) - (verint.getVertex()).get(i))	<< endl;
	    cout << "tolerance " << (-tolerance) 		<< endl;
	    exit(1);
	}
	if(((verint.getVertex()).get(i) - spmin.get(i)) < (-tolerance))
	{
	    cout << "Error! : vertex is out of range:Small"	<< endl;
	    cout << "min	" << spmin 		     	<< endl;
	    cout << "ver	" << verint.getVertex()	<< endl;
	    cout << "max	" << spmax		     	<< endl;
	    cout << "out axis is [" << i << "], val = " 	<< 
	    	((verint.getVertex()).get(i) - spmin.get(i)) 	<< endl;
	    cout << "tolerance " << (-tolerance) 		<< endl;
	    exit(1);
	}
#endif
	// まず送信は各 X,Y,Z の +- 方向へ
	if((spmax.get(i) - (verint.getVertex()).get(i)) < tolerance)
	{
	    // plus 方向に送信候補として追加(定義空間内にあるなら)
	    verint.setDestSpcPos(srcspc + AdjDir.get(i * 2));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if((verint.getVertex().get(i) - spmin.get(i)) < tolerance)
	{
	    // minus 方向に送信候補として追加(定義空間内にあるなら)
	    verint.setDestSpcPos(srcspc + AdjDir.get(i * 2 + 1));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else
	{
	    // 送信の候補にはならない
	}
    }
    // 次に複合方向へ (X+Y+, X+Y-, X-Y+, X-Y- : XZ も同様)
    Vector3 vertexpos = verint.getVertex();
    double xp = spmax.get(Vector3::X) - vertexpos.get(Vector3::X); 
    double xm = vertexpos.get(Vector3::X) - spmax.get(Vector3::X); 
    double yp = spmax.get(Vector3::Y) - vertexpos.get(Vector3::Y);
    double ym = vertexpos.get(Vector3::Y) - spmax.get(Vector3::Y);
    double zp = spmax.get(Vector3::Z) - vertexpos.get(Vector3::Z);
    double zm = vertexpos.get(Vector3::Z) - spmax.get(Vector3::Z);
    // XY, XZ
    if(xp < tolerance) 
    {
	//----- XPlus
	if(yp < tolerance)
	{			// Y+
	    verint.setDestSpcPos(srcspc + 
				   AdjDir.get(DIR_XPLUS) + 
				   AdjDir.get(DIR_YPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// まず X+ へ送信しその後 Y+ 方向へ送信する(現在は使わない)
		// 将来的に Mesh の計算機上ではこのように明示的に2回送
		// 信する方が良いだろうが現在は MPI の rank に頼って送
		// 信する (IMPROVEME)
		// verint.mRestDir = DIR_YPLUS; // X+ -> Y+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(ym < tolerance)
	{			// Y-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XPLUS) + 
				   AdjDir.get(DIR_YMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_YMINUS; // X+ -> Y-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
	if(zp < tolerance)
	{			// Z+
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XPLUS) + 
				   AdjDir.get(DIR_ZPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZPLUS; // X+ -> Z+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(zm < tolerance)
	{			// Z-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XPLUS) + 
				   AdjDir.get(DIR_ZMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZMINUS; // X+ -> Z-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
    }else if(xm < tolerance)
    {
	//----- X Minus
	if(yp < tolerance)
	{			// Y+
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XMINUS) + 
				   AdjDir.get(DIR_YPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_YPLUS; // X- -> Y+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(ym < tolerance)
	{			// Y-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XMINUS) + 
				   AdjDir.get(DIR_YMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_YMINUS; // X- -> Y-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
	if(zp < tolerance)
	{			// Z+
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XMINUS) +
				   AdjDir.get(DIR_ZPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZPLUS; // X- -> Z+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(zm < tolerance)
	{			// Z-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_XMINUS) + 
				   AdjDir.get(DIR_ZMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZMINUS; // X- -> Z-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
    }
    //-------------------- YZ
    if(yp < tolerance) 
    {
	//----- YPlus
	if(zp < tolerance)
	{			// Z+
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_YPLUS) + 
				   AdjDir.get(DIR_ZPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZPLUS; // Y+ -> Z+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(zm < tolerance)
	{			// Z-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_YPLUS) + 
				   AdjDir.get(DIR_ZMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZMINUS; // Y+ -> Z-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
    }else if(ym < tolerance)
    {
	//----- Y Minus
	if(zp < tolerance)
	{			// Z+
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_YMINUS) + 
				   AdjDir.get(DIR_ZPLUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZPLUS; // Y- -> Z+
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}else if(zm < tolerance)
	{			// Z-
	    verint.setDestSpcPos(srcspc + AdjDir.get(DIR_YMINUS) + 
				   AdjDir.get(DIR_ZMINUS));
	    if(this->checkInSpc(verint.getDestSpcPos()) == YES)
	    {
		// verint.mRestDir = DIR_ZMINUS; // Y- -> Z-
		this->sendVerIntToOtherSpcNrecv(verint);
	    }
	}
    }
}

//------------------------------
// 輝度情報の送信
//------------------------------
void PEClass::
sendVerIntToOtherSpcNrecv(const VertexIntensity& verint)
{
    const IntVec3 destPEId = 
    	this->mNIUnit.mpSpc2PE->getPEIDfromSpcPos(verint.getDestSpcPos());
    if(destPEId != this->mID)
    {
 	// 次空間は自分の担当するものではなかった -> 送信

	// PEID -> rank
	int destRank = this->getRank(destPEId);

	// 送信するものは一度 new する
	VertexIntensity *pSendVerInt = new VertexIntensity(verint);

	// rank	のものへ送信
	this->mNIUnit.sendVerInt(pSendVerInt, destRank);

	// 受信テスト
	this->mNIUnit.recvVerInt();
	
	// 受信が完了していたら受信キューの内容を取り出す
	while(this->mVerIntPtrQueue.length() > 0)
	{
	    assert(this->mVerIntPtrQueue.length() > 0);
	    VertexIntensity *pV = this->mVerIntPtrQueue.deq();
	    this->addIntensity(*pV);
	    delete pV;		// 受信したものは new されている
	}
    }else
    {
 	// 次空間は自分の担当するものだった
 	this->addIntensity(verint);
    }
}


//------------------------------
// addIntensity
//	輝度を加えられるか調べ、可能なら加える
//	加えた頂点の数を覚えておく
//------------------------------
void PEClass::
addIntensity(const VertexIntensity& verint)
{
    const int destObjNum = this->mObjectSet.getLength(verint.getDestSpcPos());
    if(destObjNum > 0)
    {
	objectsArrayClass *pObjArray = 
		this->mObjectSet.get(verint.getDestSpcPos());
	int i;
	for(i = 0; i < destObjNum; i++)
	{
	    objBaseClass *pObj = pObjArray->get(i);
	    // 何度加えても良い(いくつものポリゴンが集まった頂点の可能性がある)
	    if(pObj->who() == TRIANGLE_OBJ_E) // 受信候補は現在パッチのみ
	    {
		// ポリゴン ID と vertex 番号を比較し，同じならば加える
		pObj->addIntensityToVertex(verint);
	    }
	}
    }
}

//------------------------------
// finalizePrepareShadingStage
//	通信して加算した輝度を平均する
//------------------------------
void PEClass::
finalizePrepareShadingStage(void)
{
    Pix pidx;
    for(pidx = this->mObjList.first(); pidx != NULL; this->mObjList.next(pidx))
    {
	if(this->mObjList(pidx)->who() == TRIANGLE_OBJ_E)
	{
	    this->mObjList(pidx)->calcVerIntAveVal();
	}
    }
}


