plot_rtn.cpp 33.5 KB
Newer Older
1 2 3
/*************************/
/* Common plot routines. */
/*************************/
4 5 6 7

#include "fctsys.h"
#include "common.h"
#include "plot_common.h"
8 9 10
#include "base_struct.h"
#include "drawtxt.h"
#include "confirm.h"
11 12 13
#include "pcbnew.h"
#include "pcbplot.h"
#include "trigo.h"
charras's avatar
charras committed
14
#include "class_board_design_settings.h"
15 16


17
static void Plot_Edges_Modules( PLOTTER* plotter, BOARD* pcb, int masque_layer,
charras's avatar
charras committed
18
                                GRTraceMode trace_mode );
19
static void PlotTextModule( PLOTTER* plotter, TEXTE_MODULE* pt_texte,
charras's avatar
charras committed
20
                            GRTraceMode trace_mode );
21 22


23
/* Creates the plot for silkscreen layers
24 25 26 27
 */
void WinEDA_BasePcbFrame::Plot_Serigraphie( PLOTTER*    plotter,
                                            int         masque_layer,
                                            GRTraceMode trace_mode )
28
{
29 30 31 32 33 34 35
    wxPoint         pos, shape_pos;
    wxSize          size;
    bool            trace_val, trace_ref;
    D_PAD*          pt_pad;
    TEXTE_MODULE*   pt_texte;
    EDA_BaseStruct* PtStruct;

36
    /* Plot edge layer and graphic items */
charras's avatar
charras committed
37

38 39 40
    for( PtStruct = m_Pcb->m_Drawings;
        PtStruct != NULL;
        PtStruct = PtStruct->Next() )
41 42 43
    {
        switch( PtStruct->Type() )
        {
44
        case TYPE_DRAWSEGMENT:
45 46 47 48
            PlotDrawSegment( plotter,
                             (DRAWSEGMENT*) PtStruct,
                             masque_layer,
                             trace_mode );
49 50
            break;

51
        case TYPE_TEXTE:
52 53 54 55
            PlotTextePcb( plotter,
                          (TEXTE_PCB*) PtStruct,
                          masque_layer,
                          trace_mode );
56 57
            break;

58
        case TYPE_COTATION:
59 60 61 62
            PlotCotation( plotter,
                          (COTATION*) PtStruct,
                          masque_layer,
                          trace_mode );
63 64
            break;

65
        case TYPE_MIRE:
66 67 68 69
            PlotMirePcb( plotter,
                         (MIREPCB*) PtStruct,
                         masque_layer,
                         trace_mode );
70 71
            break;

72
        case TYPE_MARKER_PCB:
73 74 75
            break;

        default:
76 77
            DisplayError( this,
                          wxT( "Plot_Serigraphie() error: unexpected Type()" ) );
78 79 80 81
            break;
        }
    }

82
    /* Plot footprint outlines : */
charras's avatar
charras committed
83
    Plot_Edges_Modules( plotter, m_Pcb, masque_layer, trace_mode );
84

85
    /* Plot pads (creates pads outlines, for pads on silkscreen layers) */
charras's avatar
charras committed
86 87
    if( g_pcb_plot_options.PlotPadsOnSilkLayer
        || g_pcb_plot_options.Plot_Pads_All_Layers )
88
    {
charras's avatar
charras committed
89
        for( MODULE* Module = m_Pcb->m_Modules;
90 91
             Module;
             Module = Module->Next() )
92
        {
93 94 95
            for( pt_pad = (D_PAD*) Module->m_Pads;
                 pt_pad != NULL;
                 pt_pad = pt_pad->Next() )
96
            {
97
                /* Seen if the pad is on this layer */
charras's avatar
charras committed
98 99 100 101 102 103 104
                if( (pt_pad->m_Masque_Layer & masque_layer) == 0
                   /* Copper pads go on copper silk, component
                    * pads go on component silk */
                   && ( ( (pt_pad->m_Masque_Layer & CUIVRE_LAYER) == 0 )
                       || ( (masque_layer & SILKSCREEN_LAYER_CU) == 0 ) )
                   && ( ( (pt_pad->m_Masque_Layer & CMP_LAYER) == 0 )
                       || ( (masque_layer & SILKSCREEN_LAYER_CMP) == 0 ) ) )
105
                {
106
                    if( !g_pcb_plot_options.Plot_Pads_All_Layers )
107 108
                        continue;
                }
109

110
                shape_pos = pt_pad->ReturnShapePos();
111 112
                pos  = shape_pos;
                size = pt_pad->m_Size;
113 114 115

                switch( pt_pad->m_PadShape & 0x7F )
                {
dickelbeck's avatar
dickelbeck committed
116
                case PAD_CIRCLE:
charras's avatar
charras committed
117
                    plotter->flash_pad_circle( pos, size.x, FILAIRE );
118 119
                    break;

dickelbeck's avatar
dickelbeck committed
120
                case PAD_OVAL:
charras's avatar
charras committed
121 122 123
                    plotter->flash_pad_oval( pos, size,
                                             pt_pad->m_Orient, FILAIRE );
                    break;
124

charras's avatar
charras committed
125 126
                case PAD_TRAPEZOID:
                {
127 128
                    wxSize delta;
                    delta = pt_pad->m_DeltaSize;
charras's avatar
charras committed
129 130 131 132 133
                    plotter->flash_pad_trapez( pos, size,
                                               delta, pt_pad->m_Orient,
                                               FILAIRE );
                    break;
                }
134

dickelbeck's avatar
dickelbeck committed
135
                case PAD_RECT:
136
                default:
137 138 139 140
                    plotter->flash_pad_rect( pos,
                                             size,
                                             pt_pad->m_Orient,
                                             FILAIRE );
141 142 143 144
                    break;
                }
            }
        }
145
    }
146

147
    /* Plot footprints fields (ref, value ...) */
charras's avatar
charras committed
148
    for( MODULE* Module = m_Pcb->m_Modules; Module; Module = Module->Next() )
149
    {
150
        /* see if we want to plot VALUE and REF fields */
151
        trace_val = g_pcb_plot_options.Sel_Texte_Valeur;
152
        trace_ref = g_pcb_plot_options.Sel_Texte_Reference;
153

154
        TEXTE_MODULE* text = Module->m_Reference;
155
        unsigned      textLayer = text->GetLayer();
156

157 158 159 160
        if( textLayer >= 32 )
        {
            wxString errMsg;

161 162 163
            errMsg.Printf( _( "Your BOARD has a bad layer number of %u for \
module\n %s's \"reference\" text." ),
                           textLayer, GetChars( Module->GetReference() ) );
164
            DisplayError( this, errMsg );
165
            return;
166
        }
167

168
        if( ( ( 1 << textLayer ) & masque_layer ) == 0 )
169 170
            trace_ref = FALSE;

171
        if( text->m_NoShow && !g_pcb_plot_options.Sel_Texte_Invisible )
172 173
            trace_ref = FALSE;

174
        text = Module->m_Value;
175 176
        textLayer = text->GetLayer();

177 178 179 180
        if( textLayer > 32 )
        {
            wxString errMsg;

181 182 183
            errMsg.Printf( _( "Your BOARD has a bad layer number of %u for \
module\n %s's \"value\" text." ),
                           textLayer, GetChars( Module->GetReference() ) );
184
            DisplayError( this, errMsg );
185
            return;
186
        }
187 188 189 190

        if( ( (1 << textLayer) & masque_layer ) == 0 )
            trace_val = FALSE;

191
        if( text->m_NoShow && !g_pcb_plot_options.Sel_Texte_Invisible )
192 193
            trace_val = FALSE;

194
        /* Plot text fields, if allowed */
195
        if( trace_ref )
charras's avatar
charras committed
196
            PlotTextModule( plotter, Module->m_Reference, trace_mode );
197 198

        if( trace_val )
charras's avatar
charras committed
199
            PlotTextModule( plotter, Module->m_Value, trace_mode );
200

charras's avatar
charras committed
201
        for( pt_texte = (TEXTE_MODULE*) Module->m_Drawings.GetFirst();
202 203
             pt_texte != NULL;
             pt_texte = pt_texte->Next() )
204
        {
205
            if( pt_texte->Type() != TYPE_TEXTE_MODULE )
206 207
                continue;

208
            if( !g_pcb_plot_options.Sel_Texte_Divers )
209
                continue;
210 211
            if( (pt_texte->m_NoShow)
               && !g_pcb_plot_options.Sel_Texte_Invisible )
212
                continue;
213 214 215 216 217 218

            textLayer = pt_texte->GetLayer();
            if( textLayer >= 32 )
            {
                wxString errMsg;

219 220 221 222
                errMsg.Printf( _( "Your BOARD has a bad layer number of %u \
for module\n %s's \"module text\" text of %s." ),
                               textLayer, GetChars( Module->GetReference() ),
                               GetChars( pt_texte->m_Text ) );
223
                DisplayError( this, errMsg );
224
                return;
225 226
            }

227
            if( !( ( 1 << textLayer ) & masque_layer ) )
228
                continue;
229

charras's avatar
charras committed
230
            PlotTextModule( plotter, pt_texte, trace_mode );
231 232
        }
    }
233

234
    /* Plot filled areas */
235 236
    for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
    {
237 238
        ZONE_CONTAINER* edge_zone = m_Pcb->GetArea( ii );
        if( ( ( 1 << edge_zone->GetLayer() ) & masque_layer ) == 0 )
239
            continue;
charras's avatar
charras committed
240
        PlotFilledAreas( plotter, edge_zone, trace_mode );
241 242
    }

243 244
    // Plot segments used to fill zone areas (outdated, but here for old boards
    // compatibility):
245 246 247 248
    for( SEGZONE* seg = m_Pcb->m_Zone; seg != NULL; seg = seg->Next() )
    {
        if( ( ( 1 << seg->GetLayer() ) & masque_layer ) == 0 )
            continue;
charras's avatar
charras committed
249 250
        plotter->thick_segment( seg->m_Start, seg->m_End, seg->m_Width,
                                trace_mode );
251
    }
252 253
}

