	/************************************************/
	/* EDITEUR de PCB: AUTOROUTAGE: routines d'init */
	/************************************************/

	/* Fichier BOARD.CC */

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "pcbnew.h"
#include "autorout.h"
#include "cell.h"

#include "protos.h"

/* routines externes : */

/* Routines definies ici: */
int Build_Work(BOARD * Pcb, CHEVELU* pt_base_chevelu);
void PlaceCells(BOARD * Pcb, int net_code, int flag);
int InitBoard( void );
BoardCell GetCell( int, int, int );
void SetCell(int row,int col,int side,BoardCell x );
void OrCell( int, int, int, BoardCell );
void AndCell( int, int, int, BoardCell );
void AddCell( int, int, int, BoardCell );
void XorCell( int, int, int, BoardCell );
void AddCell( int, int, int, BoardCell );
DistCell GetDist( int, int, int );
void SetDist( int, int, int, DistCell );
int GetDir( int, int, int );
void SetDir( int, int, int, int );

/*****************************************************************/
bool ComputeMatriceSize(WinEDA_BasePcbFrame * frame, int g_GridRoutingSize)
/*****************************************************************/
/*
Calcule Nrows et Ncols, dimensions de la matrice de representation du BOARD
pour les routages automatiques et calculs de zone
*/
{
BOARD * pcb = frame->m_Pcb;
	
	pcb->ComputeBoundaryBox();

	/* The boundary box must have its start point on routing grid: */
	pcb->m_BoundaryBox.m_Pos.x -= pcb->m_BoundaryBox.m_Pos.x % g_GridRoutingSize;
	pcb->m_BoundaryBox.m_Pos.y -= pcb->m_BoundaryBox.m_Pos.y % g_GridRoutingSize;
	/* The boundary box must have its end point on routing grid: */
	wxPoint end = pcb->m_BoundaryBox.GetEnd();
	end.x -= end.x % g_GridRoutingSize; end.x += g_GridRoutingSize;
	end.y -= end.y % g_GridRoutingSize; end.y += g_GridRoutingSize;
	pcb->m_BoundaryBox.SetEnd(end);

	Nrows = pcb->m_BoundaryBox.m_Size.y / g_GridRoutingSize ;
	Ncols = pcb->m_BoundaryBox.m_Size.x / g_GridRoutingSize ;
	/* get a small margin for memory allocation: */
	Ncols += 2; Nrows += 2;

	return TRUE;
}

	/*******************/
	/* class BOARDHEAD */
	/*******************/

BOARDHEAD::BOARDHEAD(void)
{
	m_BoardSide[0] = m_BoardSide[1] = NULL;
	m_DistSide[0] = m_DistSide[1] = NULL;
	m_DirSide[0] = m_DirSide[1] = NULL;
	m_InitBoardDone = FALSE;
	m_Layers = 2;
	m_Nrows = m_Ncols = 0;
	m_MemSize = 0;
}

BOARDHEAD::~BOARDHEAD(void)
{
}

/******************************/
int BOARDHEAD::InitBoard (void)
/*****************************/
 /* initialize the data structures
 	retourne la taille RAM utilisee, ou -1 si defaut
*/
{
int ii, kk;

	if (Nrows <= 0 || Ncols <= 0) return(0);
	m_Nrows = Nrows;
	m_Ncols = Ncols;

	m_InitBoardDone = TRUE; /* we have been called */

	ii = (Nrows+1) * (Ncols+1);

	for ( kk = 0; kk < m_Layers; kk++ )
		{
		m_BoardSide[kk] = NULL;
		m_DistSide[kk] = NULL;
		m_DirSide[kk] = NULL;

		/* allocate Board & initialize everything to empty */
		m_BoardSide[kk] = (BoardCell*)MyZMalloc( ii * sizeof (BoardCell) );
		if( m_BoardSide[kk] == NULL) return(-1);

		/***** allocate Distances *****/
		m_DistSide[kk] = (DistCell *)MyZMalloc( ii * sizeof(DistCell) );
		if (m_DistSide[kk] == NULL) return(-1);

		/***** allocate Dir (chars) *****/
		m_DirSide[kk] = (char *)MyZMalloc( ii );
		if (m_DirSide[kk] == NULL) return( -1 );
		}

	m_MemSize = m_Layers * ii * ( sizeof(BoardCell) + sizeof(DistCell) + sizeof(char) );

	return(m_MemSize);
}

