        /*****************************/
        /* 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 LayerSearch, int typeloc);
/**/

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


/**
 * Function IsModuleLayerVisible
 * expects either of the two layers on which a module can reside, and returns
 * whether that layer is visible.
 * @param layer One of the two allowed layers for modules: CMP_N or CUIVRE_N
 * @return bool - true if the layer is visible, else false.
 */
bool inline IsModuleLayerVisible( int layer )
{
    if( layer==CMP_N )
        return DisplayOpt.Show_Modules_Cmp;
    
    else if( layer==CUIVRE_N )
        return DisplayOpt.Show_Modules_Cu;
    
    else
        return true;
}
    

/*************************************************************/
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, int LayerSearch )
/*******************************************************************************/
/* General locate function
    Display infos relatives to the item found
    return a pointer to this item ( or NULL )
*/
{
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, LayerSearch, typeloc);
    if(pt_texte_pcb ) // a PCB text is found
    {
        Affiche_Infos_PCB_Texte(this, pt_texte_pcb);
        return pt_texte_pcb;
    }

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

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

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

    /* Search for tracks and vias, with via priority */
    if ( LayerSearch == -1 ) masque_layer = ALL_LAYERS;
    else masque_layer = g_TabOneLayerMask[LayerSearch];
    Track = Locate_Pistes( m_Pcb->m_Track, masque_layer,typeloc );
    if ( Track != NULL )
    {
        TrackLocate = Track ;   /* a track or a via is found*/
        /* Search for a via */
        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;
    }


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

    /* Search for a footprint text */
    // First search: locate texts for footprints on copper or component layer
    // Priority to the active layer (component or copper.
    // this is useful for small smd components when 2 texts overlap but are not on the same layer
    if ( (LayerSearch == LAYER_CUIVRE_N) ||  (LayerSearch == CMP_N ))
    {
        for (module = m_Pcb->m_Modules; module != NULL; module = (MODULE*)module->Pnext)  
        {
        TEXTE_MODULE * pt_texte;
            if ( module->m_Layer != LayerSearch) continue;
            pt_texte = LocateTexteModule(m_Pcb, &module, typeloc | VISIBLE_ONLY);
            if( pt_texte != NULL )
            {
                Affiche_Infos_E_Texte(this,  module, pt_texte);
                return pt_texte;
            }
        }
    }

    // Now Search footprint texts on all layers
    module = NULL;
    {
    TEXTE_MODULE * pt_texte;
        pt_texte = LocateTexteModule(m_Pcb, &module, typeloc | VISIBLE_ONLY);
        if( pt_texte != NULL )
        {
            Affiche_Infos_E_Texte(this,  module, pt_texte);
            return pt_texte;
        }
    }

    /* Search for a footprint */
    if ( (module = Locate_Prefered_Module(m_Pcb, typeloc | VISIBLE_ONLY)) != NULL)
    {
        module->Display_Infos(this);
        return module;
    }

    /* Search for zones */
    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)
/*******************************************************************/

/* 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 LayerSearch, int typeloc)
/*************************************************************************/
/* Serach for a cotation item , on LayerSearch,
    (if LayerSearch == -1 , no yaere restriction )
    return a pointer to the located item, or 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 != LayerSearch) && (LayerSearch != -1) )
            continue;

        /* Localisation du texte ? */
        pt_txt = Cotation->m_Text;
        if( pt_txt )
        {
            if( pt_txt->Locate(ref_pos) ) 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 LayerSearch, 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;
        if ( (pts->m_Layer != LayerSearch) && (LayerSearch != -1) )
            continue;
        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 */
    MODULE*     Altmodule = NULL;   /* module localise sur les couches non actives */
    int         min_dim = 0x7FFFFFFF;     /* dim mini du module localise sur la couche active */
    int         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;  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;

        // if caller wants to ignore locked modules, and this one is locked, skip it.
        if( (typeloc & IGNORE_LOCKED) && pt_module->IsLocked() )
            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;

        else 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( !(typeloc & MATCH_LAYER) 
            && ( !(typeloc & VISIBLE_ONLY) || IsModuleLayerVisible( layer )) )
        {
            if( min(lx,ly) <= alt_min_dim )
            {   
                /* meilleure empreinte localisee sur autres couches */
                Altmodule = pt_module; 
                alt_min_dim = min(lx,ly);
            }
        }
    }

    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 )

	if typeloc bas the flag VISIBLE_ONLY set, only footprints which are "visible" are considered
*/
{
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 )
    {
		if ( (typeloc & VISIBLE_ONLY) )
		{
			int layer = module->m_Layer;
			if( layer==ADHESIVE_N_CU || layer==SILKSCREEN_N_CU ) layer = CUIVRE_N;
			else if( layer==ADHESIVE_N_CMP || layer==SILKSCREEN_N_CMP ) layer = CMP_N;
			if ( ! IsModuleLayerVisible( layer ) ) continue;
		}
         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 extr = START, le point de debut du segment est utilise
    si int extr = 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 Reflayer;
wxPoint pos_ref;
int ii;

    if ( extr == START) pos_ref = PtRefSegm->m_Start;
    else pos_ref = PtRefSegm->m_End;

    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( pos_ref == PtSegmN->m_Start )
                {   /* Test des couches */
                if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
                }

            if( pos_ref == PtSegmN->m_End )
                {   /* 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( pos_ref == PtSegmB->m_Start )
                {   /* Test des couches */
                if(Reflayer & PtSegmB->ReturnMaskLayer() )return(PtSegmB);
                }

            if( pos_ref == PtSegmB->m_End )
                {   /* 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( pos_ref == PtSegmN->m_Start )
            {   /* Test des couches */
            if(Reflayer & PtSegmN->ReturnMaskLayer() )return(PtSegmN);
            }

        if( pos_ref == PtSegmN->m_End )
            {   /* 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 LayerSearch, 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) )
        {
            if ( pt_txt_pcb->m_Layer == LayerSearch )
                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  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 LayerSearch,
        int typeloc)
/***********************************************************************/
/* Serach for a photo target
*/
{
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)
    {
        MIREPCB* item;
        if( PtStruct->m_StructType != TYPEMIRE ) continue;
        item = (MIREPCB*) PtStruct;
        if( LayerSearch != -1 && item->m_Layer != LayerSearch ) continue;
        
        dX = ref_pos.x - item->m_Pos.x;
        dY = ref_pos.y - item->m_Pos.y;
        rayon = item->m_Size / 2;
        if( (abs(dX) <= rayon ) && ( abs(dY) <= rayon ) )
            break;  /* Mire Localisee */
    }
    return(PtStruct);
}

