class_edge_mod.cpp 15.1 KB
Newer Older
1
/****************************************************/
stambaughw's avatar
stambaughw committed
2
/* class_module.cpp : EDGE_MODULE class definition. */
3
/****************************************************/
4 5 6 7 8 9

#include "fctsys.h"
#include "gr_basic.h"
#include "wxstruct.h"
#include "common.h"
#include "trigo.h"
10 11 12
#include "class_drawpanel.h"
#include "confirm.h"
#include "kicad_string.h"
13
#include "colors_selection.h"
14 15

#include "pcbnew.h"
charras's avatar
charras committed
16
#include "class_board_design_settings.h"
17

stambaughw's avatar
stambaughw committed
18 19
#define MAX_WIDTH 10000     /* Thickness (in 1 / 10000 ") of maximum reasonable
                             * features, text... */
20

stambaughw's avatar
stambaughw committed
21 22 23
/*********************/
/* class EDGE_MODULE */
/*********************/
24

dickelbeck's avatar
dickelbeck committed
25
EDGE_MODULE::EDGE_MODULE( MODULE* parent ) :
26
    BOARD_ITEM( parent, TYPE_EDGE_MODULE )
27
{
charras's avatar
charras committed
28 29 30 31
    m_Width = 0;
    m_Shape = S_SEGMENT;
    m_Angle = 0;
    m_Width = 120;
32 33
}

34

35 36 37 38
EDGE_MODULE::~EDGE_MODULE()
{
}

39

40
void EDGE_MODULE::Copy( EDGE_MODULE* source )
41
{
42 43 44 45 46 47
    if( source == NULL )
        return;

    m_Start  = source->m_Start;
    m_End    = source->m_End;
    m_Shape  = source->m_Shape;
stambaughw's avatar
stambaughw committed
48 49 50
    m_Start0 = source->m_Start0;
    m_End0   = source->m_End0;
    m_Angle  = source->m_Angle;
51 52
    m_Layer  = source->m_Layer;
    m_Width  = source->m_Width;
53

charras's avatar
charras committed
54
    m_PolyPoints = source->m_PolyPoints;    // std::vector copy
55 56
}

stambaughw's avatar
stambaughw committed
57

charras's avatar
charras committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/**
 * Function GetBoundingBox
 * returns the orthogonal, bounding box of this object for display purposes.
 * This box should be an enclosing perimeter for visible components of this
 * object, and the units should be in the pcb or schematic coordinate system.
 * It is OK to overestimate the size by a few counts.
 */
EDA_Rect EDGE_MODULE::GetBoundingBox()
{
    EDA_Rect bbox;

    bbox.SetOrigin( m_Start );

    switch( m_Shape )
    {
    case S_SEGMENT:
        bbox.SetEnd( m_End );
        bbox.Inflate( (m_Width / 2) + 1 );
        break;

    case S_CIRCLE:
    {
        int rayon = (int) hypot( (double) (m_End.x - m_Start.x), (double) (m_End.y - m_Start.y) );
        bbox.Inflate( rayon + 1 );
    }
    break;

    case S_ARC:
    {
        int rayon = (int) hypot( (double) (m_End.x - m_Start.x), (double) (m_End.y - m_Start.y) );
        bbox.Inflate( rayon + 1 );
    }
    break;

    case S_POLYGON:
    {
        // We must compute true coordinates from m_PolyPoints
        // which are relative to module position, orientation 0

        std::vector<wxPoint> points = m_PolyPoints;
        wxPoint p_end = m_Start;

        MODULE* Module = (MODULE*) m_Parent;
        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];

            if( Module )
            {
                RotatePoint( &pt.x, &pt.y, Module->m_Orient );
                pt.x += Module->m_Pos.x;
                pt.y += Module->m_Pos.y;
            }

            pt.x += m_Start0.x;
            pt.y += m_Start0.y;
            bbox.m_Pos.x = MIN( bbox.m_Pos.x, pt.x );
            bbox.m_Pos.y = MIN( bbox.m_Pos.y, pt.y );
            p_end.x   = MAX( p_end.x, pt.x );
            p_end.y   = MAX( p_end.y, pt.y );
        }

        bbox.SetEnd(p_end);
        bbox.Inflate( 1 );
        break;
    }
    }

    return bbox;
}