254

255
static void PlotTextModule( PLOTTER* plotter, TEXTE_MODULE* pt_texte,
charras's avatar
charras committed
256
                            GRTraceMode trace_mode )
257
{
258 259
    wxSize  size;
    wxPoint pos;
260
    int     orient, thickness;
261

262
    /* calculate some text parameters :*/
263 264
    size = pt_texte->m_Size;
    pos  = pt_texte->m_Pos;
265

266
    orient = pt_texte->GetDrawRotation();
267

268
    thickness = pt_texte->m_Width;
269 270
    if( trace_mode == FILAIRE )
        thickness = -1;
271

272
    if( pt_texte->m_Mirror )
273
        NEGATE( size.x );  // Text is mirrored
274

275
    plotter->text( pos, BLACK,
charras's avatar
charras committed
276 277 278 279
                   pt_texte->m_Text,
                   orient, size,
                   pt_texte->m_HJustify, pt_texte->m_VJustify,
                   thickness, pt_texte->m_Italic, pt_texte->m_Bold );
280 281 282
}


283
void PlotCotation( PLOTTER* plotter, COTATION* Cotation, int masque_layer,
charras's avatar
charras committed
284
                   GRTraceMode trace_mode )
285
{
286
    DRAWSEGMENT* DrawTmp;
287

288 289
    if( (g_TabOneLayerMask[Cotation->GetLayer()] & masque_layer) == 0 )
        return;
290

291
    DrawTmp = new DRAWSEGMENT( NULL );
292

charras's avatar
charras committed
293
    DrawTmp->m_Width = (trace_mode==FILAIRE) ? -1 : Cotation->m_Width;
294
    DrawTmp->SetLayer( Cotation->GetLayer() );
295

charras's avatar
charras committed
296
    PlotTextePcb( plotter, Cotation->m_Text, masque_layer, trace_mode );
297

298 299 300 301
    DrawTmp->m_Start.x = Cotation->Barre_ox;
    DrawTmp->m_Start.y = Cotation->Barre_oy;
    DrawTmp->m_End.x = Cotation->Barre_fx;
    DrawTmp->m_End.y = Cotation->Barre_fy;
charras's avatar
charras committed
302
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
303

304 305 306 307
    DrawTmp->m_Start.x = Cotation->TraitG_ox;
    DrawTmp->m_Start.y = Cotation->TraitG_oy;
    DrawTmp->m_End.x = Cotation->TraitG_fx;
    DrawTmp->m_End.y = Cotation->TraitG_fy;
charras's avatar
charras committed
308
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
309

310 311 312 313
    DrawTmp->m_Start.x = Cotation->TraitD_ox;
    DrawTmp->m_Start.y = Cotation->TraitD_oy;
    DrawTmp->m_End.x = Cotation->TraitD_fx;
    DrawTmp->m_End.y = Cotation->TraitD_fy;
charras's avatar
charras committed
314
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
315

316 317 318 319
    DrawTmp->m_Start.x = Cotation->FlecheD1_ox;
    DrawTmp->m_Start.y = Cotation->FlecheD1_oy;
    DrawTmp->m_End.x = Cotation->FlecheD1_fx;
    DrawTmp->m_End.y = Cotation->FlecheD1_fy;
charras's avatar
charras committed
320
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
321

322 323 324 325
    DrawTmp->m_Start.x = Cotation->FlecheD2_ox;
    DrawTmp->m_Start.y = Cotation->FlecheD2_oy;
    DrawTmp->m_End.x = Cotation->FlecheD2_fx;
    DrawTmp->m_End.y = Cotation->FlecheD2_fy;
charras's avatar
charras committed
326
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
327

328 329 330 331
    DrawTmp->m_Start.x = Cotation->FlecheG1_ox;
    DrawTmp->m_Start.y = Cotation->FlecheG1_oy;
    DrawTmp->m_End.x = Cotation->FlecheG1_fx;
    DrawTmp->m_End.y = Cotation->FlecheG1_fy;
charras's avatar
charras committed
332
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
333

334 335 336 337
    DrawTmp->m_Start.x = Cotation->FlecheG2_ox;
    DrawTmp->m_Start.y = Cotation->FlecheG2_oy;
    DrawTmp->m_End.x = Cotation->FlecheG2_fx;
    DrawTmp->m_End.y = Cotation->FlecheG2_fy;
charras's avatar
charras committed
338
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
339

340
    delete DrawTmp;
341 342 343
}


