		/*****************************/
		/* Localisation des elements */
		/*****************************/

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

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

#include "protos.h"


/* variables locales */
int ux0 , uy0 ,dx, dy, spot_cX, spot_cY;	/* Variables utilisees pour
							 la localisation des segments */
/* fonctions locales */
EDA_BaseStruct * Locate_MirePcb( EDA_BaseStruct * PtStruct, int typeloc);
/**/

/* Macro de calcul de la coord de pointage selon le curseur
(ON/OFF grille) choisi
A REVOIR
*/
#define SET_REF_POS(ref_pos)  if(typeloc == CURSEUR_ON_GRILLE) \
		{ ref_pos = ActiveScreen->m_Curseur;} \
	else { ref_pos = ActiveScreen->m_Curseur; }



/*************************************************************/
MODULE * ReturnModule(BOARD * pcb, const wxString & reference)
/*************************************************************/
/*
 Recherche d'un module par sa reference
	Retourne:
		un pointeur sur le module
		Null si pas localisé
*/
{
MODULE * Module = pcb->m_Modules;

	for(  ; Module != NULL ; Module = (MODULE *) Module->Pnext )
		{
		if( reference.CmpNoCase(Module->m_Reference->m_Text) == 0 )
			return Module;
		}
	return NULL;
}


/********************************************************/
D_PAD * ReturnPad(MODULE * module, const wxString & name)
/********************************************************/
/* Recherche d'un pad par son nom, pour le module Module
*/
{
D_PAD * pt_pad ;
wxString buf;

	if( module == NULL ) return NULL;

	pt_pad = module->m_Pads;

	for ( ; pt_pad != NULL; pt_pad = (D_PAD*)pt_pad->Pnext )
		{
		pt_pad->ReturnStringPadName(buf);
		if( buf.CmpNoCase(name) == 0 )
			return pt_pad;
		}
	return(NULL);
}




/*********************************************************/
EDA_BaseStruct * WinEDA_BasePcbFrame::Locate( int typeloc )
/*********************************************************/
/* Fonction de localisation generale
	Affiche les caract de la stucture localisée et retourne un pointeur
	sur celle-ci
*/
{
TEXTE_PCB * pt_texte_pcb;
TRACK * Track , * TrackLocate ;
DRAWSEGMENT * DrawSegm;
MODULE * module;
D_PAD* pt_pad;
int masque_layer;
EDA_BaseStruct * item;

	pt_texte_pcb = Locate_Texte_Pcb(m_Pcb->m_Drawings, typeloc);
	if(pt_texte_pcb ) // texte type PCB localise
		{
		Affiche_Infos_PCB_Texte(this, pt_texte_pcb);
		return pt_texte_pcb;
		}

	if ( (DrawSegm = Locate_Segment_Pcb(m_Pcb, typeloc)) != NULL)
		{
		Affiche_Infos_DrawSegment(this, DrawSegm);
		return DrawSegm;
		}

	if ( (item = Locate_Cotation(m_Pcb, typeloc)) != NULL) return item;

	if ( (item = Locate_MirePcb(m_Pcb->m_Drawings, typeloc)) != NULL) return item;

	/* Localistion des pistes et vias, avec priorite aux vias */
	masque_layer = g_TabOneLayerMask[GetScreen()->m_Active_Layer];
	Track = Locate_Pistes( m_Pcb->m_Track, NO_TST_LAYER,typeloc );
	if ( Track != NULL )
		{
		TrackLocate = Track ;	/* Reperage d'une piste ou via */
		/* recherche de 1 via eventuelle */
		while((TrackLocate = Locate_Pistes(TrackLocate,
							masque_layer,typeloc)) != NULL )
			{
			Track = TrackLocate;
			if(TrackLocate->m_StructType == TYPEVIA) break ;
			TrackLocate = (TRACK*) TrackLocate->Pnext;
			}
		Affiche_Infos_Piste(this, Track) ;
		return Track;
		}


	/* Localisation des Pads */
	if( (pt_pad = Locate_Any_Pad(m_Pcb, typeloc)) != NULL )
		{
		pt_pad->Display_Infos(this); return pt_pad;
		}

	/* Localisation d'un texte sur modules */
	module = NULL;
	{
	TEXTE_MODULE * pt_texte;
	pt_texte = LocateTexteModule(m_Pcb, &module, typeloc);
	if( pt_texte != NULL )
		{
		Affiche_Infos_E_Texte(this,  module, pt_texte);
		return pt_texte;
		}
	}

	/* Recherche d'un module */
	if ( (module = Locate_Prefered_Module(m_Pcb, typeloc)) != NULL)
		{
		module->Display_Infos(this);
		return module;
		}

	if( (TrackLocate = Locate_Zone((TRACK*)m_Pcb->m_Zone,
					GetScreen()->m_Active_Layer,typeloc)) != NULL )
		{
		Affiche_Infos_Piste(this, TrackLocate) ; return TrackLocate;
		}

	MsgPanel->EraseMsgBox();
	return NULL;
}


/*******************************************************************/
TRACK * Locate_Via(BOARD * Pcb, const wxPoint & pos, int layer = -1)
/*******************************************************************/

