	/******************************************************/
	/* Routines de localisation d'un element d'un schema. */
	/******************************************************/

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

#include "common.h"
#include "program.h"
#include "libcmp.h"
#include "general.h"
#include "trigo.h"
#include "macros.h"

#include "protos.h"

/* Routines exportees */
int distance(int dx, int dy, int spot_cX, int spot_cY, int seuil);

/* Routines Locales */
static EDA_BaseStruct *LastSnappedStruct = NULL;
static int PickedBoxMinX, PickedBoxMinY, PickedBoxMaxX, PickedBoxMaxY ;
static bool IsBox1InBox2( int StartX1, int StartY1, int EndX1, int EndY1,
							int StartX2, int StartY2, int EndX2, int EndY2 );
static bool IsPointInBox( int pX, int pY,
						 int BoxX1, int BoxY1, int BoxX2, int BoxY2 );
static bool IsPointOnSegment( int pX, int pY,
				 int SegmX1, int SegmY1, int SegmX2, int SegmY2, int seuil = 0);
static bool SnapPoint2(const wxPoint & PosRef, int SearchMask,
			 EDA_BaseStruct *DrawList, DrawPickedStruct *DontSnapList);



/*********************************************************************/
EDA_SchComponentStruct * LocateSmallestComponent( SCH_SCREEN * Screen )
/*********************************************************************/
/* Recherche du plus petit (en surface) composant pointe par la souris
	Si 2 (ou plus) composants sont trouves, un pointeur sur le composant
	le plus petit est retourne
*/
{
EDA_SchComponentStruct * DrawLibItem = NULL, * LastDrawLibItem = NULL;
EDA_BaseStruct *DrawList;
EDA_Rect BoundaryBox;
float sizeref = 0, sizecurr;

	DrawList = Screen->EEDrawList;

	while ( DrawList )
	{
		if( ( SnapPoint2(Screen->m_Curseur, LIBITEM,
			DrawList,NULL)) == FALSE ) break;
		DrawLibItem = (EDA_SchComponentStruct *) LastSnappedStruct;
		DrawList = DrawLibItem->Pnext;
		if ( LastDrawLibItem == NULL )	// First time a component is located
		{
			LastDrawLibItem = DrawLibItem;
			BoundaryBox = LastDrawLibItem->GetBoundaryBox();
			sizeref = ABS((float)BoundaryBox.GetWidth() * BoundaryBox.GetHeight());
		}
		else
		{
			BoundaryBox = DrawLibItem->GetBoundaryBox();
			sizecurr = ABS((float)BoundaryBox.GetWidth() * BoundaryBox.GetHeight());
			if ( sizeref > sizecurr )	// a smallest component is found
			{
				sizeref = sizecurr;
				LastDrawLibItem = DrawLibItem;
			}
		}
	}

	return LastDrawLibItem;
}


/* 2 functions EDA_BaseStruct * PickStruct:
	Search in  block, or Search at location pos

	SearchMask = (bitwise OR):
	LIBITEM
	WIREITEM
	BUSITEM
	RACCORDITEM
	JUNCTIONITEM
	DRAWITEM
	TEXTITEM
	LABELITEM
	SHEETITEM
	MARKERITEM
	NOCONNECTITEM
	SEARCH_PINITEM
	SHEETLABELITEM
	FIELDCMPITEM

	if EXCLUDE_WIRE_BUS_ENDPOINTS is set, in wire ou bus search and locate,
	start and end points are not included in search
	if WIRE_BUS_ENDPOINTS_ONLY is set, in wire ou bus search and locate,
	only start and end points are included in search


	Return:
		-Bloc searc:
			pointeur sur liste de pointeurs de structures si Plusieurs
					structures selectionnees.
			pointeur sur la structure si 1 seule

		Positon serach:
			pointeur sur la structure.
		Si pas de structures selectionnees: retourne NULL

*/
/***********************************************************************/
EDA_BaseStruct * PickStruct(const wxPoint & refpos,
		EDA_BaseStruct *DrawList, int SearchMask )
/************************************************************************/
/* Search an item at pos pos
*/
{
bool Snapped;

	if ( DrawList == NULL ) return NULL;

	if( (Snapped = SnapPoint2(refpos, SearchMask,
		DrawList,NULL)) != FALSE)
	{
		return( LastSnappedStruct);
	}
	return( NULL );
}

/***********************************************************************/
EDA_BaseStruct * PickStruct( EDA_Rect & block,
		EDA_BaseStruct *DrawList, int SearchMask )