344
void PlotMirePcb( PLOTTER* plotter, MIREPCB* Mire, int masque_layer,
charras's avatar
charras committed
345
                  GRTraceMode trace_mode )
346
{
347
    DRAWSEGMENT* DrawTmp;
348
    int          dx1, dx2, dy1, dy2, radius;
349

350 351
    if( (g_TabOneLayerMask[Mire->GetLayer()] & masque_layer) == 0 )
        return;
352

353
    DrawTmp = new DRAWSEGMENT( NULL );
354

355
    DrawTmp->m_Width = ( trace_mode == FILAIRE ) ? -1 : Mire->m_Width;
356 357 358
    DrawTmp->SetLayer( Mire->GetLayer() );

    DrawTmp->m_Start.x = Mire->m_Pos.x; DrawTmp->m_Start.y = Mire->m_Pos.y;
359
    DrawTmp->m_End.x   = DrawTmp->m_Start.x + ( Mire->m_Size / 4 );
360 361
    DrawTmp->m_End.y   = DrawTmp->m_Start.y;
    DrawTmp->m_Shape   = S_CIRCLE;
charras's avatar
charras committed
362
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
363 364

    DrawTmp->m_Shape = S_SEGMENT;
365

366
    radius = Mire->m_Size / 2;
367 368 369 370
    dx1    = radius;
    dy1    = 0;
    dx2    = 0;
    dy2    = radius;
371

372
    if( Mire->m_Shape ) /* Shape X */
373
    {
374
        dx1 = dy1 = ( radius * 7 ) / 5;
375 376
        dx2 = dx1;
        dy2 = -dy1;
377 378
    }

379 380 381 382
    DrawTmp->m_Start.x = Mire->m_Pos.x - dx1;
    DrawTmp->m_Start.y = Mire->m_Pos.y - dy1;
    DrawTmp->m_End.x = Mire->m_Pos.x + dx1;
    DrawTmp->m_End.y = Mire->m_Pos.y + dy1;
charras's avatar
charras committed
383
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
384

385 386 387 388
    DrawTmp->m_Start.x = Mire->m_Pos.x - dx2;
    DrawTmp->m_Start.y = Mire->m_Pos.y - dy2;
    DrawTmp->m_End.x = Mire->m_Pos.x + dx2;
    DrawTmp->m_End.y = Mire->m_Pos.y + dy2;
charras's avatar
charras committed
389
    PlotDrawSegment( plotter, DrawTmp, masque_layer, trace_mode );
390 391

    delete DrawTmp;
392 393
}

