kicad/eeschema/eelibs_draw_components.cpp

611 lines
19 KiB
C++

/****************************************/
/* Modules to handle component drawing. */
/****************************************/
#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "program.h"
#include "libcmp.h"
#include "component_class.h"
#include "general.h"
#include "trigo.h"
#include "protos.h"
//#define DRAW_ARC_WITH_ANGLE // Used to select function to draw arcs
/* Local functions */
/* Descr component <DUMMY> used when a component is not found in library,
* to draw a dummy shape
* This component is a 400 mils square with the text ??
* DEF DUMMY U 0 40 Y Y 1 0 N
* F0 "U" 0 -350 60 H V
* F1 "DUMMY" 0 350 60 H V
* DRAW
* T 0 0 0 150 0 0 0 ??
* S -200 200 200 -200 0 1 0
* ENDDRAW
* ENDDEF
*/
static void CreateDummyCmp();
static void DrawLibPartAux( WinEDA_DrawPanel * panel, wxDC * DC,
SCH_COMPONENT * Component,
EDA_LibComponentStruct * Entry,
const wxPoint &Pos,
int TransMat[2][2],
int Multi, int convert,
int DrawMode, int Color = -1, bool DrawPinText = TRUE );
/* Local variables */
static EDA_LibComponentStruct* DummyCmp;
/***************************************************************************/
wxPoint TransformCoordinate( int aTransformMatrix[2][2], wxPoint& aPosition )
/***************************************************************************/
/** Function TransformCoordinate
* Calculate the wew coordinate from the old one, according to the transform matrix.
* @param aTransformMatrix = rotation, mirror .. matrix
* @param aPosition = the position to transform
* @return the new coordinate
*/
{
wxPoint new_pos;
new_pos.x = (aTransformMatrix[0][0] * aPosition.x) + (aTransformMatrix[0][1] * aPosition.y);
new_pos.y = (aTransformMatrix[1][0] * aPosition.x) + (aTransformMatrix[1][1] * aPosition.y);
return new_pos;
}
/******************************/
void CreateDummyCmp()
/******************************/
{
DummyCmp = new EDA_LibComponentStruct( NULL );
LibDrawSquare* Square = new LibDrawSquare();
Square->m_Pos = wxPoint( -200, 200 );
Square->m_End = wxPoint( 200, -200 );
Square->m_Width = 4;
LibDrawText* Text = new LibDrawText();
Text->m_Size.x = Text->m_Size.y = 150;
Text->m_Text = wxT( "??" );
DummyCmp->m_Drawings = Square;
Square->Pnext = Text;
}
/*************************************************************/
void DrawLibEntry( WinEDA_DrawPanel* panel, wxDC* DC,
EDA_LibComponentStruct* LibEntry,
const wxPoint & aOffset,
int Multi, int convert,
int DrawMode, int Color )
/**************************************************************/
/* Routine de dessin d'un composant d'une librairie
* LibEntry = pointeur sur la description en librairie
* posX, posY = position du composant
* DrawMode = GrOR ..
* Color = 0 : dessin en vraies couleurs, sinon couleur = Color
*
* Une croix symbolise le point d'accrochage (ref position) du composant
*
* Le composant est toujours trace avec orientation 0
*/
{
int color;
int TransMat[2][2];
wxString Prefix;
LibDrawField* Field;
wxPoint text_pos;
/* Orientation normale */
TransMat[0][0] = 1; TransMat[1][1] = -1;
TransMat[1][0] = TransMat[0][1] = 0;
DrawLibPartAux( panel, DC, NULL, LibEntry, aOffset,
TransMat, Multi,
convert, DrawMode, Color );
/* Trace des 2 champs ref et value (Attention aux coord: la matrice
* de transformation change de signe les coord Y */
GRSetDrawMode( DC, DrawMode );
if( LibEntry->m_Prefix.m_Attributs & TEXT_NO_VISIBLE )
{
if( Color >= 0 )
color = Color;
else
color = g_InvisibleItemColor;
}
else color = Color;
if( LibEntry->m_UnitCount > 1 )
#if defined(KICAD_GOST)
Prefix.Printf( wxT( "%s?.%c" ), LibEntry->m_Prefix.m_Text.GetData(), Multi + '1' - 1);
#else
Prefix.Printf( wxT( "%s?%c" ), LibEntry->m_Prefix.m_Text.GetData(), Multi + 'A' - 1 );
#endif
else
Prefix = LibEntry->m_Prefix.m_Text + wxT( "?" );
if( (LibEntry->m_Prefix.m_Flags & IS_MOVED) == 0 )
LibEntry->m_Prefix.Draw( panel, DC, aOffset, color, DrawMode, &Prefix, TransMat );
if( LibEntry->m_Name.m_Attributs & TEXT_NO_VISIBLE )
{
if( Color >= 0 )
color = Color;
else
color = g_InvisibleItemColor;
}
else color = Color;
if( (LibEntry->m_Name.m_Flags & IS_MOVED) == 0 )
LibEntry->m_Name.Draw( panel, DC, aOffset, color, DrawMode, NULL, TransMat );
for( Field = LibEntry->Fields; Field != NULL; Field = (LibDrawField*) Field->Pnext )
{
if( Field->m_Text.IsEmpty() )
return;
if( (Field->m_Flags & IS_MOVED) != 0 )
continue;
if( Field->m_Attributs & TEXT_NO_VISIBLE )
{
if( Color >= 0 )
color = Color;
else
color = g_InvisibleItemColor;
}
else color = Color;
Field->Draw( panel, DC, aOffset, color, DrawMode, NULL, TransMat );
}
// Trace de l'ancre
int len = 3 * panel->GetZoom();
GRLine( &panel->m_ClipBox, DC, aOffset.x, aOffset.y - len, aOffset.x, aOffset.y + len, 0, color );
GRLine( &panel->m_ClipBox, DC, aOffset.x - len, aOffset.y, aOffset.x + len, aOffset.y, 0, color );
}
/*****************************************************************************
* Routine to draw the given part at given position, transformed/mirror as *
* specified, and in the given drawing mode. Only this one is visible... *
*****************************************************************************/
void SCH_COMPONENT::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
const wxPoint& offset, int DrawMode, int Color )
{
EDA_LibComponentStruct* Entry;
int ii;
bool dummy = FALSE;
if( ( Entry = FindLibPart( m_ChipName.GetData(), wxEmptyString, FIND_ROOT ) ) == NULL )
{
/* composant non trouve, on affiche un composant "dummy" */
dummy = TRUE;
if( DummyCmp == NULL )
CreateDummyCmp();
Entry = DummyCmp;
}
DrawLibPartAux( panel, DC, this, Entry, m_Pos + offset,
m_Transform,
dummy ? 0 : m_Multi,
dummy ? 0 : m_Convert,
DrawMode );
/* Trace des champs, avec placement et orientation selon orient. du
* composant
*/
SCH_CMP_FIELD* field = GetField( REFERENCE );
if( ( (field->m_Attributs & TEXT_NO_VISIBLE) == 0 )
&& !(field->m_Flags & IS_MOVED) )
{
if( Entry->m_UnitCount > 1 )
{
field->m_AddExtraText = true;
field->Draw( panel, DC, offset, DrawMode );
}
else
{
field->m_AddExtraText = false;
field->Draw( panel, DC, offset, DrawMode );
}
}
for( ii = VALUE; ii < GetFieldCount(); ii++ )
{
field = GetField( ii );
if( field->m_Flags & IS_MOVED )
continue;
field->Draw( panel, DC, offset, DrawMode );
}
}
/***********************************************************/
void SCH_CMP_FIELD::Draw( WinEDA_DrawPanel* panel,
wxDC* DC,
const wxPoint& offset,
int DrawMode,
int Color )
/***********************************************************/
/* Routine de trace des textes type Field du composant.
* entree:
* DrawMode: mode de trace
*/
{
int orient, color;
wxPoint pos; /* Position des textes */
SCH_COMPONENT* DrawLibItem = (SCH_COMPONENT*) m_Parent;
int hjustify, vjustify;
int LineWidth = MAX( m_Width, g_DrawMinimunLineWidth );
if( m_Attributs & TEXT_NO_VISIBLE )
return;
if( IsVoid() )
return;
GRSetDrawMode( DC, DrawMode );
/* Calcul de la position des textes, selon orientation du composant */
orient = m_Orient;
hjustify = m_HJustify; vjustify = m_VJustify;
pos = m_Pos - DrawLibItem->m_Pos;
pos = DrawLibItem->GetScreenCoord( pos );
pos += DrawLibItem->m_Pos;
/* Y a t-il rotation (pour l'orientation, la justification)*/
if( DrawLibItem->m_Transform[0][1] ) // Rotation du composant de 90deg
{
if( orient == TEXT_ORIENT_HORIZ )
orient = TEXT_ORIENT_VERT;
else
orient = TEXT_ORIENT_HORIZ;
/* Y a t-il rotation, miroir (pour les justifications)*/
EXCHG( hjustify, vjustify );
if( DrawLibItem->m_Transform[1][0] < 0 )
vjustify = -vjustify;
if( DrawLibItem->m_Transform[1][0] > 0 )
hjustify = -hjustify;
}
else
{
/* Texte horizontal: Y a t-il miroir (pour les justifications)*/
if( DrawLibItem->m_Transform[0][0] < 0 )
hjustify = -hjustify;
if( DrawLibItem->m_Transform[1][1] > 0 )
vjustify = -vjustify;
}
if( m_FieldId == REFERENCE )
color = ReturnLayerColor( LAYER_REFERENCEPART );
else if( m_FieldId == VALUE )
color = ReturnLayerColor( LAYER_VALUEPART );
else
color = ReturnLayerColor( LAYER_FIELDS );
if( !m_AddExtraText || (m_FieldId != REFERENCE) )
{
DrawGraphicText( panel, DC, pos, color, m_Text.GetData(),
orient ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ,
m_Size,
hjustify, vjustify, LineWidth );
}
else // Si il y a plusieurs parts par boitier, ajouter a la reference l'identification de la selection ( A, B ... )
{
/* On ajoute alors A ou B ... a la reference */
wxString fulltext = m_Text;
#if defined(KICAD_GOST)
fulltext.Append( '.');
fulltext.Append( '1' - 1 + DrawLibItem->m_Multi );
#else
fulltext.Append( 'A' - 1 + DrawLibItem->m_Multi );
#endif
DrawGraphicText( panel, DC, pos, color, fulltext.GetData(),
orient ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ,
m_Size,
hjustify, vjustify, LineWidth );
}
}
/********************************************************************************/
EDA_LibComponentStruct* FindLibPart( const wxChar* Name, const wxString& LibName, int Alias )
/********************************************************************************/
/*
* Routine to find a part in one of the libraries given its name.
* Name = Name of part.
* LibName = Name of Lib; if "": seach in all libs
* Alias = Flag: si flag != 0, retourne un pointeur sur une part ou un alias
* si flag = 0, retourne un pointeur sur une part meme si le nom
* correspond a un alias
* Alias = FIND_ROOT, ou Alias = FIND_ALIAS
*/
{
EDA_LibComponentStruct* Entry;
static EDA_LibComponentStruct DummyEntry( wxEmptyString ); /* Used only to call PQFind. */
LibraryStruct* Lib = g_LibraryList;
DummyEntry.m_Drawings = NULL; /* Used only to call PQFind. */
DummyEntry.m_Name.m_Text = Name;
PQCompFunc( (PQCompFuncType) LibraryEntryCompare );
Entry = NULL;
FindLibName.Empty();
while( Lib )
{
if( !LibName.IsEmpty() )
{
if( Lib->m_Name != LibName )
{
Lib = Lib->m_Pnext;
continue;
}
}
if( Lib == NULL )
break;
Entry = (EDA_LibComponentStruct*) PQFind( Lib->m_Entries, &DummyEntry );
if( Entry != NULL )
{
FindLibName = Lib->m_Name;
break;
}
Lib = Lib->m_Pnext;
}
/* Si le nom est un alias, recherche du vrai composant */
if( Entry )
{
if( (Entry->Type != ROOT ) && (Alias == FIND_ROOT) )
Entry = FindLibPart( ( (EDA_LibCmpAliasStruct*) Entry )->m_RootName.GetData(),
Lib->m_Name, FIND_ROOT );
}
return Entry;
}
/*****************************************************************************
* Routine to draw the given part at given position, transformed/mirror as
* specified, and in the given drawing mode.
* if Color < 0: Draw in normal color
* else draw in color = Color
*****************************************************************************/
/* DrawMode = GrXOR, GrOR ..*/
void DrawLibPartAux( WinEDA_DrawPanel* panel, wxDC* DC,
SCH_COMPONENT* Component,
EDA_LibComponentStruct* Entry,
const wxPoint& Pos,
int TransMat[2][2],
int Multi, int convert, int DrawMode,
int Color, bool DrawPinText )
{
wxPoint pos1, pos2;
LibEDA_BaseStruct* DEntry;
bool force_nofill;
if( Entry->m_Drawings == NULL )
return;
GRSetDrawMode( DC, DrawMode );
for( DEntry = Entry->m_Drawings; DEntry != NULL; DEntry = DEntry->Next() )
{
/* Do not draw items not attached to the current part */
if( Multi && DEntry->m_Unit && (DEntry->m_Unit != Multi) )
continue;
if( convert && DEntry->m_Convert && (DEntry->m_Convert != convert) )
continue;
if( DEntry->m_Flags & IS_MOVED )
continue; // Do do draw here an item while moving (the cursor handler does that)
force_nofill = false;
switch( DEntry->Type() )
{
case COMPONENT_PIN_DRAW_TYPE:
{
DrawPinPrms prms( Entry, DrawPinText );
DEntry->Draw( panel, DC, Pos, Color, DrawMode, &prms, TransMat );
}
break;
case COMPONENT_ARC_DRAW_TYPE:
case COMPONENT_CIRCLE_DRAW_TYPE:
case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
case COMPONENT_RECT_DRAW_TYPE:
case COMPONENT_POLYLINE_DRAW_TYPE:
default:
if( g_IsPrinting && DEntry->m_Fill == FILLED_WITH_BG_BODYCOLOR
&& GetGRForceBlackPenState() )
force_nofill = true;
DEntry->Draw( panel, DC, Pos, Color, DrawMode, (void*) force_nofill, TransMat );
break;
}
}
if( g_DebugLevel > 4 ) /* Draw the component boundary box */
{
EDA_Rect BoundaryBox;
if( Component )
BoundaryBox = Component->GetBoundaryBox();
else
BoundaryBox = Entry->GetBoundaryBox( Multi, convert );
int x1 = BoundaryBox.GetX();
int y1 = BoundaryBox.GetY();
int x2 = BoundaryBox.GetRight();
int y2 = BoundaryBox.GetBottom();
GRRect( &panel->m_ClipBox, DC, x1, y1, x2, y2, BROWN );
BoundaryBox = Component->GetField( REFERENCE )->GetBoundaryBox();
x1 = BoundaryBox.GetX();
y1 = BoundaryBox.GetY();
x2 = BoundaryBox.GetRight();
y2 = BoundaryBox.GetBottom();
GRRect( &panel->m_ClipBox, DC, x1, y1, x2, y2, BROWN );
BoundaryBox = Component->GetField( VALUE )->GetBoundaryBox();
x1 = BoundaryBox.GetX();
y1 = BoundaryBox.GetY();
x2 = BoundaryBox.GetRight();
y2 = BoundaryBox.GetBottom();
GRRect( &panel->m_ClipBox, DC, x1, y1, x2, y2, BROWN );
}
}
/*****************************************************************************
* Routine to rotate the given angular direction by the given Transformation. *
* Input (and output) angles must be as follows: *
* Unit is 0.1 degre *
* Angle1 in [0..3600], Angle2 > Angle1 in [0..7200]. Arc is assumed to be less *
* than 180.0 degrees. *
* Algorithm: *
* Map the angles to a point on the unit circle which is mapped using the *
* transform (only mirror and rotate so it remains on the unit circle) to *
* a new point which is used to detect new angle. *
*****************************************************************************/
bool MapAngles( int* Angle1, int* Angle2, int TransMat[2][2] )
{
int Angle, Delta;
double x, y, t;
bool swap = FALSE;
Delta = *Angle2 - *Angle1;
if( Delta >= 1800 )
{
*Angle1 -= 1;
*Angle2 += 1;
}
x = cos( *Angle1 * M_PI / 1800.0 );
y = sin( *Angle1 * M_PI / 1800.0 );
t = x * TransMat[0][0] + y * TransMat[0][1];
y = x * TransMat[1][0] + y * TransMat[1][1];
x = t;
*Angle1 = (int) (atan2( y, x ) * 1800.0 / M_PI + 0.5);
x = cos( *Angle2 * M_PI / 1800.0 );
y = sin( *Angle2 * M_PI / 1800.0 );
t = x * TransMat[0][0] + y * TransMat[0][1];
y = x * TransMat[1][0] + y * TransMat[1][1];
x = t;
*Angle2 = (int) (atan2( y, x ) * 1800.0 / M_PI + 0.5);
NORMALIZE_ANGLE( *Angle1 );
NORMALIZE_ANGLE( *Angle2 );
if( *Angle2 < *Angle1 )
*Angle2 += 3600;
if( *Angle2 - *Angle1 > 1800 )
{ /* Need to swap the two angles. */
Angle = (*Angle1);
*Angle1 = (*Angle2);
*Angle2 = Angle;
NORMALIZE_ANGLE( *Angle1 );
NORMALIZE_ANGLE( *Angle2 );
if( *Angle2 < *Angle1 )
*Angle2 += 3600;
swap = TRUE;
}
if( Delta >= 1800 )
{
*Angle1 += 1;
*Angle2 -= 1;
}
return swap;
}
/*****************************************************************************
* Routine to display an outline version of given library entry. *
* This routine is applied by the PlaceLibItem routine above. *
*****************************************************************************/
void DrawingLibInGhost( WinEDA_DrawPanel* panel, wxDC* DC,
EDA_LibComponentStruct* LibEntry,
SCH_COMPONENT* DrawLibItem, int PartX, int PartY,
int multi, int convert, int Color, bool DrawPinText )
{
int DrawMode = g_XorMode;
DrawLibPartAux( panel, DC, DrawLibItem, LibEntry, wxPoint( PartX, PartY ),
DrawLibItem->m_Transform,
multi, convert, DrawMode, Color, DrawPinText );
}
/************************************************************/
/* Routine to draw One LibraryDrawStruct at given position, */
/* matrice de transformation 1 0 0 -1 (normale) */
/* DrawMode = GrXOR, GrOR .. */
/************************************************************/
/* Utilise en LibEdit et Lib Browse */
void DrawLibraryDrawStruct( WinEDA_DrawPanel* aPanel, wxDC* aDC,
EDA_LibComponentStruct* aLibEntry,
wxPoint aPosition,
LibEDA_BaseStruct* aDrawItem,
int aDrawMode, int aColor )
{
int TransMat[2][2];
bool no_fill;
GRSetDrawMode( aDC, aDrawMode );
TransMat[0][0] = 1;
TransMat[0][1] = TransMat[1][0] = 0;
TransMat[1][1] = -1;
no_fill = false;
switch( aDrawItem->Type() )
{
case COMPONENT_PIN_DRAW_TYPE: /* Trace des Pins */
{
DrawPinPrms prms( aLibEntry, true );
aDrawItem->Draw( aPanel, aDC, aPosition, aColor, aDrawMode, &prms, TransMat );
}
break;
case COMPONENT_ARC_DRAW_TYPE:
case COMPONENT_CIRCLE_DRAW_TYPE:
case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
case COMPONENT_RECT_DRAW_TYPE:
case COMPONENT_POLYLINE_DRAW_TYPE:
default:
if( g_IsPrinting && aDrawItem->m_Fill == FILLED_WITH_BG_BODYCOLOR
&& GetGRForceBlackPenState() )
no_fill = true;
aDrawItem->Draw( aPanel, aDC, aPosition, aColor, aDrawMode, (void*) no_fill, TransMat );
break;
}
}