kicad/eeschema/locate.cpp

528 lines
16 KiB
C++
Raw Normal View History

2007-09-02 15:49:11 +00:00
/******************************************************/
/* Routines for locating an element of a schematic. */
2007-09-02 15:49:11 +00:00
/******************************************************/
#include "fctsys.h"
#include "common.h"
#include "trigo.h"
#include "macros.h"
#include "class_sch_screen.h"
#include "general.h"
#include "protos.h"
#include "class_library.h"
#include "sch_marker.h"
#include "sch_items.h"
#include "sch_component.h"
#include "sch_sheet.h"
#include "lib_pin.h"
#include "template_fieldnames.h"
2009-11-28 09:24:37 +00:00
static bool IsItemInBox(EDA_Rect& aBox, SCH_ITEM* DrawStruct );
static SCH_ITEM* LastSnappedStruct = NULL;
2009-01-02 13:19:34 +00:00
static bool SnapPoint2( const wxPoint& aPosRef, int SearchMask,
SCH_ITEM* DrawList, double aScaleFactor );
/**
* Search the smaller (considering its area) component under the mouse
* cursor or the pcb cursor
*
* If more than 1 component is found, a pointer to the smaller component is
* returned
2007-09-02 15:49:11 +00:00
*/
SCH_COMPONENT* LocateSmallestComponent( SCH_SCREEN* Screen )
{
SCH_COMPONENT* component = NULL, * lastcomponent = NULL;
SCH_ITEM* DrawList;
EDA_Rect BoundaryBox;
float sizeref = 0, sizecurr;
2007-09-02 15:49:11 +00:00
DrawList = Screen->EEDrawList;
while( DrawList )
{
if( ( SnapPoint2( Screen->m_MousePosition, LIBITEM,
DrawList, Screen->GetZoom() ) ) == FALSE )
2007-09-02 15:49:11 +00:00
{
if( ( SnapPoint2( Screen->m_Curseur, LIBITEM,
DrawList, Screen->GetScalingFactor() ) ) == FALSE )
2007-09-02 15:49:11 +00:00
break;
}
component = (SCH_COMPONENT*) LastSnappedStruct;
DrawList = component->Next();
if( lastcomponent == NULL ) // First time a component is located
2007-09-02 15:49:11 +00:00
{
lastcomponent = component;
BoundaryBox = lastcomponent->GetBoundaryBox();
sizeref = ABS( (float) BoundaryBox.GetWidth() *
BoundaryBox.GetHeight() );
2007-09-02 15:49:11 +00:00
}
else
{
BoundaryBox = component->GetBoundaryBox();
sizecurr = ABS( (float) BoundaryBox.GetWidth() *
BoundaryBox.GetHeight() );
2007-09-02 15:49:11 +00:00
if( sizeref > sizecurr ) // a smallest component is found
{
sizeref = sizecurr;
lastcomponent = component;
2007-09-02 15:49:11 +00:00
}
}
}
return lastcomponent;
}
/* Search an item at pos refpos
* SearchMask = (bitwise OR):
2007-09-02 15:49:11 +00:00
* LIBITEM
* WIREITEM
* BUSITEM
* RACCORDITEM
* JUNCTIONITEM
* DRAWITEM
* TEXTITEM
* LABELITEM
* SHEETITEM
* MARKERITEM
* NOCONNECTITEM
* SEARCH_PINITEM
* SHEETLABELITEM
* FIELDCMPITEM
2008-03-20 01:50:21 +00:00
*
* if EXCLUDE_WIRE_BUS_ENDPOINTS is set, in wire or bus search and locate,
2007-09-02 15:49:11 +00:00
* start and end points are not included in search
* if WIRE_BUS_ENDPOINTS_ONLY is set, in wire or bus search and locate,
2007-09-02 15:49:11 +00:00
* only start and end points are included in search
2008-03-20 01:50:21 +00:00
*
*
2007-09-02 15:49:11 +00:00
* Return:
* pointer on item found or NULL
2008-03-20 01:50:21 +00:00
*
2007-09-02 15:49:11 +00:00
*/
SCH_ITEM* PickStruct( const wxPoint& refpos,
BASE_SCREEN* screen,
int SearchMask )
{
bool Snapped;
2009-01-02 13:19:34 +00:00
if( screen == NULL || screen->EEDrawList == NULL )
2008-03-20 01:50:21 +00:00
return NULL;
2007-09-02 15:49:11 +00:00
if( ( Snapped = SnapPoint2( refpos, SearchMask,
screen->EEDrawList,
screen->GetScalingFactor() ) ) != FALSE )
2007-09-02 15:49:11 +00:00
{
return LastSnappedStruct;
}
return NULL;
}
2007-09-02 15:49:11 +00:00
/**
* Function PickStruct
* Search items in a block
* @return items count
* @param aBlock a BLOCK_SELECTOR that gives the search area boundary
* list of items is stored in aBlock
2007-09-02 15:49:11 +00:00
*/
int PickItemsInBlock( BLOCK_SELECTOR& aBlock, BASE_SCREEN* aScreen )
{
int itemcount = 0;
if( aScreen == NULL )
return itemcount;
2007-09-02 15:49:11 +00:00
2009-11-28 09:24:37 +00:00
EDA_Rect area;
area.SetOrigin( aBlock.GetOrigin());
area.SetSize( aBlock.GetSize() );
2007-09-02 15:49:11 +00:00
2009-11-28 09:24:37 +00:00
area.Normalize();
2008-03-20 01:50:21 +00:00
ITEM_PICKER picker;
SCH_ITEM* DrawStruct = aScreen->EEDrawList;
for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Next() )
2007-09-02 15:49:11 +00:00
{
2009-11-28 09:24:37 +00:00
if( IsItemInBox( area, DrawStruct ) )
2007-09-02 15:49:11 +00:00
{
/* Put this structure in the picked list: */
picker.m_PickedItem = DrawStruct;
picker.m_PickedItemType = DrawStruct->Type();
aBlock.PushItem( picker );
itemcount++;
2007-09-02 15:49:11 +00:00
}
}
return itemcount;
}
2007-09-02 15:49:11 +00:00
/*****************************************************************************
* 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). *
2009-11-28 09:24:37 +00:00
* The routine returns true if point was snapped. *
*****************************************************************************/
2009-01-02 13:19:34 +00:00
bool SnapPoint2( const wxPoint& aPosRef, int SearchMask,
SCH_ITEM* DrawList, double aScaleFactor )
{
for( ; DrawList != NULL; DrawList = DrawList->Next() )
2007-09-02 15:49:11 +00:00
{
int hitminDist = MAX( g_DrawDefaultLineThickness, 3 );
2007-09-02 15:49:11 +00:00
switch( DrawList->Type() )
{
case DRAW_POLYLINE_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_POLYLINE*) DrawList )
2007-09-02 15:49:11 +00:00
if( !( SearchMask & (DRAWITEM | WIREITEM | BUSITEM) ) )
break;
2008-03-20 01:50:21 +00:00
for( unsigned i = 0; i < STRUCT->GetCornerCount() - 1; i++ )
2007-09-02 15:49:11 +00:00
{
2009-06-13 17:06:07 +00:00
if( TestSegmentHit( aPosRef, STRUCT->m_PolyPoints[i],
STRUCT->m_PolyPoints[i + 1], hitminDist ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
}
2007-09-02 15:49:11 +00:00
break;
case DRAW_SEGMENT_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_LINE*) DrawList )
2007-09-02 15:49:11 +00:00
if( !( SearchMask & (DRAWITEM | WIREITEM | BUSITEM) ) )
break;
2009-06-13 17:06:07 +00:00
if( TestSegmentHit( aPosRef, STRUCT->m_Start, STRUCT->m_End, 0 ) )
2007-09-02 15:49:11 +00:00
{
if( ( ( SearchMask & DRAWITEM )
&& ( STRUCT->GetLayer() == LAYER_NOTES ) )
|| ( ( SearchMask & WIREITEM )
&& ( STRUCT->GetLayer() == LAYER_WIRE ) )
|| ( ( SearchMask & BUSITEM )
&& ( STRUCT->GetLayer() == LAYER_BUS ) )
2007-09-02 15:49:11 +00:00
)
{
if( SearchMask & EXCLUDE_WIRE_BUS_ENDPOINTS )
{
if( aPosRef == STRUCT->m_Start
|| aPosRef == STRUCT->m_End )
2007-09-02 15:49:11 +00:00
break;
}
if( SearchMask & WIRE_BUS_ENDPOINTS_ONLY )
{
2009-01-02 13:19:34 +00:00
if( !STRUCT->IsOneEndPointAt( aPosRef ) )
2007-09-02 15:49:11 +00:00
break;
}
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
}
break;
case DRAW_BUSENTRY_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_BUS_ENTRY*) DrawList )
2007-09-02 15:49:11 +00:00
if( !( SearchMask & (RACCORDITEM) ) )
break;
if( TestSegmentHit( aPosRef, STRUCT->m_Pos, STRUCT->m_End(),
hitminDist ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
case DRAW_JUNCTION_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_JUNCTION*) DrawList )
2007-09-02 15:49:11 +00:00
if( !(SearchMask & JUNCTIONITEM) )
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
case DRAW_NOCONNECT_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_NO_CONNECT*) DrawList )
2007-09-02 15:49:11 +00:00
if( !(SearchMask & NOCONNECTITEM) )
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
case TYPE_SCH_MARKER:
{
2007-09-02 15:49:11 +00:00
#undef STRUCT
#define STRUCT ( (SCH_MARKER*) DrawList )
2007-09-02 15:49:11 +00:00
if( !(SearchMask & MARKERITEM) )
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
}
2007-09-02 15:49:11 +00:00
2008-03-20 01:50:21 +00:00
case TYPE_SCH_TEXT:
2007-09-02 15:49:11 +00:00
#undef STRUCT
2008-03-20 01:50:21 +00:00
#define STRUCT ( (SCH_TEXT*) DrawList )
if( !( SearchMask & TEXTITEM) )
2007-09-02 15:49:11 +00:00
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
case TYPE_SCH_LABEL:
2008-03-20 01:50:21 +00:00
case TYPE_SCH_GLOBALLABEL:
case TYPE_SCH_HIERLABEL:
#undef STRUCT
#define STRUCT ( (SCH_TEXT*) DrawList ) // SCH_TEXT is the base
// class of these labels
if( !(SearchMask & LABELITEM) )
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
2008-03-20 01:50:21 +00:00
case TYPE_SCH_COMPONENT:
2007-09-02 15:49:11 +00:00
if( !( SearchMask & (LIBITEM | FIELDCMPITEM) ) )
break;
if( SearchMask & FIELDCMPITEM )
{
SCH_COMPONENT* DrawLibItem = (SCH_COMPONENT*) DrawList;
2009-01-02 17:07:50 +00:00
for( int i = REFERENCE; i < DrawLibItem->GetFieldCount(); i++ )
2007-09-02 15:49:11 +00:00
{
SCH_FIELD* field = DrawLibItem->GetField( i );
if( field->m_Attributs & TEXT_NO_VISIBLE )
2007-09-02 15:49:11 +00:00
continue;
if( field->IsVoid() )
2007-09-02 15:49:11 +00:00
continue;
EDA_Rect BoundaryBox = field->GetBoundaryBox();
2009-01-02 13:19:34 +00:00
if( BoundaryBox.Inside( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = field;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
}
}
else
{
#undef STRUCT
2008-03-20 01:50:21 +00:00
#define STRUCT ( (SCH_COMPONENT*) DrawList )
2007-09-02 15:49:11 +00:00
EDA_Rect BoundaryBox = STRUCT->GetBoundaryBox();
2009-01-02 13:19:34 +00:00
if( BoundaryBox.Inside( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
}
break;
case DRAW_SHEET_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_SHEET*) DrawList )
2007-09-02 15:49:11 +00:00
if( !(SearchMask & SHEETITEM) )
break;
if( STRUCT->HitTest( aPosRef ) )
2007-09-02 15:49:11 +00:00
{
LastSnappedStruct = DrawList;
2009-11-28 09:24:37 +00:00
return true;
2007-09-02 15:49:11 +00:00
}
break;
default:
{
wxString msg;
msg.Printf( wxT( "SnapPoint2() error: unexpected struct type %d (" ),
DrawList->Type() );
msg << DrawList->GetClass() << wxT( ")" );
2009-08-01 19:26:05 +00:00
wxMessageBox( msg );
2007-09-02 15:49:11 +00:00
break;
}
}
}
return FALSE;
}
/*****************************************************************************
* Routine to test if an object has non empty intersection with the box *
2009-11-28 09:24:37 +00:00
* 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. *
*****************************************************************************/
2009-11-28 09:24:37 +00:00
bool IsItemInBox( EDA_Rect& aBox, SCH_ITEM* DrawStruct )
{
2009-11-28 09:24:37 +00:00
EDA_Rect BoundaryBox;
2007-09-02 15:49:11 +00:00
switch( DrawStruct->Type() )
{
case DRAW_POLYLINE_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_POLYLINE*) DrawStruct )
for( unsigned i = 0; i < STRUCT->GetCornerCount(); i++ )
2007-09-02 15:49:11 +00:00
{
2009-11-28 09:24:37 +00:00
if( aBox.Inside(STRUCT->m_PolyPoints[i]) )
return true;
2007-09-02 15:49:11 +00:00
}
break;
case DRAW_SEGMENT_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_LINE*) DrawStruct )
2009-11-28 09:24:37 +00:00
if( aBox.Inside(STRUCT->m_Start) )
return true;
if( aBox.Inside(STRUCT->m_End) )
return true;
2007-09-02 15:49:11 +00:00
break;
case DRAW_BUSENTRY_STRUCT_TYPE:
#undef STRUCT
#define STRUCT ( (SCH_BUS_ENTRY*) DrawStruct )
2009-11-28 09:24:37 +00:00
if( aBox.Inside(STRUCT->m_Pos) )
return true;
if( aBox.Inside(STRUCT->m_End() ) )
return true;
2007-09-02 15:49:11 +00:00
break;
case DRAW_JUNCTION_STRUCT_TYPE:
#undef STRUCT
2010-01-17 20:25:10 +00:00
#define STRUCT ( (SCH_JUNCTION*) DrawStruct )
if( aBox.Inside(STRUCT->m_Pos) )
return true;
break;
2010-01-17 20:25:10 +00:00
2007-09-02 15:49:11 +00:00
case DRAW_NOCONNECT_STRUCT_TYPE:
2008-03-20 01:50:21 +00:00
case TYPE_SCH_LABEL:
case TYPE_SCH_TEXT:
case TYPE_SCH_HIERLABEL:
case TYPE_SCH_GLOBALLABEL:
2007-09-02 15:49:11 +00:00
case DRAW_SHEET_STRUCT_TYPE:
case TYPE_SCH_MARKER:
2009-11-28 09:24:37 +00:00
BoundaryBox = DrawStruct->GetBoundingBox();
if( aBox.Intersects( BoundaryBox ) )
return true;
2007-09-02 15:49:11 +00:00
break;
case TYPE_SCH_COMPONENT:
// Use a more restrictive area than GetBoundingBox()
// Area is restricted to the body area, excludint fields outside this area
BoundaryBox = ((SCH_COMPONENT*)DrawStruct)->GetBoundaryBox();
if( aBox.Intersects( BoundaryBox ) )
return true;
break;
2008-04-15 19:38:19 +00:00
case DRAW_HIERARCHICAL_PIN_SHEET_STRUCT_TYPE:
2007-09-02 15:49:11 +00:00
break;
default:
2009-11-28 09:24:37 +00:00
{
wxString msg;
msg.Printf( wxT( "IsItemInBox() Err: unexpected StructType %d (" ),
DrawStruct->Type() );
msg << DrawStruct->GetClass() << wxT( ")" );
2009-08-01 19:26:05 +00:00
wxMessageBox( msg );
2007-09-02 15:49:11 +00:00
break;
}
2009-11-28 09:24:37 +00:00
}
2007-09-02 15:49:11 +00:00
return FALSE;
}
SCH_SHEET_PIN* LocateSheetLabel( SCH_SHEET* Sheet, const wxPoint& pos )
{
return Sheet->GetLabel( pos );
}
2007-09-02 15:49:11 +00:00
LIB_PIN* LocateAnyPin( SCH_ITEM* DrawList, const wxPoint& RefPos, SCH_COMPONENT** libpart )
{
SCH_ITEM* DrawStruct;
LIB_COMPONENT* Entry;
SCH_COMPONENT* schItem = NULL;
LIB_PIN* Pin = NULL;
2007-09-02 15:49:11 +00:00
for( DrawStruct = DrawList; DrawStruct != NULL;
DrawStruct = DrawStruct->Next() )
2007-09-02 15:49:11 +00:00
{
2008-03-20 01:50:21 +00:00
if( DrawStruct->Type() != TYPE_SCH_COMPONENT )
2007-09-02 15:49:11 +00:00
continue;
schItem = (SCH_COMPONENT*) DrawStruct;
Entry = CMP_LIBRARY::FindLibraryComponent( schItem->m_ChipName );
2007-09-02 15:49:11 +00:00
if( Entry == NULL )
continue;
/* we use LocateDrawItem to locate pins. but this function suppose a
* component.
2009-10-06 13:52:43 +00:00
* at 0,0 location
* So we must calculate the ref position relative to the component
*/
wxPoint libPos = RefPos - schItem->m_Pos;
Pin = (LIB_PIN*) Entry->LocateDrawItem( schItem->m_Multi,
schItem->m_Convert,
COMPONENT_PIN_DRAW_TYPE,
libPos, schItem->m_Transform );
2007-09-02 15:49:11 +00:00
if( Pin )
break;
}
if( libpart )
*libpart = schItem;
2007-09-02 15:49:11 +00:00
return Pin;
}
2007-09-02 15:49:11 +00:00
SCH_SHEET_PIN* LocateAnyPinSheet( const wxPoint& RefPos, SCH_ITEM* DrawList )
{
SCH_ITEM* DrawStruct;
SCH_SHEET_PIN* PinSheet = NULL;
2007-09-02 15:49:11 +00:00
for( DrawStruct = DrawList; DrawStruct != NULL;
DrawStruct = DrawStruct->Next() )
2007-09-02 15:49:11 +00:00
{
if( DrawStruct->Type() != DRAW_SHEET_STRUCT_TYPE )
continue;
PinSheet = LocateSheetLabel( (SCH_SHEET*) DrawStruct, RefPos );
2007-09-02 15:49:11 +00:00
if( PinSheet )
break;
}
return PinSheet;
}