130
void EDGE_MODULE::SetDrawCoord()
131
{
132 133 134 135 136 137 138 139 140
    MODULE* Module = (MODULE*) m_Parent;

    m_Start = m_Start0;
    m_End   = m_End0;

    if( Module )
    {
        RotatePoint( &m_Start.x, &m_Start.y, Module->m_Orient );
        RotatePoint( &m_End.x, &m_End.y, Module->m_Orient );
charras's avatar
charras committed
141 142
        m_Start += Module->m_Pos;
        m_End   += Module->m_Pos;
143
    }
144 145 146
}


stambaughw's avatar
stambaughw committed
147 148 149 150 151 152 153 154
/* Draw EDGE_MODULE:
 * Entry: offset = offset trace
 * Draw_mode mode = trace (GR_OR, GR_XOR, GR_AND)
 * The contours are of different types:
 * - Segment
 * - Circles
 * - Arcs
 */
155
void EDGE_MODULE::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
dickelbeck's avatar
dickelbeck committed
156
                        int draw_mode, const wxPoint& offset )
157
{
158 159 160 161 162
    int                  ux0, uy0, dx, dy, rayon, StAngle, EndAngle;
    int                  color, type_trace;
    int                  typeaff;
    PCB_SCREEN*          screen;
    WinEDA_BasePcbFrame* frame;
163
    MODULE* module = (MODULE*) m_Parent;
164

165 166
    if( module == NULL )
        return;
167

168 169
    BOARD * brd = GetBoard( );
    if( brd->IsLayerVisible( m_Layer ) == false )
170 171
        return;

172
    color = brd->GetLayerColor(m_Layer);
173

174
    frame = (WinEDA_BasePcbFrame*) panel->GetParent();
175

176 177
    screen = frame->GetScreen();

178
    type_trace = m_Shape;
dickelbeck's avatar
dickelbeck committed
179 180

    ux0 = m_Start.x - offset.x;
181
    uy0 = m_Start.y - offset.y;
dickelbeck's avatar
dickelbeck committed
182

charras's avatar
charras committed
183 184
    dx = m_End.x - offset.x;
    dy = m_End.y - offset.y;
185 186 187

    GRSetDrawMode( DC, draw_mode );
    typeaff = frame->m_DisplayModEdge;
188
    if( m_Layer <= LAST_COPPER_LAYER )
189 190 191 192 193
    {
        typeaff = frame->m_DisplayPcbTrackFill;
        if( !typeaff )
            typeaff = SKETCH;
    }
194 195 196 197

#ifdef USE_WX_ZOOM
    if( DC->LogicalToDeviceXRel( m_Width ) < L_MIN_DESSIN )
#else
198
    if( screen->Scale( m_Width ) < L_MIN_DESSIN )
199
#endif
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        typeaff = FILAIRE;

    switch( type_trace )
    {
    case S_SEGMENT:
        if( typeaff == FILAIRE )
            GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, 0, color );
        else if( typeaff == FILLED )
            GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, m_Width, color );
        else
            // SKETCH Mode
            GRCSegm( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, m_Width, color );
        break;

    case S_CIRCLE:
        rayon = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
        if( typeaff == FILAIRE )
        {
            GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon, color );
        }
        else
        {
            if( typeaff == FILLED )
            {
224 225
                GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon,
                          m_Width, color );
226 227 228
            }
            else        // SKETCH Mode
            {
229 230 231 232
                GRCircle( &panel->m_ClipBox, DC, ux0, uy0,
                          rayon + (m_Width / 2), color );
                GRCircle( &panel->m_ClipBox, DC, ux0, uy0,
                          rayon - (m_Width / 2), color );
233 234 235 236 237 238 239 240 241 242 243 244
            }
        }
        break;

    case S_ARC:
        rayon    = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
        StAngle  = (int) ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;
        if( StAngle > EndAngle )
            EXCHG( StAngle, EndAngle );
        if( typeaff == FILAIRE )
        {
245 246
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon, color );
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
        }
        else if( typeaff == FILLED )
        {
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle, rayon,
                   m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon + (m_Width / 2), color );
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon - (m_Width / 2), color );
        }
        break;

    case S_POLYGON:
charras's avatar
charras committed
263

264 265
        // We must compute true coordinates from m_PolyPoints
        // which are relative to module position, orientation 0
266

stambaughw's avatar
stambaughw committed
267
        std::vector<wxPoint>        points = m_PolyPoints;
268

269 270 271
        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];
272

273 274 275
            RotatePoint( &pt.x, &pt.y, module->m_Orient );
            pt += module->m_Pos;
            pt += m_Start0 - offset;