charras's avatar
charras committed
394

395
/* Plot footprints graphic items (outlines) */
396
void Plot_Edges_Modules( PLOTTER* plotter, BOARD* pcb, int masque_layer,
charras's avatar
charras committed
397
                         GRTraceMode trace_mode )
398
{
399
    for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
400
    {
charras's avatar
charras committed
401
        for( EDGE_MODULE* edge = (EDGE_MODULE*) module->m_Drawings.GetFirst();
402 403
             edge;
             edge = edge->Next() )
404
        {
dickelbeck's avatar
dickelbeck committed
405
            if( edge->Type() != TYPE_EDGE_MODULE )
406
                continue;
dickelbeck's avatar
dickelbeck committed
407

408
            if( ( g_TabOneLayerMask[edge->GetLayer()] & masque_layer ) == 0 )
409
                continue;
dickelbeck's avatar
dickelbeck committed
410

411
            Plot_1_EdgeModule( plotter, edge, trace_mode );
412 413
        }
    }
414 415
}

416

417
/* Plot a graphic item (outline) relative to a footprint */
418
void Plot_1_EdgeModule( PLOTTER* plotter, EDGE_MODULE* PtEdge,
charras's avatar
charras committed
419
                        GRTraceMode trace_mode )
420
{
421 422 423
    int     type_trace;         /* Type of item to plot. */
    int     thickness;          /* Segment thickness. */
    int     radius;             /* Circle radius. */
424
    int     StAngle, EndAngle;
425
    wxPoint pos, end;
426

427
    if( PtEdge->Type() != TYPE_EDGE_MODULE )
428
        return;
429

430
    type_trace = PtEdge->m_Shape;
431
    thickness  = PtEdge->m_Width;
dickelbeck's avatar
dickelbeck committed
432

433 434 435 436 437 438
    pos = PtEdge->m_Start;
    end = PtEdge->m_End;

    switch( type_trace )
    {
    case S_SEGMENT:
charras's avatar
charras committed
439 440
        plotter->thick_segment( pos, end, thickness, trace_mode );
        break;
441 442

    case S_CIRCLE:
443 444
        radius = (int) hypot( (double) ( end.x - pos.x ),
                              (double) ( end.y - pos.y ) );
charras's avatar
charras committed
445
        plotter->thick_circle( pos, radius * 2, thickness, trace_mode );
446 447 448
        break;

    case S_ARC:
449 450
        radius = (int) hypot( (double) ( end.x - pos.x ),
                              (double) ( end.y - pos.y ) );
451 452
        StAngle  = ArcTangente( end.y - pos.y, end.x - pos.x );
        EndAngle = StAngle + PtEdge->m_Angle;
453 454 455 456 457 458
        plotter->thick_arc( pos,
                            -EndAngle,
                            -StAngle,
                            radius,
                            thickness,
                            trace_mode );
459 460 461
        break;

    case S_POLYGON:
462 463 464 465 466 467
    {
        // We must compute true coordinates from m_PolyList
        // which are relative to module position, orientation 0
        MODULE* Module = NULL;
        if( PtEdge->GetParent() && (PtEdge->GetParent()->Type() == TYPE_MODULE) )
            Module = (MODULE*) PtEdge->GetParent();
468

469 470
        int* ptr_base =
            (int*) MyMalloc( 2 * PtEdge->m_PolyPoints.size() * sizeof(int) );
471
        int* ptr = ptr_base;
472

473
        int* source = (int*) &PtEdge->m_PolyPoints[0];
474

475 476 477 478
        for( unsigned ii = 0; ii < PtEdge->m_PolyPoints.size(); ii++ )
        {
            int x = *source++;
            int y = *source++;
479

480 481 482 483 484
            if( Module )
            {
                RotatePoint( &x, &y, Module->m_Orient );
                x += Module->m_Pos.x;
                y += Module->m_Pos.y;
485
            }
486

487 488 489 490 491
            x += PtEdge->m_Start0.x;
            y += PtEdge->m_Start0.y;

            *ptr++ = x;
            *ptr++ = y;
492
        }
493

494 495
        plotter->poly( PtEdge->m_PolyPoints.size(), ptr_base, NO_FILL,
                       thickness );
496 497
        free( ptr_base );
    }
498
    break;
499
    }
500 501 502
}


503
/* Plot a PCB Text, i;e. a text found on a copper or technical layer */
504
void PlotTextePcb( PLOTTER* plotter, TEXTE_PCB* pt_texte, int masque_layer,
charras's avatar
charras committed
505
                   GRTraceMode trace_mode )
