		/***************************************************/
		/* Localisation des elements pointes par la souris */
		/***************************************************/

#include "fctsys.h"

#include "common.h"
#include "gerbview.h"
#include "trigo.h"

#include "protos.h"


/* variables locales */
int ux0 , uy0 ,dx, dy, spot_cX, spot_cY;	/* Variables utilisees pour
							 la localisation des segments */
/* fonctions locales */
static TRACK * Locate_Zone(TRACK * start_adresse,int layer, int typeloc );
static TRACK * Locate_Zone(TRACK * start_adresse, wxPoint ref, int layer);
static TRACK * Locate_Pistes(TRACK * start_adresse,int Layer, int typeloc );
static TRACK * Locate_Pistes(TRACK * start_adresse, wxPoint ref,int Layer);
static DRAWSEGMENT * Locate_Segment_Pcb(BOARD * Pcb, int typeloc);
static TEXTE_PCB * Locate_Texte_Pcb(TEXTE_PCB* pt_txt_pcb, int typeloc);
static int distance(int seuil);
/**/

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




/*************************************************************/
EDA_BaseStruct * WinEDA_GerberFrame::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;
int layer;

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

	pt_texte_pcb = Locate_Texte_Pcb((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)
		{
		return DrawSegm;
		}

	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;
}



/********************************************************/
DRAWSEGMENT * Locate_Segment_Pcb(BOARD * Pcb, int typeloc)
/********************************************************/
/* Localisation de segments de contour du type edge pcb ou draw
	(selon couche active)
	Retourne:
		Pointeur sur DEBUT du segment localise
		NULL si rien trouve
*/
{
EDA_BaseStruct * PtStruct;
DRAWSEGMENT * pts;
wxPoint ref;
PCB_SCREEN * screen = (PCB_SCREEN *) ActiveScreen;
	SET_REF_POS(ref);

	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.x - ux0; spot_cY = ref.y - uy0 ;

		/* detection : */
		if(pts->m_Layer != screen->m_Active_Layer) continue;

		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) return(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) )
					return(pts);
				}
			}

		else
			{
			if( distance( pts->m_Width /2 ) ) return( pts ) ;
			}
		}
	return(NULL) ;
}


/****************************************************************************/
/* TRACK *Locate_Pistes(TRACK * start_adresse, int MasqueLayer,int typeloc)	*/
/* TRACK *Locate_Pistes(TRACK * start_adresse, wxPoint ref, 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_pX , ref_pY.r

	La recherche commence a l'adresse start_adresse
*/

TRACK * Locate_Pistes(TRACK * start_adresse,int Layer, int typeloc )
{
wxPoint ref;

	SET_REF_POS(ref);

	return( Locate_Pistes(start_adresse, ref, Layer) );
}


TRACK * Locate_Pistes(TRACK * start_adresse, wxPoint ref, int Layer)
{
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;
		/* 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.x - ux0 ; spot_cY = ref.y - uy0 ;

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

		if(Layer >= 0)
			if( Track->m_Layer != Layer )
				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,wxPoint ref, 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_pX , ref_pY.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;

	SET_REF_POS(ref);

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


TRACK * Locate_Zone(TRACK * start_adresse, wxPoint ref, 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.x - ux0 ; spot_cY = ref.y - uy0 ;

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



	/***************************************************************/
	/* TEXTE_PCB * Locate_Texte_Pcb(char * pt_txt_pcb,int typeloc) */
	/***************************************************************/

/* localisation des inscriptions sur le Pcb: 
	entree : char pointeur sur le debut de la zone de recherche
	retour : pointeur sur la description du texte localise
*/

TEXTE_PCB * Locate_Texte_Pcb(TEXTE_PCB* pt_txt_pcb, int typeloc)
{
int angle ;
EDA_BaseStruct * PtStruct;
wxPoint ref;

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

		angle = pt_txt_pcb->m_Orient;
		ux0 = pt_txt_pcb->m_Pos.x; uy0 = pt_txt_pcb->m_Pos.y;
		dx  = (pt_txt_pcb->m_Size.x * pt_txt_pcb->GetLength()) / 2;
		dy = pt_txt_pcb->m_Size.y /2 ;

		dx *= 13; dx /= 9;  /* Facteur de forme des lettres : 13/9 */

		/* la souris est-elle dans ce rectangle  autour du centre  */
		spot_cX = ref.x - ux0 ; spot_cY = ref.y - uy0 ;
		RotatePoint(&spot_cX, &spot_cY, -angle);
		if( (abs(spot_cX) <= abs(dx) ) && ( abs(spot_cY) <= abs(dy) ) )
			 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) ;
}