/* Localise une via au point pX,pY
	Si layer < 0 la via sera localisee quelle que soit la couche
	Si layer = 0 .. 15 la via sera localisee selon son type:
		- traversante : toutes couches
		- aveugle = entre couches utiles
		- borgnes idem
	Entree : coord du point de reference, couche
	Sortie: NULL si pas de via
			(TRACK*) adresse de la via
*/
{
TRACK * Track;

	for(Track = Pcb->m_Track; Track != NULL; Track = Track->Next())
	{
		if( Track->m_StructType != TYPEVIA) continue;
		if( Track->m_Start != pos) continue;
		if( Track->GetState(BUSY|DELETED) ) continue;
		if(layer < 0 ) return(Track);
		if ( ((SEGVIA *)Track)->IsViaOnLayer(layer) )
			return(Track);
	}
	return(NULL);
}


/********************************************************************/
D_PAD * Locate_Pad_Connecte(BOARD * Pcb, TRACK * ptr_piste, int extr)
/********************************************************************/
/* localisation de la pastille connectee au point de piste a tester
	entree : ptr_piste: pointeur sur le segment de piste
			extr = flag = START -> debut du segment a tester
						= END -> fin du segment a tester
	retourne:
		 un pointeur sur la description de la pastille si localisation
		 pointeur NULL si pastille non trouvee
*/
{
D_PAD * ptr_pad = NULL;
int masque_layer;
MODULE * module;
wxPoint ref_pos;

	masque_layer = g_TabOneLayerMask[ptr_piste->m_Layer];
	if( extr == START)
		{
		ref_pos = ptr_piste->m_Start;
		}
	else
		{
		ref_pos = ptr_piste->m_End;
		}
	module = Pcb->m_Modules;
	for(; module != NULL; module = (MODULE*) module->Pnext)
		{
		ptr_pad = Locate_Pads(module, ref_pos, masque_layer) ;
		if ( ptr_pad != NULL ) break ;
		}
	return(ptr_pad);
}



/****************************************************************/
EDGE_MODULE * Locate_Edge_Module(MODULE * module, int typeloc)
/****************************************************************/
/* Localisation de segments de contour du type edge MODULE
		Les contours sont de differents type:
		simple : succession de droites
		Arcs de cercles : on a alors debut arc, fin arc , centre
						si debut arc = fin arc : cercle complet

	Retourne:
		Pointeur sur le segment localise
		NULL si rien trouve
*/
{
EDGE_MODULE * edge_mod;
EDA_BaseStruct * PtStruct;
int uxf, uyf, type_trace;
int rayon, dist;
wxPoint ref_pos;	/* coord du point de localisation */
int StAngle, EndAngle, MouseAngle; /* pour localisation d'arcs,
									angle du point de debut, de fin et du point
									de reference */

	if ( ! module ) return NULL;

	SET_REF_POS(ref_pos);

	PtStruct = module->m_Drawings;
	for ( ;PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		if( PtStruct->m_StructType != TYPEEDGEMODULE ) continue;
		edge_mod = (EDGE_MODULE *) PtStruct;
		type_trace = edge_mod->m_Shape ;
		ux0 = edge_mod->m_Start.x; uy0 = edge_mod->m_Start.y;
		uxf = edge_mod->m_End.x; uyf = edge_mod->m_End.y;

		switch(type_trace)
			{
			case S_SEGMENT :
				/* recalcul des coordonnees avec ux0,uy0 = origine des coord. */
				spot_cX = ref_pos.x - ux0; spot_cY = ref_pos.y - uy0;
				dx = uxf - ux0 ; dy = uyf - uy0 ;
				/* detection : */
				if( distance(edge_mod->m_Width/2) ) return( edge_mod) ;
				break;

			case S_CIRCLE:
				rayon = (int)hypot((double)(uxf-ux0),(double)(uyf-uy0) );
				dist = (int)hypot((double)(ref_pos.x - ux0),(double)(ref_pos.y - uy0) );

				if(abs(rayon-dist) <= edge_mod->m_Width) return(edge_mod);
				break;

			case S_ARC:
				rayon = (int)hypot((double)(uxf-ux0),(double)(uyf-uy0) );
				dist = (int)hypot((double)(ref_pos.x - ux0),(double)(ref_pos.y - uy0) );

				if(abs(rayon-dist) > edge_mod->m_Width) break;

				/* pour un arc, controle complementaire */
				MouseAngle = (int) ArcTangente(ref_pos.y - uy0, ref_pos.x - ux0);
				StAngle = (int) ArcTangente(uyf - uy0, uxf - ux0);
				EndAngle = StAngle + edge_mod->m_Angle;

				if( EndAngle > 3600 )
					{
					StAngle -= 3600; EndAngle -= 3600;
					}

				if( (MouseAngle >= StAngle) && (MouseAngle <= EndAngle) )
					return(edge_mod);

				break;
			}
		}
	return(NULL) ;
}