506
{
507
    int     orient, thickness;
508 509 510 511 512
    wxPoint pos;
    wxSize  size;

    if( pt_texte->m_Text.IsEmpty() )
        return;
513
    if( ( g_TabOneLayerMask[pt_texte->GetLayer()] & masque_layer ) == 0 )
514 515
        return;

516 517
    size = pt_texte->m_Size;
    pos  = pt_texte->m_Pos;
518
    orient    = pt_texte->m_Orient;
519
    thickness = ( trace_mode==FILAIRE ) ? -1 : pt_texte->m_Width;
520

521
    if( pt_texte->m_Mirror )
522 523
        size.x = -size.x;

524 525 526 527 528 529 530 531
    if( pt_texte->m_MultilineAllowed )
    {
        wxArrayString* list = wxStringSplit( pt_texte->m_Text, '\n' );
        wxPoint        offset;

        offset.y = pt_texte->GetInterline();

        RotatePoint( &offset, orient );
532
        for( unsigned i = 0; i < list->Count(); i++ )
533 534
        {
            wxString txt = list->Item( i );
535
            plotter->text( pos, BLACK,
charras's avatar
charras committed
536 537 538 539
                           txt,
                           orient, size,
                           pt_texte->m_HJustify, pt_texte->m_VJustify,
                           thickness, pt_texte->m_Italic, pt_texte->m_Bold );
540 541 542 543 544 545
            pos += offset;
        }

        delete (list);
    }
    else
546
        plotter->text( pos, BLACK,
charras's avatar
charras committed
547 548 549 550
                       pt_texte->m_Text,
                       orient, size,
                       pt_texte->m_HJustify, pt_texte->m_VJustify,
                       thickness, pt_texte->m_Italic, pt_texte->m_Bold );
551 552 553
}


554
/* Plot areas (given by .m_FilledPolysList member) in a zone
555
 */
556 557
void PlotFilledAreas( PLOTTER* plotter, ZONE_CONTAINER* aZone,
                      GRTraceMode trace_mode )
558 559 560
{
    static int*     CornersBuffer     = NULL;
    static unsigned CornersBufferSize = 0;
561
    unsigned        imax = aZone->m_FilledPolysList.size();
562 563 564 565 566

    if( imax == 0 )  // Nothing to draw
        return;

    // We need a buffer to store corners coordinates:
567

568
    imax++;   // provide room to sore an extra coordinate to close the polygon
569 570
    if( CornersBuffer == NULL )
    {
571
        CornersBufferSize = imax * 2;
572
        CornersBuffer     = (int*) MyMalloc( CornersBufferSize * sizeof(int) );
573 574 575 576
    }

    if( (imax * 4) > CornersBufferSize )
    {
577
        CornersBufferSize = imax * 2;
578 579
        CornersBuffer     = (int*) realloc( CornersBuffer,
                                            CornersBufferSize * sizeof(int) );
580 581
    }

582 583
    imax--;

584 585 586
    /* Plot all filled areas: filled areas have a filled area and a thick
     * outline we must plot the filled area itself ( as a filled polygon
     * OR a set of segments ) and plot the thick outline itself
587 588 589
     *
     * in non filled mode the outline is plotted, but not the filling items
     */
590 591 592 593 594 595 596
    int corners_count = 0;
    for( unsigned ic = 0, ii = 0; ic < imax; ic++ )
    {
        CPolyPt* corner = &aZone->m_FilledPolysList[ic];
        CornersBuffer[ii++] = corner->x;
        CornersBuffer[ii++] = corner->y;
        corners_count++;
597 598 599
        if( corner->end_contour )   // Plot the current filled area outline
        {
            // First, close the outline
charras's avatar
charras committed
600 601
            if( CornersBuffer[0] != CornersBuffer[ii - 2]
                || CornersBuffer[1] != CornersBuffer[ii - 1] )
602 603 604 605 606 607
            {
                CornersBuffer[ii++] = CornersBuffer[0];
                CornersBuffer[ii]   = CornersBuffer[1];
                corners_count++;
            }

608
            // Plot the current filled area and its outline
charras's avatar
charras committed
609 610
            if( trace_mode == FILLED )
            {
611
                // Plot the current filled area polygon
612 613
                if( aZone->m_FillMode == 0 )    // We are using solid polygons
                                                // (if != 0: using segments )
charras's avatar
charras committed
614
                    plotter->poly( corners_count, CornersBuffer, FILLED_SHAPE );
615 616
                else                            // We are using areas filled by
                                                // segments: plot hem )
617
                {
618 619 620
                    for( unsigned iseg = 0;
                         iseg < aZone->m_FillSegmList.size();
                         iseg++ )
621 622
                    {
                        wxPoint start = aZone->m_FillSegmList[iseg].m_Start;
623
                        wxPoint end   = aZone->m_FillSegmList[iseg].m_End;
624 625 626 627
                        plotter->thick_segment( start,
                                                end,
                                                aZone->m_ZoneMinThickness,
                                                trace_mode );
628 629 630 631
                    }
                }

                // Plot the current filled area outline
charras's avatar
charras committed
632 633 634 635 636 637 638 639 640 641 642 643 644 645
                if( aZone->m_ZoneMinThickness > 0 )
                    plotter->poly( corners_count, CornersBuffer, NO_FILL,
                                   aZone->m_ZoneMinThickness );
            }
            else
            {
                if( aZone->m_ZoneMinThickness > 0 )
                {
                    for( int ii = 1; ii<corners_count; ii++ )
                        plotter->thick_segment(
                            wxPoint( CornersBuffer[ii * 2 - 2],
                                     CornersBuffer[ii * 2 - 1] ),
                            wxPoint( CornersBuffer[ii * 2],
                                     CornersBuffer[ii * 2 + 1] ),
646
                            ( trace_mode == FILAIRE ) ? -1 : aZone->m_ZoneMinThickness,
charras's avatar
charras committed
647 648 649 650
                            trace_mode );
                }
                plotter->set_current_line_width( -1 );
            }
651 652 653 654 655
            corners_count = 0;
            ii = 0;
        }
    }
}
656

