	/*******************************************/
	/* class_board.cpp - BOARD class functions */
	/*******************************************/
#include "fctsys.h"
#include "common.h"

#include "pcbnew.h"

#include "bitmaps.h"



	/*****************/
	/* Class BOARD: */
	/*****************/

/* Constructor */
BOARD::BOARD(EDA_BaseStruct * parent, WinEDA_BasePcbFrame * frame):
		EDA_BaseStruct(parent, TYPEPCB)
{
	m_PcbFrame = frame;
	m_Status_Pcb = 0;					// Mot d'etat: Bit 1 = Chevelu calcule
	m_NbNets = 0;					// Nombre de nets (equipotentielles)
	m_BoardSettings = &g_DesignSettings;
	m_NbPads = 0;					// nombre total de pads
	m_NbNodes = 0;					// nombre de pads connectes
	m_NbLinks = 0;					// nombre de chevelus (donc aussi nombre
									// minimal de pistes a tracer
	m_NbSegmTrack = 0;				// nombre d'elements de type segments de piste
	m_NbSegmZone = 0;				// nombre d'elements de type segments de zone
	m_NbNoconnect=0;				// nombre de chevelus actifs
	m_NbLoclinks = 0;				// nb ratsnest local

	m_Drawings = NULL;			// pointeur sur liste drawings
	m_Modules = NULL;				// pointeur sur liste zone modules
	m_Equipots = NULL;			// pointeur liste zone equipot
	m_Track = NULL;				// pointeur relatif zone piste
	m_Zone = NULL;				// pointeur tableau zone zones de cuivre
	m_Pads = NULL;				// pointeur liste d'acces aux pads
	m_Ratsnest = NULL;			// pointeur liste rats
	m_LocalRatsnest = NULL;		// pointeur liste rats local
	m_CurrentLimitZone = NULL;	// pointeur liste des EDEGE_ZONES
								// de determination des contours de zone
}

	/***************/
	/* Destructeur */
	/***************/
BOARD::~BOARD(void)
{
}


void BOARD::UnLink( void )
{
	/* Modification du chainage arriere */
	if( Pback )
		{
		if( Pback->m_StructType == TYPEPCB)
			{
			Pback->Pnext = Pnext;
			}

		else /* Le chainage arriere pointe sur la structure "Pere" */
			{
//			Pback-> = Pnext;
			}
		}

	/* Modification du chainage avant */
	if( Pnext) Pnext->Pback = Pback;

	Pnext = Pback = NULL;
}

/* Routines de calcul des nombres de segments pistes et zones */
int BOARD::GetNumSegmTrack(void)
{
TRACK * CurTrack = m_Track;
int ii = 0;

	for ( ;CurTrack != NULL; CurTrack = (TRACK*)CurTrack->Pnext ) ii++;
	m_NbSegmTrack = ii;
	return(ii);
}
int BOARD::GetNumSegmZone(void)
{
TRACK * CurTrack = m_Zone;
int ii = 0;

	for ( ;CurTrack != NULL; CurTrack = (TRACK*)CurTrack->Pnext ) ii++;
	m_NbSegmZone = ii;
	return(ii);
}


	// retourne le nombre de connexions manquantes
int BOARD::GetNumNoconnect(void)
{
	return(m_NbNoconnect);
}

	// retourne le nombre de chevelus
int BOARD::GetNumRatsnests(void)
{
	return(m_NbLinks);
}

	// retourne le nombre de pads a netcode > 0
int BOARD::GetNumNodes(void)
{
	return(m_NbNodes);
}


/***********************************/
bool BOARD::ComputeBoundaryBox(void)
/***********************************/