/*********************************************************/
EDA_BaseStruct * Locate_Cotation(BOARD * Pcb, int typeloc)
/*********************************************************/
/* Localise un element de cotation, en priorite sur la couche active,
	et a defaut sur les autres couches
	retourne un pointeur sur l'element localise
	sinon returne NULL
*/
{
EDA_BaseStruct * PtStruct;
COTATION * Cotation;
TEXTE_PCB* pt_txt;
wxPoint ref_pos;
int ux0, uy0;

	SET_REF_POS(ref_pos);

	PtStruct = Pcb->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		if( PtStruct->m_StructType != TYPECOTATION ) continue;
		Cotation = (COTATION*) PtStruct;
		if( Cotation->m_Layer != ((PCB_SCREEN *)ActiveScreen)->m_Active_Layer ){};

		/* Localisation du texte ? */
		pt_txt = Cotation->m_Text;
		if( pt_txt )
			{
			if( pt_txt->Locate(wxPoint(spot_cX, spot_cY)) ) return(PtStruct);
			}

		/* Localisation des SEGMENTS ?) */
		ux0 = Cotation->Barre_ox ; uy0 = Cotation->Barre_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx =Cotation->Barre_fx - ux0 ; dy = Cotation->Barre_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->TraitG_ox ; uy0 = Cotation->TraitG_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->TraitG_fx - ux0 ; dy = Cotation->TraitG_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->TraitD_ox ; uy0 = Cotation->TraitD_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->TraitD_fx - ux0 ; dy = Cotation->TraitD_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->FlecheD1_ox ; uy0 = Cotation->FlecheD1_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->FlecheD1_fx - ux0 ; dy = Cotation->FlecheD1_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->FlecheD2_ox ; uy0 = Cotation->FlecheD2_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->FlecheD2_fx - ux0 ; dy = Cotation->FlecheD2_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->FlecheG1_ox ; uy0 = Cotation->FlecheG1_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->FlecheG1_fx - ux0 ; dy = Cotation->FlecheG1_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );

		ux0 = Cotation->FlecheG2_ox ; uy0 = Cotation->FlecheG2_oy;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = Cotation->FlecheG2_fx - ux0 ; dy = Cotation->FlecheG2_fy - uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( distance( Cotation->m_Width/2 )) return( PtStruct );
		}

	return(NULL);
}

/*********************************************************/
DRAWSEGMENT * Locate_Segment_Pcb(BOARD * Pcb, int typeloc)
/*********************************************************/
/* Localisation de segments de contour du type drawing
	Retourne:
		Pointeur sur DEBUT du segment localise
		NULL si rien trouve
	Le segment sur la couche active est détecté en priorite
*/
{
EDA_BaseStruct * PtStruct;
DRAWSEGMENT * pts, *locate_segm = NULL;
wxPoint ref_pos;
PCB_SCREEN *screen = (PCB_SCREEN *)ActiveScreen;
	
	SET_REF_POS(ref_pos);

	PtStruct = Pcb->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		if( PtStruct->m_StructType != TYPEDRAWSEGMENT ) continue;
		pts = ( DRAWSEGMENT * ) PtStruct;
		ux0 = pts->m_Start.x ; uy0 = pts->m_Start.y;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = pts->m_End.x - ux0 ; dy = pts->m_End.y - uy0 ;
		spot_cX = ref_pos.x - ux0; spot_cY = ref_pos.y - uy0 ;

		/* detection : */
		if( (pts->m_Shape == S_CIRCLE) || (pts->m_Shape == S_ARC) )
			{
			int rayon, dist, StAngle, EndAngle, MouseAngle;
			rayon = (int) hypot((double)(dx),(double)(dy) );
			dist = (int) hypot((double)(spot_cX),(double)(spot_cY) );
			if( abs(rayon-dist) <= (pts->m_Width/2) )
				{
				if(pts->m_Shape == S_CIRCLE)
					{
					if(pts->m_Layer == screen->m_Active_Layer)
						return( pts ) ;
					else if ( ! locate_segm ) locate_segm = pts;
					}
				/* pour un arc, controle complementaire */
				MouseAngle = (int) ArcTangente(spot_cY, spot_cX);
				StAngle = (int) ArcTangente(dy, dx);
				EndAngle = StAngle + pts->m_Angle;

				if( EndAngle > 3600 )
					{
					StAngle -= 3600; EndAngle -= 3600;
					}
				if( (MouseAngle >= StAngle) && (MouseAngle <= EndAngle) )
					{
					if(pts->m_Layer == screen->m_Active_Layer)
						return( pts ) ;
					else if ( ! locate_segm ) locate_segm = pts;
					}
				}
			}

		else
			{
			if( distance( pts->m_Width /2 ) )
				{
				if(pts->m_Layer == screen->m_Active_Layer)
					return( pts ) ;
				else if ( ! locate_segm ) locate_segm = pts;
				}
			}
		}
	return(locate_segm) ;
}


	/*************************************************/
	/*		D_PAD * Locate_Any_Pad(int typeloc, bool OnlyCurrentLayer)	*/
	/* D_PAD* Locate_Any_Pad(int ref_pos, bool OnlyCurrentLayer) */
	/*************************************************/

/*
localisation de la pastille pointee par la coordonnee ref_pos.x,,ref_pos.y, ou
par la souris,  recherche faite sur toutes les empreintes.
	entree :
		- coord souris 
		 ou ref_pos
	retourne:
		 pointeur sur la description de la pastille si localisation
		 pointeur NULL si pastille non trouvee
		 num_empr = numero d'empreinte du pad

	la priorité est donnée a la couche active
*/

D_PAD * Locate_Any_Pad(BOARD * Pcb, int typeloc, bool OnlyCurrentLayer)
{
wxPoint ref_pos;

	SET_REF_POS(ref_pos);
	return(Locate_Any_Pad(Pcb, ref_pos, OnlyCurrentLayer)) ;
}