/*********************************/
void BOARDHEAD::UnInitBoard(void)
/*********************************/
/* deallocation de la memoire */
{
int ii;

	m_InitBoardDone = FALSE;

	for ( ii = 0; ii < 2; ii++ )
	{
		/***** de-allocate Dir (chars) *****/
		if( m_DirSide[ii] )
		{
			MyFree(m_DirSide[ii]); m_DirSide[ii] = NULL;
		}

		/***** de-allocate Distances *****/
		if( m_DistSide[ii] )
		{
			MyFree(m_DistSide[ii]); m_DistSide[ii] = NULL;
		}

		/**** de-allocate Board *****/
		if( m_BoardSide[ii] )
		{
			MyFree(m_BoardSide[ii]); m_BoardSide[ii] = NULL;
		}
	}

	m_Nrows = m_Ncols = 0;
}



/*****************************************************/
void PlaceCells(BOARD * Pcb, int net_code, int flag)
/*****************************************************/
/* Initialise les cellules du board a la valeur HOLE et VIA_IMPOSSIBLE
	selon les marges d'isolement
	les elements de net_code = net_code ne seront pas places comme occupe
	mais en VIA_IMPOSSIBLE uniquement
	Pour Routage 1 seule face:
		le plan BOTTOM est utilise
		et Route_Layer_BOTTOM = Route_Layer_TOP

	Selon les bits = 1 du parametre flag:
		si FORCE_PADS : tous les pads seront places meme ceux de meme net_code
*/
{
int ii;
LISTE_PAD* ptr;
TRACK * pt_segm;
TEXTE_PCB * PtText;
DRAWSEGMENT * DrawSegm;
EDA_BaseStruct * PtStruct;
int ux0 = 0 , uy0 = 0, ux1, uy1, dx, dy;
int marge, via_marge;
int masque_layer;

	marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth /2);
	via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize /2);

	/////////////////////////////////////
	// Placement des PADS sur le board //
	/////////////////////////////////////
	ptr = (LISTE_PAD*)Pcb->m_Pads; ii = Pcb->m_NbPads;
	for( ; ii > 0 ; ii-- , ptr++)
		{
		if( (net_code != (*ptr)->m_NetCode ) || (flag & FORCE_PADS) )
			{
			Place_1_Pad_Board(Pcb, *ptr, HOLE, marge, WRITE_CELL);
			}
		Place_1_Pad_Board(Pcb, *ptr, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL);
		}

	///////////////////////////////////////////////
	// Placement des elements de modules sur PCB //
	///////////////////////////////////////////////
	PtStruct = Pcb->m_Modules;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		EDA_BaseStruct * PtModStruct = ((MODULE*)PtStruct)->m_Drawings;
		for( ;PtModStruct != NULL; PtModStruct = PtModStruct->Pnext )
			{
			switch( PtModStruct->m_StructType )
				{
				case TYPEEDGEMODULE:
					{
					TRACK * TmpSegm = new TRACK(NULL);
					TmpSegm->m_Layer = ((EDGE_MODULE *) PtModStruct)->m_Layer;
					if(TmpSegm->m_Layer == EDGE_N) TmpSegm->m_Layer = -1;

					TmpSegm->m_Start = ((EDGE_MODULE *) PtModStruct)->m_Start;
					TmpSegm->m_End = ((EDGE_MODULE *) PtModStruct)->m_End;
					TmpSegm->m_Shape = ((EDGE_MODULE *) PtModStruct)->m_Shape;
					TmpSegm->m_Width = ((EDGE_MODULE *) PtModStruct)->m_Width;
					TmpSegm->m_Param = ((EDGE_MODULE *) PtModStruct)->m_Angle;
					TmpSegm->m_NetCode = -1;

					TraceSegmentPcb(Pcb, TmpSegm, HOLE, marge,WRITE_CELL );
					TraceSegmentPcb(Pcb, TmpSegm, VIA_IMPOSSIBLE, via_marge,
									WRITE_OR_CELL );
					delete TmpSegm;
					break;
					}

				default: break;
				}
			}
		}

	////////////////////////////////////////////
	// Placement des contours et segments PCB //
	////////////////////////////////////////////
	PtStruct = Pcb->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		switch( PtStruct->m_StructType)
			{
			case TYPEDRAWSEGMENT:
				{
				int type_cell = HOLE;
				TRACK * TmpSegm = new TRACK(NULL);
				DrawSegm = (DRAWSEGMENT *) PtStruct;
				TmpSegm->m_Layer = DrawSegm->m_Layer;
				if(DrawSegm->m_Layer == EDGE_N)
					{
					TmpSegm->m_Layer = -1;
					type_cell |= CELL_is_EDGE;
					}

				TmpSegm->m_Start = DrawSegm->m_Start;
				TmpSegm->m_End = DrawSegm->m_End;
				TmpSegm->m_Shape = DrawSegm->m_Shape;
				TmpSegm->m_Width = DrawSegm->m_Width;
				TmpSegm->m_Param = DrawSegm->m_Angle;
				TmpSegm->m_NetCode = -1;

				TraceSegmentPcb(Pcb, TmpSegm, type_cell, marge,WRITE_CELL );
//				TraceSegmentPcb(Pcb, TmpSegm, VIA_IMPOSSIBLE, via_marge,WRITE_OR_CELL );
				delete TmpSegm;
				break;
				}

			case TYPETEXTE:
				PtText = (TEXTE_PCB*) PtStruct;
				if(PtText->GetLength() == 0 ) break;
				ux0 = PtText->m_Pos.x; uy0 = PtText->m_Pos.y;

				dx = PtText->Pitch()* PtText->GetLength();
				dy = PtText->m_Size.y + PtText->m_Width;

				/* Calcul du rectangle d'encadrement */
				dx /= 2; dy /= 2; /* dx et dy = demi dimensionx X et Y */
				ux1 = ux0 + dx; uy1 = uy0 + dy;
				ux0 -= dx; uy0 -= dy;

				masque_layer = g_TabOneLayerMask[PtText->m_Layer];

				TraceFilledRectangle(Pcb, ux0-marge, uy0-marge, ux1+marge, uy1+marge,
								(int)(PtText->m_Orient),
								masque_layer, HOLE, WRITE_CELL);
				TraceFilledRectangle(Pcb, ux0-via_marge, uy0-via_marge,
								ux1+via_marge, uy1+via_marge,
								(int)(PtText->m_Orient),
								masque_layer, VIA_IMPOSSIBLE, WRITE_OR_CELL);
				break;

			default: break;
			}
		}

	/* Placement des PISTES */
	pt_segm = Pcb->m_Track;
	for( ; pt_segm != NULL; pt_segm = (TRACK*) pt_segm->Pnext)
		{
		if(net_code == pt_segm->m_NetCode) continue;
		TraceSegmentPcb(Pcb, pt_segm, HOLE, marge, WRITE_CELL );
		TraceSegmentPcb(Pcb, pt_segm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
		}

	/* Placement des ZONES */
	pt_segm = (TRACK*) Pcb->m_Zone;
	for( ; pt_segm != NULL; pt_segm = (TRACK*) pt_segm->Pnext)
		{
		if(net_code == pt_segm->m_NetCode) continue;
		TraceSegmentPcb(Pcb, pt_segm, HOLE, marge, WRITE_CELL );
		TraceSegmentPcb(Pcb, pt_segm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
		}
}

/******************************************************/
int Build_Work(BOARD * Pcb, CHEVELU* pt_base_chevelu)
/*****************************************************/
 /* Build liste conn */
{
int ii;
CHEVELU* pt_rats = pt_base_chevelu;
D_PAD * pt_pad;
int r1,r2, c1,c2, current_net_code;
CHEVELU * pt_ch;
int demi_pas = g_GridRoutingSize /2;
wxString msg;
	
	InitWork(); /* clear work list */
	Ntotal = 0;
	for ( ii = Pcb->GetNumRatsnests(); ii > 0 ; ii-- , pt_rats++)
		{
		/* On ne route que les chevelus actifs et routables */
		if( (pt_rats->status & CH_ACTIF) == 0) continue;
		if( pt_rats->status & CH_UNROUTABLE) continue;
		if( (pt_rats->status & CH_ROUTE_REQ) == 0 ) continue;
		pt_pad = pt_rats->pad_start;

		current_net_code = pt_pad->m_NetCode;
		pt_ch = pt_rats;

		r1 = (pt_pad->m_Pos.y - Pcb->m_BoundaryBox.m_Pos.y + demi_pas ) / g_GridRoutingSize;
		if( r1 < 0 || r1 >= Nrows)
			{
			msg.Printf( wxT("erreur : row = %d ( padY %d pcbY %d) "), r1,
						pt_pad->m_Pos.y, Pcb->m_BoundaryBox.m_Pos.y);
			DisplayError(NULL, msg);
			return(0);
			}
		c1 = (pt_pad->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + demi_pas ) / g_GridRoutingSize;
		if( c1 < 0 || c1 >= Ncols)
			{
			msg.Printf( wxT("erreur : col = %d ( padX %d pcbX %d) "), c1,
						pt_pad->m_Pos.x, Pcb->m_BoundaryBox.m_Pos.x);
			DisplayError(NULL, msg);
			return(0);
			}

		pt_pad = pt_rats->pad_end;

		r2 = (pt_pad->m_Pos.y - Pcb->m_BoundaryBox.m_Pos.y + demi_pas ) / g_GridRoutingSize;
		if( r2 < 0 || r2 >= Nrows)
			{
			msg.Printf( wxT("erreur : row = %d ( padY %d pcbY %d) "), r2,
						pt_pad->m_Pos.y, Pcb->m_BoundaryBox.m_Pos.y);
			DisplayError(NULL, msg);
			return(0);
			}
		c2 = (pt_pad->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + demi_pas ) / g_GridRoutingSize;
		if( c2 < 0 || c2 >= Ncols)
			{
			msg.Printf( wxT("erreur : col = %d ( padX %d pcbX %d) "), c2,
						pt_pad->m_Pos.x, Pcb->m_BoundaryBox.m_Pos.x);
			DisplayError(NULL, msg);
			return(0);
			}

		SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 ); Ntotal++;
		}

	SortWork();
	return(Ntotal);
}



