/*=========================================================================
*
* Altimap.h	- Altimap functions
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include "Altimaps.h"

#include "sprobj.h"			

#include "SpoSave.h"		

//--------------------------------------------------------------------



/****************************************************************************
*		Description:	Test if an element is altimap or not
*
*		Parameters:		p_fX			: elements to test 
*						p_iEqualX		: returns the equal elements 
*						p_stGeometric	: geometric object
*						k				: returns number of equal elements 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_bIsAltimap(float **p_fX, int **p_iEqualX, MLT_tdstGeometricObject *p_stGeometric, int *k)
{
  int	i=0;
  BOOL	bTrue;
  float x1;

  (*p_iEqualX)[0]=1;
  *k=0;
  
  // get the elements from the array with x coordinates which 
  // are closed till a limit fLimit with the first element of the sorted array
  // continue with completing the arrays with equal elements
  while (i<=p_stGeometric->xNbPoints)
  {
	  x1=(*p_fX)[i];
	  // when all the values are equal, get that number
	  while ( (*p_fX)[i+1] == x1) 
	  {
		  i++;
		  (*p_iEqualX)[*k]++;
	  }
	  i++;
	  (*k)++;
	  (*p_iEqualX)[(*k)]=1;
  }
  bTrue=TRUE;
  
  //test if the number of equal elements is exactly the same for all the pars
  for (i=0;i<*k-2; i++)
	  if ((*p_iEqualX)[i]!=(*p_iEqualX)[i+1])
	  	  bTrue = FALSE;
  return bTrue;
}

/****************************************************************************
*		Description:	complete the structure of the altimap element
*
*		Parameters:		p_stGeometric	: geometric object 
*						p_stAltimap		: altimap element 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vCompleteAltimapStructure(MLT_tdstGeometricObject *p_stGeometric,   MLT_tdstElementAltimap* p_stAltimap)
{
  MLT_tdstElementIndexedTriangles	*p_stGeom, *p_stGeomNext;
  MLT_tdstTripledIndex				*d_stVertexIndexes;
  BOOL								bIsAltimap, bIsFirstTriangle;  
  float								*d_fX, *d_fY;
  int								m, i, k, j, l, iNew, iIndexSquare;
  int								*d_iInd, *d_iXIndex, *d_iXIndexFinal, *d_iEqualX;
  int								iLin, iCol;
  int								iFirst;
  int								iLast;

  //allocate the intermediare vectors for vertexes
  d_fX = (float *)malloc(p_stGeometric->xNbPoints*sizeof(float));
  if (d_fX==NULL)  //test if it could be allocated
  {
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  d_fY = (float *)malloc(p_stGeometric->xNbPoints*sizeof(float));
  //test if it could be allocated
  if (d_fY==NULL)
  {
	  free(d_fX);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  p_stAltimap->d_stPointNormals = (MTH3D_tdstVector *)malloc(sizeof(MTH3D_tdstVector)*p_stGeometric->xNbPoints);
  //test if it could be allocated
  if (p_stAltimap->d_stPointNormals==NULL)
  {
	  free(d_fX);
	  free(d_fY);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  p_stAltimap->d_xHeight = (MTH_tdxReal *)malloc(sizeof(MTH_tdxReal)*p_stGeometric->xNbPoints);
  //test if it could be allocated
  if (p_stAltimap->d_xHeight==NULL)
  {
	  free(d_fX);
	  free(d_fY);
	  free(p_stAltimap->d_stPointNormals);
	  free(p_stAltimap);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  d_iXIndex = (int *)malloc(p_stGeometric->xNbPoints*sizeof(int));
  //test if it could be allocated
  if (d_iXIndex==NULL)
  {
	  free(d_fX);
	  free(d_fY);
	  MLT_vFree(p_stAltimap);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }

  //determine the number of faces and the number of UVs for the element altimap
  p_stGeom = (MLT_tdstElementIndexedTriangles*)(p_stGeometric->d_stListOfElements[0]);
  p_stAltimap->xNbElementUV=0;
  p_stAltimap->xNbFaces = 0;
  for(i=0; i<p_stGeometric->xNbElements; i++)
  { p_stGeom = (MLT_tdstElementIndexedTriangles*)(p_stGeometric->d_stListOfElements[i]);
	//get the number of Faces and maximum number of elementUV for the altimap
    p_stAltimap->xNbFaces += p_stGeom->xNbFaces;
  	p_stAltimap->xNbElementUV += p_stGeom->xNbElementUV;
  }

  d_stVertexIndexes = (MLT_tdstTripledIndex *)malloc((p_stAltimap->xNbFaces)*sizeof(MLT_tdstTripledIndex));
  if (d_stVertexIndexes==NULL)//test if it could be allocated
  {
	  free(d_fX);
	  free(d_fY);
	  MLT_vFree(p_stAltimap);
	  free(d_iXIndex);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  //get the initial values for the X, Y coordinates, the height, and the normals in X, Y, Z
  for (i=0; i< p_stGeometric->xNbPoints; i++)
  {	d_fX[i] = p_stGeometric->d_stListOfPoints[i].xX;
	d_fY[i] = p_stGeometric->d_stListOfPoints[i].xY;
	p_stAltimap->d_xHeight[i] = p_stGeometric->d_stListOfPoints[i].xZ;
    MTH3D_M_vSetVectorElements(&p_stAltimap->d_stPointNormals[i], 
		p_stGeometric->d_stListOfPointsNormals[i].xX, 
		p_stGeometric->d_stListOfPointsNormals[i].xY, 
		p_stGeometric->d_stListOfPointsNormals[i].xZ);
	d_iXIndex[i] = i;
  }

  //get also the indexes of the vertexes which creates a face
  k=0;
  for(j=0; j<p_stGeometric->xNbElements; j++)
  {	p_stGeom = (MLT_tdstElementIndexedTriangles*)(p_stGeometric->d_stListOfElements[j]);
	for (i=0; i<p_stGeom->xNbFaces; i++)
	{	d_stVertexIndexes[k+i].a3_xIndex[0] = p_stGeom->d_stListOfFacesTripled[i].a3_xIndex[0];
		d_stVertexIndexes[k+i].a3_xIndex[1] = p_stGeom->d_stListOfFacesTripled[i].a3_xIndex[1];
		d_stVertexIndexes[k+i].a3_xIndex[2] = p_stGeom->d_stListOfFacesTripled[i].a3_xIndex[2];
	}
	k += p_stGeom->xNbFaces;
  }

  //sort the array with x coordinates
  MLT_vBubbleSort(&d_fX, &d_iXIndex, p_stGeometric->xNbPoints);
  //update all the vectors (y, z and normalx, normaly, normalz vor the vertexes after the sorted x array
  MLT_vExchange(&d_fY, d_iXIndex, p_stGeometric->xNbPoints);
  MLT_vExchange(&p_stAltimap->d_xHeight, d_iXIndex, p_stGeometric->xNbPoints);
  MLT_vExchangeNormals(&p_stAltimap->d_stPointNormals, d_iXIndex, p_stGeometric->xNbPoints);
  MLT_vExchangeIndexes(&d_stVertexIndexes, d_iXIndex, p_stAltimap->xNbFaces, p_stGeometric->xNbPoints);

  d_iEqualX= (int *)malloc(1000*sizeof(int));
  if (d_iEqualX==NULL)//test if it could be allocated
  {
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  MLT_vFree(p_stAltimap);
	  free(d_iXIndex);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  if (bIsAltimap=MLT_bIsAltimap(&d_fX, &d_iEqualX, p_stGeometric, &k))  //if the object is an altimap
  {	for (i=0; i< p_stGeometric->xNbPoints; i++)
		d_iXIndex[i] = i;
  	MLT_vBubbleSort(&d_fY, &d_iXIndex, p_stGeometric->xNbPoints);  //sort the array with the y coordinates
	//update all the vectors (x, z and normalx, normaly, normalz vor the vertexes after the sorted x array
	MLT_vExchange(&d_fX, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchange(&p_stAltimap->d_xHeight, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchangeNormals(&p_stAltimap->d_stPointNormals, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchangeIndexes(&d_stVertexIndexes, d_iXIndex, p_stAltimap->xNbFaces, p_stGeometric->xNbPoints);

	iFirst = 0;
	iLast = k-2;
	//sort the array of X coordinates between the indexes: 0:k-2,k-1:... 
	for (i=0; i< p_stGeometric->xNbPoints; i++)
		d_iXIndex[i] = i;
	while (iLast<p_stGeometric->xNbPoints-1)
	{
		MLT_vFinalSort(&d_fX, &d_iXIndex, iFirst, iLast);
		iFirst += k-1;
		iLast += k-1;
	}
	MLT_vExchange(&d_fY, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchange(&p_stAltimap->d_xHeight, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchangeNormals(&p_stAltimap->d_stPointNormals, d_iXIndex, p_stGeometric->xNbPoints);
	MLT_vExchangeIndexes(&d_stVertexIndexes, d_iXIndex, p_stAltimap->xNbFaces, p_stGeometric->xNbPoints);

  }
  free(d_iXIndex);
  //if it was not an altimap return, after deallocated all
  if (!bIsAltimap)  
  {	  
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  if (d_iEqualX) free(d_iEqualX);
	  MLT_vFree(p_stAltimap);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return;
  }
  //set the components of the altimap
  //set the origin
  MTH3D_M_vSetVectorElements(&p_stAltimap->stOrigin, d_fX[0], d_fY[0], p_stAltimap->d_xHeight[0]);
  //set the square pattern
  p_stAltimap->xDeltaX	= (d_fX[k-2]-d_fX[0])/(k-2); 
  p_stAltimap->xDeltaY	= (d_fY[p_stGeometric->xNbPoints-k+1]-d_fY[0])/(d_iEqualX[0]-1); //d_fY[p_stGeometric->xNbPoints/d_iEqualX[0]]-d_fY[0];
  p_stAltimap->xWidth	= k-2;
  p_stAltimap->xDepth	= d_iEqualX[0]-1;
  free(d_iEqualX);

  //see if the values are good in a precision of fLimit=0.001
  bIsAltimap=TRUE;
  for (i=0; i<p_stGeometric->xNbPoints; i++)
  {
	  //get the column and line for the index i
	  iCol = i % ( p_stAltimap->xWidth+1);
	  iLin = (i-iCol)/(p_stAltimap->xWidth+1);
	  //if the data is in the precision, arange the values, if not is not an altimap
	  if (fabs(d_fX[i]-d_fX[0]-iCol*p_stAltimap->xDeltaX)<=g_fLimit1)
		  d_fX[i] = d_fX[0]+iCol*p_stAltimap->xDeltaX;
	  else
		  bIsAltimap=FALSE;
	  if (fabs(d_fY[i]-d_fY[0]-iLin*p_stAltimap->xDeltaY)<=g_fLimit1)
		  d_fY[i] = d_fY[0]+iLin*p_stAltimap->xDeltaY;
	  else
		  bIsAltimap=FALSE;
  }
  //if it was not an altimap return, after deallocated all
  if (!bIsAltimap)  
  {
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  MLT_vFree(p_stAltimap);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return;
  }

  //set the number of squares and vertexes
  p_stAltimap->xNbSquares  = p_stAltimap->xWidth*p_stAltimap->xDepth; //k-2;
  p_stAltimap->xNbVertexes = p_stGeometric->xNbPoints;
  p_stAltimap->d_stSquare  = (MLT_tdstAltimapSquare *)malloc(sizeof(MLT_tdstAltimapSquare)*p_stAltimap->xNbSquares);
  //alloc all the structure needed by the altimap
  //test if it could be allocated
  if (p_stAltimap->d_stSquare==NULL)
  {
	  MLT_vFree(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  p_stAltimap->d_stFaceNormals	= (MTH3D_tdstVector *)malloc(sizeof(MTH3D_tdstVector)*p_stAltimap->xNbFaces);
  //test if it could be allocated
  if (p_stAltimap->d_stFaceNormals==NULL)
  {
	  free(p_stAltimap->d_stSquare);
	  MLT_vFree(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  p_stAltimap->d_hFMD			= (MLT_tdxHandleOfFMD *)malloc(sizeof(MLT_tdxHandleOfFMD)*p_stAltimap->xNbFaces);
  //test if it could be allocated
  if (p_stAltimap->d_hFMD==NULL)
  {
	  free(p_stAltimap->d_stSquare);
	  free(p_stAltimap->d_stFaceNormals);
	  MLT_vFree(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  for (i=0; i<p_stAltimap->xNbFaces; i++)
  {	  p_stAltimap->d_hFMD[i]	= (MLT_tdstHandleOfFMD *)malloc(sizeof(MLT_tdstHandleOfFMD));
	  if (p_stAltimap->d_hFMD[i]==NULL)//test if it could be allocated
	  {
		free(p_stAltimap->d_stSquare);
		free(p_stAltimap->d_stFaceNormals);
		free(p_stAltimap->d_hFMD);
		MLT_vFree(p_stAltimap);
		MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	    p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
		return ;
	  }
  }
  p_stAltimap->d_stUVValues       = (ACP_tdst2DUVValues *)malloc(sizeof(ACP_tdst2DUVValues)*p_stAltimap->xNbElementUV);
  if (p_stAltimap->d_stUVValues==NULL)//test if it could be allocated
  {
	  free(p_stAltimap->d_stSquare);
	  free(p_stAltimap->d_stFaceNormals);
	  for (i=0; i<p_stAltimap->xNbFaces; i++)
		  free(p_stAltimap->d_hFMD[i]);
	  free(p_stAltimap->d_hFMD);
	  MLT_vFree(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }

  //set the types, number of faces and the index of the first triangle for every square
  for (i=0;i<p_stAltimap->xNbSquares;i++)
  {	p_stAltimap->d_stSquare[i].ucType = 0;
    p_stAltimap->d_stSquare[i].sNbFacesForSquare = 0;
    p_stAltimap->d_stSquare[i].xFaceIndex = -1;
  }
  d_iXIndex = (int *)malloc(2*p_stAltimap->xNbSquares*sizeof(int));
  if (d_iXIndex==NULL)
  {
	  MLT_vFreeAltimap(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }

  d_iXIndexFinal = (int *)malloc(p_stAltimap->xNbFaces*sizeof(int));
  //test if it could be allocated
  if (d_iXIndexFinal==NULL)
  {
	  MLT_vFreeAltimap(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  free(d_iXIndex);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }
  for (i=0; i<2*p_stAltimap->xNbSquares; i++)
	  d_iXIndex[i]=-1;
  //for every square get the indexes for the triangles associated with a square
  for (i=0; i<p_stAltimap->xNbFaces; i++)
  {	  iIndexSquare = MLT_iIndexSquare(&d_stVertexIndexes[i], p_stAltimap, &bIsFirstTriangle);
	  if (iIndexSquare==-1)  
	  {	
		if (d_iXIndex) free(d_iXIndex);
		if (d_iXIndexFinal) free(d_iXIndexFinal);
	    MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
		MLT_vFreeAltimap(p_stAltimap);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	    return;
	  }
	  if (d_iXIndex[2*iIndexSquare] == -1) 
		  d_iXIndex[2*iIndexSquare] = i;
	  else
		  if (bIsFirstTriangle)
		  {  d_iXIndex[2*iIndexSquare+1]	= d_iXIndex[2*iIndexSquare];  
			 d_iXIndex[2*iIndexSquare]	= i;
		  }
		  else
			 d_iXIndex[2*iIndexSquare+1]	= i;
  }
  j=0;
  for (i=0; i<2*p_stAltimap->xNbSquares; i++)
  {		if (d_iXIndex[i] != -1)
		{	d_iXIndexFinal[j] = d_iXIndex[i];
			j++;
		}
  }
  free(d_iXIndex);

  //get the UVs for the altimap element
  p_stGeom=(MLT_tdstElementIndexedTriangles*)(p_stGeometric->d_stListOfElements[0]);
  for (i=0; i<p_stGeom->xNbElementUV; i++)
  {	 p_stAltimap->d_stUVValues[i].xU = p_stGeom->d_stListOfElementUV[i].xU;
	 p_stAltimap->d_stUVValues[i].xV = p_stGeom->d_stListOfElementUV[i].xV;
  }
  p_stAltimap->xNbElementUV = p_stGeom->xNbElementUV;

  //get also the material for a face
  for (i=0; i<p_stAltimap->xNbFaces; i++)
	if (d_iXIndexFinal[i] < p_stGeom->xNbFaces)
		strcpy(p_stAltimap->d_hFMD[i]->sMaterial, p_stGeom->sMaterial);
	//for every element indexed triangle,  of the geometric object
	for (l=1; l<p_stGeometric->xNbElements; l++)
	{ p_stGeomNext=(MLT_tdstElementIndexedTriangles*)(p_stGeometric->d_stListOfElements[l]);
	  j=p_stGeom->xNbFaces;
	  m=p_stGeom->xNbElementUV;
	  p_stGeom->d_stListOfFacesNormals=(MTH3D_tdstVector *)realloc(p_stGeom->d_stListOfFacesNormals, 
																  (p_stGeomNext->xNbFaces+j)*sizeof(MTH3D_tdstVector));
	  p_stGeom->d_stListOfElementUV=(ACP_tdst2DUVValues *)realloc(p_stGeom->d_stListOfElementUV, 
																 (p_stGeomNext->xNbElementUV+m)*sizeof(ACP_tdst2DUVValues));
	  p_stGeom->d_stListOfFacesTripledIndexUV=(MLT_tdstTripledIndex *)realloc(p_stGeom->d_stListOfFacesTripledIndexUV, 
																 (p_stGeomNext->xNbFaces+j)*sizeof(MLT_tdstTripledIndex));
	  for (i=0; i<p_stGeomNext->xNbFaces; i++)
	  {	  //set the normals
		  MTH3D_M_vSetVectorElements(&p_stGeom->d_stListOfFacesNormals[i+j], p_stGeomNext->d_stListOfFacesNormals[i].xX, p_stGeomNext->d_stListOfFacesNormals[i].xY, p_stGeomNext->d_stListOfFacesNormals[i].xZ);
		  for (k=0; k<3; k++)
			//add or not the new UV at the list of UVs for the indexed triangle which will contain a concatanation of indexed traingles
			//and set also the list with tripled indexes for them
			if(!MLT_bExist(p_stAltimap->d_stUVValues, p_stGeomNext->d_stListOfElementUV[p_stGeomNext->d_stListOfFacesTripledIndexUV[i].a3_xIndex[k]], &iNew, p_stAltimap->xNbElementUV))
			{	p_stGeom->d_stListOfFacesTripledIndexUV[i+j].a3_xIndex[k] = m;
				p_stAltimap->xNbElementUV++;
				p_stGeom->d_stListOfElementUV[m].xU=p_stGeomNext->d_stListOfElementUV[p_stGeomNext->d_stListOfFacesTripledIndexUV[i].a3_xIndex[k]].xU;
				p_stGeom->d_stListOfElementUV[m].xV=p_stGeomNext->d_stListOfElementUV[p_stGeomNext->d_stListOfFacesTripledIndexUV[i].a3_xIndex[k]].xV;
				p_stAltimap->d_stUVValues[m].xU=p_stGeomNext->d_stListOfElementUV[p_stGeomNext->d_stListOfFacesTripledIndexUV[i].a3_xIndex[k]].xU;
				p_stAltimap->d_stUVValues[m].xV=p_stGeomNext->d_stListOfElementUV[p_stGeomNext->d_stListOfFacesTripledIndexUV[i].a3_xIndex[k]].xV;
				m++;
			}
			else
				p_stGeom->d_stListOfFacesTripledIndexUV[i+j].a3_xIndex[k] = iNew;
	  }
  	  p_stGeom->xNbFaces += p_stGeomNext->xNbFaces;
	  p_stGeom->xNbElementUV = m;
	  //set the materials for the faces which are own by the processed element indexed triangle
	  for (k=0; k<p_stAltimap->xNbFaces; k++)
		  if ((d_iXIndexFinal[k] < p_stGeomNext->xNbFaces+j) &&(d_iXIndexFinal[k] >= j))
			strcpy(p_stAltimap->d_hFMD[k]->sMaterial, p_stGeomNext->sMaterial);
	}
  d_iInd = (int *)malloc(3*sizeof(int));
  //test if it could be allocated
  if (d_iInd==NULL)
  {
	  MLT_vFreeAltimap(p_stAltimap);
	  MLT_vFreeAlloc(d_fX, d_fY, d_stVertexIndexes);
	  free(d_iXIndexFinal);
	  p_stGeometric->iFlags |= IS_NOT_ALTIMAP;
	  return ;
  }

  for (i=0; i<p_stAltimap->xNbFaces; i++)
  {
	//get the normals to the faces for tthe altimap element
	MTH3D_M_vSetVectorElements(&p_stAltimap->d_stFaceNormals[i], 
		p_stGeom->d_stListOfFacesNormals[d_iXIndexFinal[i]].xX,
		p_stGeom->d_stListOfFacesNormals[d_iXIndexFinal[i]].xY,
		p_stGeom->d_stListOfFacesNormals[d_iXIndexFinal[i]].xZ);
	MLT_vSortIndex(&d_stVertexIndexes[d_iXIndexFinal[i]], p_stAltimap,/* d_fX, d_fY,*/ &d_iInd);
    //and the UVs
	for (j=0; j<3; j++)
		p_stAltimap->d_hFMD[i]->stTrianglesIndexUVValues.a3_xIndex[j]=
			p_stGeom->d_stListOfFacesTripledIndexUV[d_iXIndexFinal[i]].a3_xIndex[d_iInd[j]];
  }
  //set also the index to start for every square, for every triangle
  if (p_stAltimap->d_stSquare[0].sNbFacesForSquare) 
	  p_stAltimap->d_stSquare[0].xFaceIndex = 0;
  for (i=1; i<p_stAltimap->xNbSquares; i++)
	  p_stAltimap->d_stSquare[i].xFaceIndex += p_stAltimap->d_stSquare[i-1].xFaceIndex + p_stAltimap->d_stSquare[i-1].sNbFacesForSquare+1;
  //deallocate all it used
  free(d_stVertexIndexes);
  free(d_iXIndexFinal);
  free(d_iInd);
  free(d_fX);
  free(d_fY);
}