D_PAD * Locate_Any_Pad(BOARD * Pcb, const wxPoint & ref_pos, bool OnlyCurrentLayer)
{
D_PAD * pt_pad ;
MODULE * module;
int layer_mask = g_TabOneLayerMask[ ((PCB_SCREEN*)ActiveScreen)->m_Active_Layer];
	module = Pcb->m_Modules;
	for( ; module != NULL ; module = (MODULE *) module->Pnext )
	{
		/* First: Search a pad on the active layer: */
		 if ( (pt_pad = Locate_Pads(module, ref_pos,layer_mask) ) != NULL )
								 return(pt_pad) ;

		 /* If not found, search on other layers: */
		if ( ! OnlyCurrentLayer )
		{
			if ( (pt_pad = Locate_Pads(module, ref_pos,ALL_LAYERS) ) != NULL )
								 return(pt_pad) ;
		}
	}
	return(NULL) ;
}


/******************************************************************************/
/* D_PAD* Locate_Pads(MODULE * module, int masque_layer,int typeloc)		  */
/* D_PAD* Locate_Pads(MODULE * module, const wxPoint & ref_pos,int masque_layer) */
/******************************************************************************/

/* localisation de la pastille pointee par la coordonnee ref_pos.x,,ref_pos.y, ou
par la souris,  concernant l'empreinte  en cours.
	entree :
		- parametres generaux de l'empreinte mise a jour par caract()
		- masque_layer = couche(s) (bit_masque)sur laquelle doit etre la pastille
	retourne:
		 un pointeur sur la description de la pastille si localisation
		 pointeur NULL si pastille non trouvee
*/

D_PAD * Locate_Pads(MODULE * module, int masque_layer,int typeloc)
{
wxPoint ref_pos;

	SET_REF_POS(ref_pos);
	return(Locate_Pads(module, ref_pos, masque_layer) );
}


D_PAD * Locate_Pads(MODULE * module, const wxPoint & ref_pos, int masque_layer)
{
D_PAD * pt_pad ;
int deltaX, deltaY;
wxPoint shape_pos;
double dist;
	
	pt_pad = module->m_Pads;
	for ( ; pt_pad != NULL; pt_pad = (D_PAD*)pt_pad->Pnext )
	{
        shape_pos = pt_pad->ReturnShapePos();
		ux0 = shape_pos.x; uy0 = shape_pos.y; /* pos x,y du centre du pad */

		deltaX = ref_pos.x - ux0; deltaY = ref_pos.y - uy0;

		/* Test rapide: le point a tester doit etre a l'interieur du cercle
		exinscrit ... */
		if ( (abs(deltaX) > pt_pad->m_Rayon ) ||
			 (abs(deltaY) > pt_pad->m_Rayon) )
			continue;

		/* ... et sur la bonne couche */
		if( (pt_pad->m_Masque_Layer & masque_layer) == 0) continue ;

		/* calcul des demi dim  dx et dy */
		dx = pt_pad->m_Size.x >> 1;	// dx also is the radius for rounded pads
		dy = pt_pad->m_Size.y >> 1;

		/* localisation ? */
		switch (pt_pad->m_PadShape & 0x7F)
		{
			case CIRCLE :
				dist = hypot(deltaX, deltaY);
				if ( (int)(round(dist)) <= dx ) return(pt_pad) ;
				break;
			
			default:
				/* calcul des coord du point test  dans le repere du Pad */
				RotatePoint(&deltaX, &deltaY, - pt_pad->m_Orient);
				if ( (abs(deltaX) <= dx ) && (abs(deltaY) <= dy) )
					return(pt_pad) ;
				break;
		}
	}
	return(NULL);
}


/********************************************************/
MODULE * Locate_Prefered_Module(BOARD * Pcb, int typeloc)
/********************************************************/
/*
 localisation d'une empreinte par son rectangle d'encadrement
	Si plusieurs empreintes sont possibles, la priorite est:
		- sur la couche active
		- la plus petite
*/
{
MODULE * pt_module;
int lx , ly;			/* dimensions du rectangle d'encadrement du module */
MODULE * module = NULL, /* module localise sur la couche active */
	* Altmodule = NULL; /* module localise sur les couches non actives */
int min_dim = 0x7FFFFFFF,	/* dim mini du module localise sur la couche active */
	alt_min_dim = 0x7FFFFFFF; /* dim mini du module localise sur les couches non actives */
int layer;				/* pour calcul de couches prioritaires */
wxPoint ref_pos;		/* coord du point de reference pour la localisation */

	SET_REF_POS(ref_pos);
	pt_module = Pcb->m_Modules;
	for(  ; pt_module != NULL ; pt_module = (MODULE *) pt_module->Pnext )
		{
		/* calcul des dimensions du cadre :*/
		lx = pt_module->m_BoundaryBox.GetWidth();
		ly = pt_module->m_BoundaryBox.GetHeight();

		/* Calcul des coord souris dans le repere module */
		spot_cX = ref_pos.x - pt_module->m_Pos.x;
		spot_cY = ref_pos.y - pt_module->m_Pos.y;
		RotatePoint(&spot_cX, &spot_cY, - pt_module->m_Orient);

		/* la souris est-elle dans ce rectangle : */
		if( ! pt_module->m_BoundaryBox.Inside(spot_cX, spot_cY) )
			continue;

		/* Localisation: test des dimensions minimales, choix du meilleur candidat */

		/* calcul de priorite: la priorite est donnee a la couche
			d'appartenance du module et a la couche cuivre si le module
			est sur couche serigr,adhesive cuivre, a la couche cmp si le module
			est sur couche serigr,adhesive composant */
		layer = pt_module->m_Layer;
		if( (layer == ADHESIVE_N_CU) || (layer == SILKSCREEN_N_CU) )
			layer = CUIVRE_N;
		if( (layer == ADHESIVE_N_CMP) || (layer == SILKSCREEN_N_CMP) )
			layer = CMP_N;

		if( ((PCB_SCREEN*)ActiveScreen)->m_Active_Layer == layer )
			{
			if( min(lx,ly) <= min_dim )
				{ /* meilleure empreinte localisee sur couche active */
				module = pt_module ; min_dim = min(lx,ly) ;
				}
			}

		else
			{
			if( min(lx,ly) <= alt_min_dim )
				{	/* meilleure empreinte localisee sur autres couches */
				Altmodule = pt_module ; alt_min_dim = min(lx,ly) ;
				}
			}
		}	/* fin boucle d'examen des modules */

	if(module)
		{
		return(module);
		}
	if(Altmodule)
		{
		return(Altmodule);
		}
	return(NULL);
}