/************************************************************************/
/* Search items in block
*/
{
int x, y, OrigX, OrigY;
DrawPickedStruct *PickedList = NULL, *PickedItem;
EDA_BaseStruct *DrawStruct;
	
	OrigX = block.GetX();
	OrigY = block.GetY();
	x = block.GetRight();
	y = block.GetBottom();

	if (x < OrigX) EXCHG(x, OrigX);
	if (y < OrigY) EXCHG(y, OrigY);

	for (DrawStruct = DrawList; DrawStruct != NULL; DrawStruct = DrawStruct->Pnext)
	{
		if( DrawStructInBox(OrigX, OrigY, x, y, DrawStruct) )
		{
			/* Put this structure in the picked list: */
			PickedItem = new DrawPickedStruct(DrawStruct);
			PickedItem->Pnext = PickedList;
			PickedList = PickedItem;
		}
	}

	if (PickedList && PickedList->Pnext == NULL)
	{
		/* Only one item was picked - convert to scalar form (no list): */
		PickedItem = PickedList;
		PickedList = (DrawPickedStruct *) PickedList->m_PickedStruct;
		delete PickedItem;
	}

	if (PickedList != NULL)
	{
		PickedBoxMinX = OrigX;  PickedBoxMinY = OrigY;
		PickedBoxMaxX = x; PickedBoxMaxY = y;
	}

	return PickedList;
}