/****************************************************************************
*		Description:	free some parts of the altimap
*
*		Parameters:		p_stAltimap		: altimap element 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vFreeAltimap(MLT_tdstElementAltimap* p_stAltimap)
{
	int i;

	free(p_stAltimap->d_stFaceNormals);
	free(p_stAltimap->d_stSquare);
	for (i=0; i<p_stAltimap->xNbFaces; i++)
		free(p_stAltimap->d_hFMD[i]);
	free(p_stAltimap->d_hFMD);
	free(p_stAltimap->d_stUVValues);
	MLT_vFree(p_stAltimap);
}



/****************************************************************************
*		Description:	free the altimap
*
*		Parameters:		p_stAltimap		: altimap element 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vFree(MLT_tdstElementAltimap* p_stAltimap)
{
	free(p_stAltimap->d_xHeight);
	free(p_stAltimap->d_stPointNormals);
    free(p_stAltimap);
}


/****************************************************************************
*		Description:	free some allocated structures
*
*		Parameters:		d_fX			  : array of x coordinates 
*						d_fY			  : array of y coordinates 
*						d_stVertexIndexes : array of indexes
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vFreeAlloc(float *d_fX, float *d_fY, MLT_tdstTripledIndex *d_stVertexIndexes)
{	
	free(d_fX);
	free(d_fY);
	free(d_stVertexIndexes);
}




/****************************************************************************
*		Description:	sort an array using the bubble sort method
*
*		Parameters:		p_fX		: array of cooridnates to sort 
*						p_iXIndex	: array of indexes 
*						lNbPoints	: nb of points in the array
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vBubbleSort (float **p_fX, int **p_iXIndex, long lNbPoints)
{
  BOOL	bSwapped;
  float fTemp;
  int	i, iTemp;

  // sort the array using the bubble sort method, 
  // and also update the p_iXIndex array using the same method 
  // in p_iXIndex are the indices for the modified array
   do 
   {
	    bSwapped=FALSE;      
		for(i = 0; i < lNbPoints-1; i++) 
		{
			if ((*p_fX)[i+1]<(*p_fX)[i])
			{	if (fabs((*p_fX)[i+1]-(*p_fX)[i])<=g_fLimit1)
					(*p_fX)[i+1] = (*p_fX)[i];
				else
				{   // perform the swap 
					fTemp=(*p_fX)[i];
					(*p_fX)[i]=(*p_fX)[i+1];
					//change the values of array to sort
					(*p_fX)[i+1]=fTemp; 
					iTemp=(*p_iXIndex)[i];
					(*p_iXIndex)[i]=(*p_iXIndex)[i+1];
					//change the ordered array
					(*p_iXIndex)[i+1]=iTemp; 
					//according to the array to sort, for saving the indexes
					bSwapped = TRUE;        
				}
			}
			else
			{	if (fabs((*p_fX)[i+1]-(*p_fX)[i])<=g_fLimit1)
					(*p_fX)[i+1] = (*p_fX)[i];
			}
		}
	} while (bSwapped);    
}


/****************************************************************************
*		Description:	sort an array using the bubble sort method
*
*		Parameters:		p_fX		: array of cooridnates to sort 
*						p_iXIndex	: array of indexes 
*						iFirst		: first index
*						iLast		: last index
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vFinalSort(float **p_fX, int **p_iXIndex, int iFirst, int iLast)
{
  BOOL	bSwapped;
  float fTemp;
  int	i, iTemp;

  do 
  {	
	    bSwapped=FALSE;      
		for(i = iFirst; i < iLast-1; i++) 
		{
		  	if ((*p_fX)[i+1]<(*p_fX)[i]) 
			{   // perform the swap 
				fTemp=(*p_fX)[i];
				(*p_fX)[i]=(*p_fX)[i+1];
				//change the values of array to sort
				(*p_fX)[i+1]=fTemp; 
			    iTemp=(*p_iXIndex)[i];
				(*p_iXIndex)[i]=(*p_iXIndex)[i+1];
				//change the ordered array 
				(*p_iXIndex)[i+1]=iTemp;
				//according to the array to sort, for saving the indexes
				bSwapped = TRUE;        
			}
		}
	} while (bSwapped);    
}


/****************************************************************************
*		Description:	Sort the arrays with indexes of columns and lines
*
*		Parameters:		p_stListOfFaces	: list of faces 
*						p_stAltimap		: altimap element 
*						p_iInd			: array of indexes
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSortIndex(MLT_tdstTripledIndex *p_stListOfFaces, MLT_tdstElementAltimap* p_stAltimap, int **p_iInd)
{
	int i, *d_iCol, *d_iLin;
	d_iCol = (int *)malloc(sizeof(int)*3);
	d_iLin = (int *)malloc(sizeof(int)*3);
	for (i=0; i<3; i++)
	{   
		(*p_iInd)[i] = i;
		//get the column and the line of every triangle
		d_iCol[i] = p_stListOfFaces->a3_xIndex[i] % (p_stAltimap->xWidth+1);
		d_iLin[i] = (p_stListOfFaces->a3_xIndex[i] -d_iCol[i]) / (p_stAltimap->xWidth+1);
	}
	MLT_vOrder(&d_iCol, p_iInd);
	MLT_vArrangeArray(&d_iLin, *p_iInd);
	MLT_vOrder(&d_iLin, p_iInd);
	free(d_iCol);
	free(d_iLin);
}




/****************************************************************************
*		Description:	Change an array according with an array of indexes
*
*		Parameters:		p_fX		: array to change 
*						p_iXIndex	: array of indexes 
*						lNbPoints	: nb of points
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vExchange(float **p_fX, int *p_iXIndex, long lNbPoints)
{	
	int		i;
	float	*d_fTemp;

    d_fTemp = (float *)malloc(lNbPoints*sizeof(float));
	//set the x, y, and z arrays with coordinates after the positions from the p_iXIndex array
	for (i=0; i<lNbPoints; i++)
		d_fTemp[i] = (*p_fX)[p_iXIndex[i]];
	for (i=0; i<lNbPoints; i++)
		(*p_fX)[i] = d_fTemp[i];
	free(d_fTemp);
}


/****************************************************************************
*		Description:	Change the Tripled Indexes according with an given index
*
*		Parameters:		p_fX		: array to change 
*						p_iXIndex	: array of indexes 
*						lNbPoints	: nb of points
*						lGeomPoints	: nb of points in geometry
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vExchangeIndexes(MLT_tdstTripledIndex **p_fX, int *p_iXIndex, long lNbPoints, long lGeomPoints)
{	
	int						i=0;
	MLT_tdstTripledIndex	*d_stTemp;

    d_stTemp = (MLT_tdstTripledIndex *)malloc(lNbPoints*sizeof(MLT_tdstTripledIndex));
	//set the tripled indexes according to the indexes
	for (i=0; i<lNbPoints; i++)
	{
		d_stTemp[i].a3_xIndex[0] = MLT_iGetIndex(p_iXIndex, (*p_fX)[i].a3_xIndex[0],lGeomPoints);
		d_stTemp[i].a3_xIndex[1] = MLT_iGetIndex(p_iXIndex, (*p_fX)[i].a3_xIndex[1],lGeomPoints);
		d_stTemp[i].a3_xIndex[2] = MLT_iGetIndex(p_iXIndex, (*p_fX)[i].a3_xIndex[2],lGeomPoints);
	}
	for (i=0; i<lNbPoints; i++)
	{	(*p_fX)[i].a3_xIndex[0] = d_stTemp[i].a3_xIndex[0];
		(*p_fX)[i].a3_xIndex[1] = d_stTemp[i].a3_xIndex[1];
		(*p_fX)[i].a3_xIndex[2] = d_stTemp[i].a3_xIndex[2];
	}
	free(d_stTemp);
}


/****************************************************************************
*		Description:	Change the normals according with an given index
*
*		Parameters:		p_fX		: array to change 
*						p_iXIndex	: array of indexes 
*						lNbPoints	: nb of points
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vExchangeNormals(MTH3D_tdstVector **p_fX, int *p_iXIndex, long lNbPoints)
{	
	int					i;
	MTH3D_tdstVector	*d_stTemp;

    d_stTemp = (MTH3D_tdstVector *)malloc(lNbPoints*sizeof(MTH3D_tdstVector));
	//set the x, y, and z arrays with coordinates after the positions from the p_iXIndex array
	for (i=0; i<lNbPoints; i++)
		MTH3D_M_vSetVectorElements(&d_stTemp[i], 
			(*p_fX)[p_iXIndex[i]].xX, 
			(*p_fX)[p_iXIndex[i]].xY, 
			(*p_fX)[p_iXIndex[i]].xZ);
	for (i=0; i<lNbPoints; i++)
		MTH3D_M_vSetVectorElements(&(*p_fX)[i], 
			d_stTemp[i].xX, 
			d_stTemp[i].xY, 
			d_stTemp[i].xZ);

	free(d_stTemp);
}



/****************************************************************************
*		Description:	order an array according with a given index
*
*		Parameters:		p_iValues	: array to order 
*						p_iInd		: array of indexes 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vOrder (int **p_iValues, int ** p_iInd)
{ 
  BOOL	bSwapped;
  int	i, iTemp;
  
  do 
  { 
	  bSwapped=FALSE;      
	  for(i = 0; i < 2; i++) 
	  {
		//arrange an array with integers
		if ((*p_iValues)[i+1] < (*p_iValues)[i]) 
		{   
			iTemp=(*p_iValues)[i];
			(*p_iValues)[i]=(*p_iValues)[i+1];
			(*p_iValues)[i+1]=iTemp; 
			//arrange the array with indexes for showing how the first array is update
			iTemp=(*p_iInd)[i];		
			(*p_iInd)[i]=(*p_iInd)[i+1];
			(*p_iInd)[i+1]=iTemp;
			bSwapped = TRUE;        
		}   
	  }
  } while (bSwapped);    
}


/****************************************************************************
*		Description:	Arrange an array with integers after an array with indexes
*
*		Parameters:		p_iCol	: array to order 
*						p_iInd	: array of indexes 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vArrangeArray(int **p_iCol, int *p_iInd)
{	
	int i, iTemp[3];
	for (i=0; i<3; i++)
		iTemp[i] = (*p_iCol)[p_iInd[i]];
	for (i=0; i<3; i++)
		(*p_iCol)[i] = iTemp[i];
}


/****************************************************************************
*		Description:	Get the minumum value from an array
*
*		Parameters:		p_iValues	: array to search 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
int MLT_iMin (int *p_iValues)
{
    int i, iMin=p_iValues[0];
	//get the minimum value of an array
	for (i=1; i<3; i++)
		if (p_iValues[i]<iMin)
			iMin=p_iValues[i];
	return iMin;

}

/****************************************************************************
*		Description:	Get the index of value in an array 
*
*		Parameters:		p_iXIndex	: array to search 
*						iValue		: value to search for 
*						lNbPoints	: number of points
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
int MLT_iGetIndex (int *p_iXIndex, int iValue, long lNbPoints)
{	
	int i;

	for (i=0; i<lNbPoints;i++)
	{
		//return the index of the element which have a value equal to the searched one
		if (p_iXIndex[i]==iValue)
			return i;
	}
    return -1;
}



/****************************************************************************
*		Description:	Get the index of a square which contains the triangle
*
*		Parameters:		p_stListOfFaces	: list of faces
*						p_stAltimap		: altimap element 
*						bIsFirst		: flag for the search
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
int MLT_iIndexSquare(MLT_tdstTripledIndex *p_stListOfFaces, MLT_tdstElementAltimap* p_stAltimap, BOOL *bIsFirst)
{
	int i, *d_iCol, *d_iLin, *d_iInd;

	d_iCol = (int *)malloc(sizeof(int)*3);
	d_iLin = (int *)malloc(sizeof(int)*3);
	d_iInd = (int *)malloc(sizeof(int)*3);

	//get the indexes of the columns and lines for the three points which forms a triangle
	for (i=0; i<3; i++)
	{   d_iInd[i] = i;
		d_iCol[i] = p_stListOfFaces->a3_xIndex[i] % (p_stAltimap->xWidth+1);
		d_iLin[i] = (p_stListOfFaces->a3_xIndex[i] -d_iCol[i]) / (p_stAltimap->xWidth+1);
	}

	//get the sorted array with the column indexes
	MLT_vOrder(&d_iCol, &d_iInd);
	MLT_vArrangeArray(&d_iLin, d_iInd);
	for (i=0; i<3; i++)
	    d_iInd[i] = i;
	MLT_vOrder(&d_iLin, &d_iInd);
	MLT_vArrangeArray(&d_iCol, d_iInd);

	//determine the index of the square
	if (((d_iCol[0]==d_iCol[1]) || (d_iCol[2]==d_iCol[1]) || (d_iCol[0]==d_iCol[2]))&&
		((d_iLin[0]==d_iLin[1]) || (d_iLin[2]==d_iLin[1]) || (d_iLin[0]==d_iLin[2])))
		i=MLT_iMin(d_iLin)*p_stAltimap->xWidth + MLT_iMin(d_iCol);
	else return i=-1;

	//determine also the type of the square (how many triangles are in it, and how are they located in the square)
	if ((d_iCol[0]==d_iCol[2])&&(d_iCol[0]==d_iCol[1]+1))
	{	if (!p_stAltimap->d_stSquare[i].ucType || (p_stAltimap->d_stSquare[i].ucType==2))
			p_stAltimap->d_stSquare[i].ucType  += 1;
		else return i=-1;
		*bIsFirst = TRUE;
		p_stAltimap->d_stSquare[i].sNbFacesForSquare++;
	}
	if ((d_iCol[0]==d_iCol[2]) && (d_iCol[0]==d_iCol[1]-1))
	{	if (!p_stAltimap->d_stSquare[i].ucType || (p_stAltimap->d_stSquare[i].ucType==1))
			p_stAltimap->d_stSquare[i].ucType+=2;
		else return i=-1;
		*bIsFirst = FALSE; //it is not the first triangle (with index 0)
		p_stAltimap->d_stSquare[i].sNbFacesForSquare++;
	}
	if ((d_iCol[0]==d_iCol[1])&&(d_iCol[0]==d_iCol[2]-1))
	{	if (!p_stAltimap->d_stSquare[i].ucType || (p_stAltimap->d_stSquare[i].ucType==8))
			p_stAltimap->d_stSquare[i].ucType+=4;
		else return i=-1;
		*bIsFirst = TRUE;
		p_stAltimap->d_stSquare[i].sNbFacesForSquare++;
	}
	if ((d_iCol[0]==d_iCol[1]-1) && (d_iCol[1]==d_iCol[2]))
	{	if (!p_stAltimap->d_stSquare[i].ucType || (p_stAltimap->d_stSquare[i].ucType==4))
			p_stAltimap->d_stSquare[i].ucType+=8;
		else return i=-1;
		*bIsFirst = FALSE;//it is not the first triangle (with index 0)
		p_stAltimap->d_stSquare[i].sNbFacesForSquare++;
	}
	free(d_iCol);
	free(d_iLin);
	free(d_iInd);
	return i;
}


/****************************************************************************
*		Description:	Test if an UV exist in the array of UVs
*
*		Parameters:		p_stUV		: array to search
*						stUVi		: value to search for 
*						iNew		: returns the index of the found element
*						lNumber		: rnb of elements
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_bExist (ACP_tdst2DUVValues *p_stUV, ACP_tdst2DUVValues stUVi, int *iNew, long lNumber)
{
	int i;

	for (i=0; i<lNumber; i++)
	{
		//if it exist return the index of it
		if ((stUVi.xU == p_stUV[i].xU)&&(stUVi.xV == p_stUV[i].xV))
		{	*iNew = i;
			return TRUE;
		}
	}
	return FALSE;
}