/*****************************************************************************/
TEXTE_MODULE * LocateTexteModule(BOARD * Pcb, MODULE ** PtModule, int typeloc)
/*****************************************************************************/
/* localisation du texte pointe par la souris (texte sur empreinte)

	si * PtModule == NULL; recherche sur tous les modules
	sinon sur le module pointe par module

	retourne
	- pointeur sur le texte localise ( ou NULL )
	- si Ptmodule != NULL: pointeur sur module module ( non modifie sinon )
*/
{
EDA_BaseStruct * PtStruct;
TEXTE_MODULE * pt_txt_mod ;
MODULE * module;
wxPoint ref_pos;

	SET_REF_POS(ref_pos);

	module = * PtModule;
	if( module == NULL )
		{
		module = Pcb->m_Modules;
		}

	for( ; module != NULL; module = (MODULE*)module->Pnext )
		{
		 pt_txt_mod = module->m_Reference;
		/* la souris est-elle dans le rectangle autour du texte*/
		if( pt_txt_mod->Locate(ref_pos) )
			{
			if( PtModule) *PtModule = module;
			return(pt_txt_mod);
			}
		pt_txt_mod = module->m_Value;
		/* la souris est-elle dans le rectangle autour du texte*/
		if( pt_txt_mod->Locate(ref_pos) )
			{
			if( PtModule) *PtModule = module;
			return(pt_txt_mod);
			}

		PtStruct = module->m_Drawings;
		for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
			{
			if( PtStruct->m_StructType != TYPETEXTEMODULE ) continue;
			pt_txt_mod = (TEXTE_MODULE*) PtStruct;
			/* la souris est-elle dans le rectangle autour du texte*/
			if( pt_txt_mod->Locate(ref_pos) )
				{
				if( PtModule) *PtModule = module;
				return(pt_txt_mod);
				}
			}
		if( *PtModule != NULL ) break; /* Recherche limitee a 1 seul module */
		}
	return(NULL) ;
}


/**************************************************************/
TRACK * Locate_Piste_Connectee( TRACK * PtRefSegm, TRACK * pt_base,
								TRACK * pt_lim, int extr)
/**************************************************************/
/* recherche le segment connecte au segment pointe par
	PtRefSegm:
	si int = START, le point de debut du segment est utilise
	si int = END, le point de fin du segment est utilise
	La recherche ne se fait que sur les EXTREMITES des segments

	La recherche se fait de l'adresse :
		pt_base a pt_lim (borne finale comprise)
		si pt_lim = NULL, la recherche se fait jusqu'a la fin de la liste
	Afin d'accelerer la recherche, une 1ere passe est faite, avec une recherche
	realisee sur un ensemble de +/- 100 points autour du point courant.
	Si echec: recherche generale
*/
{
TRACK * PtSegmB, * PtSegmN;
int x, y , Reflayer;
int ii;

	if ( extr == START)
		{
		x = PtRefSegm->m_Start.x; y = PtRefSegm->m_Start.y;
		}
	else
		{
		x = PtRefSegm->m_End.x; y = PtRefSegm->m_End.y;
		}

	Reflayer = PtRefSegm->ReturnMaskLayer();

	/* 1ere passe */
	PtSegmB = PtSegmN = PtRefSegm;

	for ( ii = 0; ii < 50; ii++ )
		{
		if( (PtSegmN == NULL) && (PtSegmB == NULL) ) break;
		if( PtSegmN )
			{
			if( PtSegmN->GetState(BUSY|DELETED) ) goto suite;
			if (PtSegmN == PtRefSegm) goto suite;
			if( (x == PtSegmN->m_Start.x ) && (y == PtSegmN->m_Start.y) )
				{	/* Test des couches */
				if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
				}

			if( (x == PtSegmN->m_End.x ) && (y == PtSegmN->m_End.y) )
				{	/* Test des couches */
				if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
				}
			suite:
			if( PtSegmN == pt_lim ) PtSegmN = NULL;
			else PtSegmN = (TRACK*)PtSegmN->Pnext;
			}

		if( PtSegmB )
			{
			if(PtSegmB->GetState(BUSY|DELETED) ) goto suite1;
			if (PtSegmB == PtRefSegm) goto suite1;
			if( (x == PtSegmB->m_Start.x ) && (y == PtSegmB->m_Start.y) )
				{	/* Test des couches */
				if(Reflayer & PtSegmB->ReturnMaskLayer() )return(PtSegmB);
				}

			if( (x == PtSegmB->m_End.x ) && (y == PtSegmB->m_End.y) )
				{	/* Test des couches */
				if(Reflayer & PtSegmB->ReturnMaskLayer() )return(PtSegmB);
				}
			suite1:
			if( PtSegmB == pt_base ) PtSegmB = NULL;
			else if( PtSegmB->m_StructType != TYPEPCB) PtSegmB = (TRACK*)PtSegmB->Pback;
			else PtSegmB = NULL;
			}
		}

	/* Recherche generale */
	for ( PtSegmN = pt_base; PtSegmN != NULL; PtSegmN = (TRACK*) PtSegmN->Pnext )
		{
		if(PtSegmN->GetState(DELETED|BUSY))
			{
			if (PtSegmN == pt_lim ) break;
			continue;
			}
		if (PtSegmN == PtRefSegm)
			{
			if (PtSegmN == pt_lim ) break;
			continue;
			}

		if( (x == PtSegmN->m_Start.x ) && (y == PtSegmN->m_Start.y) )
			{	/* Test des couches */
			if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
			}

		if( (x == PtSegmN->m_End.x ) && (y == PtSegmN->m_End.y) )
			{	/* Test des couches */
			if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
			}
		if (PtSegmN == pt_lim ) break;
		}
	return (NULL);
}