276
        }
277 278 279

        GRPoly( &panel->m_ClipBox, DC, points.size(), &points[0],
                TRUE, m_Width, color, color );
280 281
        break;
    }
282
}
283 284


dickelbeck's avatar
dickelbeck committed
285
// see class_edge_mod.h
286
void EDGE_MODULE::DisplayInfo( WinEDA_DrawFrame* frame )
287
{
288
    wxString msg;
289

charras's avatar
charras committed
290 291
    MODULE*  module = (MODULE*) m_Parent;

292 293
    if( !module )
        return;
dickelbeck's avatar
dickelbeck committed
294

295
    BOARD* board = (BOARD*) module->GetParent();
dickelbeck's avatar
dickelbeck committed
296 297 298
    if( !board )
        return;

299
    frame->ClearMsgPanel();
300

301
    frame->AppendMsgPanel( _( "Graphic Item" ), wxEmptyString, DARKCYAN );
302

stambaughw's avatar
stambaughw committed
303 304
    frame->AppendMsgPanel( _( "Module" ), module->m_Reference->m_Text,
                           DARKCYAN );
305
    frame->AppendMsgPanel( _( "Value" ), module->m_Value->m_Text, BLUE );
306

307
    msg.Printf( wxT( "%8.8lX" ), module->m_TimeStamp );
308
    frame->AppendMsgPanel( _( "TimeStamp" ), msg, BROWN );
309

stambaughw's avatar
stambaughw committed
310 311
    frame->AppendMsgPanel( _( "Mod Layer" ),
                           board->GetLayerName( module->GetLayer() ), RED );
312

stambaughw's avatar
stambaughw committed
313 314
    frame->AppendMsgPanel( _( "Seg Layer" ),
                           board->GetLayerName( GetLayer() ), RED );
315

316
    valeur_param( m_Width, msg );
317
    frame->AppendMsgPanel( _( "Width" ), msg, BLUE );
318
}
319 320


321
/*******************************************/
dickelbeck's avatar
dickelbeck committed
322
bool EDGE_MODULE::Save( FILE* aFile ) const
323
/*******************************************/
dickelbeck's avatar
dickelbeck committed
324 325 326 327 328 329 330
{
    int ret = -1;

    switch( m_Shape )
    {
    case S_SEGMENT:
        ret = fprintf( aFile, "DS %d %d %d %d %d %d\n",
stambaughw's avatar
stambaughw committed
331 332 333
                       m_Start0.x, m_Start0.y,
                       m_End0.x, m_End0.y,
                       m_Width, m_Layer );
dickelbeck's avatar
dickelbeck committed
334 335 336 337
        break;

    case S_CIRCLE:
        ret = fprintf( aFile, "DC %d %d %d %d %d %d\n",
stambaughw's avatar
stambaughw committed
338 339 340
                       m_Start0.x, m_Start0.y,
                       m_End0.x, m_End0.y,
                       m_Width, m_Layer );
dickelbeck's avatar
dickelbeck committed
341 342 343 344
        break;

    case S_ARC:
        ret = fprintf( aFile, "DA %d %d %d %d %d %d %d\n",
stambaughw's avatar
stambaughw committed
345 346 347 348
                       m_Start0.x, m_Start0.y,
                       m_End0.x, m_End0.y,
                       m_Angle,
                       m_Width, m_Layer );
dickelbeck's avatar
dickelbeck committed
349 350 351 352
        break;

    case S_POLYGON:
        ret = fprintf( aFile, "DP %d %d %d %d %d %d %d\n",
353 354
                       m_Start0.x, m_Start0.y,
                       m_End0.x, m_End0.y,
charras's avatar
charras committed
355
                       (int) m_PolyPoints.size(),
356
                       m_Width, m_Layer );
dickelbeck's avatar
dickelbeck committed
357

charras's avatar
charras committed
358
        for( unsigned i = 0;  i<m_PolyPoints.size();  ++i )
stambaughw's avatar
stambaughw committed
359 360
            fprintf( aFile, "Dl %d %d\n", m_PolyPoints[i].x,
                     m_PolyPoints[i].y );
charras's avatar
charras committed
361

dickelbeck's avatar
dickelbeck committed
362 363 364
        break;

    default:
charras's avatar
charras committed
365

dickelbeck's avatar
dickelbeck committed
366
        // future: throw an exception here
dickelbeck's avatar
dickelbeck committed
367
#if defined(DEBUG)
dickelbeck's avatar
dickelbeck committed
368
        printf( "EDGE_MODULE::Save(): unexpected m_Shape: %d\n", m_Shape );
dickelbeck's avatar
dickelbeck committed
369
#endif
dickelbeck's avatar
dickelbeck committed
370 371 372
        break;
    }

charras's avatar
charras committed
373
    return ret > 5;
dickelbeck's avatar
dickelbeck committed
374
}
dickelbeck's avatar
dickelbeck committed
375 376


