1087 lines
32 KiB
C++
1087 lines
32 KiB
C++
/****************************************************/
|
||
/* class_module.cpp : fonctions de la classe MODULE */
|
||
/****************************************************/
|
||
|
||
#include "fctsys.h"
|
||
#include "gr_basic.h"
|
||
#include "wxstruct.h"
|
||
#include "common.h"
|
||
#include "plot_common.h"
|
||
#include "class_drawpanel.h"
|
||
#include "trigo.h"
|
||
#include "confirm.h"
|
||
#include "kicad_string.h"
|
||
#include "pcbcommon.h"
|
||
|
||
#include "pcbnew.h"
|
||
#include "class_board_design_settings.h"
|
||
|
||
#include "autorout.h"
|
||
#include "drag.h"
|
||
|
||
#include "3d_struct.h"
|
||
#include "protos.h"
|
||
|
||
|
||
/*************************************************/
|
||
/* Class MODULE : description d'un composant pcb */
|
||
/*************************************************/
|
||
MODULE::MODULE( BOARD* parent ) :
|
||
BOARD_ITEM( parent, TYPE_MODULE )
|
||
{
|
||
m_Attributs = MOD_DEFAULT;
|
||
m_Layer = CMP_N;
|
||
m_Orient = 0;
|
||
m_ModuleStatus = 0;
|
||
flag = 0;
|
||
m_CntRot90 = m_CntRot180 = 0;
|
||
m_Surface = 0;
|
||
m_Link = 0;
|
||
m_LastEdit_Time = time( NULL );
|
||
m_LocalClearance = 0;
|
||
m_LocalSolderMaskMargin = 0;
|
||
m_LocalSolderPasteMargin = 0;
|
||
m_LocalSolderPasteMarginRatio = 0.0;
|
||
|
||
m_Reference = new TEXTE_MODULE( this, TEXT_is_REFERENCE );
|
||
|
||
m_Value = new TEXTE_MODULE( this, TEXT_is_VALUE );
|
||
|
||
// Reserve one void 3D entry, to avoid problems with void list
|
||
m_3D_Drawings.PushBack( new S3D_MASTER( this ) );
|
||
}
|
||
|
||
|
||
MODULE::~MODULE()
|
||
{
|
||
delete m_Reference;
|
||
delete m_Value;
|
||
}
|
||
|
||
|
||
/*********************************************************************************/
|
||
void MODULE::DrawAncre( WinEDA_DrawPanel* panel, wxDC* DC, const wxPoint& offset,
|
||
int dim_ancre, int draw_mode )
|
||
/*********************************************************************************/
|
||
|
||
/* trace de l'ancre (croix verticale)
|
||
* (doit etre fait apres les pads,
|
||
* car le trace du trou efface tout donc peut etre l'ancre */
|
||
{
|
||
int anchor_size = panel->GetScreen()->Unscale( dim_ancre );
|
||
|
||
GRSetDrawMode( DC, draw_mode );
|
||
|
||
if( g_DesignSettings.IsElementVisible( ANCHOR_VISIBLE ) )
|
||
{
|
||
GRLine( &panel->m_ClipBox, DC,
|
||
m_Pos.x - offset.x - anchor_size, m_Pos.y - offset.y,
|
||
m_Pos.x - offset.x + anchor_size, m_Pos.y - offset.y,
|
||
0, g_AnchorColor );
|
||
GRLine( &panel->m_ClipBox, DC,
|
||
m_Pos.x - offset.x, m_Pos.y - offset.y - anchor_size,
|
||
m_Pos.x - offset.x, m_Pos.y - offset.y + anchor_size,
|
||
0, g_AnchorColor );
|
||
}
|
||
}
|
||
|
||
|
||
/*********************************/
|
||
void MODULE::Copy( MODULE* aModule )
|
||
/*********************************/
|
||
{
|
||
m_Pos = aModule->m_Pos;
|
||
m_Layer = aModule->m_Layer;
|
||
m_LibRef = aModule->m_LibRef;
|
||
m_Attributs = aModule->m_Attributs;
|
||
m_Orient = aModule->m_Orient;
|
||
m_BoundaryBox = aModule->m_BoundaryBox;
|
||
m_PadNum = aModule->m_PadNum;
|
||
m_CntRot90 = aModule->m_CntRot90;
|
||
m_CntRot180 = aModule->m_CntRot180;
|
||
m_LastEdit_Time = aModule->m_LastEdit_Time;
|
||
m_Path = aModule->m_Path; //is this correct behavior?
|
||
m_TimeStamp = GetTimeStamp();
|
||
m_LocalSolderMaskMargin = aModule->m_LocalSolderMaskMargin;
|
||
m_LocalSolderPasteMargin = aModule->m_LocalSolderPasteMargin;
|
||
m_LocalSolderPasteMarginRatio = aModule->m_LocalSolderPasteMarginRatio;
|
||
|
||
/* Copy des structures auxiliaires: Reference et value */
|
||
m_Reference->Copy( aModule->m_Reference );
|
||
m_Value->Copy( aModule->m_Value );
|
||
|
||
/* Copy auxiliary data: Pads */
|
||
m_Pads.DeleteAll();
|
||
for( D_PAD* pad = aModule->m_Pads; pad; pad = pad->Next() )
|
||
{
|
||
D_PAD* newpad = new D_PAD( this );
|
||
newpad->Copy( pad );
|
||
|
||
m_Pads.PushBack( newpad );
|
||
}
|
||
|
||
/* Copy auxiliary data: Drawings */
|
||
m_Drawings.DeleteAll();
|
||
for( BOARD_ITEM* item = aModule->m_Drawings; item; item = item->Next() )
|
||
{
|
||
switch( item->Type() )
|
||
{
|
||
case TYPE_TEXTE_MODULE:
|
||
TEXTE_MODULE * textm;
|
||
textm = new TEXTE_MODULE( this );
|
||
textm->Copy( (TEXTE_MODULE*) item );
|
||
m_Drawings.PushBack( textm );
|
||
break;
|
||
|
||
case TYPE_EDGE_MODULE:
|
||
EDGE_MODULE * edge;
|
||
edge = new EDGE_MODULE( this );
|
||
edge->Copy( (EDGE_MODULE*) item );
|
||
m_Drawings.PushBack( edge );
|
||
break;
|
||
|
||
default:
|
||
wxMessageBox( wxT( "MODULE::Copy() Internal Err: unknown type" ) );
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Copy auxiliary data: 3D_Drawings info */
|
||
m_3D_Drawings.DeleteAll();
|
||
|
||
// Ensure there is one (or more) item in m_3D_Drawings
|
||
m_3D_Drawings.PushBack( new S3D_MASTER( this ) ); // push a void item
|
||
for( S3D_MASTER* item = aModule->m_3D_Drawings; item; item = item->Next() )
|
||
{
|
||
if( item->m_Shape3DName.IsEmpty() ) // do not copy empty shapes.
|
||
continue;
|
||
S3D_MASTER* t3d = m_3D_Drawings;
|
||
if( t3d && t3d->m_Shape3DName.IsEmpty() ) // The first entry can exist, but is empty : use it.
|
||
t3d->Copy( item );
|
||
else
|
||
{
|
||
t3d = new S3D_MASTER( this );
|
||
t3d->Copy( item );
|
||
m_3D_Drawings.PushBack( t3d );
|
||
}
|
||
}
|
||
|
||
/* Copie des elements complementaires */
|
||
m_Doc = aModule->m_Doc;
|
||
m_KeyWord = aModule->m_KeyWord;
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
void MODULE::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
|
||
int draw_mode, const wxPoint& offset )
|
||
/**********************************************************/
|
||
|
||
/** Function Draw
|
||
* Draws the footprint to the current Device Context
|
||
* @param panel = The active Draw Panel (used to know the clip box)
|
||
* @param DC = current Device Context
|
||
* @param offset = draw offset (usually wxPoint(0,0)
|
||
* @param draw_mode = GR_OR, GR_XOR, GR_AND
|
||
*/
|
||
{
|
||
if( (m_Flags & DO_NOT_DRAW) )
|
||
return;
|
||
|
||
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
|
||
{
|
||
if( pad->m_Flags & IS_MOVED )
|
||
continue;
|
||
|
||
pad->Draw( panel, DC, draw_mode, offset );
|
||
}
|
||
|
||
// Draws foootprint anchor
|
||
DrawAncre( panel, DC, offset, DIM_ANCRE_MODULE, draw_mode );
|
||
|
||
/* Draw graphic items */
|
||
if( !(m_Reference->m_Flags & IS_MOVED) )
|
||
m_Reference->Draw( panel, DC, draw_mode, offset );
|
||
|
||
if( !(m_Value->m_Flags & IS_MOVED) )
|
||
m_Value->Draw( panel, DC, draw_mode, offset );
|
||
|
||
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
|
||
{
|
||
if( item->m_Flags & IS_MOVED )
|
||
continue;
|
||
|
||
switch( item->Type() )
|
||
{
|
||
case TYPE_TEXTE_MODULE:
|
||
case TYPE_EDGE_MODULE:
|
||
item->Draw( panel, DC, draw_mode, offset );
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**************************************************************/
|
||
void MODULE::DrawEdgesOnly( WinEDA_DrawPanel* panel, wxDC* DC,
|
||
const wxPoint& offset, int draw_mode )
|
||
/**************************************************************/
|
||
|
||
/** Function DrawEdgesOnly
|
||
* Draws the footprint edges only to the current Device Context
|
||
* @param panel = The active Draw Panel (used to know the clip box)
|
||
* @param DC = current Device Context
|
||
* @param offset = draw offset (usually wxPoint(0,0)
|
||
* @param draw_mode = GR_OR, GR_XOR, GR_AND
|
||
*/
|
||
{
|
||
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
|
||
{
|
||
switch( item->Type() )
|
||
{
|
||
case TYPE_EDGE_MODULE:
|
||
item->Draw( panel, DC, draw_mode, offset );
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**************************************/
|
||
bool MODULE::Save( FILE* aFile ) const
|
||
/**************************************/
|
||
{
|
||
char statusTxt[8];
|
||
BOARD_ITEM* item;
|
||
|
||
if( GetState( DELETED ) )
|
||
return true;
|
||
|
||
bool rc = false;
|
||
|
||
fprintf( aFile, "$MODULE %s\n", CONV_TO_UTF8( m_LibRef ) );
|
||
|
||
// Generation des coord et caracteristiques
|
||
memset( statusTxt, 0, sizeof(statusTxt) );
|
||
if( IsLocked() )
|
||
statusTxt[0] = 'F';
|
||
else
|
||
statusTxt[0] = '~';
|
||
|
||
if( m_ModuleStatus & MODULE_is_PLACED )
|
||
statusTxt[1] = 'P';
|
||
else
|
||
statusTxt[1] = '~';
|
||
|
||
fprintf( aFile, "Po %d %d %d %d %8.8lX %8.8lX %s\n",
|
||
m_Pos.x, m_Pos.y,
|
||
m_Orient, m_Layer, m_LastEdit_Time,
|
||
m_TimeStamp, statusTxt );
|
||
|
||
fprintf( aFile, "Li %s\n", CONV_TO_UTF8( m_LibRef ) );
|
||
|
||
if( !m_Doc.IsEmpty() )
|
||
{
|
||
fprintf( aFile, "Cd %s\n", CONV_TO_UTF8( m_Doc ) );
|
||
}
|
||
|
||
if( !m_KeyWord.IsEmpty() )
|
||
{
|
||
fprintf( aFile, "Kw %s\n", CONV_TO_UTF8( m_KeyWord ) );
|
||
}
|
||
|
||
fprintf( aFile, "Sc %8.8lX\n", m_TimeStamp );
|
||
fprintf( aFile, "AR %s\n", CONV_TO_UTF8( m_Path ) );
|
||
fprintf( aFile, "Op %X %X 0\n", m_CntRot90, m_CntRot180 );
|
||
if( m_LocalSolderMaskMargin != 0 )
|
||
fprintf( aFile, ".SolderMask %d\n",m_LocalSolderMaskMargin );
|
||
if( m_LocalSolderPasteMargin != 0 )
|
||
fprintf( aFile, ".SolderPaste %d\n",m_LocalSolderPasteMargin);
|
||
if( m_LocalSolderPasteMarginRatio != 0)
|
||
fprintf( aFile, ".SolderPasteRatio %g\n",m_LocalSolderPasteMarginRatio);
|
||
|
||
// attributes
|
||
if( m_Attributs != MOD_DEFAULT )
|
||
{
|
||
fprintf( aFile, "At " );
|
||
if( m_Attributs & MOD_CMS )
|
||
fprintf( aFile, "SMD " );
|
||
if( m_Attributs & MOD_VIRTUAL )
|
||
fprintf( aFile, "VIRTUAL " );
|
||
fprintf( aFile, "\n" );
|
||
}
|
||
|
||
// save reference
|
||
if( !m_Reference->Save( aFile ) )
|
||
goto out;
|
||
|
||
// save value
|
||
if( !m_Value->Save( aFile ) )
|
||
goto out;
|
||
|
||
// save drawing elements
|
||
for( item = m_Drawings; item; item = item->Next() )
|
||
{
|
||
switch( item->Type() )
|
||
{
|
||
case TYPE_TEXTE_MODULE:
|
||
case TYPE_EDGE_MODULE:
|
||
if( !item->Save( aFile ) )
|
||
goto out;
|
||
break;
|
||
|
||
default:
|
||
#if defined(DEBUG)
|
||
printf( "MODULE::Save() ignoring type %d\n", item->Type() );
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
|
||
// save the pads
|
||
for( item = m_Pads; item; item = item->Next() )
|
||
if( !item->Save( aFile ) )
|
||
goto out;
|
||
|
||
// Generation des informations de trac<61>3D
|
||
Write_3D_Descr( aFile );
|
||
|
||
fprintf( aFile, "$EndMODULE %s\n", CONV_TO_UTF8( m_LibRef ) );
|
||
|
||
rc = true;
|
||
out:
|
||
return rc;
|
||
}
|
||
|
||
|
||
/***************************************/
|
||
int MODULE::Write_3D_Descr( FILE* File ) const
|
||
/***************************************/
|
||
|
||
/* Sauvegarde de la description 3D du MODULE
|
||
*/
|
||
{
|
||
char buf[512];
|
||
|
||
for( S3D_MASTER* t3D = m_3D_Drawings; t3D; t3D = t3D->Next() )
|
||
{
|
||
if( !t3D->m_Shape3DName.IsEmpty() )
|
||
{
|
||
fprintf( File, "$SHAPE3D\n" );
|
||
|
||
fprintf( File, "Na \"%s\"\n", CONV_TO_UTF8( t3D->m_Shape3DName ) );
|
||
|
||
sprintf( buf, "Sc %lf %lf %lf\n",
|
||
t3D->m_MatScale.x,
|
||
t3D->m_MatScale.y,
|
||
t3D->m_MatScale.z );
|
||
fprintf( File, "%s", to_point( buf ) );
|
||
|
||
sprintf( buf, "Of %lf %lf %lf\n",
|
||
t3D->m_MatPosition.x,
|
||
t3D->m_MatPosition.y,
|
||
t3D->m_MatPosition.z );
|
||
fprintf( File, "%s", to_point( buf ) );
|
||
|
||
sprintf( buf, "Ro %lf %lf %lf\n",
|
||
t3D->m_MatRotation.x,
|
||
t3D->m_MatRotation.y,
|
||
t3D->m_MatRotation.z );
|
||
fprintf( File, "%s", to_point( buf ) );
|
||
|
||
fprintf( File, "$EndSHAPE3D\n" );
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/****************************************************/
|
||
int MODULE::Read_3D_Descr( FILE* File, int* LineNum )
|
||
/****************************************************/
|
||
|
||
/* Lecture de la description d'un MODULE (format Ascii)
|
||
* la 1ere ligne de descr ($MODULE) est supposee etre deja lue
|
||
* retourne 0 si OK
|
||
*/
|
||
{
|
||
char Line[1024];
|
||
char* text = Line + 3;
|
||
|
||
S3D_MASTER* t3D = m_3D_Drawings;
|
||
|
||
if( !t3D->m_Shape3DName.IsEmpty() )
|
||
{
|
||
S3D_MASTER* n3D = new S3D_MASTER( this );
|
||
|
||
m_3D_Drawings.PushBack( n3D );
|
||
|
||
t3D = n3D;
|
||
}
|
||
|
||
while( GetLine( File, Line, LineNum, sizeof(Line) - 1 ) != NULL )
|
||
{
|
||
switch( Line[0] )
|
||
{
|
||
case '$': // Fin de description
|
||
if( Line[1] == 'E' )
|
||
return 0;
|
||
return 1;
|
||
|
||
case 'N': // Shape File Name
|
||
{
|
||
char buf[512];
|
||
ReadDelimitedText( buf, text, 512 );
|
||
t3D->m_Shape3DName = CONV_FROM_UTF8( buf );
|
||
break;
|
||
}
|
||
|
||
case 'S': // Scale
|
||
sscanf( text, "%lf %lf %lf\n",
|
||
&t3D->m_MatScale.x,
|
||
&t3D->m_MatScale.y,
|
||
&t3D->m_MatScale.z );
|
||
break;
|
||
|
||
case 'O': // Offset
|
||
sscanf( text, "%lf %lf %lf\n",
|
||
&t3D->m_MatPosition.x,
|
||
&t3D->m_MatPosition.y,
|
||
&t3D->m_MatPosition.z );
|
||
break;
|
||
|
||
case 'R': // Rotation
|
||
sscanf( text, "%lf %lf %lf\n",
|
||
&t3D->m_MatRotation.x,
|
||
&t3D->m_MatRotation.y,
|
||
&t3D->m_MatRotation.z );
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
/**************************************************/
|
||
int MODULE::ReadDescr( FILE* File, int* LineNum )
|
||
/**************************************************/
|
||
|
||
/* Read a MODULE description
|
||
* The first description line ($MODULE) is already read
|
||
* @return 0 if no error
|
||
*/
|
||
{
|
||
char Line[256], BufLine[256], BufCar1[128], * PtLine;
|
||
int itmp1, itmp2;
|
||
|
||
while( GetLine( File, Line, LineNum, sizeof(Line) - 1 ) != NULL )
|
||
{
|
||
if( Line[0] == '$' )
|
||
{
|
||
if( Line[1] == 'E' )
|
||
break;
|
||
if( Line[1] == 'P' )
|
||
{
|
||
D_PAD* pad = new D_PAD( this );
|
||
pad->ReadDescr( File, LineNum );
|
||
RotatePoint( &pad->m_Pos.x, &pad->m_Pos.y, m_Orient );
|
||
pad->m_Pos.x += m_Pos.x;
|
||
pad->m_Pos.y += m_Pos.y;
|
||
|
||
m_Pads.PushBack( pad );
|
||
continue;
|
||
}
|
||
if( Line[1] == 'S' )
|
||
Read_3D_Descr( File, LineNum );
|
||
}
|
||
|
||
if( strlen( Line ) < 4 )
|
||
continue;
|
||
|
||
PtLine = Line + 3;
|
||
|
||
/* Decode the first code of the current line and read the correspondint data
|
||
*/
|
||
switch( Line[0] )
|
||
{
|
||
case 'P':
|
||
memset( BufCar1, 0, sizeof(BufCar1) );
|
||
sscanf( PtLine, "%d %d %d %d %lX %lX %s",
|
||
&m_Pos.x, &m_Pos.y,
|
||
&m_Orient, &m_Layer,
|
||
&m_LastEdit_Time, &m_TimeStamp, BufCar1 );
|
||
|
||
m_ModuleStatus = 0;
|
||
if( BufCar1[0] == 'F' )
|
||
SetLocked( true );
|
||
if( BufCar1[1] == 'P' )
|
||
m_ModuleStatus |= MODULE_is_PLACED;
|
||
break;
|
||
|
||
case 'L': /* Li = read the library name of the footprint */
|
||
*BufLine = 0;
|
||
sscanf( PtLine, " %s", BufLine );
|
||
m_LibRef = CONV_FROM_UTF8( BufLine );
|
||
break;
|
||
|
||
case 'S':
|
||
sscanf( PtLine, " %lX", &m_TimeStamp );
|
||
break;
|
||
|
||
|
||
case 'O': /* (Op)tions for auto placement */
|
||
itmp1 = itmp2 = 0;
|
||
sscanf( PtLine, " %X %X", &itmp1, &itmp2 );
|
||
|
||
m_CntRot180 = itmp2 & 0x0F;
|
||
if( m_CntRot180 > 10 )
|
||
m_CntRot180 = 10;
|
||
|
||
m_CntRot90 = itmp1 & 0x0F;
|
||
if( m_CntRot90 > 10 )
|
||
m_CntRot90 = 0;
|
||
itmp1 = (itmp1 >> 4) & 0x0F;
|
||
if( itmp1 > 10 )
|
||
itmp1 = 0;
|
||
m_CntRot90 |= itmp1 << 4;
|
||
break;
|
||
|
||
case 'A':
|
||
if( Line[1] == 't' )
|
||
{
|
||
/* At = (At)tributes of module */
|
||
if( strstr( PtLine, "SMD" ) )
|
||
m_Attributs |= MOD_CMS;
|
||
if( strstr( PtLine, "VIRTUAL" ) )
|
||
m_Attributs |= MOD_VIRTUAL;
|
||
}
|
||
if( Line[1] == 'R' )
|
||
{
|
||
//alternate reference, e.g. /478C2408/478AD1B6
|
||
sscanf( PtLine, " %s", BufLine );
|
||
m_Path = CONV_FROM_UTF8( BufLine );
|
||
}
|
||
break;
|
||
|
||
case 'T': /* Read a footprint text description (ref, value, or drawing */
|
||
TEXTE_MODULE * textm;
|
||
sscanf( Line + 1, "%d", &itmp1 );
|
||
if( itmp1 == TEXT_is_REFERENCE )
|
||
textm = m_Reference;
|
||
else if( itmp1 == TEXT_is_VALUE )
|
||
textm = m_Value;
|
||
else /* text is a drawing */
|
||
{
|
||
textm = new TEXTE_MODULE( this );
|
||
m_Drawings.PushBack( textm );
|
||
}
|
||
textm->ReadDescr( Line, File, LineNum );
|
||
break;
|
||
|
||
case 'D': /* read a drawing item */
|
||
EDGE_MODULE * edge;
|
||
edge = new EDGE_MODULE( this );
|
||
m_Drawings.PushBack( edge );
|
||
edge->ReadDescr( Line, File, LineNum );
|
||
edge->SetDrawCoord();
|
||
break;
|
||
|
||
case 'C': /* read documentation data */
|
||
m_Doc = CONV_FROM_UTF8( StrPurge( PtLine ) );
|
||
break;
|
||
|
||
case 'K': /* Read key words */
|
||
m_KeyWord = CONV_FROM_UTF8( StrPurge( PtLine ) );
|
||
break;
|
||
|
||
case '.': /* Read specific data */
|
||
if( strnicmp(Line, ".SolderMask ", 12 ) == 0 )
|
||
m_LocalSolderMaskMargin = atoi(Line+12);
|
||
else if( strnicmp(Line, ".SolderPaste ", 13) == 0 )
|
||
m_LocalSolderPasteMargin = atoi(Line+13);
|
||
else if( strnicmp(Line, ".SolderPasteRatio ", 18) == 0 )
|
||
m_LocalSolderPasteMarginRatio = atof(Line+18);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
/* Recalculate the bounding box */
|
||
Set_Rectangle_Encadrement();
|
||
return 0;
|
||
}
|
||
|
||
|
||
/************************************************/
|
||
void MODULE::Set_Rectangle_Encadrement()
|
||
/************************************************/
|
||
|
||
/* Mise a jour du rectangle d'encadrement du module
|
||
* Entree : pointeur sur module
|
||
* Le rectangle d'encadrement est le rectangle comprenant les contours et les
|
||
* pads.
|
||
* Le rectangle est calcule:
|
||
* pour orient 0
|
||
* en coord relatives / position ancre
|
||
*/
|
||
{
|
||
int width;
|
||
int cx, cy, uxf, uyf, rayon;
|
||
int xmax, ymax;
|
||
|
||
|
||
/* Init des pointeurs */
|
||
/* Init des coord du cadre a une valeur limite non nulle */
|
||
m_BoundaryBox.m_Pos.x = -500; xmax = 500;
|
||
m_BoundaryBox.m_Pos.y = -500; ymax = 500;
|
||
|
||
/* Contours: Recherche des coord min et max et mise a jour du cadre */
|
||
for( EDGE_MODULE* pt_edge_mod = (EDGE_MODULE*) m_Drawings.GetFirst();
|
||
pt_edge_mod; pt_edge_mod = pt_edge_mod->Next() )
|
||
{
|
||
if( pt_edge_mod->Type() != TYPE_EDGE_MODULE )
|
||
continue;
|
||
|
||
width = pt_edge_mod->m_Width / 2;
|
||
|
||
switch( pt_edge_mod->m_Shape )
|
||
{
|
||
case S_ARC:
|
||
case S_CIRCLE:
|
||
{
|
||
cx = pt_edge_mod->m_Start0.x; cy = pt_edge_mod->m_Start0.y; // centre
|
||
uxf = pt_edge_mod->m_End0.x; uyf = pt_edge_mod->m_End0.y;
|
||
rayon = (int) hypot( (double) (cx - uxf), (double) (cy - uyf) );
|
||
rayon += width;
|
||
m_BoundaryBox.m_Pos.x = MIN( m_BoundaryBox.m_Pos.x, cx - rayon );
|
||
m_BoundaryBox.m_Pos.y = MIN( m_BoundaryBox.m_Pos.y, cy - rayon );
|
||
xmax = MAX( xmax, cx + rayon );
|
||
ymax = MAX( ymax, cy + rayon );
|
||
break;
|
||
}
|
||
|
||
default:
|
||
m_BoundaryBox.m_Pos.x = MIN( m_BoundaryBox.m_Pos.x, pt_edge_mod->m_Start0.x - width );
|
||
m_BoundaryBox.m_Pos.x = MIN( m_BoundaryBox.m_Pos.x, pt_edge_mod->m_End0.x - width );
|
||
m_BoundaryBox.m_Pos.y = MIN( m_BoundaryBox.m_Pos.y, pt_edge_mod->m_Start0.y - width );
|
||
m_BoundaryBox.m_Pos.y = MIN( m_BoundaryBox.m_Pos.y, pt_edge_mod->m_End0.y - width );
|
||
xmax = MAX( xmax, pt_edge_mod->m_Start0.x + width );
|
||
xmax = MAX( xmax, pt_edge_mod->m_End0.x + width );
|
||
ymax = MAX( ymax, pt_edge_mod->m_Start0.y + width );
|
||
ymax = MAX( ymax, pt_edge_mod->m_End0.y + width );
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Pads: Recherche des coord min et max et mise a jour du cadre */
|
||
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
|
||
{
|
||
rayon = pad->m_Rayon;
|
||
cx = pad->m_Pos0.x; cy = pad->m_Pos0.y;
|
||
m_BoundaryBox.m_Pos.x = MIN( m_BoundaryBox.m_Pos.x, cx - rayon );
|
||
m_BoundaryBox.m_Pos.y = MIN( m_BoundaryBox.m_Pos.y, cy - rayon );
|
||
xmax = MAX( xmax, cx + rayon );
|
||
ymax = MAX( ymax, cy + rayon );
|
||
}
|
||
|
||
m_BoundaryBox.SetWidth( xmax - m_BoundaryBox.m_Pos.x );
|
||
m_BoundaryBox.SetHeight( ymax - m_BoundaryBox.m_Pos.y );
|
||
}
|
||
|
||
|
||
/****************************************/
|
||
void MODULE::SetRectangleExinscrit()
|
||
/****************************************/
|
||
|
||
/* Analogue a MODULE::Set_Rectangle_Encadrement() mais en coord reelles:
|
||
* Mise a jour du rectangle d'encadrement reel du module c.a.d en coord PCB
|
||
* Entree : pointeur sur module
|
||
* Le rectangle d'encadrement est le rectangle comprenant les contours et les
|
||
* pads.
|
||
* Met egalement a jour la surface (.m_Surface) du module.
|
||
*/
|
||
{
|
||
int width;
|
||
int cx, cy, uxf, uyf, rayon;
|
||
int xmax, ymax;
|
||
|
||
m_RealBoundaryBox.m_Pos.x = xmax = m_Pos.x;
|
||
m_RealBoundaryBox.m_Pos.y = ymax = m_Pos.y;
|
||
|
||
/* Contours: Recherche des coord min et max et mise a jour du cadre */
|
||
for( EDGE_MODULE* edge = (EDGE_MODULE*) m_Drawings.GetFirst(); edge; edge = edge->Next() )
|
||
{
|
||
if( edge->Type() != TYPE_EDGE_MODULE )
|
||
continue;
|
||
|
||
width = edge->m_Width / 2;
|
||
|
||
switch( edge->m_Shape )
|
||
{
|
||
case S_ARC:
|
||
case S_CIRCLE:
|
||
{
|
||
cx = edge->m_Start.x; cy = edge->m_Start.y; // centre
|
||
uxf = edge->m_End.x; uyf = edge->m_End.y;
|
||
rayon = (int) hypot( (double) (cx - uxf), (double) (cy - uyf) );
|
||
rayon += width;
|
||
m_RealBoundaryBox.m_Pos.x = MIN( m_RealBoundaryBox.m_Pos.x, cx - rayon );
|
||
m_RealBoundaryBox.m_Pos.y = MIN( m_RealBoundaryBox.m_Pos.y, cy - rayon );
|
||
xmax = MAX( xmax, cx + rayon );
|
||
ymax = MAX( ymax, cy + rayon );
|
||
break;
|
||
}
|
||
|
||
default:
|
||
m_RealBoundaryBox.m_Pos.x = MIN( m_RealBoundaryBox.m_Pos.x, edge->m_Start.x - width );
|
||
m_RealBoundaryBox.m_Pos.x = MIN( m_RealBoundaryBox.m_Pos.x, edge->m_End.x - width );
|
||
m_RealBoundaryBox.m_Pos.y = MIN( m_RealBoundaryBox.m_Pos.y, edge->m_Start.y - width );
|
||
m_RealBoundaryBox.m_Pos.y = MIN( m_RealBoundaryBox.m_Pos.y, edge->m_End.y - width );
|
||
xmax = MAX( xmax, edge->m_Start.x + width );
|
||
xmax = MAX( xmax, edge->m_End.x + width );
|
||
ymax = MAX( ymax, edge->m_Start.y + width );
|
||
ymax = MAX( ymax, edge->m_End.y + width );
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Pads: Recherche des coord min et max et mise a jour du cadre */
|
||
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
|
||
{
|
||
rayon = pad->m_Rayon;
|
||
|
||
cx = pad->m_Pos.x;
|
||
cy = pad->m_Pos.y;
|
||
|
||
m_RealBoundaryBox.m_Pos.x = MIN( m_RealBoundaryBox.m_Pos.x, cx - rayon );
|
||
m_RealBoundaryBox.m_Pos.y = MIN( m_RealBoundaryBox.m_Pos.y, cy - rayon );
|
||
|
||
xmax = MAX( xmax, cx + rayon );
|
||
ymax = MAX( ymax, cy + rayon );
|
||
}
|
||
|
||
m_RealBoundaryBox.SetWidth( xmax - m_RealBoundaryBox.m_Pos.x );
|
||
m_RealBoundaryBox.SetHeight( ymax - m_RealBoundaryBox.m_Pos.y );
|
||
m_Surface = ABS( (float) m_RealBoundaryBox.GetWidth() * m_RealBoundaryBox.GetHeight() );
|
||
}
|
||
|
||
|
||
/**
|
||
* Function GetBoundingBox
|
||
* returns the full bounding box of this Footprint, including texts
|
||
* Mainly used to redraw the screen area occuped by the footprint
|
||
*/
|
||
EDA_Rect MODULE::GetBoundingBox()
|
||
{
|
||
// Calculate area without text fields:
|
||
SetRectangleExinscrit();
|
||
EDA_Rect area = m_RealBoundaryBox;
|
||
|
||
// Calculate extended area including text field:
|
||
EDA_Rect text_area;
|
||
text_area = m_Reference->GetBoundingBox();
|
||
area.Merge( text_area );
|
||
|
||
text_area = m_Value->GetBoundingBox();
|
||
area.Merge( text_area );
|
||
|
||
for( EDGE_MODULE* edge = (EDGE_MODULE*) m_Drawings.GetFirst(); edge; edge = edge->Next() )
|
||
{
|
||
if( edge->Type() != TYPE_TEXTE_MODULE )
|
||
continue;
|
||
text_area = ( (TEXTE_MODULE*) edge )->GetBoundingBox();
|
||
area.Merge( text_area );
|
||
}
|
||
|
||
// Add the Clearence shape size: (shape around the pads when the clearence is shown
|
||
// Not optimized, but the draw cost is small (perhaps smaller than optimization)
|
||
int biggest_clearance = GetBoard()->GetBiggestClearanceValue();
|
||
area.Inflate( biggest_clearance );
|
||
|
||
return area;
|
||
}
|
||
|
||
|
||
/*******************************************************/
|
||
void MODULE::DisplayInfo( WinEDA_DrawFrame* frame )
|
||
/*******************************************************/
|
||
|
||
/* Virtual function, from EDA_BaseStruct.
|
||
* display module info on MsgPanel
|
||
*/
|
||
{
|
||
int nbpad;
|
||
char bufcar[512], Line[512];
|
||
bool flag = FALSE;
|
||
wxString msg;
|
||
BOARD* board = (BOARD*) m_Parent;
|
||
|
||
frame->EraseMsgBox();
|
||
if( frame->m_Ident != PCB_FRAME )
|
||
flag = TRUE;
|
||
|
||
frame->AppendMsgPanel( m_Reference->m_Text, m_Value->m_Text,
|
||
DARKCYAN );
|
||
|
||
if( flag ) // Display last date the component was edited( useful in Module Editor)
|
||
{
|
||
time_t edit_time = m_LastEdit_Time;
|
||
strcpy( Line, ctime( &edit_time ) );
|
||
strtok( Line, " \n\r" );
|
||
strcpy( bufcar, strtok( NULL, " \n\r" ) ); strcat( bufcar, " " );
|
||
strcat( bufcar, strtok( NULL, " \n\r" ) ); strcat( bufcar, ", " );
|
||
strtok( NULL, " \n\r" );
|
||
strcat( bufcar, strtok( NULL, " \n\r" ) );
|
||
msg = CONV_FROM_UTF8( bufcar );
|
||
frame->AppendMsgPanel( _( "Last Change" ), msg, BROWN );
|
||
}
|
||
else // displa time stamp in schematic
|
||
{
|
||
msg.Printf( wxT( "%8.8lX" ), m_TimeStamp );
|
||
frame->AppendMsgPanel( _( "Netlist path" ), m_Path, BROWN );
|
||
}
|
||
|
||
frame->AppendMsgPanel( _( "Layer" ), board->GetLayerName( m_Layer ), RED );
|
||
|
||
EDA_BaseStruct* PtStruct = m_Pads;
|
||
nbpad = 0;
|
||
while( PtStruct )
|
||
{
|
||
nbpad++;
|
||
PtStruct = PtStruct->Next();
|
||
}
|
||
|
||
msg.Printf( wxT( "%d" ), nbpad );
|
||
frame->AppendMsgPanel( _( "Pads" ), msg, BLUE );
|
||
|
||
msg = wxT( ".." );
|
||
if( IsLocked() )
|
||
msg[0] = 'L';
|
||
if( m_ModuleStatus & MODULE_is_PLACED )
|
||
msg[1] = 'P';
|
||
frame->AppendMsgPanel( _( "Stat" ), msg, MAGENTA );
|
||
|
||
msg.Printf( wxT( "%.1f" ), (float) m_Orient / 10 );
|
||
frame->AppendMsgPanel( _( "Orient" ), msg, BROWN );
|
||
|
||
frame->AppendMsgPanel( _( "Module" ), m_LibRef, BLUE );
|
||
|
||
if( m_3D_Drawings != NULL )
|
||
msg = m_3D_Drawings->m_Shape3DName;
|
||
else
|
||
msg = _( "No 3D shape" );
|
||
frame->AppendMsgPanel( _( "3D-Shape" ), msg, RED );
|
||
|
||
wxString doc = _( "Doc: " ) + m_Doc;
|
||
wxString keyword = _( "KeyW: " ) + m_KeyWord;
|
||
frame->AppendMsgPanel( doc, keyword, BLACK );
|
||
}
|
||
|
||
|
||
/**
|
||
* Function HitTest
|
||
* tests if the given wxPoint is within the bounds of this object.
|
||
* @param refPos A wxPoint to test
|
||
* @return bool - true if a hit, else false
|
||
*/
|
||
bool MODULE::HitTest( const wxPoint& refPos )
|
||
{
|
||
/* Calcul des coord souris dans le repere module */
|
||
int spot_cX = refPos.x - m_Pos.x;
|
||
int spot_cY = refPos.y - m_Pos.y;
|
||
|
||
RotatePoint( &spot_cX, &spot_cY, -m_Orient );
|
||
|
||
/* la souris est-elle dans ce rectangle : */
|
||
if( m_BoundaryBox.Inside( spot_cX, spot_cY ) )
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
/**
|
||
* Function HitTest (overlayed)
|
||
* tests if the given EDA_Rect intersect the bounds of this object.
|
||
* @param refArea : the given EDA_Rect
|
||
* @return bool - true if a hit, else false
|
||
*/
|
||
bool MODULE::HitTest( EDA_Rect& refArea )
|
||
{
|
||
bool is_out_of_box = false;
|
||
|
||
SetRectangleExinscrit();
|
||
|
||
if( m_RealBoundaryBox.m_Pos.x < refArea.GetX() )
|
||
is_out_of_box = true;
|
||
if( m_RealBoundaryBox.m_Pos.y < refArea.GetY() )
|
||
is_out_of_box = true;
|
||
if( m_RealBoundaryBox.GetRight() > refArea.GetRight() )
|
||
is_out_of_box = true;
|
||
if( m_RealBoundaryBox.GetBottom() > refArea.GetBottom() )
|
||
is_out_of_box = true;
|
||
|
||
return is_out_of_box ? false : true;
|
||
}
|
||
|
||
|
||
D_PAD* MODULE::FindPadByName( const wxString& aPadName ) const
|
||
{
|
||
wxString buf;
|
||
|
||
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
|
||
{
|
||
pad->ReturnStringPadName( buf );
|
||
#if 1
|
||
if( buf.CmpNoCase( aPadName ) == 0 ) // why case insensitive?
|
||
#else
|
||
if( buf == aPadName )
|
||
#endif
|
||
|
||
|
||
return pad;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
// see class_module.h
|
||
SEARCH_RESULT MODULE::Visit( INSPECTOR* inspector, const void* testData,
|
||
const KICAD_T scanTypes[] )
|
||
{
|
||
KICAD_T stype;
|
||
SEARCH_RESULT result = SEARCH_CONTINUE;
|
||
const KICAD_T* p = scanTypes;
|
||
bool done = false;
|
||
|
||
#if 0 && defined(DEBUG)
|
||
std::cout << GetClass().mb_str() << ' ';
|
||
#endif
|
||
|
||
while( !done )
|
||
{
|
||
stype = *p;
|
||
|
||
switch( stype )
|
||
{
|
||
case TYPE_MODULE:
|
||
result = inspector->Inspect( this, testData ); // inspect me
|
||
++p;
|
||
break;
|
||
|
||
case TYPE_PAD:
|
||
result = IterateForward( m_Pads, inspector, testData, p );
|
||
++p;
|
||
break;
|
||
|
||
case TYPE_TEXTE_MODULE:
|
||
result = inspector->Inspect( m_Reference, testData );
|
||
if( result == SEARCH_QUIT )
|
||
break;
|
||
|
||
result = inspector->Inspect( m_Value, testData );
|
||
if( result == SEARCH_QUIT )
|
||
break;
|
||
|
||
// m_Drawings can hold TYPETEXTMODULE also, so fall thru
|
||
|
||
case TYPE_EDGE_MODULE:
|
||
result = IterateForward( m_Drawings, inspector, testData, p );
|
||
|
||
// skip over any types handled in the above call.
|
||
for( ; ; )
|
||
{
|
||
switch( stype = *++p )
|
||
{
|
||
case TYPE_TEXTE_MODULE:
|
||
case TYPE_EDGE_MODULE:
|
||
continue;
|
||
|
||
default:
|
||
;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
done = true;
|
||
break;
|
||
}
|
||
|
||
if( result == SEARCH_QUIT )
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
#if defined(DEBUG)
|
||
|
||
/**
|
||
* Function Show
|
||
* is used to output the object tree, currently for debugging only.
|
||
* @param nestLevel An aid to prettier tree indenting, and is the level
|
||
* of nesting of this object within the overall tree.
|
||
* @param os The ostream& to output to.
|
||
*/
|
||
void MODULE::Show( int nestLevel, std::ostream& os )
|
||
{
|
||
BOARD* board = (BOARD*) m_Parent;
|
||
|
||
// for now, make it look like XML, expand on this later.
|
||
NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
|
||
" ref=\"" << m_Reference->m_Text.mb_str() << '"' <<
|
||
" value=\"" << m_Value->m_Text.mb_str() << '"' <<
|
||
" layer=\"" << board->GetLayerName( m_Layer ).mb_str() << '"' <<
|
||
">\n";
|
||
|
||
NestedSpace( nestLevel + 1, os ) <<
|
||
"<boundingBox" << m_BoundaryBox.m_Pos << m_BoundaryBox.m_Size << "/>\n";
|
||
|
||
NestedSpace( nestLevel + 1, os ) << "<orientation tenths=\"" << m_Orient << "\"/>\n";
|
||
|
||
EDA_BaseStruct* p;
|
||
|
||
NestedSpace( nestLevel + 1, os ) << "<mpads>\n";
|
||
p = m_Pads;
|
||
for( ; p; p = p->Next() )
|
||
p->Show( nestLevel + 2, os );
|
||
|
||
NestedSpace( nestLevel + 1, os ) << "</mpads>\n";
|
||
|
||
NestedSpace( nestLevel + 1, os ) << "<mdrawings>\n";
|
||
p = m_Drawings;
|
||
for( ; p; p = p->Next() )
|
||
p->Show( nestLevel + 2, os );
|
||
|
||
NestedSpace( nestLevel + 1, os ) << "</mdrawings>\n";
|
||
|
||
p = m_Son;
|
||
for( ; p; p = p->Next() )
|
||
{
|
||
p->Show( nestLevel + 1, os );
|
||
}
|
||
|
||
NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
|
||
}
|
||
|
||
|
||
#endif
|