/****************************************************************************/
/* TRACK *Locate_Pistes(TRACK * start_adresse, int MasqueLayer,int typeloc)	*/
/* TRACK *Locate_Pistes(TRACK * start_adresse, int ref_pos.x, int ref_pos.y,*/
/*										int MasqueLayer)					*/
/****************************************************************************/

/*
1 -  routine de localisation du segment de piste pointe par la souris.
2 -  routine de localisation du segment de piste pointe par le point
			ref_pos.x , ref_pos.y.r

	La recherche commence a l'adresse start_adresse
*/

TRACK * Locate_Pistes(TRACK * start_adresse,int MasqueLayer, int typeloc )
{
wxPoint ref_pos;

	SET_REF_POS(ref_pos);

	return( Locate_Pistes(start_adresse, ref_pos,MasqueLayer) );
}


TRACK * Locate_Pistes(TRACK * start_adresse, const wxPoint & ref_pos,int MasqueLayer)
{
TRACK * Track;		/* pointeur sur les pistes */
int l_piste ;					/* demi-largeur de la piste */

	for( Track = start_adresse; Track != NULL; Track = (TRACK*) Track->Pnext)
	{
		if( Track->GetState(BUSY|DELETED) ) continue;
		if ( (g_DesignSettings.m_LayerColor[Track->m_Layer] & ITEM_NOT_SHOW) )
			continue;
		/* calcul des coordonnees du segment teste */
		l_piste = Track->m_Width >> 1;  /* l_piste = demi largeur piste */
		ux0 = Track->m_Start.x ; uy0 = Track->m_Start.y ; /* coord de depart */
		dx =  Track->m_End.x ; dy =  Track->m_End.y ; /* coord d'arrivee */

		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx -= ux0 ; dy -= uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		if ( Track->m_StructType == TYPEVIA ) /* VIA rencontree */
		{
			if ((abs(spot_cX) <= l_piste ) && (abs(spot_cY) <=l_piste))
			{
				return(Track) ;
			}
			continue ;
		}

		if(MasqueLayer != -1)
			if( (g_TabOneLayerMask[Track->m_Layer] & MasqueLayer) == 0)
				continue;	/* Segments sur couches differentes */
		if( distance(l_piste) ) return(Track) ;
	}
	return(NULL) ;
}

	/****************************************************************/
	/* TRACK *  Locate_Zone(TRACK * start_adresse, int layer,	 */
	/*											int typeloc)		*/
	/* TRACK *  Locate_Zone(TRACK * start_adresse,				*/
	/*										const wxPoint & ref_pos, */
	/*										int layer)				*/
	/****************************************************************/

/*
1 -  routine de localisation du segment de zone pointe par la souris.
2 -  routine de localisation du segment de zone pointe par le point
			ref_pos.x , ref_pos.y.r

	Si layer == -1 , le tst de la couche n'est pas fait

	La recherche commence a l'adresse start_adresse
*/

TRACK * Locate_Zone(TRACK * start_adresse,int layer, int typeloc )
{
wxPoint ref_pos;

	SET_REF_POS(ref_pos);

	return( Locate_Zone(start_adresse, ref_pos, layer) );
}


TRACK * Locate_Zone(TRACK * start_adresse, const wxPoint & ref_pos, int layer)
{
TRACK * Zone;		/* pointeur sur les pistes */
int l_segm ;					/* demi-largeur de la piste */

	for( Zone = start_adresse; Zone != NULL; Zone = (TRACK *) Zone->Pnext)
		{
		/* calcul des coordonnees du segment teste */
		l_segm = Zone->m_Width >> 1;  /* l_piste = demi largeur piste */
		ux0 = Zone->m_Start.x ; uy0 = Zone->m_Start.y ; /* coord de depart */
		dx =  Zone->m_End.x ; dy =  Zone->m_End.y ; /* coord d'arrivee */

		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx -= ux0 ; dy -= uy0 ;
		spot_cX = ref_pos.x - ux0 ; spot_cY = ref_pos.y - uy0 ;

		if((layer != -1) && (Zone->m_Layer != layer)) continue;
		if( distance(l_segm) ) return(Zone) ;
		}
	return(NULL) ;
}