charras's avatar
charras committed
657 658

/* Plot items type DRAWSEGMENT on layers allowed by masque_layer
659
 */
660 661
void PlotDrawSegment( PLOTTER* plotter, DRAWSEGMENT* pt_segm, int masque_layer,
                      GRTraceMode trace_mode )
662
{
663
    wxPoint start, end;
664 665
    int     thickness;
    int     radius = 0, StAngle = 0, EndAngle = 0;
666 667 668 669

    if( (g_TabOneLayerMask[pt_segm->GetLayer()] & masque_layer) == 0 )
        return;

670 671 672
    if( trace_mode == FILAIRE )
        thickness = g_pcb_plot_options.PlotLine_Width;
    else
charras's avatar
charras committed
673
        thickness = pt_segm->m_Width;
674

675 676
    start = pt_segm->m_Start;
    end   = pt_segm->m_End;
677

charras's avatar
charras committed
678 679
    plotter->set_current_line_width( thickness );
    switch( pt_segm->m_Shape )
680
    {
681
    case S_CIRCLE:
682 683 684
        radius =
            (int) hypot( (double) ( end.x - start.x ),
                         (double) ( end.y - start.y ) );
charras's avatar
charras committed
685 686
        plotter->thick_circle( start, radius * 2, thickness, trace_mode );
        break;
687

688
    case S_ARC:
689 690 691
        radius =
            (int) hypot( (double) ( end.x - start.x ),
                         (double) ( end.y - start.y ) );
692 693
        StAngle  = ArcTangente( end.y - start.y, end.x - start.x );
        EndAngle = StAngle + pt_segm->m_Angle;
694 695 696 697 698 699
        plotter->thick_arc( start,
                            -EndAngle,
                            -StAngle,
                            radius,
                            thickness,
                            trace_mode );
charras's avatar
charras committed
700
        break;
charras's avatar
charras committed
701

charras's avatar
charras committed
702 703 704
    case S_CURVE:
        for( unsigned i = 1; i < pt_segm->m_BezierPoints.size(); i++ )
            plotter->thick_segment( pt_segm->m_BezierPoints[i - 1],
705 706 707
                                    pt_segm->m_BezierPoints[i],
                                    thickness,
                                    trace_mode );
708

charras's avatar
charras committed
709 710 711 712 713
        break;

    default:
        plotter->thick_segment( start, end, thickness, trace_mode );
    }
714
}
715

charras's avatar
charras committed
716

717
void WinEDA_BasePcbFrame::Plot_Layer( PLOTTER* plotter, int Layer,
charras's avatar
charras committed
718
                                      GRTraceMode trace_mode )
719 720 721 722
{
    // Specify that the contents of the "Edges Pcb" layer are to be plotted
    // in addition to the contents of the currently specified layer.
    int layer_mask = g_TabOneLayerMask[Layer];
charras's avatar
charras committed
723

724
    if( !g_pcb_plot_options.Exclude_Edges_Pcb )
charras's avatar
charras committed
725
        layer_mask |= EDGE_LAYER;
726

727
    switch( Layer )
charras's avatar
charras committed
728
    {
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
    case FIRST_COPPER_LAYER:
    case LAYER_N_2:
    case LAYER_N_3:
    case LAYER_N_4:
    case LAYER_N_5:
    case LAYER_N_6:
    case LAYER_N_7:
    case LAYER_N_8:
    case LAYER_N_9:
    case LAYER_N_10:
    case LAYER_N_11:
    case LAYER_N_12:
    case LAYER_N_13:
    case LAYER_N_14:
    case LAYER_N_15:
    case LAST_COPPER_LAYER:
745
        Plot_Standard_Layer( plotter, layer_mask, true, trace_mode );
746

747 748 749 750
        // Adding drill marks, if required and if the plotter is able to plot
        // them:
        if( g_pcb_plot_options.DrillShapeOpt !=
            PCB_Plot_Options::NO_DRILL_SHAPE )
751 752
        {
            if( plotter->GetPlotterType() == PLOT_FORMAT_POST )
753 754 755 756
                PlotDrillMark( plotter,
                               trace_mode,
                               g_pcb_plot_options.DrillShapeOpt ==
                               PCB_Plot_Options::SMALL_DRILL_SHAPE );
757
        }
charras's avatar
charras committed
758
        break;
charras's avatar
charras committed
759

760 761
    case SOLDERMASK_N_CU:
    case SOLDERMASK_N_CMP:
charras's avatar
charras committed
762 763 764
        Plot_Standard_Layer( plotter, layer_mask,
                             g_pcb_plot_options.DrawViaOnMaskLayer, trace_mode );
        break;
charras's avatar
charras committed
765

766 767
    case SOLDERPASTE_N_CU:
    case SOLDERPASTE_N_CMP:
768
        Plot_Standard_Layer( plotter, layer_mask, false, trace_mode );
charras's avatar
charras committed
769
        break;
charras's avatar
charras committed
770

charras's avatar
charras committed
771 772
    default:
        Plot_Serigraphie( plotter, layer_mask, trace_mode );
773 774
        break;
    }
775 776
}

charras's avatar
charras committed
777

778 779
/* Plot a copper layer or mask in HPGL format.
 * HPGL unit = 0.98 mils (1 mil = 1.02041 unit HPGL).
780
 */