/*******************************************/
BoardCell GetCell(int row,int col,int side )
/*******************************************/
 /* fetch board cell :
*/
{
BoardCell *p;

	p = Board.m_BoardSide[side];
	return( p[row*Ncols +col] );
}


/************************************************/
/* void SetCell(int r,int c,int s,BoardCell x ) */
/************************************************/

/* store board cell */
void SetCell(int row,int col,int side,BoardCell x )
{
BoardCell *p;

	p = Board.m_BoardSide[side];
	p[row*Ncols+col] = x;
}


	/******************************************/
	/* void OrCell(int r,int c,int s,BoardCell x ) */
	/******************************************/

void OrCell(int r,int c,int s,BoardCell x )
{
BoardCell *p;

	p = Board.m_BoardSide[s];
	p[r*Ncols+c] |= x;
}

	/******************************************/
	/* void XorCell(int r,int c,int s,BoardCell x ) */
	/******************************************/

void XorCell(int r,int c,int s,BoardCell x )
{
BoardCell *p;

	p = Board.m_BoardSide[s];
	p[r*Ncols+c] ^= x;
}


	/************************************************/
	/* void AndCell(int r,int c,int s,BoardCell x ) */
	/************************************************/

void AndCell(int r,int c,int s,BoardCell x )
{
BoardCell *p;

	p = Board.m_BoardSide[s];
	p[r*Ncols+c] &= x;
}

	/************************************************/
	/* void AddCell(int r,int c,int s,BoardCell x ) */
	/************************************************/

