gen_modules_placefile.cpp 16 KB
Newer Older
1 2 3
/*****************************/
/* gen_modules_placefile.cpp */
/*****************************/
4 5

/*
6 7 8
 *  1 - create ascii files for automatic placement of smd components
 *  2 - create a module report (pos and module descr) (ascii file)
 */
9 10
#include "fctsys.h"
#include "common.h"
11 12 13
#include "confirm.h"
#include "kicad_string.h"
#include "gestfich.h"
14
#include "pcbnew.h"
charras's avatar
charras committed
15
#include "wxPcbStruct.h"
16
#include "trigo.h"
17
#include "appl_wxstruct.h"
18

19 20
#include "build_version.h"

21
class LIST_MOD      /* Can list the elements of useful modules. */
22 23
{
public:
24 25 26
    MODULE*       m_Module;
    const wxChar* m_Reference;
    const wxChar* m_Value;
27 28 29
};


30
static wxPoint File_Place_Offset;  /* Offset coordinates for generated file. */
31

32
static void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile );
33

34 35

/* Sort function use by GenereModulesPosition() */
36
static int ListeModCmp( const void* o1, const void* o2 )
37
{
38 39 40 41
    LIST_MOD*   ref = (LIST_MOD*) o1;
    LIST_MOD*   cmp = (LIST_MOD*) o2;

    return StrLenNumCmp( ref->m_Reference, cmp->m_Reference, 16 );
42 43 44
}


45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
#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


68
/* Generate the module positions, used component placement.
69
 */
