kicad/pcbnew/gen_modules_placefile.cpp

496 lines
16 KiB
C++
Raw Normal View History

2007-08-23 04:28:46 +00:00
/*************************************/
/* fichier gen_modules_placefile.cpp */
/*************************************/
/*
2007-08-23 04:28:46 +00:00
* 1 - create ascii files for automatic placement of smd components
* 2 - create a module report (pos and module descr) (ascii file)
*/
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
#include "trigo.h"
2007-08-23 04:28:46 +00:00
class LIST_MOD /* Permet de lister les elements utiles des modules */
{
public:
2007-08-23 04:28:46 +00:00
MODULE* m_Module;
const wxChar* m_Reference;
const wxChar* m_Value;
};
/* variables locale : */
2007-08-23 04:28:46 +00:00
static wxPoint File_Place_Offset; /* Offset des coord de placement pour le fichier g<>n<EFBFBD>r<EFBFBD> */
/* Routines Locales */
2007-08-23 04:28:46 +00:00
static void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile );
/* Routine de tri utilisee par GenereModulesPosition() */
2007-08-23 04:28:46 +00:00
static int ListeModCmp( LIST_MOD* Ref, LIST_MOD* Cmp )
{
2007-08-23 04:28:46 +00:00
return StrLenNumCmp( Ref->m_Reference, Cmp->m_Reference, 16 );
}
#if defined(DEBUG)
/**
* Function HasNonSMDPins
* returns true if the given module has any non smd pins, such as through hole
* and therefore cannot be placed automatically.
*/
static bool HasNonSMDPins( MODULE* aModule )
{
D_PAD* pad;
for( pad = aModule->m_Pads; pad; pad = pad->Next() )
{
if( pad->m_Attribut != PAD_SMD )
return true;
}
return false;
}
#endif
/**************************************************************/
2007-08-23 04:28:46 +00:00
void WinEDA_PcbFrame::GenModulesPosition( wxCommandEvent& event )
/**************************************************************/
2007-08-23 04:28:46 +00:00
/* Routine de generation du fichier de positionnement des modules,
2007-08-23 04:28:46 +00:00
* utilis<EFBFBD> pour les machines de placement de composants
*/
{
2007-08-23 04:28:46 +00:00
float conv_unit;
int NbMod, ii;
bool GenCu = FALSE;
MODULE* Module;
LIST_MOD* Liste;
char Line[1024], Buff[80];
wxString NameLayerCu, NameLayerCmp, msg;
FILE* LayerCu = NULL, * LayerCmp = NULL;
/* Calcul des echelles de conversion */
conv_unit = 0.0001; /* unites = INCHES */
// if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
2007-08-23 04:28:46 +00:00
File_Place_Offset = m_Auxiliary_Axis_Position;
/* Calcul du nombre de modules utiles ( Attribut CMS, non VIRTUAL ) ) */
NbMod = 0;
for( Module = m_Pcb->m_Modules; Module; Module = Module->Next() )
2007-08-23 04:28:46 +00:00
{
if( Module->m_Attributs & MOD_VIRTUAL )
{
D(printf("skipping module %s because its virtual\n", CONV_TO_UTF8(Module->GetReference()) );)
2007-08-23 04:28:46 +00:00
continue;
}
2007-08-23 04:28:46 +00:00
if( (Module->m_Attributs & MOD_CMS) == 0 )
{
#if 0 && defined(DEBUG) // enable this code to fix a bunch of mis-labeled modules:
if( !HasNonSMDPins( Module ) )
Module->m_Attributs |= MOD_CMS; // all pins are SMD, fix the problem
else
{
printf( "skipping %s because its attribute is not CMS and it has non SMD pins\n", CONV_TO_UTF8(Module->GetReference()) );
continue;
}
#else
2007-08-23 04:28:46 +00:00
continue;
#endif
}
if( Module->GetLayer() == COPPER_LAYER_N )
2007-08-23 04:28:46 +00:00
GenCu = TRUE;
NbMod++;
}
if( NbMod == 0 )
{
DisplayError( this, _( "No Modules for Automated Placement" ), 20 ); return;
}
/* Init nom fichier */
NameLayerCmp = GetScreen()->m_FileName;
2007-08-23 04:28:46 +00:00
ChangeFileNameExt( NameLayerCmp, wxT( "-cmp.pos" ) );
LayerCmp = wxFopen( NameLayerCmp, wxT( "wt" ) );
if( LayerCmp == 0 )
{
msg = _( "Unable to create " ) + NameLayerCu;
DisplayError( this, msg ); return;
}
if( GenCu )
{
NameLayerCu = GetScreen()->m_FileName;
2007-08-23 04:28:46 +00:00
ChangeFileNameExt( NameLayerCu, wxT( "-copper.pos" ) );
LayerCu = wxFopen( NameLayerCu, wxT( "wt" ) );
if( LayerCu == 0 )
{
msg = _( "Unable to create " ) + NameLayerCu;
DisplayError( this, msg );
fclose( LayerCmp );
return;
}
}
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
setlocale( LC_NUMERIC, "C" );
/* Affichage du bilan : */
MsgPanel->EraseMsgBox();
Affiche_1_Parametre( this, 0, _( "Component side place file:" ), NameLayerCmp, BLUE );
if( GenCu )
Affiche_1_Parametre( this, 32, _( "Copper side place file:" ), NameLayerCu, BLUE );
msg.Empty(); msg << NbMod;
Affiche_1_Parametre( this, 65, _( "Module count" ), msg, RED );
/* Etablissement de la liste des modules par ordre alphabetique */
Liste = (LIST_MOD*) MyZMalloc( NbMod * sizeof(LIST_MOD) );
Module = m_Pcb->m_Modules;
for( ii = 0; Module; Module = Module->Next() )
2007-08-23 04:28:46 +00:00
{
if( Module->m_Attributs & MOD_VIRTUAL )
continue;
if( (Module->m_Attributs & MOD_CMS) == 0 )
continue;
Liste[ii].m_Module = Module;
Liste[ii].m_Reference = Module->m_Reference->m_Text;
Liste[ii].m_Value = Module->m_Value->m_Text;
ii++;
}
qsort( Liste, NbMod, sizeof(LIST_MOD),
( int( * ) ( const void*, const void* ) )ListeModCmp );
/* Generation entete du fichier 'commentaires) */
sprintf( Line, "### Module positions - created on %s ###\n",
DateAndTime( Buff ) );
fputs( Line, LayerCmp );
if( GenCu )
fputs( Line, LayerCu );
wxString Title = g_Main_Title + wxT( " " ) + GetBuildVersion();
sprintf( Line, "### Printed by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
fputs( Line, LayerCmp );
if( GenCu )
fputs( Line, LayerCu );
sprintf( Line, "## Unit = inches, Angle = deg.\n" );
fputs( Line, LayerCmp );
if( GenCu )
fputs( Line, LayerCu );
sprintf( Line, "## Side : Components\n" );
fputs( Line, LayerCmp );
if( GenCu )
{
sprintf( Line, "## Side : Copper\n" );
fputs( Line, LayerCu );
}
sprintf( Line,
"# Ref Val PosX PosY Rot Side\n" );
fputs( Line, LayerCmp );
if( GenCu )
fputs( Line, LayerCu );
/* Generation lignes utiles du fichier */
for( ii = 0; ii < NbMod; ii++ )
{
wxPoint module_pos;
wxString ref = Liste[ii].m_Reference;
wxString val = Liste[ii].m_Value;
sprintf( Line, "%-8.8s %-16.16s ", CONV_TO_UTF8( ref ), CONV_TO_UTF8( val ) );
module_pos = Liste[ii].m_Module->m_Pos;
module_pos.x -= File_Place_Offset.x;
module_pos.y -= File_Place_Offset.y;
char* text = Line + strlen( Line );
sprintf( text, " %9.4f %9.4f %8.1f ",
(float) module_pos.x * conv_unit,
(float) module_pos.y * conv_unit,
(float) Liste[ii].m_Module->m_Orient / 10 );
if( Liste[ii].m_Module->GetLayer() == CMP_N )
{
strcat( Line, "Cmp.\n" );
fputs( Line, LayerCmp );
}
else if( Liste[ii].m_Module->GetLayer() == COPPER_LAYER_N )
2007-08-23 04:28:46 +00:00
{
strcat( Line, "Cu\n" );
fputs( Line, LayerCu );
}
}
/* Generation fin du fichier */
fputs( "## End\n", LayerCmp );
fclose( LayerCmp );
if( GenCu )
{
fputs( "## End\n", LayerCu );
fclose( LayerCu );
}
MyFree( Liste );
setlocale( LC_NUMERIC, "" ); // revert to the current locale
msg = wxT( "Cmp File: " ) + NameLayerCmp;
if( GenCu )
msg += wxT( "\nCu File: " ) + NameLayerCu;
DisplayInfo( this, msg );
}
/**************************************************************/
2007-08-23 04:28:46 +00:00
void WinEDA_PcbFrame::GenModuleReport( wxCommandEvent& event )
/**************************************************************/
2007-08-23 04:28:46 +00:00
/* Print a module report.
2007-08-23 04:28:46 +00:00
*/
{
2007-08-23 04:28:46 +00:00
float conv_unit;
MODULE* Module;
D_PAD* pad;
char Line[1024], Buff[80];
wxString FullFileName, NameLayerCmp, msg;
FILE* rptfile;
wxPoint module_pos;
/* Calcul des echelles de conversion */
conv_unit = 0.0001; /* unites = INCHES */
// if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
2007-08-23 04:28:46 +00:00
File_Place_Offset = wxPoint( 0, 0 );
/* Init nom fichier */
FullFileName = GetScreen()->m_FileName;
2007-08-23 04:28:46 +00:00
ChangeFileNameExt( FullFileName, wxT( ".rpt" ) );
rptfile = wxFopen( FullFileName, wxT( "wt" ) );
if( rptfile == NULL )
{
msg = _( "Unable to create " ) + FullFileName;
DisplayError( this, msg ); return;
}
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
setlocale( LC_NUMERIC, "C" );
/* Generation entete du fichier 'commentaires) */
sprintf( Line, "## Module report - date %s\n", DateAndTime( Buff ) );
fputs( Line, rptfile );
wxString Title = g_Main_Title + wxT( " " ) + GetBuildVersion();
sprintf( Line, "## Created by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
fputs( Line, rptfile );
fputs( "## Unit = inches, Angle = deg.\n", rptfile );
/* Generation lignes utiles du fichier */
fputs( "##\n", rptfile );
fputs( "\n$BeginDESCRIPTION\n", rptfile );
m_Pcb->ComputeBoundaryBox();
fputs( "\n$BOARD\n", rptfile );
fputs( "unit INCH\n", rptfile );
sprintf( Line, "upper_left_corner %9.6f %9.6f\n",
(float) m_Pcb->m_BoundaryBox.GetX() * conv_unit,
(float) m_Pcb->m_BoundaryBox.GetY() * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "lower_right_corner %9.6f %9.6f\n",
(float) ( m_Pcb->m_BoundaryBox.GetRight() ) * conv_unit,
(float) ( m_Pcb->m_BoundaryBox.GetBottom() ) * conv_unit );
fputs( Line, rptfile );
fputs( "$EndBOARD\n\n", rptfile );
Module = (MODULE*) m_Pcb->m_Modules;
for( ; Module != NULL; Module = Module->Next() )
{
sprintf( Line, "$MODULE \"%s\"\n", CONV_TO_UTF8( Module->m_Reference->m_Text ) );
fputs( Line, rptfile );
sprintf( Line, "reference \"%s\"\n", CONV_TO_UTF8( Module->m_Reference->m_Text ) );
fputs( Line, rptfile );
sprintf( Line, "value \"%s\"\n", CONV_TO_UTF8( Module->m_Value->m_Text ) );
fputs( Line, rptfile );
sprintf( Line, "footprint \"%s\"\n", CONV_TO_UTF8( Module->m_LibRef ) );
fputs( Line, rptfile );
msg = wxT( "attribut" );
if( Module->m_Attributs & MOD_VIRTUAL )
msg += wxT( " virtual" );
if( Module->m_Attributs & MOD_CMS )
msg += wxT( " smd" );
if( ( Module->m_Attributs & (MOD_VIRTUAL | MOD_CMS) ) == 0 )
msg += wxT( " none" );
msg += wxT( "\n" );
fputs( CONV_TO_UTF8( msg ), rptfile );
module_pos = Module->m_Pos;
module_pos.x -= File_Place_Offset.x;
module_pos.y -= File_Place_Offset.y;
sprintf( Line, "position %9.6f %9.6f\n",
(float) module_pos.x * conv_unit,
(float) module_pos.y * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "orientation %.2f\n", (float) Module->m_Orient / 10 );
if( Module->GetLayer() == CMP_N )
strcat( Line, "layer component\n" );
else if( Module->GetLayer() == COPPER_LAYER_N )
2007-08-23 04:28:46 +00:00
strcat( Line, "layer copper\n" );
else
strcat( Line, "layer other\n" );
fputs( Line, rptfile );
Module->Write_3D_Descr( rptfile );
for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
{
fprintf( rptfile, "$PAD \"%.4s\"\n", pad->m_Padname );
sprintf( Line, "position %9.6f %9.6f\n",
(float) pad->m_Pos0.x * conv_unit,
(float) pad->m_Pos0.y * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "size %9.6f %9.6f\n",
(float) pad->m_Size.x * conv_unit,
(float) pad->m_Size.y * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "drill %9.6f\n", (float) pad->m_Drill.x * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "shape_offset %9.6f %9.6f\n",
(float) pad->m_Offset.x * conv_unit,
(float) pad->m_Offset.y * conv_unit );
fputs( Line, rptfile );
sprintf( Line, "orientation %.2f\n", (float) (pad->m_Orient - Module->m_Orient) / 10 );
fputs( Line, rptfile );
const char* shape_name[6] =
{ "??? ", "Circ", "Rect", "Oval", "trap", "spec" };
2007-08-23 04:28:46 +00:00
sprintf( Line, "Shape %s\n", shape_name[pad->m_PadShape] );
fputs( Line, rptfile );
int layer = 0;
if( pad->m_Masque_Layer & CUIVRE_LAYER )
layer = 1;
if( pad->m_Masque_Layer & CMP_LAYER )
layer |= 2;
const char* layer_name[4] = { "??? ", "copper", "component", "all" };
2007-08-23 04:28:46 +00:00
sprintf( Line, "Layer %s\n", layer_name[layer] );
fputs( Line, rptfile );
fprintf( rptfile, "$EndPAD\n" );
}
fprintf( rptfile, "$EndMODULE %s\n\n",
(const char*) Module->m_Reference->m_Text.GetData() );
}
/* Write board Edges */
EDA_BaseStruct* PtStruct;
for( PtStruct = m_Pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Pnext )
{
2007-09-01 12:00:30 +00:00
if( PtStruct->Type() != TYPEDRAWSEGMENT )
2007-08-23 04:28:46 +00:00
continue;
if( ( (DRAWSEGMENT*) PtStruct )->GetLayer() != EDGE_N )
continue;
WriteDrawSegmentPcb( (DRAWSEGMENT*) PtStruct, rptfile );
}
/* Generation fin du fichier */
fputs( "$EndDESCRIPTION\n", rptfile );
fclose( rptfile );
setlocale( LC_NUMERIC, "" ); // revert to the current locale
}
/*******************************************************************/
2007-08-23 04:28:46 +00:00
void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile )
/*******************************************************************/
2007-08-23 04:28:46 +00:00
/* Sortie dsur rptfile d'un segment type drawing PCB:
2007-08-23 04:28:46 +00:00
* Les contours sont de differents type:
* segment
* cercle
* arc
*/
{
2007-08-23 04:28:46 +00:00
double conv_unit, ux0, uy0, dx, dy;
double rayon, width;
char Line[1024];
/* Calcul des echelles de conversion */
conv_unit = 0.0001; /* unites = INCHES */
/* coord de depart */
ux0 = PtDrawSegment->m_Start.x * conv_unit;
uy0 = PtDrawSegment->m_Start.y * conv_unit;
/* coord d'arrivee */
dx = PtDrawSegment->m_End.x * conv_unit;
dy = PtDrawSegment->m_End.y * conv_unit;
width = PtDrawSegment->m_Width * conv_unit;
switch( PtDrawSegment->m_Shape )
{
case S_CIRCLE:
rayon = hypot( dx - ux0, dy - uy0 );
sprintf( Line, "$CIRCLE \n" ); fputs( Line, rptfile );
sprintf( Line, "centre %.6lf %.6lf\n", ux0, uy0 );
sprintf( Line, "radius %.6lf\n", rayon );
sprintf( Line, "width %.6lf\n", width );
sprintf( Line, "$EndCIRCLE \n" );
fputs( Line, rptfile );
break;
case S_ARC:
{
int endx = PtDrawSegment->m_End.x, endy = PtDrawSegment->m_End.y;
rayon = hypot( dx - ux0, dy - uy0 );
RotatePoint( &endx,
&endy,
PtDrawSegment->m_Start.x,
PtDrawSegment->m_Start.y,
PtDrawSegment->m_Angle );
sprintf( Line, "$ARC \n" ); fputs( Line, rptfile );
sprintf( Line, "centre %.6lf %.6lf\n", ux0, uy0 );
sprintf( Line, "start %.6lf %.6lf\n", endx * conv_unit, endy * conv_unit );
sprintf( Line, "end %.6lf %.6lf\n", dx, dy );
sprintf( Line, "width %.6lf\n", width );
sprintf( Line, "$EndARC \n" );
fputs( Line, rptfile );
}
break;
default:
sprintf( Line, "$LINE \n" );
fputs( Line, rptfile );
sprintf( Line, "start %.6lf %.6lf\n", ux0, uy0 );
sprintf( Line, "end %.6lf %.6lf\n", dx, dy );
sprintf( Line, "width %.6lf\n", width );
sprintf( Line, "$EndLINE \n" );
fputs( Line, rptfile );
break;
}
}