void AddCell(int r,int c,int s,BoardCell x )
{
BoardCell *p;

	p = Board.m_BoardSide[s];
	p[r*Ncols+c] += x;
}



	/****************************************/
	/* DistCell GetDist(int r,int c,int s ) */
	/****************************************/

/* fetch distance cell */
DistCell GetDist(int r,int c,int s ) /* fetch distance cell */
{
DistCell *p;

	p = Board.m_DistSide[s];
	return( p[r*Ncols+c] );
}


	/***********************************************/
	/* void SetDist(int r,int c,int s,DistCell x ) */
	/***********************************************/

/* store distance cell */
void SetDist(int r,int c,int s,DistCell x )
{
DistCell *p;

	p = Board.m_DistSide[s];
	p[r*Ncols+c] = x;
}


	/**********************************/
	/* int GetDir(int r,int c,int s ) */
	/**********************************/

/* fetch direction cell */
int GetDir(int r,int c,int s )
{
char *p;

	p = Board.m_DirSide[s];
	return( (int)(p[r*Ncols+c]) );
}


	/*****************************************/
	/* void SetDir(int r,int c,int s,int x ) */
	/*****************************************/

/* store direction cell */

void SetDir(int r,int c,int s,int x )
{
char *p;

	p = Board.m_DirSide[s];
	p[r*Ncols+c] = (char)x;
}