70
void WinEDA_PcbFrame::GenModulesPosition( wxCommandEvent& event )
71
{
72 73
    bool        doBoardBack = false;
    MODULE*     module;
74
    LIST_MOD*   Liste = 0;
75 76
    char        line[1024];
    char        Buff[80];
77 78
    wxFileName  fnFront;
    wxFileName  fnBack;
79 80 81 82
    wxString    msg;
    wxString    frontLayerName;
    wxString    backLayerName;
    wxString    Title;
83 84
    FILE*       fpFront = 0;
    FILE*       fpBack = 0;
85
    bool        switchedLocale = false;
86

87
    /* Calculate conversion scales. */
dickelbeck's avatar
dickelbeck committed
88
    double conv_unit = 0.0001; /* unites = INCHES */
89

90
//  if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
91

92 93
    File_Place_Offset = m_Auxiliary_Axis_Position;

94
    /* Calculating the number of useful modules (CMS attribute, not VIRTUAL) */
95
    int moduleCount = 0;
96

97
    for( module = GetBoard()->m_Modules;  module;  module = module->Next() )
98
    {
99
        if( module->m_Attributs & MOD_VIRTUAL )
100
        {
101 102
            D( printf( "skipping module %s because it's virtual\n",
                       CONV_TO_UTF8( module->GetReference() ) );)
103
            continue;
104 105
        }

106
        if( ( module->m_Attributs & MOD_CMS )  == 0 )
107
        {
108
#if 1 && defined(DEBUG)  // enable this code to fix a bunch of mis-labeled modules:
109
            if( !HasNonSMDPins( module ) )
110 111 112 113
            {
                // all module's pins are SMD, mark the part for pick and place
                module->m_Attributs |= MOD_CMS;
            }
114 115
            else
            {
116 117
                printf( "skipping %s because its attribute is not CMS and it has non SMD pins\n",
                        CONV_TO_UTF8(module->GetReference()) );
118 119 120
                continue;
            }
#else
121
            continue;
122 123 124
#endif
        }

dickelbeck's avatar
dickelbeck committed
125
        if( module->GetLayer() == LAYER_N_BACK )
126 127 128
            doBoardBack = true;

        moduleCount++;
129 130
    }

131
    if( moduleCount == 0 )
132
    {
133
        DisplayError( this, _( "No modules for automated placement." ) );
134
        return;
135 136
    }

137
    fnFront = GetScreen()->m_FileName;
dickelbeck's avatar
dickelbeck committed
138
    frontLayerName = GetBoard()->GetLayerName( LAYER_N_FRONT );
139
    fnFront.SetName( fnFront.GetName() + frontLayerName );
140
    fnFront.SetExt( wxT( "pos") );
141

142
    fpFront = wxFopen( fnFront.GetFullPath(), wxT( "wt" ) );
143
    if( fpFront == 0 )
144
    {
145
        msg = _( "Unable to create " ) + fnFront.GetFullPath();
146 147
        DisplayError( this, msg );
        goto exit;
148 149
    }

150
    if( doBoardBack )
151
    {
152
        fnBack = GetScreen()->m_FileName;
dickelbeck's avatar
dickelbeck committed
153
        backLayerName = GetBoard()->GetLayerName( LAYER_N_BACK );
154
        fnBack.SetName( fnBack.GetName() + backLayerName );
155 156 157
        fnBack.SetExt( wxT( "pos" ) );

        fpBack = wxFopen( fnBack.GetFullPath(), wxT( "wt" ) );
158 159

        if( fpBack == 0 )
160
        {
161
            msg = _( "Unable to create " ) + fnBack.GetFullPath();
162
            DisplayError( this, msg );
163
            goto exit;
164 165 166
        }
    }

167 168
    // Switch the locale to standard C (needed to print floating point
    // numbers like 1.3)
charras's avatar
charras committed
169
    SetLocaleTo_C_standard( );
170
    switchedLocale = true;
171

172
    /* Display results */
173
    MsgPanel->EraseMsgBox();
174 175
    Affiche_1_Parametre( this, 0, _( "Component side place file:" ),
                         fnFront.GetFullPath(), BLUE );
176

177
    if( doBoardBack )
178 179
        Affiche_1_Parametre( this, 32, _( "Copper side place file:" ),
                             fnBack.GetFullPath(), BLUE );
180

181
    msg.Empty(); msg << moduleCount;
182 183
    Affiche_1_Parametre( this, 65, _( "Module count" ), msg, RED );

184
    /* Sort the list of modules by alphabetical order */
185
    Liste = (LIST_MOD*) MyZMalloc( moduleCount * sizeof(LIST_MOD) );
186

187
    module = GetBoard()->m_Modules;
188
    for( int ii = 0;  module;  module = module->Next() )
189
    {
190
        if( module->m_Attributs & MOD_VIRTUAL )
191
            continue;
192

193
        if( (module->m_Attributs & MOD_CMS)  == 0 )
194 195
            continue;

196 197
        Liste[ii].m_Module    = module;
        Liste[ii].m_Reference = module->m_Reference->m_Text;
198
        Liste[ii].m_Value     = module->m_Value->m_Text;
199 200 201
        ii++;
    }

202
    qsort( Liste, moduleCount, sizeof(LIST_MOD), ListeModCmp );
203

204
    /* Generation header file comments. */
205
    sprintf( line, "### Module positions - created on %s ###\n",
206
             DateAndTime( Buff ) );
207 208 209
    fputs( line, fpFront );
    if( doBoardBack )
        fputs( line, fpBack );
210

211
    Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion();
212 213 214 215
    sprintf( line, "### Printed by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
    fputs( line, fpFront );
    if( doBoardBack )
        fputs( line, fpBack );
216

217 218 219 220
    sprintf( line, "## Unit = inches, Angle = deg.\n" );
    fputs( line, fpFront );
    if( doBoardBack )
        fputs( line, fpBack );
221

222 223
    sprintf( line, "## Side : %s\n", CONV_TO_UTF8( frontLayerName ) );
    fputs( line, fpFront );
224

225
    if( doBoardBack )
226
    {
227 228
        sprintf( line, "## Side : %s\n", CONV_TO_UTF8( backLayerName ) );
        fputs( line, fpBack );
229 230
    }

231
    sprintf( line,
232
             "# Ref    Val                  PosX       PosY        Rot     Side\n" );
233 234 235
    fputs( line, fpFront );
    if( doBoardBack )
        fputs( line, fpBack );
236

237
    for( int ii = 0; ii < moduleCount; ii++ )
238 239 240 241
    {
        wxPoint  module_pos;
        wxString ref = Liste[ii].m_Reference;
        wxString val = Liste[ii].m_Value;
242 243
        sprintf( line, "%-8.8s %-16.16s ", CONV_TO_UTF8( ref ),
                 CONV_TO_UTF8( val ) );
244 245 246 247 248

        module_pos    = Liste[ii].m_Module->m_Pos;
        module_pos.x -= File_Place_Offset.x;
        module_pos.y -= File_Place_Offset.y;

249
        char* text = line + strlen( line );
250
        sprintf( text, " %9.4f  %9.4f  %8.1f    ",
dickelbeck's avatar
dickelbeck committed
251 252 253
                 module_pos.x * conv_unit,
                 module_pos.y * conv_unit,
                 double(Liste[ii].m_Module->m_Orient) / 10 );
254

255 256
        int layer = Liste[ii].m_Module->GetLayer();

dickelbeck's avatar
dickelbeck committed
257
        wxASSERT( layer==LAYER_N_FRONT || layer==LAYER_N_BACK );
258

dickelbeck's avatar
dickelbeck committed
259
        if( layer == LAYER_N_FRONT )
260
        {
261 262 263
            strcat( line, CONV_TO_UTF8( frontLayerName ) );
            strcat( line, "\n" );
            fputs( line, fpFront );
264
        }
dickelbeck's avatar
dickelbeck committed
265
        else if( layer == LAYER_N_BACK )
266
        {
267 268 269
            strcat( line, CONV_TO_UTF8( backLayerName ) );
            strcat( line, "\n" );
            fputs( line, fpBack );
270 271 272
        }
    }

273
    /* Generate EOF. */
274 275 276 277 278
    fputs( "## End\n", fpFront );

    if( doBoardBack )
        fputs( "## End\n", fpBack );

279
    msg = frontLayerName + wxT( " File: " ) + fnFront.GetFullPath();
280 281

    if( doBoardBack )
282 283
        msg += wxT("\n\n") + backLayerName + wxT( " File: " ) +
            fnBack.GetFullPath();
284

285
    DisplayInfoMessage( this, msg );
286

287 288 289 290 291 292

exit:   // the only safe way out of here, no returns please.

    if( Liste )
        MyFree( Liste );

293
    if( switchedLocale )
294
        SetLocaleTo_Default( );      // revert to the current locale
295

296 297 298 299 300
    if( fpFront )
        fclose( fpFront );

    if( fpBack )
        fclose( fpBack );
301 302 303 304
}


/* Print a module report.
305
 */
306
void WinEDA_PcbFrame::GenModuleReport( wxCommandEvent& event )
307
{
dickelbeck's avatar
dickelbeck committed
308
    double   conv_unit;
309 310
    MODULE*  Module;
    D_PAD*   pad;
311
    char     line[1024], Buff[80];
312 313
    wxFileName fn;
    wxString fnFront, msg;
314 315 316 317 318
    FILE*    rptfile;
    wxPoint  module_pos;

    conv_unit = 0.0001; /* unites = INCHES */

319
//  if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
320

321 322
    File_Place_Offset = wxPoint( 0, 0 );

323 324
    fn = GetScreen()->m_FileName;
    fn.SetExt( wxT( "rpt" ) );
325

326
    rptfile = wxFopen( fn.GetFullPath(), wxT( "wt" ) );
327 328
    if( rptfile == NULL )
    {
329 330 331
        msg = _( "Unable to create " ) + fn.GetFullPath();
        DisplayError( this, msg );
        return;
332 333
    }

334 335
    // Switch the locale to standard C (needed to print floating point
    // numbers like 1.3)
charras's avatar
charras committed
336
    SetLocaleTo_C_standard( );
337

338
    /* Generate header file comments.) */
339 340
    sprintf( line, "## Module report - date %s\n", DateAndTime( Buff ) );
    fputs( line, rptfile );
341

342
    wxString Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion();
343 344
    sprintf( line, "## Created by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
    fputs( line, rptfile );
345 346 347 348 349
    fputs( "## Unit = inches, Angle = deg.\n", rptfile );

    fputs( "##\n", rptfile );
    fputs( "\n$BeginDESCRIPTION\n", rptfile );

350
    GetBoard()->ComputeBoundaryBox();
351 352
    fputs( "\n$BOARD\n", rptfile );
    fputs( "unit INCH\n", rptfile );
353
    sprintf( line, "upper_left_corner %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
354 355
             GetBoard()->m_BoundaryBox.GetX() * conv_unit,
             GetBoard()->m_BoundaryBox.GetY() * conv_unit );
356
    fputs( line, rptfile );
357

358
    sprintf( line, "lower_right_corner %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
359 360
             GetBoard()->m_BoundaryBox.GetRight() * conv_unit,
             GetBoard()->m_BoundaryBox.GetBottom() * conv_unit );
361
    fputs( line, rptfile );
362 363 364

    fputs( "$EndBOARD\n\n", rptfile );

365
    Module = (MODULE*) GetBoard()->m_Modules;
366 367
    for( ; Module != NULL; Module = Module->Next() )
    {
368 369
        sprintf( line, "$MODULE \"%s\"\n",
                 CONV_TO_UTF8( Module->m_Reference->m_Text ) );
370
        fputs( line, rptfile );
371

372 373
        sprintf( line, "reference \"%s\"\n",
                 CONV_TO_UTF8( Module->m_Reference->m_Text ) );
374
        fputs( line, rptfile );
375 376
        sprintf( line, "value \"%s\"\n",
                 CONV_TO_UTF8( Module->m_Value->m_Text ) );
377 378 379
        fputs( line, rptfile );
        sprintf( line, "footprint \"%s\"\n", CONV_TO_UTF8( Module->m_LibRef ) );
        fputs( line, rptfile );
380 381 382 383 384 385 386 387 388 389 390 391 392 393

        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;
dickelbeck's avatar
dickelbeck committed
394

395
        sprintf( line, "position %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
396 397
                 module_pos.x * conv_unit,
                 module_pos.y * conv_unit );
398
        fputs( line, rptfile );
399

dickelbeck's avatar
dickelbeck committed
400
        sprintf( line, "orientation  %.2f\n", (double) Module->m_Orient / 10 );
dickelbeck's avatar
dickelbeck committed
401
        if( Module->GetLayer() == LAYER_N_FRONT )
402
            strcat( line, "layer component\n" );
dickelbeck's avatar
dickelbeck committed
403
        else if( Module->GetLayer() == LAYER_N_BACK )
404
            strcat( line, "layer copper\n" );
405
        else
406 407
            strcat( line, "layer other\n" );
        fputs( line, rptfile );
408 409 410 411 412 413

        Module->Write_3D_Descr( rptfile );

        for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
        {
            fprintf( rptfile, "$PAD \"%.4s\"\n", pad->m_Padname );
414
            sprintf( line, "position %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
415 416
                     pad->m_Pos0.x * conv_unit,
                     pad->m_Pos0.y * conv_unit );
417
            fputs( line, rptfile );
418

419
            sprintf( line, "size %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
420 421
                     pad->m_Size.x * conv_unit,
                     pad->m_Size.y * conv_unit );
422
            fputs( line, rptfile );
dickelbeck's avatar
dickelbeck committed
423
            sprintf( line, "drill %9.6f\n", pad->m_Drill.x * conv_unit );
424 425
            fputs( line, rptfile );
            sprintf( line, "shape_offset %9.6f %9.6f\n",
dickelbeck's avatar
dickelbeck committed
426 427
                     pad->m_Offset.x * conv_unit,
                     pad->m_Offset.y * conv_unit );
428
            fputs( line, rptfile );
429

430 431
            sprintf( line, "orientation  %.2f\n",
                     double(pad->m_Orient - Module->m_Orient) / 10 );
432
            fputs( line, rptfile );
433
            const char* shape_name[6] =
434
                { "??? ", "Circ", "Rect", "Oval", "trap", "spec" };
435 436
            sprintf( line, "Shape  %s\n", shape_name[pad->m_PadShape] );
            fputs( line, rptfile );
437 438

            int layer = 0;
439
            if( pad->m_Masque_Layer & LAYER_BACK )
440
                layer = 1;
441
            if( pad->m_Masque_Layer & LAYER_FRONT )
442
                layer |= 2;
443
            const char* layer_name[4] = { "??? ", "copper", "component", "all" };
444 445
            sprintf( line, "Layer  %s\n", layer_name[layer] );
            fputs( line, rptfile );
446 447 448 449
            fprintf( rptfile, "$EndPAD\n" );
        }

        fprintf( rptfile, "$EndMODULE  %s\n\n",
450
                 CONV_TO_UTF8(Module->m_Reference->m_Text ) );
451 452 453 454
    }

    /* Write board Edges */
    EDA_BaseStruct* PtStruct;
455
    for( PtStruct = GetBoard()->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
456
    {
457
        if( PtStruct->Type() != TYPE_DRAWSEGMENT )
458 459 460 461 462 463
            continue;
        if( ( (DRAWSEGMENT*) PtStruct )->GetLayer() != EDGE_N )
            continue;
        WriteDrawSegmentPcb( (DRAWSEGMENT*) PtStruct, rptfile );
    }

464
    /* Generate EOF. */
465 466
    fputs( "$EndDESCRIPTION\n", rptfile );
    fclose( rptfile );
467
    SetLocaleTo_Default( );      // revert to the current locale
468 469 470
}


471 472 473 474 475
/* Output to rpt file a segment type from the PCB drawing.
 * The contours are of different types:
 * Segment
 * Circle
 * Arc
476
 */
477
void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile )
478
{
479 480
    double conv_unit, ux0, uy0, dx, dy;
    double rayon, width;
481
    char   line[1024];
482

483
    conv_unit = 0.0001; /* units = INCHES */
484

485 486
    ux0 = PtDrawSegment->m_Start.x * conv_unit;
    uy0 = PtDrawSegment->m_Start.y * conv_unit;
487

488 489 490 491 492 493 494 495 496
    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 );
charras's avatar
charras committed
497 498 499 500 501
        fprintf( rptfile, "$CIRCLE \n" );
        fprintf( rptfile, "centre %.6lf %.6lf\n", ux0, uy0 );
        fprintf( rptfile, "radius %.6lf\n", rayon );
        fprintf( rptfile, "width %.6lf\n", width );
        fprintf( rptfile, "$EndCIRCLE \n" );
502 503 504
        break;

    case S_ARC:
505 506 507 508 509 510 511 512 513
        {
            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 );

charras's avatar
charras committed
514 515
            fprintf( rptfile, "$ARC \n" );
            fprintf( rptfile, "centre %.6lf %.6lf\n", ux0, uy0 );
516 517
            fprintf( rptfile, "start %.6lf %.6lf\n",
                     endx * conv_unit, endy * conv_unit );
charras's avatar
charras committed
518 519 520
            fprintf( rptfile, "end %.6lf %.6lf\n", dx, dy );
            fprintf( rptfile, "width %.6lf\n", width );
            fprintf( rptfile, "$EndARC \n" );
521
        }
522 523 524
        break;

    default:
525 526 527
        sprintf( line, "$LINE \n" );
        fputs( line, rptfile );

charras's avatar
charras committed
528 529 530 531
        fprintf( rptfile, "start %.6lf %.6lf\n", ux0, uy0 );
        fprintf( rptfile, "end %.6lf %.6lf\n", dx, dy );
        fprintf( rptfile, "width %.6lf\n", width );
        fprintf( rptfile, "$EndLINE \n" );
532 533
        break;
    }
534
}