/*******************************************************************/
TEXTE_PCB * Locate_Texte_Pcb(EDA_BaseStruct * PtStruct, int typeloc)
/*******************************************************************/
/* localisation des inscriptions sur le Pcb:
	entree : EDA_BaseStruct pointeur sur le debut de la zone de recherche
	retour : pointeur sur la description du texte localise
*/
{
wxPoint ref;

	SET_REF_POS(ref);
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		if( PtStruct->m_StructType != TYPETEXTE ) continue;
		TEXTE_PCB * pt_txt_pcb = (TEXTE_PCB *) PtStruct;
		if( pt_txt_pcb->Locate(ref) ) return pt_txt_pcb;
		}
	return(NULL) ;
}



	/*****************************/
	/* int distance(int seuil) */
	/*****************************/

/*
 Calcul de la distance du curseur souris a un segment de droite :
 ( piste, edge, contour module ..
	retourne:
		0 si distance > seuil
		1 si distance <= seuil
	Variables utilisees ( doivent etre initialisees avant appel , et
	sont ramenees au repere centre sur l'origine du segment)
		dx, dy = coord de l'extremite segment.
		spot_cX,spot_cY = coord du curseur souris
	la recherche se fait selon 4 cas:
		segment horizontal
		segment vertical
		segment 45
		segment quelconque
*/

int distance(int seuil)
{
int  cXrot, cYrot ,		/* coord du point (souris) dans le repere tourne */
	 segX, segY;		/* coord extremite segment tj >= 0 */
int pointX, pointY;	/* coord point a tester dans repere modifie dans lequel
	 					segX et segY sont >=0 */

	segX = dx ; segY = dy; pointX = spot_cX ; pointY = spot_cY ;

	/*Recalcul coord pour que le segment soit dans 1er quadrant (coord >= 0)*/
	if (segX < 0)	/* mise en >0 par symetrie par rapport a l'axe Y */
		{
		segX = -segX ; pointX = - pointX ;
		}
	if (segY < 0)	/* mise en > 0 par symetrie par rapport a l'axe X */
		{
		segY = -segY ; pointY = -pointY ;
		}


	if ( segY == 0 ) /* piste Horizontale */
		{
		if(abs(pointY) <= seuil )
			{
			if((pointX >= 0) && (pointX <= segX) ) return(1);
			/* Etude des extremites : cercle de rayon seuil */
			if( (pointX < 0) && (pointX >= -seuil) )
				{
				if( ((pointX * pointX) + (pointY*pointY)) <= (seuil*seuil) )
					return(1);
				}
			if( (pointX > segX) && (pointX <= (segX+seuil)) )
				{
				if( (((pointX-segX) * (pointX-segX)) + (pointY*pointY)) <= (seuil*seuil) )
					return(1);
				}
			}
		}

	else if ( segX == 0 ) /* piste verticale */
		{
		if( abs(pointX) <= seuil)
			{
			if((pointY >= 0 ) && (pointY <= segY) ) return(1);
			if( (pointY < 0) && (pointY >= -seuil) )
				{
				if( ((pointY * pointY) + (pointX*pointX)) <= (seuil*seuil) )
					return(1);
				}
			if( (pointY > segY) && (pointY <= (segY+seuil)) )
				{
				if( ( ((pointY-segY) * (pointY-segY)) + (pointX*pointX)) <= (seuil*seuil) )
					return(1);
				}
			}
		}

	else if ( segX == segY )	/* piste a 45 degre */
		{
		/* on fait tourner les axes de 45 degre. la souris a alors les
		coord : x1 = x*cos45 + y*sin45
				y1 = y*cos45 - x*sin45
		et le segment de piste est alors horizontal.
		recalcul des coord de la souris ( sin45 = cos45 = .707 = 7/10
		remarque : sin ou cos45 = .707, et lors du recalcul des coord
		dx45 et dy45, lec coeff .707 est neglige, dx et dy sont en fait .707 fois
		trop grands. (c.a.d trop petits)
		spot_cX,Y doit etre * par .707 * .707 = 0.5 */

		cXrot = (pointX + pointY) >> 1 ;
		cYrot = (pointY - pointX) >> 1 ;

		/* recalcul des coord de l'extremite du segment , qui sera vertical
		suite a l'orientation des axes sur l'ecran : dx45 = pointX (ou pointY)
		et est en fait 1,414 plus grand , et dy45 = 0 */

		// seuil doit etre * .707 pour tenir compte du coeff de reduction sur dx,dy
		seuil *= 7 ; seuil /= 10 ;
		if ( abs(cYrot) <= seuil) /* ok sur axe vertical) */
			{
			if ((cXrot >= 0) && (cXrot <= segX) ) return(1) ;

			/* Etude des extremites : cercle de rayon seuil */
			if( (cXrot < 0) && (cXrot >= -seuil) )
				{
				if( ((cXrot * cXrot) + (cYrot*cYrot)) <= (seuil*seuil) )
					return(1);
				}
			if( (cXrot > segX) && (cXrot <= (segX+seuil)) )
				{
				if( (((cXrot-segX) * (cXrot-segX)) + (cYrot*cYrot)) <= (seuil*seuil) )
					return(1);
				}
			}
		}
	else	/* orientation quelconque */
		{
		/* On fait un changement d'axe (rotation) de facon a ce que le segment
		de piste soit horizontal dans le nouveau repere */
		int angle;

		angle = (int)( atan2((float)segY, (float)segX) * 1800 / M_PI) ;
		cXrot = pointX;	cYrot = pointY;
		RotatePoint(&cXrot, &cYrot, angle);	/* Rotation du point a tester */
		RotatePoint(&segX, &segY, angle) ;	/* Rotation du segment */

		/*la piste est Horizontale , par suite des modifs de coordonnes
		et d'axe, donc segX = longueur du segment */

		if ( abs(cYrot) <= seuil ) /* ok sur axe vertical) */
			{
			if ((cXrot >= 0) && (cXrot <= segX) ) return(1) ;
			/* Etude des extremites : cercle de rayon seuil */
			if( (cXrot < 0) && (cXrot >= -seuil) )
				{
				if( ((cXrot * cXrot) + (cYrot*cYrot)) <= (seuil*seuil) )
					return(1);
				}
			if( (cXrot > segX) && (cXrot <= (segX+seuil)) )
				{
				if( (((cXrot-segX) * (cXrot-segX)) + (cYrot*cYrot)) <= (seuil*seuil) )
					return(1);
				}
			}
		}
	return(0) ;
}