781 782 783 784
void WinEDA_BasePcbFrame::Plot_Standard_Layer( PLOTTER*    aPlotter,
                                               int         aLayerMask,
                                               bool        aPlotVia,
                                               GRTraceMode aPlotMode )
785
{
charras's avatar
charras committed
786 787 788
    wxPoint  pos;
    wxSize   size;
    wxString msg;
789

790
    // Plot pcb draw items.
charras's avatar
charras committed
791
    for( BOARD_ITEM* item = m_Pcb->m_Drawings; item; item = item->Next() )
792
    {
793 794 795
        switch( item->Type() )
        {
        case TYPE_DRAWSEGMENT:
796 797 798 799
            PlotDrawSegment( aPlotter,
                             (DRAWSEGMENT*) item,
                             aLayerMask,
                             aPlotMode );
charras's avatar
charras committed
800
            break;
801

802
        case TYPE_TEXTE:
803
            PlotTextePcb( aPlotter, (TEXTE_PCB*) item, aLayerMask, aPlotMode );
charras's avatar
charras committed
804
            break;
805

806
        case TYPE_COTATION:
807
            PlotCotation( aPlotter, (COTATION*) item, aLayerMask, aPlotMode );
charras's avatar
charras committed
808
            break;
809

810
        case TYPE_MIRE:
811
            PlotMirePcb( aPlotter, (MIREPCB*) item, aLayerMask, aPlotMode );
812
            break;
813

814
        case TYPE_MARKER_PCB:
charras's avatar
charras committed
815
            break;
816

817 818
        default:
            DisplayError( this,
819
                          wxT( "Plot_Standard_Layer() error : Unexpected Draw Type" ) );
charras's avatar
charras committed
820
            break;
821 822 823 824
        }
    }

    /* Draw footprint shapes without pads (pads will plotted later) */
charras's avatar
charras committed
825
    for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
826
    {
charras's avatar
charras committed
827
        for( BOARD_ITEM* item = module->m_Drawings; item; item = item->Next() )
828 829 830 831
        {
            switch( item->Type() )
            {
            case TYPE_EDGE_MODULE:
832
                if( aLayerMask & g_TabOneLayerMask[ item->GetLayer() ] )
833 834 835
                    Plot_1_EdgeModule( aPlotter,
                                       (EDGE_MODULE*) item,
                                       aPlotMode );
836
                break;
837

838
            default:
charras's avatar
charras committed
839 840
                break;
            }
841 842
        }
    }
843

844
    /* Plot footprint pads */
charras's avatar
charras committed
845
    for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
846
    {
847
        for( D_PAD* pad = module->m_Pads; pad; pad = pad->Next() )
848 849
        {
            wxPoint shape_pos;
850
            if( (pad->m_Masque_Layer & aLayerMask) == 0 )
851
                continue;
852

853 854
            shape_pos = pad->ReturnShapePos();
            pos = shape_pos;
855
            wxSize margin;
856 857 858
            switch( aLayerMask &
                   ( SOLDERMASK_LAYER_CU | SOLDERMASK_LAYER_CMP |
                     SOLDERPASTE_LAYER_CU | SOLDERPASTE_LAYER_CMP ) )
859
            {
860 861 862 863
            case SOLDERMASK_LAYER_CMP:
            case SOLDERMASK_LAYER_CU:
                margin.x = margin.y = pad->GetSolderMaskMargin();
                break;
864

865 866 867 868
            case SOLDERPASTE_LAYER_CMP:
            case SOLDERPASTE_LAYER_CU:
                margin = pad->GetSolderPasteMargin();
                break;
869

870
            default:
871 872 873
                break;
            }

874 875
            size.x = pad->m_Size.x + ( 2 * margin.x );
            size.y = pad->m_Size.y + ( 2 * margin.y );
876 877 878 879 880 881

            /* Don't draw a null size item : */
            if( size.x <= 0 || size.y <= 0 )
                continue;

            switch( pad->m_PadShape )
charras's avatar
charras committed
882
            {
883
            case PAD_CIRCLE:
884
                aPlotter->flash_pad_circle( pos, size.x, aPlotMode );
charras's avatar
charras committed
885
                break;
886

887
            case PAD_OVAL:
888
                aPlotter->flash_pad_oval( pos, size, pad->m_Orient, aPlotMode );
889 890 891
                break;

            case PAD_TRAPEZOID:
892
            {
893
                wxSize delta = pad->m_DeltaSize;
894 895 896 897 898
                aPlotter->flash_pad_trapez( pos,
                                            size,
                                            delta,
                                            pad->m_Orient,
                                            aPlotMode );
charras's avatar
charras committed
899 900
            }
            break;
901

902 903
            case PAD_RECT:
            default:
904
                aPlotter->flash_pad_rect( pos, size, pad->m_Orient, aPlotMode );
charras's avatar
charras committed
905 906
                break;
            }
907 908
        }
    }
909

910
    /* Plot vias : */
911
    if( aPlotVia )
912
    {
charras's avatar
charras committed
913
        for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
914 915 916
        {
            if( track->Type() != TYPE_VIA )
                continue;
917

918 919
            SEGVIA* Via = (SEGVIA*) track;

920 921 922
            // vias are not plotted if not on selected layer, but if layer
            // is SOLDERMASK_LAYER_CU or SOLDERMASK_LAYER_CMP,vias are drawn,
            // if they are on an external copper layer
923 924 925 926 927
            int via_mask_layer = Via->ReturnMaskLayer();
            if( via_mask_layer & CUIVRE_LAYER )
                via_mask_layer |= SOLDERMASK_LAYER_CU;
            if( via_mask_layer & CMP_LAYER )
                via_mask_layer |= SOLDERMASK_LAYER_CMP;
928
            if( ( via_mask_layer & aLayerMask ) == 0 )
929
                continue;
930

931
            int via_margin = 0;
932 933 934 935

            // If the current layer is a solder mask, use the global mask
            // clearance for vias
            if( ( aLayerMask & ( SOLDERMASK_LAYER_CU | SOLDERMASK_LAYER_CMP ) ) )
936
                via_margin = g_DesignSettings.m_SolderMaskMargin;
937
            pos    = Via->m_Start;
938
            size.x = size.y = Via->m_Width + 2 * via_margin;
939

940 941 942
            /* Don't draw a null size item : */
            if( size.x <= 0 )
                continue;
943

944
            aPlotter->flash_pad_circle( pos, size.x, aPlotMode );
945
        }
946 947
    }

948
    /* Plot tracks (not vias) : */
charras's avatar
charras committed
949
    for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
950 951
    {
        wxPoint end;
952

953 954
        if( track->Type() == TYPE_VIA )
            continue;
955

956
        if( (g_TabOneLayerMask[track->GetLayer()] & aLayerMask) == 0 )
957
            continue;
958

959 960 961
        size.x = size.y = track->m_Width;
        pos    = track->m_Start;
        end    = track->m_End;
962

963
        aPlotter->thick_segment( pos, end, size.x, aPlotMode );
964
    }
965

966
    /* Plot zones (outdated, for old boards compatibility): */
charras's avatar
charras committed
967
    for( TRACK* track = m_Pcb->m_Zone; track; track = track->Next() )
968
    {
969
        wxPoint end;
970

971
        if( (g_TabOneLayerMask[track->GetLayer()] & aLayerMask) == 0 )
972
            continue;
973

974 975 976
        size.x = size.y = track->m_Width;
        pos    = track->m_Start;
        end    = track->m_End;
977

978
        aPlotter->thick_segment( pos, end, size.x, aPlotMode );
979
    }
980

981 982 983 984
    /* Plot filled ares */
    for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* edge_zone = m_Pcb->GetArea( ii );
985
        if( ( ( 1 << edge_zone->GetLayer() ) & aLayerMask ) == 0 )
986
            continue;
987
        PlotFilledAreas( aPlotter, edge_zone, aPlotMode );
charras's avatar
charras committed
988
    }
