package blobDetection;

//==================================================
//class Metaballs2D
//==================================================
public class Metaballs2D
{
// Isovalue
// ------------------
protected float isovalue;

// Grid
// ------------------
protected int  resx,resy;
protected float stepx,stepy;
protected float[] gridValue;
protected int nbGridValue;  

// Voxels      
// ------------------
protected int[] voxel;
protected int nbVoxel;

// EdgeVertex
// ------------------
protected EdgeVertex[] edgeVrt;
protected int nbEdgeVrt;  

// Lines
// what we pass to the renderer
// ------------------
protected int[] lineToDraw;  
protected int nbLineToDraw;

// Constructor
// ------------------
public Metaballs2D(){}


// init(int, int)
// ------------------
public void init(int resx, int resy)
{
	this.resx = resx;
	this.resy = resy;

	this.stepx = 1.0f/( (float)(resx-1));
	this.stepy = 1.0f/( (float)(resy-1));

	// Allocate gridValue
	nbGridValue	= resx*resy;
	gridValue	= new float[nbGridValue];

	// Allocate voxels
	nbVoxel		= nbGridValue;
	voxel		= new int[nbVoxel];

	// Allocate EdgeVertices
     edgeVrt 	= new EdgeVertex [2*nbVoxel];
     nbEdgeVrt 	= 2*nbVoxel;

	// Allocate Lines
	lineToDraw 		= new int[2*nbVoxel];
     nbLineToDraw 	= 0;
	
     // Precompute some values
	int x,y,n,index;
	n = 0;
	for (x=0 ; x<resx ; x++)
		for (y=0 ; y<resy ; y++)
		{
			index = 2*n;
			// index to edgeVrt
                     voxel[x+resx*y] = index;
			// values
                     edgeVrt[index]   = new EdgeVertex(x*stepx, y*stepy);
                     edgeVrt[index+1] = new EdgeVertex(x*stepx, y*stepy);

			// Next!
			n++;
		}
	
}

// computeIsovalue()
// ------------------
public void computeIsovalue()
{

 // A simple test : put a metaball on center of the screen
/*
	float	ballx = 0.5f;
	float	bally = 0.5f;
	float	vx,vy;
	float	dist;

	int x,y;
	vx = 0.0f;
	for (x=0 ; x<resx; x++)
	{	
		vy = 0.0f;
		for (y=0 ; y<resy; y++)
		{
			dist = (float)sqrt((vx-ballx)*(vx-ballx) + (vy-bally)*(vy-bally));
			gridValue[x+resx*y] = 10.0f/(dist*dist+0.001f);
			vy+=stepy;
		}
		vx+=stepx;
	}
*/
 
         
}


// computeMesh()
// ------------------
public void computeMesh()
{
	// Compute IsoValue
	computeIsovalue();
	// Get Lines indices

	int					x,y,squareIndex,n;
	int					iEdge;
	int					offx, offy, offAB;
	int					toCompute;
	int					offset;
	float					t;
	float					vx,vy;
	int[]                                   edgeOffsetInfo;

	nbLineToDraw = 0;
	vx	     = 0.0f;
	for (x=0 ; x<resx-1 ; x++)
	{
		vy = 0.0f;
		for (y=0 ; y<resy-1 ; y++)
		{
			offset		= x + resx*y;
			squareIndex = getSquareIndex(x,y);

			n	        = 0;
			while ( (iEdge = MetaballsTable.edgeCut[squareIndex][n++]) != -1)
			{
				edgeOffsetInfo          = MetaballsTable.edgeOffsetInfo[iEdge];
				offx			= edgeOffsetInfo[0];
				offy			= edgeOffsetInfo[1];
				offAB			= edgeOffsetInfo[2];

                            lineToDraw[nbLineToDraw++] = voxel[(x+offx) + resx*(y+offy)] + offAB;
			}

            toCompute = MetaballsTable.edgeToCompute[squareIndex];
			if (toCompute>0)
			{
                if ( (toCompute & 1) > 0) // Edge 0
				{
					t	= (isovalue - gridValue[offset]) / (gridValue[offset+1] - gridValue[offset]); 
					edgeVrt[voxel[offset]].x = vx*(1.0f-t) + t*(vx+stepx);
                             }
				if ( (toCompute & 2) > 0) // Edge 3
				{
					t	= (isovalue - gridValue[offset]) / (gridValue[offset+resx] - gridValue[offset]); 
					edgeVrt[voxel[offset]+1].y = vy*(1.0f-t) + t*(vy+stepy);
				}
			
			} // toCompute
			vy += stepy;
		}	// for y

		vx += stepx;
	}	// for x

	nbLineToDraw /= 2;
 
}

// getSquareIndex(int,int)
// ------------------
protected int getSquareIndex(int x, int y)
{
	int squareIndex = 0;
    int offy  = resx*y;
    int offy1 = resx*(y+1);
	if (gridValue[x+offy]		< isovalue) squareIndex |= 1;
	if (gridValue[x+1+offy]		< isovalue) squareIndex |= 2;
	if (gridValue[x+1+offy1]	< isovalue) squareIndex |= 4;
	if (gridValue[x+offy1]		< isovalue) squareIndex |= 8;
	return squareIndex;
}

// setIsoValue(float)
// ------------------
public void setIsovalue(float iso){this.isovalue = iso;}



}