377
/* Read a description line like:
378 379 380 381 382 383 384
 *  DS 2600 0 2600 -600 120 21
 *  this description line is in Line
 *  EDGE_MODULE type can be:
 *  - Circle,
 *  - Segment (line)
 *  - Arc
 *  - Polygon
dickelbeck's avatar
dickelbeck committed
385
 *
386
 */
stambaughw's avatar
stambaughw committed
387 388
int EDGE_MODULE::ReadDescr( char* Line, FILE* File,
                            int* LineNum )
389
{
390
    int  ii;
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
    int  error = 0;
    char Buf[1024];

    switch( Line[1] )
    {
    case 'S':
        m_Shape = S_SEGMENT;
        break;

    case 'C':
        m_Shape = S_CIRCLE;
        break;

    case 'A':
        m_Shape = S_ARC;
        break;

    case 'P':
        m_Shape = S_POLYGON;
        break;

    default:
        wxString msg;
        msg.Printf( wxT( "Unknown EDGE_MODULE type <%s>" ), Line );
        DisplayError( NULL, msg );
        error = 1;
        break;
    }

    switch( m_Shape )
    {
charras's avatar
charras committed
422
    case S_ARC:
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
        sscanf( Line + 3, "%d %d %d %d %d %d %d",
                &m_Start0.x, &m_Start0.y,
                &m_End0.x, &m_End0.y,
                &m_Angle, &m_Width, &m_Layer );
        break;

    case S_SEGMENT:
    case S_CIRCLE:
        sscanf( Line + 3, "%d %d %d %d %d %d",
                &m_Start0.x, &m_Start0.y,
                &m_End0.x, &m_End0.y,
                &m_Width, &m_Layer );
        break;

    case S_POLYGON:
438
        int pointCount;
439 440 441
        sscanf( Line + 3, "%d %d %d %d %d %d %d",
                &m_Start0.x, &m_Start0.y,
                &m_End0.x, &m_End0.y,
442 443
                &pointCount, &m_Width, &m_Layer );

444
        (*LineNum)++;
445 446 447
        m_PolyPoints.clear();
        m_PolyPoints.reserve( pointCount );
        for( ii = 0;  ii<pointCount;  ii++ )
448 449 450 451 452
        {
            if( GetLine( File, Buf, LineNum, sizeof(Buf) - 1 ) != NULL )
            {
                if( strncmp( Buf, "Dl", 2 ) != 0 )
                {
453 454
                    error = 1;
                    break;
455
                }
456 457 458 459 460

                int x;
                int y;
                sscanf( Buf + 3, "%d %d\n", &x, &y );

charras's avatar
charras committed
461
                m_PolyPoints.push_back( wxPoint( x, y ) );
462 463

                (*LineNum)++;
464 465 466
            }
            else
            {
467 468
                error = 1;
                break;
469 470 471 472 473 474 475 476 477 478 479 480 481
            }
        }

        break;

    default:
        sscanf( Line + 3, "%d %d %d %d %d %d",
                &m_Start0.x, &m_Start0.y,
                &m_End0.x, &m_End0.y,
                &m_Width, &m_Layer );
        break;
    }

stambaughw's avatar
stambaughw committed
482
    // Check for a reasonable width:
483 484 485 486 487
    if( m_Width <= 1 )
        m_Width = 1;
    if( m_Width > MAX_WIDTH )
        m_Width = MAX_WIDTH;

stambaughw's avatar
stambaughw committed
488
    // Check for a reasonable layer:
dickelbeck's avatar
dickelbeck committed
489 490 491
    // m_Layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints
    // can use the copper layers m_Layer < FIRST_NON_COPPER_LAYER is allowed.
    // @todo: changes use of EDGE_MODULE these footprints and allows only m_Layer >= FIRST_NON_COPPER_LAYER
charras's avatar
charras committed
492
    if( (m_Layer < 0) || (m_Layer > LAST_NON_COPPER_LAYER) )
493
        m_Layer = SILKSCREEN_N_FRONT;
494 495 496
    return error;
}