/*****************************************************************************
* Routine to search all objects for the closest point to a given point, in	 *
* drawing space, and snap it to that points if closer than SnapDistance.	 *
* Note we use L1 norm as distance measure, as it is the fastest.			 *
* This routine updates LastSnappedStruct to the last object used in to snap  *
* a point. This variable is global to this module only (see above).			 *
* If DontSnapList is not NULL, structes in this list are skipped.			 *
* The routine returns TRUE if point was snapped.							 *
*****************************************************************************/
bool SnapPoint2(const wxPoint & PosRef, int SearchMask,
			 EDA_BaseStruct *DrawList, DrawPickedStruct *DontSnapList)
{
int i, *Points, x = PosRef.x, y = PosRef.y;
int x1, y1, x2, y2, NumOfPoints2;
DrawPickedStruct *DontSnap;
int dx, dy;

	for (; DrawList != NULL; DrawList = DrawList->Pnext)
	{
		/* Make sure this structure is NOT in the dont snap list: */
		DontSnap = DontSnapList;
		for( ; DontSnap != NULL; DontSnap = (DrawPickedStruct *)DontSnap->Pnext)
			 if (DontSnap->m_PickedStruct == DrawList) break;

		if(DontSnap) if (DontSnap->m_PickedStruct == DrawList) continue;

		switch (DrawList->m_StructType)
		{
			case DRAW_POLYLINE_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawPolylineStruct *) DrawList)
				if( !(SearchMask & (DRAWITEM|WIREITEM|BUSITEM)) ) break;
				Points = STRUCT->m_Points;
				NumOfPoints2 = STRUCT->m_NumOfPoints * 2;
				for (i = 0; i < NumOfPoints2 - 2; i += 2)
				{
					x1 = Points[i]; y1 = Points[i+1];
					x2 = Points[i+2]; y2 = Points[i+3];
					if (IsPointOnSegment(x,y, x1, y1, x2, y2) )
					{
						LastSnappedStruct = DrawList;
						return(TRUE);
					}
				}
				break;

			case DRAW_SEGMENT_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((EDA_DrawLineStruct *) DrawList)
				if( !(SearchMask & (DRAWITEM|WIREITEM|BUSITEM)) ) break;

				if (IsPointOnSegment(x,y, STRUCT->m_Start.x,STRUCT->m_Start.y ,
										STRUCT->m_End.x, STRUCT->m_End.y) )
				{
					if( ((SearchMask & DRAWITEM) && (STRUCT->m_Layer == LAYER_NOTES)) ||
						((SearchMask & WIREITEM) && (STRUCT->m_Layer == LAYER_WIRE)) ||
						((SearchMask & BUSITEM) && (STRUCT->m_Layer == LAYER_BUS))
						)
					{
						if (SearchMask & EXCLUDE_WIRE_BUS_ENDPOINTS)
						{
							if ( x == STRUCT->m_Start.x && y == STRUCT->m_Start.y )
								break;
							if ( x == STRUCT->m_End.x && y == STRUCT->m_End.y )
								break;
						}
						
						if (SearchMask & WIRE_BUS_ENDPOINTS_ONLY)
						{
							if ( ! STRUCT->IsOneEndPointAt(wxPoint(x, y)) ) break;
						}

						LastSnappedStruct = DrawList;
						return(TRUE);
					}
				}
				break;


			case DRAW_BUSENTRY_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawBusEntryStruct *) DrawList)
				if( !(SearchMask & (RACCORDITEM)) ) break;

				if (IsPointOnSegment(x,y, STRUCT->m_Pos.x,STRUCT->m_Pos.y,
								STRUCT->m_End().x, STRUCT->m_End().y) )
				{
					LastSnappedStruct = DrawList;
					return(TRUE);
				}
				break;

			case DRAW_JUNCTION_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawJunctionStruct *) DrawList)
				if( !(SearchMask & JUNCTIONITEM) )break;
				x1 = STRUCT->m_Pos.x - (DRAWJUNCTION_SIZE / 2);
				y1 = STRUCT->m_Pos.y - (DRAWJUNCTION_SIZE / 2);
				x2 = STRUCT->m_Pos.x + (DRAWJUNCTION_SIZE / 2);
				y2 = STRUCT->m_Pos.y + (DRAWJUNCTION_SIZE / 2);
				if(IsPointInBox(x, y, x1,y1, x2,y2) )
				{
					LastSnappedStruct = DrawList;
					return(TRUE);
				}
				break;


			case DRAW_NOCONNECT_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawNoConnectStruct *) DrawList)
				if( !(SearchMask & NOCONNECTITEM) )break;
				x1 = STRUCT->m_Pos.x - (DRAWNOCONNECT_SIZE / 2);
				y1 = STRUCT->m_Pos.y - (DRAWNOCONNECT_SIZE / 2);
				x2 = STRUCT->m_Pos.x + (DRAWNOCONNECT_SIZE / 2);
				y2 = STRUCT->m_Pos.y + (DRAWNOCONNECT_SIZE / 2);
				if(IsPointInBox(x, y, x1,y1, x2,y2) )
				{
					LastSnappedStruct = DrawList;
					return(TRUE);
				}
				break;

			case DRAW_MARKER_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawMarkerStruct *) DrawList)
				if( !(SearchMask & MARKERITEM) )break;
				x1 = STRUCT->m_Pos.x - DRAWMARKER_SIZE / 4;
				y1 = STRUCT->m_Pos.y - DRAWMARKER_SIZE / 4;
				x2 = STRUCT->m_Pos.x + DRAWMARKER_SIZE / 4;
				y2 = STRUCT->m_Pos.y + DRAWMARKER_SIZE / 4;
				if(IsPointInBox(x, y, x1,y1, x2,y2) )
				{
					LastSnappedStruct = DrawList;
					return(TRUE);
				}
				break;

			case DRAW_LABEL_STRUCT_TYPE:
			case DRAW_TEXT_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawTextStruct *) DrawList)
				if( !(SearchMask & (TEXTITEM|LABELITEM)) ) break;
				dx = STRUCT->m_Size.x * STRUCT->GetLength();
				dy = STRUCT->m_Size.y;
				x1 = x2 = STRUCT->m_Pos.x;
				y1 = y2 = STRUCT->m_Pos.y;
				switch( STRUCT->m_Orient)
					{
					case 0 :	/* HORIZONTAL */
						x2 += dx; y2 -= dy;
						break;

					case 1 :	/* VERTICAL UP */
						x2 -= dy; y2 -= dx;
						break;

					case 2 :	/* horizontal inverse */
						x2 -= dx; y2 += dy;
						break;

					case 3 :	/* vertical DOWN */
						x2 += dy; y2 += dx;
						break;
					}
				if(IsPointInBox(x, y, x1,y1, x2,y2) )
					{
					LastSnappedStruct = DrawList;
					return(TRUE);
					}
				break;


			case DRAW_GLOBAL_LABEL_STRUCT_TYPE:
				#undef  STRUCT
				#define STRUCT ((DrawGlobalLabelStruct *) DrawList)
				if( !(SearchMask & LABELITEM) ) break;
				dx = STRUCT->m_Size.x * ( STRUCT->GetLength() + 1 ); /* longueur */
				dy = STRUCT->m_Size.y / 2;		/* Demi hauteur */
				x1 = x2 = STRUCT->m_Pos.x;
				y1 = y2 = STRUCT->m_Pos.y;
				switch( STRUCT->m_Orient)
				{
					case 0 :	/* HORIZONTAL */
						x2 -= dx; y2 += dy; y1 -= dy;
						break;

					case 1 :	/* VERTICAL UP */
						x1 -= dy; x2 += dy; y2 += dx;
						break;

					case 2 :	/* horizontal inverse */
						x2 += dx; y2 += dy; y1 -= dy;
						break;

					case 3 :	/* vertical DOWN */
						x1 -= dy; x2 += dy; y2 -= dx;
						break;
				}
				if(IsPointInBox(x, y, x1,y1, x2,y2) )
				{
					LastSnappedStruct = DrawList;
					return(TRUE);
				}
				break;

			case DRAW_LIB_ITEM_STRUCT_TYPE:
				if( !(SearchMask & (LIBITEM|FIELDCMPITEM) ) ) break;

				if ( SearchMask & FIELDCMPITEM )
				{
					PartTextStruct * Field;
					EDA_SchComponentStruct * DrawLibItem = (EDA_SchComponentStruct *) DrawList;
					for ( i = REFERENCE; i < NUMBER_OF_FIELDS; i++ )
					{
						Field = &DrawLibItem->m_Field[i];
						if ( (Field->m_Attributs & TEXT_NO_VISIBLE) ) continue;
						if ( Field->IsVoid() ) continue;
 						EDA_Rect BoundaryBox = Field->GetBoundaryBox();
 						if(BoundaryBox.Inside(x, y) )
						{
							LastSnappedStruct = Field;
							return TRUE;
						}
					}
				}
				else
				{
					#undef  STRUCT
					#define STRUCT ((EDA_SchComponentStruct *) DrawList)
					EDA_Rect BoundaryBox = STRUCT->GetBoundaryBox();
					if ( BoundaryBox.Inside(x, y) )
					{
						LastSnappedStruct = DrawList;
						return TRUE;
					}
				}
				break;

			case DRAW_SHEET_STRUCT_TYPE:
				#undef STRUCT
				#define STRUCT ((DrawSheetStruct *) DrawList)
				if( !(SearchMask & SHEETITEM) ) break;
				/* Recalcul des coordonnees de l'encadrement du composant */
				x1 = STRUCT->m_Pos.x;
				y1 = STRUCT->m_Pos.y;
				x2 = STRUCT->m_Pos.x + STRUCT->m_Size.x;
				y2 = STRUCT->m_Pos.y + STRUCT->m_Size.y;

				if(IsPointInBox(x, y, x1, y1, x2, y2) )
					{
					LastSnappedStruct = DrawList;
					return TRUE;
					}
				break;

			case DRAW_PICK_ITEM_STRUCT_TYPE : break;

			default:
			{
				wxString msg;
				msg.Printf(wxT("SnapPoint2() error: unexpected strct type %d ("), DrawList->m_StructType);
				msg << DrawList->ReturnClassName() << wxT(")");
				DisplayError(NULL, msg);
				break;
			}
		}
	}
	return FALSE;
}