/*******************************************************************************/
D_PAD * Fast_Locate_Pad_Connecte(BOARD * Pcb, const wxPoint & ref_pos, int masque_layer)
/*******************************************************************************/
/* Routine cherchant le pad de centre px,py,
	sur la couche indiquee par masque_layer (bit a bit)
	( extremite de piste )
	La liste des pads doit deja exister.

	retourne :
		NULL si pas de pad localise.
		pointeur sur la structure descr_pad correspondante si pad trouve
		(bonne position ET bonne couche).
*/
{
D_PAD * pad;
LISTE_PAD * ptr_pad , * lim;

	lim = (LISTE_PAD*)Pcb->m_Pads + Pcb->m_NbPads;
	for (ptr_pad = (LISTE_PAD*)Pcb->m_Pads; ptr_pad < lim ; ptr_pad++)
		{
		pad = * ptr_pad;
		if( pad->m_Pos != ref_pos ) continue ;

		/* Pad peut-etre trouve ici : il doit etre sur la bonne couche */
		if (pad->m_Masque_Layer & masque_layer) return(pad) ;

		}
	return(NULL);
}


/***********************************************************************************/
TRACK * Fast_Locate_Piste(TRACK *start_adr, TRACK* end_adr,
								const wxPoint & ref_pos, int MaskLayer)
/***********************************************************************************/
/* Localiste le segment dont une extremite coincide avec le point x,y
	sur les couches donnees par masklayer
	la recherche se fait de l'adresse start_adr a end_adr
	si end_adr = NULL, recherche jusqu'a la fin de la liste
	Les segments de piste marques avec le flag DELETED ne sont pas
	pris en compte
*/
{
TRACK * PtSegm;

	if( start_adr == NULL ) return(NULL);
	for ( PtSegm = start_adr; PtSegm != NULL; PtSegm = (TRACK*) PtSegm->Pnext )
		{
		if( PtSegm->GetState(DELETED|BUSY) == 0)
			{
			if( ref_pos == PtSegm->m_Start )
				{	/* Test des couches */
				if(MaskLayer & PtSegm->ReturnMaskLayer() ) return(PtSegm);
				}

			if( ref_pos == PtSegm->m_End )
				{	/* Test des couches */
				if(MaskLayer & PtSegm->ReturnMaskLayer() ) return(PtSegm);
				}
			}
		if( PtSegm == end_adr) break;
		}
	return (NULL);
}

/*******************************************************************/
TRACK * Fast_Locate_Via(TRACK *start_adr, TRACK* end_adr,
								const wxPoint & pos, int MaskLayer)
/*******************************************************************/

/* Localise la via de centre le point x,y , sur les couches donnees
	par masklayer
	la recherche se fait de l'adresse start_adr a end_adr.
	si end_adr = NULL, recherche jusqu'a la fin de la liste
	les vias dont le parametre State a le bit DELETED ou BUSY = 1 sont ignorees
*/
{
TRACK * PtSegm;

	for ( PtSegm = start_adr; PtSegm != NULL; PtSegm = (TRACK*)PtSegm->Pnext )
		{
		if(PtSegm->m_StructType == TYPEVIA)
			{
			if( pos == PtSegm->m_Start )
				{
				if( PtSegm->GetState(BUSY|DELETED) == 0)
					{/* Test des couches */
					if( MaskLayer & PtSegm->ReturnMaskLayer() )return(PtSegm);
					}
				}
			}
		if( PtSegm == end_adr ) break;
		}
	return (NULL);
}


/***********************************************************************/
EDA_BaseStruct * Locate_MirePcb( EDA_BaseStruct * PtStruct, int typeloc)
/***********************************************************************/
/* Routine d'initialisation du deplacement d'une mire
*/
{
wxPoint ref_pos;	/* coord du point de localisation */
int dX, dY, rayon;

	if(PtStruct == NULL ) return(NULL);

	SET_REF_POS(ref_pos);

	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext)
	{
		if( PtStruct->m_StructType != TYPEMIRE ) continue;
		dX = ref_pos.x - ((MIREPCB*) PtStruct)->m_Pos.x;
		dY = ref_pos.y - ((MIREPCB*) PtStruct)->m_Pos.y;
		rayon = ((MIREPCB*) PtStruct)->m_Size / 2;
		if( (abs(dX) <= rayon ) && ( abs(dY) <= rayon ) )
			break; 	/* Mire Localisee */
	}
	return(PtStruct);
}