497

dickelbeck's avatar
dickelbeck committed
498 499 500 501 502 503 504 505
/**
 * 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 EDGE_MODULE::HitTest( const wxPoint& ref_pos )
{
charras's avatar
charras committed
506 507 508 509
    int uxf, uyf;
    int rayon, dist;
    int dx, dy, spot_cX, spot_cY;
    int ux0, uy0;
dickelbeck's avatar
dickelbeck committed
510

dickelbeck's avatar
dickelbeck committed
511
    ux0 = m_Start.x;
dickelbeck's avatar
dickelbeck committed
512
    uy0 = m_Start.y;
dickelbeck's avatar
dickelbeck committed
513 514

    uxf = m_End.x;
dickelbeck's avatar
dickelbeck committed
515 516 517 518 519
    uyf = m_End.y;

    switch( m_Shape )
    {
    case S_SEGMENT:
dickelbeck's avatar
dickelbeck committed
520
        spot_cX = ref_pos.x - ux0;
dickelbeck's avatar
dickelbeck committed
521
        spot_cY = ref_pos.y - uy0;
dickelbeck's avatar
dickelbeck committed
522 523

        dx = uxf - ux0;
dickelbeck's avatar
dickelbeck committed
524
        dy = uyf - uy0;
charras's avatar
charras committed
525
        if( DistanceTest( m_Width / 2, dx, dy, spot_cX, spot_cY ) )
dickelbeck's avatar
dickelbeck committed
526 527 528 529 530
            return true;
        break;

    case S_CIRCLE:
        rayon = (int) hypot( (double) (uxf - ux0), (double) (uyf - uy0) );
stambaughw's avatar
stambaughw committed
531
        dist  = (int) hypot( (double) (ref_pos.x - ux0),
charras's avatar
charras committed
532
                            (double) (ref_pos.y - uy0) );
dickelbeck's avatar
dickelbeck committed
533 534 535 536 537 538
        if( abs( rayon - dist ) <= m_Width )
            return true;
        break;

    case S_ARC:
        rayon = (int) hypot( (double) (uxf - ux0), (double) (uyf - uy0) );
stambaughw's avatar
stambaughw committed
539
        dist  = (int) hypot( (double) (ref_pos.x - ux0),
charras's avatar
charras committed
540
                            (double) (ref_pos.y - uy0) );
dickelbeck's avatar
dickelbeck committed
541 542 543 544 545 546 547 548 549 550

        if( abs( rayon - dist ) > m_Width )
            break;

        int mouseAngle = (int) ArcTangente( ref_pos.y - uy0, ref_pos.x - ux0 );
        int stAngle    = (int) ArcTangente( uyf - uy0, uxf - ux0 );
        int endAngle   = stAngle + m_Angle;

        if( endAngle > 3600 )
        {
dickelbeck's avatar
dickelbeck committed
551
            stAngle  -= 3600;
dickelbeck's avatar
dickelbeck committed
552 553 554 555 556 557 558 559 560
            endAngle -= 3600;
        }

        if( (mouseAngle >= stAngle) && (mouseAngle <= endAngle) )
            return true;

        break;
    }

dickelbeck's avatar
dickelbeck committed
561
    return false;       // an unknown m_Shape also returns false
dickelbeck's avatar
dickelbeck committed
562 563 564
}


565
#if defined(DEBUG)
566

stambaughw's avatar
stambaughw committed
567

568 569 570 571 572 573 574 575 576
/**
 * 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 EDGE_MODULE::Show( int nestLevel, std::ostream& os )
{
577
    wxString shape = ShowShape( (Track_Shapes) m_Shape );
578

579
    // for now, make it look like XML:
dickelbeck's avatar
dickelbeck committed
580
    NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
charras's avatar
charras committed
581
    " type=\"" << CONV_TO_UTF8( shape ) << "\">";
dickelbeck's avatar
dickelbeck committed
582

dickelbeck's avatar
dickelbeck committed
583 584
    os << " <start" << m_Start0 << "/>";
    os << " <end" << m_End0 << "/>";
dickelbeck's avatar
dickelbeck committed
585

dickelbeck's avatar
dickelbeck committed
586
    os << " </" << GetClass().Lower().mb_str() << ">\n";
587 588
}

charras's avatar
charras committed
589

590
#endif