/*****************************************************************************
* Routine to test if an object has non empty intersection with the box		 *
* defined by x1/y1 and x2/y2 (x1 < x2, y1 < y2), and return TRUE if so. This *
* routine is used to pick all points in a given box.						 *
*****************************************************************************/
bool DrawStructInBox(int x1, int y1, int x2, int y2,
						EDA_BaseStruct *DrawStruct)
{
int i, *Points, xt1, yt1, xt2, yt2, NumOfPoints2;
int dx, dy;
wxString msg;

	switch (DrawStruct->m_StructType)
		{
		case DRAW_POLYLINE_STRUCT_TYPE:
			#undef  STRUCT
			#define STRUCT ((DrawPolylineStruct *) DrawStruct)
			Points = STRUCT->m_Points;
			NumOfPoints2 = STRUCT->m_NumOfPoints * 2;
			for (i = 0; i < NumOfPoints2; i += 2)
				{
				if (Points[i] >= x1 && Points[i] <= x2 &&
					Points[i+1] >= y1 && Points[i+1] <=y2) return TRUE;
				}
			break;

		case DRAW_SEGMENT_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((EDA_DrawLineStruct *) DrawStruct)
			if( STRUCT->m_Start.x >= x1 && STRUCT->m_Start.x <= x2 &&
					STRUCT->m_Start.y >= y1 && STRUCT->m_Start.y <=y2) return TRUE;
			if( (STRUCT->m_End.x >= x1) && (STRUCT->m_End.x <= x2) &&
				(STRUCT->m_End.y >= y1) && (STRUCT->m_End.y <=y2) ) return TRUE;
			break;

		case DRAW_BUSENTRY_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawBusEntryStruct *) DrawStruct)
			if( STRUCT->m_Pos.x >= x1 && STRUCT->m_Pos.x <= x2 &&
				STRUCT->m_Pos.y >= y1 && STRUCT->m_Pos.y <=y2)
					return TRUE;
			if( (STRUCT->m_End().x >= x1) && ( STRUCT->m_End().x <= x2) &&
				( STRUCT->m_End().y >= y1) && ( STRUCT->m_End().y <=y2) )
				return TRUE;
			break;

		case DRAW_JUNCTION_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawJunctionStruct *) DrawStruct)
			if( (STRUCT->m_Pos.x >= x1) && (STRUCT->m_Pos.x <= x2) &&
				(STRUCT->m_Pos.y >= y1) && (STRUCT->m_Pos.y <= y2) )
				  return TRUE;
			break;


		case DRAW_NOCONNECT_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawNoConnectStruct *) DrawStruct)
			if( (STRUCT->m_Pos.x >= x1) && (STRUCT->m_Pos.x <= x2) &&
				(STRUCT->m_Pos.y >= y1) && (STRUCT->m_Pos.y <= y2) )
				  return TRUE;
			break;


		case DRAW_MARKER_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawMarkerStruct *) DrawStruct)
			if( (STRUCT->m_Pos.x >= x1) && (STRUCT->m_Pos.x <= x2) &&
				(STRUCT->m_Pos.y >= y1) && (STRUCT->m_Pos.y <= y2) )
				  return TRUE;
			break;

		case DRAW_LABEL_STRUCT_TYPE:
		case DRAW_TEXT_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawTextStruct *) DrawStruct)
			dx = STRUCT->m_Size.x * STRUCT->GetLength();
			dy = STRUCT->m_Size.y;
			xt1 = xt2 = STRUCT->m_Pos.x;
			yt1 = yt2 = STRUCT->m_Pos.y;
			switch( STRUCT->m_Orient)
				{
				case 0 :	/* HORIZONTAL */
					xt2 += dx; yt2 -= dy;
					break;

				case 1 :	/* VERTICAL UP */
					xt2 -= dy; yt2 -= dx;
					break;

				case 2 :	/* horizontal inverse */
					xt2 -= dx; yt2 += dy;
					break;

				case 3 :	/* vertical DOWN */
					xt2 += dy; yt2 += dx;
					break;
				}
			if( IsBox1InBox2(xt1,yt1, xt2, yt2, x1, y1, x2, y2) ) return TRUE;
			break;

		case DRAW_GLOBAL_LABEL_STRUCT_TYPE:
			#undef STRUCT
			#define STRUCT ((DrawGlobalLabelStruct *) DrawStruct)
			dx = STRUCT->m_Size.x * ( STRUCT->GetLength() + 1);	/* longueur totale */
			dy = STRUCT->m_Size.y / 2; 		/* Demi hauteur */
			xt1 = xt2 = STRUCT->m_Pos.x;
			yt1 = yt2 = STRUCT->m_Pos.y;
			switch( STRUCT->m_Orient)
				{
				case 0 :	/* HORIZONTAL */
					xt2 -= dx; yt2 += dy; yt1 -= dy;
					break;

				case 1 :	/* VERTICAL UP */
					xt1 -= dy; xt2 += dy; yt2 += dx;
					break;

				case 2 :	/* horizontal inverse */
					xt2 += dx; yt2 += dy; yt1 -= dy;
					break;

				case 3 :	/* vertical DOWN */
					xt1 -= dy; xt2 += dy; yt2 -= dx;
					break;
				}
			if( IsBox1InBox2(xt1,yt1, xt2, yt2, x1, y1, x2, y2) ) return TRUE;
			break;

		case DRAW_LIB_ITEM_STRUCT_TYPE:
		{
			#undef STRUCT
			#define STRUCT ((EDA_SchComponentStruct *) DrawStruct)
			EDA_Rect BoundaryBox = STRUCT->GetBoundaryBox();
			xt1 = BoundaryBox.GetX();
			yt1 = BoundaryBox.GetY();
			xt2 = BoundaryBox.GetRight();
			yt2 = BoundaryBox.GetBottom();
			if( IsBox1InBox2(xt1,yt1, xt2, yt2, x1, y1, x2, y2) ) return TRUE;
			break;
		}

		case DRAW_SHEET_STRUCT_TYPE :
			#undef STRUCT
			#define STRUCT ((DrawSheetStruct *) DrawStruct)
			/* Recalcul des coordonnees de l'encadrement du composant */
			xt1 = STRUCT->m_Pos.x;
			yt1 = STRUCT->m_Pos.y;
			xt2 = STRUCT->m_Pos.x + STRUCT->m_Size.x;
			yt2 = STRUCT->m_Pos.y + STRUCT->m_Size.y;

			if( IsBox1InBox2(xt1,yt1, xt2, yt2, x1, y1, x2, y2) )
				return TRUE;
			break;

		case DRAW_SHEETLABEL_STRUCT_TYPE : break;
		case DRAW_PICK_ITEM_STRUCT_TYPE : break;

		default:
			msg.Printf(
					wxT("DrawStructInBox() Err: unexpected StructType %d ("),
					DrawStruct->m_StructType );
			msg << DrawStruct->ReturnClassName() << wxT(")");
			DisplayError(NULL, msg );
			break;
		}

	return FALSE;
}