989 990
}

991

992 993
/** function PlotDrillMark
 * Draw a drill mark for pads and vias.
994
 * Must be called after all drawings, because it
995 996
 * redraw the drill mark on a pad or via, as a negative (i.e. white) shape in
 * FILLED plot mode
997 998
 * @param aPlotter = the PLOTTER
 * @param aTraceMode = the mode of plot (FILLED, SKETCH)
999 1000
 * @param aSmallDrillShape = true to plot a small drill shape, false to plot
 * the actual drill shape
1001
 */
1002 1003 1004
void WinEDA_BasePcbFrame::PlotDrillMark( PLOTTER*    aPlotter,
                                         GRTraceMode aTraceMode,
                                         bool        aSmallDrillShape )
1005 1006 1007 1008 1009 1010 1011 1012
{
    const int SMALL_DRILL = 150;
    wxPoint   pos;
    wxSize    diam;
    MODULE*   Module;
    D_PAD*    PtPad;
    TRACK*    pts;

1013
    if( aTraceMode == FILLED )
charras's avatar
charras committed
1014
    {
1015
        aPlotter->set_color( WHITE );
1016 1017
    }

1018 1019 1020 1021 1022
    for( pts = m_Pcb->m_Track; pts != NULL; pts = pts->Next() )
    {
        if( pts->Type() != TYPE_VIA )
            continue;
        pos = pts->m_Start;
1023 1024
        if( g_pcb_plot_options.DrillShapeOpt ==
            PCB_Plot_Options::SMALL_DRILL_SHAPE )
1025 1026 1027
            diam.x = diam.y = SMALL_DRILL;
        else
            diam.x = diam.y = pts->GetDrillValue();
1028

1029
        aPlotter->flash_pad_circle( pos, diam.x, aTraceMode );
1030
    }
1031

charras's avatar
charras committed
1032
    for( Module = m_Pcb->m_Modules;
1033 1034
         Module != NULL;
         Module = Module->Next() )
1035
    {
charras's avatar
charras committed
1036
        for( PtPad = Module->m_Pads;
1037 1038
             PtPad != NULL;
             PtPad = PtPad->Next() )
1039 1040 1041
        {
            if( PtPad->m_Drill.x == 0 )
                continue;
1042

1043 1044 1045 1046 1047
            // Output hole shapes:
            pos = PtPad->m_Pos;
            if( PtPad->m_DrillShape == PAD_OVAL )
            {
                diam = PtPad->m_Drill;
1048 1049 1050 1051
                aPlotter->flash_pad_oval( pos,
                                          diam,
                                          PtPad->m_Orient,
                                          aTraceMode );
1052 1053 1054
            }
            else
            {
1055 1056
                diam.x = aSmallDrillShape ? SMALL_DRILL : PtPad->m_Drill.x;
                aPlotter->flash_pad_circle( pos, diam.x, aTraceMode );
1057 1058 1059
            }
        }
    }
charras's avatar
charras committed
1060

1061
    if( aTraceMode == FILLED )
charras's avatar
charras committed
1062
    {
1063
        aPlotter->set_color( BLACK );
1064
    }
1065
}