/* Determine le rectangle d'encadrement du pcb
	Ce rectangle englobe les contours pcb, pads , vias et piste
	Sortie:
	m_PcbBox

	retourne:
		0 si aucun element utile
		1 sinon
*/
{
int rayon, cx, cy, d, xmin, ymin, xmax, ymax;
bool Has_Items = FALSE;
EDA_BaseStruct * PtStruct;
DRAWSEGMENT* ptr;
TRACK * Track;

	xmin = ymin =  0x7FFFFFFFl ;
	xmax = ymax = -0x7FFFFFFFl ;

	/* Analyse des Contours PCB */
	PtStruct = m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
	{
		if( PtStruct->m_StructType != TYPEDRAWSEGMENT ) continue;
		ptr = (DRAWSEGMENT*) PtStruct;
		d = (ptr->m_Width /2) + 1;
		if(ptr->m_Shape == S_CIRCLE)
		{
			cx = ptr->m_Start.x; cy = ptr->m_Start.y;
			rayon = (int)hypot((double)(ptr->m_End.x-cx),(double)(ptr->m_End.y-cy) );
			rayon += d;
			xmin = min(xmin,cx-rayon);
			ymin = min(ymin,cy-rayon);
			xmax = max(xmax,cx+rayon);
			ymax = max(ymax,cy+rayon);
			Has_Items = TRUE;
		}
		else
		{
			cx = min(ptr->m_Start.x, ptr->m_End.x );
			cy = min(ptr->m_Start.y, ptr->m_End.y);
			xmin = min(xmin,cx - d);
			ymin = min(ymin,cy - d);
			cx = max(ptr->m_Start.x, ptr->m_End.x );
			cy = max(ptr->m_Start.y, ptr->m_End.y);
			xmax = max(xmax,cx + d);
			ymax = max(ymax,cy + d);
			Has_Items = TRUE;
		}
	}

	/* Analyse des Modules  */
	MODULE * module = m_Modules;
	for( ; module != NULL; module = (MODULE *) module->Pnext )
	{
		Has_Items = TRUE;
		xmin = min(xmin,(module->m_Pos.x + module->m_BoundaryBox.GetX()));
		ymin = min(ymin,(module->m_Pos.y + module->m_BoundaryBox.GetY()));
		xmax = max(xmax,module->m_Pos.x + module->m_BoundaryBox.GetRight());
		ymax = max(ymax,module->m_Pos.y + module->m_BoundaryBox.GetBottom());

		D_PAD * pt_pad = module->m_Pads;
		for ( ;pt_pad != NULL; pt_pad = (D_PAD*) pt_pad->Pnext )
		{
			d = pt_pad->m_Rayon;
			xmin = min(xmin,pt_pad->m_Pos.x - d);
			ymin = min(ymin,pt_pad->m_Pos.y - d);
			xmax = max(xmax,pt_pad->m_Pos.x + d);
			ymax = max(ymax,pt_pad->m_Pos.y + d);
		}
	}

	/* Analyse des segments de piste et zone*/
	for( Track = m_Track; Track != NULL; Track = (TRACK*) Track->Pnext)
	{
		d = (Track->m_Width /2) + 1;
		cx = min(Track->m_Start.x, Track->m_End.x );
		cy = min(Track->m_Start.y, Track->m_End.y);
		xmin = min(xmin,cx - d);
		ymin = min(ymin,cy - d);
		cx = max(Track->m_Start.x, Track->m_End.x );
		cy = max(Track->m_Start.y, Track->m_End.y);
		xmax = max(xmax,cx + d);
		ymax = max(ymax,cy + d);
		Has_Items = TRUE;
	}

	for( Track = m_Zone; Track != NULL; Track = (TRACK*) Track->Pnext)
	{
		d = (Track->m_Width /2) + 1;
		cx = min(Track->m_Start.x, Track->m_End.x );
		cy = min(Track->m_Start.y, Track->m_End.y);
		xmin = min(xmin,cx - d);
		ymin = min(ymin,cy - d);
		cx = max(Track->m_Start.x, Track->m_End.x );
		cy = max(Track->m_Start.y, Track->m_End.y);
		xmax = max(xmax,cx + d);
		ymax = max(ymax,cy + d);
		Has_Items = TRUE;
	}

	if ( ! Has_Items && m_PcbFrame )
	{
		if ( m_PcbFrame->m_Draw_Sheet_Ref )
		{
			xmin = ymin = 0;
			xmax = m_PcbFrame->m_CurrentScreen->ReturnPageSize().x;
			ymax = m_PcbFrame->m_CurrentScreen->ReturnPageSize().y;
		}
		else
		{
			xmin = - m_PcbFrame->m_CurrentScreen->ReturnPageSize().x/2;
			ymin = - m_PcbFrame->m_CurrentScreen->ReturnPageSize().y/2;
			xmax = m_PcbFrame->m_CurrentScreen->ReturnPageSize().x/2;
			ymax = m_PcbFrame->m_CurrentScreen->ReturnPageSize().y/2;
		}
	}

	m_BoundaryBox.SetX(xmin);
	m_BoundaryBox.SetY(ymin);
	m_BoundaryBox.SetWidth(xmax - xmin);
	m_BoundaryBox.SetHeight(ymax - ymin);

	return(Has_Items);
}