/****************************************************************************/
static bool IsBox1InBox2( int StartX1, int StartY1, int EndX1, int EndY1,
								int StartX2, int StartY2, int EndX2, int EndY2 )
/****************************************************************************/
/* Routine detectant que le rectangle 1 (Box1) et le rectangle 2 (Box2) se
recouvrent.
	Retourne TRUE ou FALSE.

	On Considere ici qu'il y a recouvrement si l'un au moins des coins
	d'un 'Box' est compris dans l'autre
*/
{
int cX, cY;

	if(StartX1 > EndX1) EXCHG(StartX1, EndX1);
	if(StartX2 > EndX2) EXCHG(StartX2, EndX2);
	if(StartY1 > EndY1) EXCHG(StartY1, EndY1);
	if(StartY2 > EndY2) EXCHG(StartY2, EndY2);

	/* Tst des 4 coins du rectangle 1 */
	cX = StartX1; cY = StartY1; /* 1er coin */
	if( (cX >= StartX2) && (cX <= EndX2) && (cY >= StartY2) && (cY <= EndY2) )
		return(TRUE);

	cX = EndX1; cY = StartY1;	/* 2er coin */
	if( (cX >= StartX2) && (cX <= EndX2) && (cY >= StartY2) && (cY <= EndY2) )
		return(TRUE);

	cX = EndX1; cY = EndY1;	  /* 3eme coin */
	if( (cX >= StartX2) && (cX <= EndX2) && (cY >= StartY2) && (cY <= EndY2) )
		return(TRUE);

	cX = StartX1; cY = EndY1;	/* 4eme coin */
	if( (cX >= StartX2) && (cX <= EndX2) && (cY >= StartY2) && (cY <= EndY2) )
		return(TRUE);

	/* Tst des 4 coins du rectangle 2 */
	cX = StartX2; cY = StartY2;	  /* 1er coin */
	if( (cX >= StartX1) && (cX <= EndX1) && (cY >= StartY1) && (cY <= EndY1) )
		return(TRUE);

	cX = EndX2; cY = StartY2;	/* 2er coin */
	if( (cX >= StartX1) && (cX <= EndX1) && (cY >= StartY1) && (cY <= EndY1) )
		return(TRUE);

	cX = EndX2; cY = EndY2;	  /* 3er coin */
	if( (cX >= StartX1) && (cX <= EndX1) && (cY >= StartY1) && (cY <= EndY1) )
		return(TRUE);

	cX = StartX2; cY = EndY2;	/* 4er coin */
	if( (cX >= StartX1) && (cX <= EndX1) && (cY >= StartY1) && (cY <= EndY1) )
		return(TRUE);


	return(FALSE);
}


/**********************************************************************/
static bool IsPointInBox( int pX, int pY,
						 int BoxX1, int BoxY1, int BoxX2, int BoxY2 )
/**********************************************************************/
/* Routine detectant que le point pX,pY est dans le rectangle (Box)
	Retourne TRUE ou FALSE.

*/
{
	if(BoxX1 > BoxX2) EXCHG(BoxX1, BoxX2);
	if(BoxY1 > BoxY2) EXCHG(BoxY1, BoxY2);

	if( (pX >= BoxX1) && (pX <= BoxX2) && (pY >= BoxY1) && (pY <= BoxY2) )
		return(TRUE);

	else return(FALSE);
}


/********************************************************************************/
static bool IsPointOnSegment( int pX, int pY,
					 int SegmX1, int SegmY1, int SegmX2, int SegmY2, int seuil )
/********************************************************************************/
/* Routine detectant que le point pX,pY est sur le Segment X1,Y1 a X2,Y2
	Retourne TRUE ou FALSE.
*/
{
	/* Recalcul des coord avec SegmX1, SegmX2 comme origine */
	pX -= SegmX1; pY -= SegmY1;
	SegmX2 -= SegmX1; SegmY2 -= SegmY1;

	if( distance( SegmX2, SegmY2, pX, pY, seuil ) ) return(TRUE);

	else return(FALSE);
}

/****************************************************************/
LibEDA_BaseStruct * LocateDrawItem(SCH_SCREEN * Screen, EDA_LibComponentStruct * LibEntry,
						int Unit, int Convert, int masque)
/****************************************************************/
/* Routine de localisation d'un element de dessin de symbole( sauf pins )
	Unit = Unite d'appartenance (si Unit = 0, recherche sur toutes unites)
	Convert = Conversion d'appartenance (si Convert = 0, recherche sur
	toutes variantes)
*/
{
int x, y, dx, dy, ii, *ptpoly;
int px, py;
LibEDA_BaseStruct * DrawItem;
int seuil;

	if( LibEntry == NULL ) return(NULL);

	if ( LibEntry->Type != ROOT )
		{
		DisplayError(NULL, wxT("Error in LocateDrawItem: Entry is ALIAS"));
		return(NULL);
		}

	DrawItem = LibEntry->m_Drawings;

	seuil =  3;		/* Tolerance: 1/2 pas de petite grille */
	px = Screen->m_Curseur.x;
	py = Screen->m_Curseur.y;

	for( ; DrawItem != NULL ; DrawItem = DrawItem->Next() )
		{
		if(Unit && DrawItem->m_Unit && (Unit != DrawItem->m_Unit) ) continue;
		if(Convert && DrawItem->m_Convert && (Convert != DrawItem->m_Convert) )
			continue;

		switch ( DrawItem->m_StructType )
			{
			case COMPONENT_ARC_DRAW_TYPE:
				{
				LibDrawArc * Arc = (LibDrawArc *) DrawItem;
				if( (masque & LOCATE_COMPONENT_ARC_DRAW_TYPE) == 0) break;
				dx = px - Arc->m_Pos.x;
				dy = py + Arc->m_Pos.y;
				ii = (int)sqrt( dx*dx + dy*dy);
				if ( abs(ii - Arc->m_Rayon) <= seuil) return( DrawItem);
				}
				break;

			case COMPONENT_CIRCLE_DRAW_TYPE:
				{
				LibDrawCircle * Circle = (LibDrawCircle *) DrawItem;
				if( (masque & LOCATE_COMPONENT_CIRCLE_DRAW_TYPE) == 0) break;
				dx = px - Circle->m_Pos.x;
				dy = py + Circle->m_Pos.y;
				ii = (int)sqrt( dx*dx + dy*dy);
				if ( abs(ii - Circle->m_Rayon) <= seuil) return( DrawItem);
				}
				break;

			case COMPONENT_RECT_DRAW_TYPE:
				{
				LibDrawSquare * Square = (LibDrawSquare *) DrawItem;
				if( (masque & LOCATE_COMPONENT_RECT_DRAW_TYPE) == 0) break;
				if(IsPointOnSegment(px,py,
							Square->m_Start.x, - Square->m_Start.y,
							Square->m_End.x, - Square->m_Start.y, seuil) )
					return(DrawItem);
				if(IsPointOnSegment(px, py,
							Square->m_End.x, - Square->m_Start.y,
							Square->m_End.x, - Square->m_End.y, seuil) )
					return(DrawItem);
				if(IsPointOnSegment(px, py,
							Square->m_End.x, - Square->m_End.y,
							Square->m_Start.x, - Square->m_End.y, seuil) )
					return(DrawItem);
				if(IsPointOnSegment(px, py,
							Square->m_Start.x, - Square->m_End.y,
							Square->m_Start.x, - Square->m_Start.y, seuil) )
					return(DrawItem);
				}
				break;

			case COMPONENT_POLYLINE_DRAW_TYPE:
				{
				LibDrawPolyline * polyline = (LibDrawPolyline *) DrawItem;
				if( (masque & LOCATE_COMPONENT_POLYLINE_DRAW_TYPE) == 0) break;
				ptpoly = polyline->PolyList;
				for( ii = polyline->n-1; ii > 0; ii--, ptpoly += 2)
					{
					if(IsPointOnSegment(px, py,
						ptpoly[0], - ptpoly[1], ptpoly[2], - ptpoly[3], seuil) )
						return(DrawItem);
					}
				}
				break;

			case COMPONENT_LINE_DRAW_TYPE:
				{
				LibDrawSegment * Segment = (LibDrawSegment *) DrawItem;
				if( (masque & LOCATE_COMPONENT_LINE_DRAW_TYPE) == 0) break;
				if(IsPointOnSegment(px, py,
							Segment->m_Start.x, - Segment->m_Start.y,
							Segment->m_End.x, - Segment->m_End.y, seuil) )
						 return(DrawItem);
				}
				break;

			case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
				{
				LibDrawText * Text = (LibDrawText *) DrawItem;
				if( (masque & LOCATE_COMPONENT_GRAPHIC_TEXT_DRAW_TYPE) == 0) break;
				ii = Text->m_Text.Len(); if ( ii < 2 ) ii = 2;
				dx = (Text->m_Size.x * ii) / 2;
				dy = Text->m_Size.y / 2;
				if(Text->m_Horiz == TEXT_ORIENT_VERT)
					{
					EXCHG(dx,dy);
					}
				x = px - Text->m_Pos.x;
				y = py + Text->m_Pos.y;
				if( (abs(x) <= dx) && (abs(y) <= dy) )
						return(DrawItem);	/* Texte trouve */
				}
				break;
			}
		}
	return(NULL);
}


/****************************************************************/
int distance(int dx, int dy, int spot_cX, int spot_cY, int seuil)
/****************************************************************/
/*
 Calcul de la distance du point spot_cx,spot_cy a un segment de droite,
	d'origine 0,0 et d'extremite dx, dy;
	retourne:
		0 si distance > seuil
		1 si distance <= seuil
	Variables utilisees ( 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 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 en0 par symetrie par rapport a l'axe Y */
		{
		segX = -segX ; pointX = - pointX ;
		}
	if (segY < 0)	/* mise en > 0 par symymetrie 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	/* 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) ;
}



/*******************************************************************/
LibEDA_BaseStruct * LocatePin( const wxPoint & RefPos,
			EDA_LibComponentStruct * Entry,
			int Unit, int convert, EDA_SchComponentStruct * DrawLibItem)
/*******************************************************************/
/* Routine de localisation d'une PIN de la PartLib pointee par Entry
	retourne un pointeur sur la pin, ou NULL si pas trouve
	Si Unit = 0, le numero d'unite n'est pas teste
	Si convert = 0, le numero convert n'est pas teste

	m_Transform = matrice de transformation.
	Si NULL: 	matrice de transformation " normale" [1 , 0 , 0 , -1]
	(la matrice de transformation " normale" etant [1 , 0 , 0 , -1]
	la coord dy doit etre inversee).
	PartX, PartY: coordonnees de positionnement du composant
*/
{
LibEDA_BaseStruct * DrawItem;
LibDrawPin * Pin;
int x1, y1, x2, y2;

	if ( Entry == NULL ) return(NULL);

	if ( Entry->Type != ROOT )
	{
		DisplayError(NULL, wxT("LocatePin() error: Entry is ALIAS"));
		return(NULL);
	}

	DrawItem = Entry->m_Drawings;
	for ( ; DrawItem != NULL; DrawItem = DrawItem->Next())
	{
		if(DrawItem->m_StructType == COMPONENT_PIN_DRAW_TYPE) /* Pin Trouvee */
			{
			Pin = (LibDrawPin *) DrawItem;

			if( Unit && DrawItem->m_Unit && (DrawItem->m_Unit != Unit) )
				continue;

			if( convert && DrawItem->m_Convert && (DrawItem->m_Convert != convert) )
				continue;

			x2 = Pin->m_Pos.x;
			y2 = Pin->m_Pos.y;
			x1 = Pin->ReturnPinEndPoint().x;
			y1 = Pin->ReturnPinEndPoint().y;

			if(DrawLibItem == NULL )
			{
				y1 = -y1; y2 = -y2;
			}
			else
			{
				int x = x1, y = y1;
				x1 = DrawLibItem->m_Pos.x + DrawLibItem->m_Transform[0][0] * x
								+ DrawLibItem->m_Transform[0][1] * y;
				y1 = DrawLibItem->m_Pos.y + DrawLibItem->m_Transform[1][0] * x
								+ DrawLibItem->m_Transform[1][1] * y;
				x = x2; y = y2;
				x2 = DrawLibItem->m_Pos.x + DrawLibItem->m_Transform[0][0] * x
								+ DrawLibItem->m_Transform[0][1] * y;
				y2 = DrawLibItem->m_Pos.y + DrawLibItem->m_Transform[1][0] * x
								+ DrawLibItem->m_Transform[1][1] * y;
			}

			if (x1 > x2 ) EXCHG(x1,x2); if (y1 > y2 ) EXCHG(y1,y2);

			if( (RefPos.x >= x1) && (RefPos.x <= x2) &&
				(RefPos.y >= y1) && (RefPos.y <= y2) )
				return(DrawItem);
		}
	}
	return(NULL);
}

/***********************************************************************************/
DrawSheetLabelStruct * LocateSheetLabel(DrawSheetStruct *Sheet, const wxPoint & pos)
/***********************************************************************************/
{
int size , dy, minx, maxx;
DrawSheetLabelStruct * SheetLabel;

	SheetLabel = Sheet->m_Label;
	while((SheetLabel) && (SheetLabel->m_StructType==DRAW_SHEETLABEL_STRUCT_TYPE))
		{
		size = ( SheetLabel->GetLength()+1 ) * SheetLabel->m_Size.x;
		if (SheetLabel->m_Edge) size = -size ;
		minx = SheetLabel->m_Pos.x; maxx = SheetLabel->m_Pos.x + size;
		if( maxx < minx ) EXCHG(maxx,minx);
		dy = SheetLabel->m_Size.x / 2;
		if( (ABS(pos.y - SheetLabel->m_Pos.y) <= dy ) &&
					(pos.x <= maxx) &&
					(pos.x >= minx) )
			return(SheetLabel);
		SheetLabel = (DrawSheetLabelStruct *) SheetLabel->Pnext;
		}
	return(NULL);
}

/**************************************************************************/
LibDrawPin * LocateAnyPin(EDA_BaseStruct *DrawList, const wxPoint & RefPos,
		EDA_SchComponentStruct ** libpart)
/**************************************************************************/
{
EDA_BaseStruct *DrawStruct;
EDA_LibComponentStruct * Entry;
EDA_SchComponentStruct * LibItem = NULL;
LibDrawPin * Pin = NULL;

	for(DrawStruct = DrawList; DrawStruct != NULL; DrawStruct = DrawStruct->Pnext )
	{
		if( DrawStruct->m_StructType != DRAW_LIB_ITEM_STRUCT_TYPE )
					continue;
		LibItem = (EDA_SchComponentStruct *) DrawStruct;
		Entry = FindLibPart( LibItem->m_ChipName.GetData(), wxEmptyString, FIND_ROOT);
		if( Entry == NULL ) continue;
		Pin = (LibDrawPin *) LocatePin(RefPos, Entry, LibItem->m_Multi,
							LibItem->m_Convert, LibItem);
		if( Pin ) break;
	}
	if ( libpart ) *libpart = LibItem;
	return Pin;
}

/***************************************************************/
DrawSheetLabelStruct * LocateAnyPinSheet(const wxPoint & RefPos,
					EDA_BaseStruct *DrawList)
/***************************************************************/
{
EDA_BaseStruct *DrawStruct;
DrawSheetLabelStruct * PinSheet = NULL;

	for( DrawStruct = DrawList; DrawStruct != NULL; DrawStruct = DrawStruct->Pnext )
		{
		if( DrawStruct->m_StructType != DRAW_SHEET_STRUCT_TYPE )
					continue;
		PinSheet = LocateSheetLabel( (DrawSheetStruct *) DrawStruct,
					RefPos);
		if( PinSheet ) break;
		}
	return PinSheet;
}

