muonde.cpp 32.5 KB
Newer Older
1 2 3
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
4 5 6 7
 * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
 * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
 * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

27 28 29 30
/**
 * @file muonde.cpp
 * @brief Microwave pcb layout code.
 */
plyatov's avatar
plyatov committed
31

32 33 34 35 36 37 38 39 40 41 42 43
#include <fctsys.h>
#include <class_drawpanel.h>
#include <confirm.h>
#include <trigo.h>
#include <kicad_string.h>
#include <gestfich.h>
#include <wxPcbStruct.h>
#include <dialog_helpers.h>
#include <richio.h>
#include <filter_reader.h>
#include <gr_basic.h>
#include <macros.h>
44
#include <base_units.h>
45

46 47 48
#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
49

50
#include <pcbnew.h>
51

52

plyatov's avatar
plyatov committed
53
#define COEFF_COUNT 6
54 55

static std::vector< double > PolyEdges;
charras's avatar
charras committed
56 57 58
static double  ShapeScaleX, ShapeScaleY;
static wxSize  ShapeSize;
static int     PolyShapeType;
plyatov's avatar
plyatov committed
59

dickelbeck's avatar
dickelbeck committed
60

61
static void Exit_Self( EDA_DRAW_PANEL* Panel, wxDC* DC );
62 63 64 65
static void gen_arc( std::vector <wxPoint>& aBuffer,
                     wxPoint                aStartPoint,
                     wxPoint                aCenter,
                     int                    a_ArcAngle );
66 67 68 69
static void ShowBoundingBoxMicroWaveInductor( EDA_DRAW_PANEL* apanel,
                                              wxDC*           aDC,
                                              const wxPoint&  aPosition,
                                              bool            aErase );
dickelbeck's avatar
dickelbeck committed
70 71


72 73 74 75
int         BuildCornersList_S_Shape( std::vector <wxPoint>& aBuffer,
                                      wxPoint aStartPoint, wxPoint aEndPoint,
                                      int aLength, int aWidth );

76
class SELFPCB
dickelbeck's avatar
dickelbeck committed
77 78
{
public:
79
    int     forme;          // Shape: coil, spiral, etc ..
dickelbeck's avatar
dickelbeck committed
80
    wxPoint m_Start;
81
    wxPoint m_End;
dickelbeck's avatar
dickelbeck committed
82
    wxSize  m_Size;
83
    int     lng;                        // Trace length.
84
    int     m_Width;                    // Trace width.
dickelbeck's avatar
dickelbeck committed
85 86 87 88 89 90
};

static SELFPCB Mself;
static int     Self_On;


91 92 93
/* This function shows on screen the bounding box of the inductor that will be
 * created at the end of the build inductor process
 */
94 95
static void ShowBoundingBoxMicroWaveInductor( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                              const wxPoint& aPosition, bool aErase )
dickelbeck's avatar
dickelbeck committed
96
{
97 98 99
    /* Calculate the orientation and size of the box containing the inductor:
     * the box is a rectangle with height = lenght/2
     * the shape is defined by a rectangle, nor necessary horizontal or vertical
dickelbeck's avatar
dickelbeck committed
100
     */
101
    GRSetDrawMode( aDC, GR_XOR );
102

103 104
    wxPoint poly[5];
    wxPoint pt    = Mself.m_End - Mself.m_Start;
105 106
    double  angle = -ArcTangente( pt.y, pt.x );
    int     len   = KiROUND( EuclideanNorm( pt ) );
107 108 109 110 111 112 113 114 115 116 117 118

    // calculate corners
    pt.x = 0; pt.y = len / 4;
    RotatePoint( &pt, angle );
    poly[0] = Mself.m_Start + pt;
    poly[1] = Mself.m_End + pt;
    pt.x    = 0; pt.y = -len / 4;
    RotatePoint( &pt, angle );
    poly[2] = Mself.m_End + pt;
    poly[3] = Mself.m_Start + pt;
    poly[4] = poly[0];

119
    if( aErase )
dickelbeck's avatar
dickelbeck committed
120
    {
121
        GRPoly( aPanel->GetClipBox(), aDC, 5, poly, false, 0, YELLOW, YELLOW );
dickelbeck's avatar
dickelbeck committed
122 123
    }

124
    Mself.m_End = aPanel->GetParent()->GetCrossHairPosition();
125
    pt    = Mself.m_End - Mself.m_Start;
126 127
    angle = -ArcTangente( pt.y, pt.x );
    len   = KiROUND( EuclideanNorm( pt ) );
dickelbeck's avatar
dickelbeck committed
128

129 130 131 132 133 134 135 136 137 138
    // calculate new corners
    pt.x = 0; pt.y = len / 4;
    RotatePoint( &pt, angle );
    poly[0] = Mself.m_Start + pt;
    poly[1] = Mself.m_End + pt;
    pt.x    = 0; pt.y = -len / 4;
    RotatePoint( &pt, angle );
    poly[2] = Mself.m_End + pt;
    poly[3] = Mself.m_Start + pt;
    poly[4] = poly[0];
dickelbeck's avatar
dickelbeck committed
139

140
    GRPoly( aPanel->GetClipBox(), aDC, 5, poly, false, 0, YELLOW, YELLOW );
dickelbeck's avatar
dickelbeck committed
141 142 143
}


144
void Exit_Self( EDA_DRAW_PANEL* Panel, wxDC* DC )
dickelbeck's avatar
dickelbeck committed
145 146 147 148
{
    if( Self_On )
    {
        Self_On = 0;
149
        Panel->CallMouseCapture( DC, wxDefaultPosition, 0 );
dickelbeck's avatar
dickelbeck committed
150 151 152 153
    }
}


154
void PCB_EDIT_FRAME::Begin_Self( wxDC* DC )
dickelbeck's avatar
dickelbeck committed
155 156 157 158 159 160 161
{
    if( Self_On )
    {
        Genere_Self( DC );
        return;
    }

162
    Mself.m_Start = GetCrossHairPosition();
163
    Mself.m_End   = Mself.m_Start;
dickelbeck's avatar
dickelbeck committed
164 165 166

    Self_On = 1;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
167
    // Update the initial coordinates.
168
    GetScreen()->m_O_Curseur = GetCrossHairPosition();
169
    UpdateStatusBar();
dickelbeck's avatar
dickelbeck committed
170

171
    m_canvas->SetMouseCapture( ShowBoundingBoxMicroWaveInductor, Exit_Self );
172
    m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
dickelbeck's avatar
dickelbeck committed
173 174 175
}


176
MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC )
dickelbeck's avatar
dickelbeck committed
177
{
Dick Hollenbeck's avatar
Dick Hollenbeck committed
178
    D_PAD*   pad;
179 180
    int      ll;
    wxString msg;
dickelbeck's avatar
dickelbeck committed
181

182
    m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
183
    m_canvas->SetMouseCapture( NULL, NULL );
dickelbeck's avatar
dickelbeck committed
184 185 186 187 188 189 190 191 192

    if( Self_On == 0 )
    {
        DisplayError( this, wxT( "Starting point not init.." ) );
        return NULL;
    }

    Self_On = 0;

193
    Mself.m_End = GetCrossHairPosition();
dickelbeck's avatar
dickelbeck committed
194

195
    wxPoint pt = Mself.m_End - Mself.m_Start;
196
    int     min_len = KiROUND( EuclideanNorm( pt ) );
197
    Mself.lng = min_len;
dickelbeck's avatar
dickelbeck committed
198

Dick Hollenbeck's avatar
Dick Hollenbeck committed
199
    // Enter the desired length.
200
    msg = StringFromValue( g_UserUnit, Mself.lng );
jean-pierre charras's avatar
jean-pierre charras committed
201
    wxTextEntryDialog dlg( this, _( "Length:" ), _( "Length" ), msg );
202

jean-pierre charras's avatar
jean-pierre charras committed
203
    if( dlg.ShowModal() != wxID_OK )
204
        return NULL; // canceled by user
dickelbeck's avatar
dickelbeck committed
205

206
    msg = dlg.GetValue();
207
    Mself.lng = ValueFromString( g_UserUnit, msg );
dickelbeck's avatar
dickelbeck committed
208

Dick Hollenbeck's avatar
Dick Hollenbeck committed
209
    // Control values (ii = minimum length)
210
    if( Mself.lng < min_len )
dickelbeck's avatar
dickelbeck committed
211 212 213 214 215
    {
        DisplayError( this, _( "Requested length < minimum length" ) );
        return NULL;
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
216
    // Calculate the elements.
217
    Mself.m_Width = GetDesignSettings().GetCurrentTrackWidth();
dickelbeck's avatar
dickelbeck committed
218

219
    std::vector <wxPoint> buffer;
220 221
    ll = BuildCornersList_S_Shape( buffer, Mself.m_Start, Mself.m_End, Mself.lng, Mself.m_Width );

222
    if( !ll )
dickelbeck's avatar
dickelbeck committed
223
    {
224 225
        DisplayError( this, _( "Requested length too large" ) );
        return NULL;
dickelbeck's avatar
dickelbeck committed
226 227
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
228 229 230
    // Generate module.
    MODULE* module;
    module = Create_1_Module( wxEmptyString );
231

Dick Hollenbeck's avatar
Dick Hollenbeck committed
232
    if( module == NULL )
dickelbeck's avatar
dickelbeck committed
233 234
        return NULL;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
235
    // here the module is already in the BOARD, Create_1_Module() does that.
236
    module->SetFPID( FPID( std::string( "MuSelf" ) ) );
237
    module->SetAttributes( MOD_VIRTUAL | MOD_CMS );
238
    module->ClearFlags();
239
    module->SetPosition( Mself.m_End );
240

Dick Hollenbeck's avatar
Dick Hollenbeck committed
241
    // Generate segments
242 243 244
    for( unsigned jj = 1; jj < buffer.size(); jj++ )
    {
        EDGE_MODULE* PtSegm;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
245 246 247 248 249 250 251 252
        PtSegm = new EDGE_MODULE( module );
        PtSegm->SetStart( buffer[jj - 1] );
        PtSegm->SetEnd( buffer[jj] );
        PtSegm->SetWidth( Mself.m_Width );
        PtSegm->SetLayer( module->GetLayer() );
        PtSegm->SetShape( S_SEGMENT );
        PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() );
        PtSegm->SetEnd0(   PtSegm->GetEnd()   - module->GetPosition() );
253
        module->GraphicalItems().PushBack( PtSegm );
dickelbeck's avatar
dickelbeck committed
254 255
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
256
    // Place a pad on each end of coil.
Dick Hollenbeck's avatar
Dick Hollenbeck committed
257 258
    pad = new D_PAD( module );

259
    module->Pads().PushFront( pad );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
260 261 262 263

    pad->SetPadName( wxT( "1" ) );
    pad->SetPosition( Mself.m_End );
    pad->SetPos0( pad->GetPosition() - module->GetPosition() );
dickelbeck's avatar
dickelbeck committed
264

Dick Hollenbeck's avatar
Dick Hollenbeck committed
265
    pad->SetSize( wxSize( Mself.m_Width, Mself.m_Width ) );
dickelbeck's avatar
dickelbeck committed
266

Dick Hollenbeck's avatar
Dick Hollenbeck committed
267
    pad->SetLayerSet( LSET( module->GetLayer() ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
268 269
    pad->SetAttribute( PAD_SMD );
    pad->SetShape( PAD_CIRCLE );
dickelbeck's avatar
dickelbeck committed
270

Dick Hollenbeck's avatar
Dick Hollenbeck committed
271
    D_PAD* newpad = new D_PAD( *pad );
dickelbeck's avatar
dickelbeck committed
272

273
    module->Pads().Insert( newpad, pad->Next() );
dickelbeck's avatar
dickelbeck committed
274

Dick Hollenbeck's avatar
Dick Hollenbeck committed
275 276 277 278
    pad = newpad;
    pad->SetPadName( wxT( "2" ) );
    pad->SetPosition( Mself.m_Start );
    pad->SetPos0( pad->GetPosition() - module->GetPosition() );
dickelbeck's avatar
dickelbeck committed
279

Dick Hollenbeck's avatar
Dick Hollenbeck committed
280
    // Modify text positions.
281
    SetMsgPanel( module );
dickelbeck's avatar
dickelbeck committed
282

283 284 285 286 287 288 289 290 291 292 293
    wxPoint refPos( ( Mself.m_Start.x + Mself.m_End.x ) / 2,
                    ( Mself.m_Start.y + Mself.m_End.y ) / 2 );

    wxPoint valPos = refPos;

    refPos.y -= module->Reference().GetSize().y;
    module->Reference().SetTextPosition( refPos );
    valPos.y += module->Value().GetSize().y;
    module->Value().SetTextPosition( valPos );
    module->Reference().SetPos0( module->Reference().GetTextPosition() - module->GetPosition() );
    module->Value().SetPos0( module->Value().GetTextPosition() - module->GetPosition() );
dickelbeck's avatar
dickelbeck committed
294

Dick Hollenbeck's avatar
Dick Hollenbeck committed
295
    module->CalculateBoundingBox();
296
    module->Draw( m_canvas, DC, GR_OR );
dickelbeck's avatar
dickelbeck committed
297

Dick Hollenbeck's avatar
Dick Hollenbeck committed
298
    return module;
dickelbeck's avatar
dickelbeck committed
299 300 301
}


302 303 304
/**
 * Function  gen_arc
 * generates an arc using arc approximation by lines:
305 306 307 308 309 310
 * Center aCenter
 * Angle "angle" (in 0.1 deg)
 * @param  aBuffer = a buffer to store points.
 * @param  aStartPoint = starting point of arc.
 * @param  aCenter = arc centre.
 * @param  a_ArcAngle = arc length in 0.1 degrees.
dickelbeck's avatar
dickelbeck committed
311
 */
312 313 314 315
static void gen_arc( std::vector <wxPoint>& aBuffer,
                     wxPoint                aStartPoint,
                     wxPoint                aCenter,
                     int                    a_ArcAngle )
dickelbeck's avatar
dickelbeck committed
316
{
317 318
    #define SEGM_COUNT_PER_360DEG 16
    wxPoint first_point = aStartPoint - aCenter;
319
    int     seg_count   = ( ( abs( a_ArcAngle ) ) * SEGM_COUNT_PER_360DEG ) / 3600;
320 321 322 323

    if( seg_count == 0 )
        seg_count = 1;

324
    double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count;
325 326 327 328 329 330 331 332 333 334

    // Creates nb_seg point to approximate arc by segments:
    for( int ii = 1; ii <= seg_count; ii++ )
    {
        double  rot_angle = increment_angle * ii;
        double  fcos = cos( rot_angle );
        double  fsin = sin( rot_angle );
        wxPoint currpt;

        // Rotate current point:
335 336
        currpt.x = KiROUND( ( first_point.x * fcos + first_point.y * fsin ) );
        currpt.y = KiROUND( ( first_point.y * fcos - first_point.x * fsin ) );
337 338 339 340 341

        wxPoint corner = aCenter + currpt;
        aBuffer.push_back( corner );
    }
}
dickelbeck's avatar
dickelbeck committed
342 343


344 345
/**
 * Function BuildCornersList_S_Shape
346
 * Create a path like a S-shaped coil
347 348
 * @param  aBuffer =  a buffer where to store points (ends of segments)
 * @param  aStartPoint = starting point of the path
349 350
 * @param  aEndPoint = ending point of the path
 * @param  aLength = full lenght of the path
351
 * @param  aWidth = segment width
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
 */
int BuildCornersList_S_Shape( std::vector <wxPoint>& aBuffer,
                              wxPoint aStartPoint, wxPoint aEndPoint,
                              int aLength, int aWidth )
{
/* We must determine:
 * segm_count = number of segments perpendicular to the direction
 * segm_len = length of a strand
 * radius = radius of rounded parts of the coil
 * stubs_len = length of the 2 stubs( segments parallel to the direction)
 *         connecting the start point to the start point of the S shape
 *         and the ending point to the end point of the S shape
 * The equations are (assuming the area size of the entire shape is Size:
 * Size.x = 2 * radius + segm_len
 * Size.y = (segm_count + 2 ) * 2 * radius + 2 * stubs_len
 * Mself.lng = 2 * delta // connections to the coil
 *             + (segm_count-2) * segm_len      // length of the strands except 1st and last
 *             + (segm_count) * (PI * radius)   // length of rounded
 * segm_len + / 2 - radius * 2)                 // length of 1st and last bit
 *
 * The constraints are:
 * segm_count >= 2
 * radius < m_Size.x
 * Size.y = (radius * 4) + (2 * stubs_len)
 * segm_len > radius * 2
 *
 * The calculation is conducted in the following way:
 * first:
 * segm_count = 2
 * radius = 4 * Size.x (arbitrarily fixed value)
 * Then:
 * Increasing the number of segments to the desired length
 * (radius decreases if necessary)
 */
386
    wxSize size;
387

Dick Hollenbeck's avatar
Dick Hollenbeck committed
388
    // This scale factor adjusts the arc length to handle
389 390 391
    // the arc to segment approximation.
    // because we use SEGM_COUNT_PER_360DEG segment to approximate a circle,
    // the trace len must be corrected when calculated using arcs
392
    // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified
393 394 395 396 397 398
    // because trace using segment is shorter the corresponding arc
    // ADJUST_SIZE is the ratio between tline len and the arc len for an arc
    // of 360/ADJUST_SIZE angle
    #define ADJUST_SIZE 0.988

    wxPoint pt       = aEndPoint - aStartPoint;
399 400
    double  angle    = -ArcTangente( pt.y, pt.x );
    int     min_len  = KiROUND( EuclideanNorm( pt ) );
401
    int     segm_len = 0;           // length of segments
402 403 404 405 406 407 408 409 410
    int     full_len;               // full len of shape (sum of lenght of all segments + arcs)


    /* Note: calculations are made for a vertical coil (more easy calculations)
     * and after points are rotated to their actual position
     * So the main direction is the Y axis.
     * the 2 stubs are on the Y axis
     * the others segments are parallel to the X axis.
     */
411

412 413 414
    // Calculate the size of area (for a vertical shape)
    size.x = min_len / 2;
    size.y = min_len;
dickelbeck's avatar
dickelbeck committed
415

416
    // Choose a reasonable starting value for the radius of the arcs.
417
    int radius = std::min( aWidth * 5, size.x / 4 );
dickelbeck's avatar
dickelbeck committed
418

419 420 421
    int segm_count;     // number of full len segments
                        // the half size segments (first and last segment) are not counted here
    int stubs_len = 0;  // lenght of first or last segment (half size of others segments)
422

423
    for( segm_count = 0; ; segm_count++ )
dickelbeck's avatar
dickelbeck committed
424
    {
425
        stubs_len = ( size.y - ( radius * 2 * (segm_count + 2 ) ) ) / 2;
426

427
        if( stubs_len < size.y / 10 ) // Reduce radius.
dickelbeck's avatar
dickelbeck committed
428
        {
429 430
            stubs_len = size.y / 10;
            radius    = ( size.y - (2 * stubs_len) ) / ( 2 * (segm_count + 2) );
431

432 433 434 435 436 437
            if( radius < aWidth ) // Radius too small.
            {
                // Unable to create line: Requested length value is too large for room
                return 0;
            }
        }
438

439
        segm_len  = size.x - ( radius * 2 );
440 441
        full_len  = 2 * stubs_len;               // Length of coil connections.
        full_len += segm_len * segm_count;       // Length of full length segments.
442
        full_len += KiROUND( ( segm_count + 2 ) * M_PI * ADJUST_SIZE * radius );    // Ard arcs len
443 444
        full_len += segm_len - (2 * radius);     // Length of first and last segments
                                                 // (half size segments len = segm_len/2 - radius).
445 446 447 448

        if( full_len >= aLength )
            break;
    }
dickelbeck's avatar
dickelbeck committed
449

450 451
    // Adjust len by adjusting segm_len:
    int delta_size = full_len - aLength;
452

453
    // reduce len of the segm_count segments + 2 half size segments (= 1 full size segment)
454
    segm_len -= delta_size / (segm_count + 1);
dickelbeck's avatar
dickelbeck committed
455

456 457 458 459 460
    // Generate first line (the first stub) and first arc (90 deg arc)
    pt = aStartPoint;
    aBuffer.push_back( pt );
    pt.y += stubs_len;
    aBuffer.push_back( pt );
dickelbeck's avatar
dickelbeck committed
461

462 463 464 465
    wxPoint centre = pt;
    centre.x -= radius;
    gen_arc( aBuffer, pt, centre, -900 );
    pt = aBuffer.back();
dickelbeck's avatar
dickelbeck committed
466

467
    int half_size_seg_len = segm_len / 2 - radius;
468

469 470 471 472 473 474
    if( half_size_seg_len )
    {
        pt.x -= half_size_seg_len;
        aBuffer.push_back( pt );
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
475
    // Create shape.
476 477 478
    int ii;
    int sign = 1;
    segm_count += 1;    // increase segm_count to create the last half_size segment
479

480 481 482
    for( ii = 0; ii < segm_count; ii++ )
    {
        int arc_angle;
dickelbeck's avatar
dickelbeck committed
483

Dick Hollenbeck's avatar
Dick Hollenbeck committed
484
        if( ii & 1 ) // odd order arcs are greater than 0
485 486 487
            sign = -1;
        else
            sign = 1;
488

489 490 491 492 493 494 495 496 497 498 499 500 501 502
        arc_angle = 1800 * sign;
        centre    = pt;
        centre.y += radius;
        gen_arc( aBuffer, pt, centre, arc_angle );
        pt    = aBuffer.back();
        pt.x += segm_len * sign;
        aBuffer.push_back( pt );
    }

    // The last point is false:
    // it is the end of a full size segment, but must be
    // the end of the second half_size segment. Change it.
    sign *= -1;
    aBuffer.back().x = aStartPoint.x + radius * sign;
dickelbeck's avatar
dickelbeck committed
503

504 505 506 507 508
    // create last arc
    pt        = aBuffer.back();
    centre    = pt;
    centre.y += radius;
    gen_arc( aBuffer, pt, centre, 900 * sign );    pt = aBuffer.back();
dickelbeck's avatar
dickelbeck committed
509

510 511
    // Rotate point
    angle += 900;
512

513 514
    for( unsigned jj = 0; jj < aBuffer.size(); jj++ )
    {
515
        RotatePoint( &aBuffer[jj].x, &aBuffer[jj].y, aStartPoint.x, aStartPoint.y, angle );
dickelbeck's avatar
dickelbeck committed
516 517
    }

518 519 520 521
    // push last point (end point)
    aBuffer.push_back( aEndPoint );

    return 1;
dickelbeck's avatar
dickelbeck committed
522 523
}

plyatov's avatar
plyatov committed
524

525
MODULE* PCB_EDIT_FRAME::Create_MuWaveBasicShape( const wxString& name, int pad_count )
plyatov's avatar
plyatov committed
526
{
Dick Hollenbeck's avatar
Dick Hollenbeck committed
527
    MODULE*  module;
528 529 530
    int      pad_num = 1;
    wxString Line;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
531
    module = Create_1_Module( name );
532

Dick Hollenbeck's avatar
Dick Hollenbeck committed
533
    if( module == NULL )
534 535
        return NULL;

536
    #define DEFAULT_SIZE 30
Dick Hollenbeck's avatar
Dick Hollenbeck committed
537
    module->SetTimeStamp( GetNewTimeStamp() );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
538

539
    module->Value().SetSize( wxSize( DEFAULT_SIZE, DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
540

541
    module->Value().SetPos0( wxPoint( 0, -DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
542

543
    module->Value().Offset( wxPoint( 0, module->Value().GetPos0().y ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
544

545
    module->Value().SetThickness( DEFAULT_SIZE / 4 );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
546

547
    module->Reference().SetSize( wxSize( DEFAULT_SIZE, DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
548

549
    module->Reference().SetPos0( wxPoint( 0, DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
550

551
    module->Reference().Offset( wxPoint( 0, module->Reference().GetPos0().y ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
552

553
    module->Reference().SetThickness( DEFAULT_SIZE / 4 );
554

Dick Hollenbeck's avatar
Dick Hollenbeck committed
555 556
    // Create 2 pads used in gaps and stubs.  The gap is between these 2 pads
    // the stub is the pad 2
557 558
    while( pad_count-- )
    {
Dick Hollenbeck's avatar
Dick Hollenbeck committed
559
        D_PAD* pad = new D_PAD( module );
560

561
        module->Pads().PushFront( pad );
562

563
        int tw = GetDesignSettings().GetCurrentTrackWidth();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
564 565 566 567 568
        pad->SetSize( wxSize( tw, tw ) );

        pad->SetPosition( module->GetPosition() );
        pad->SetShape( PAD_RECT );
        pad->SetAttribute( PAD_SMD );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
569
        pad->SetLayerSet( F_Cu );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
570

571 572 573 574
        Line.Printf( wxT( "%d" ), pad_num );
        pad->SetPadName( Line );
        pad_num++;
    }
575

Dick Hollenbeck's avatar
Dick Hollenbeck committed
576
    return module;
plyatov's avatar
plyatov committed
577 578 579
}


580
MODULE* PCB_EDIT_FRAME::Create_MuWaveComponent( int shape_type )
plyatov's avatar
plyatov committed
581
{
582
    int      oX;
charras's avatar
charras committed
583
    D_PAD*   pad;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
584
    MODULE*  module;
585 586
    wxString msg, cmp_name;
    int      pad_count = 2;
587
    int      angle     = 0;
588

Dick Hollenbeck's avatar
Dick Hollenbeck committed
589
    // Enter the size of the gap or stub
590
    int      gap_size = GetDesignSettings().GetCurrentTrackWidth();
591 592 593 594

    switch( shape_type )
    {
    case 0:
595
        msg = _( "Gap" );
596 597 598 599
        cmp_name = wxT( "GAP" );
        break;

    case 1:
600
        msg = _( "Stub" );
601 602 603 604 605
        cmp_name  = wxT( "STUB" );
        pad_count = 2;
        break;

    case 2:
606
        msg = _( "Arc Stub" );
607 608 609 610 611 612 613 614 615
        cmp_name  = wxT( "ASTUB" );
        pad_count = 1;
        break;

    default:
        msg = wxT( "???" );
        break;
    }

616
    wxString          value = StringFromValue( g_UserUnit, gap_size );
617
    wxTextEntryDialog dlg( this, msg, _( "Create microwave module" ), value );
618

jean-pierre charras's avatar
jean-pierre charras committed
619
    if( dlg.ShowModal() != wxID_OK )
620
    {
621
        m_canvas->MoveCursorToCrossHair();
jean-pierre charras's avatar
jean-pierre charras committed
622
        return NULL; // cancelled by user
623 624
    }

625
    value    = dlg.GetValue();
626
    gap_size = ValueFromString( g_UserUnit, value );
627

jean-pierre charras's avatar
jean-pierre charras committed
628
    bool abort = false;
629

jean-pierre charras's avatar
jean-pierre charras committed
630
    if( shape_type == 2 )
631
    {
632
        double            fcoeff = 10.0, fval;
jean-pierre charras's avatar
jean-pierre charras committed
633
        msg.Printf( wxT( "%3.1f" ), angle / fcoeff );
634 635 636
        wxTextEntryDialog angledlg( this, _( "Angle (0.1deg):" ),
                                    _( "Create microwave module" ), msg );

637 638
        if( angledlg.ShowModal() != wxID_OK )
        {
639
            m_canvas->MoveCursorToCrossHair();
640 641
            return NULL; // cancelled by user
        }
642

643
        msg = angledlg.GetValue();
644

jean-pierre charras's avatar
jean-pierre charras committed
645
        if( !msg.ToDouble( &fval ) )
646 647
        {
            DisplayError( this, _( "Incorrect number, abort" ) );
648
            abort = true;
649
        }
650

651
        angle = std::abs( KiROUND( fval * fcoeff ) );
652

653 654 655 656 657 658
        if( angle > 1800 )
            angle = 1800;
    }

    if( abort )
    {
659
        m_canvas->MoveCursorToCrossHair();
660 661 662
        return NULL;
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
663
    module = Create_MuWaveBasicShape( cmp_name, pad_count );
664
    pad    = module->Pads();
665 666 667 668

    switch( shape_type )
    {
    case 0:     //Gap :
Dick Hollenbeck's avatar
Dick Hollenbeck committed
669 670 671 672 673
        oX = -( gap_size + pad->GetSize().x ) / 2;
        pad->SetX0( oX );

        pad->SetX( pad->GetPos0().x + pad->GetPosition().x );

charras's avatar
charras committed
674
        pad = pad->Next();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
675 676 677

        pad->SetX0( oX + gap_size + pad->GetSize().x );
        pad->SetX( pad->GetPos0().x + pad->GetPosition().x );
678 679 680
        break;

    case 1:     //Stub :
charras's avatar
charras committed
681 682
        pad->SetPadName( wxT( "1" ) );
        pad = pad->Next();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
683 684 685
        pad->SetY0( -( gap_size + pad->GetSize().y ) / 2 );
        pad->SetSize( wxSize( pad->GetSize().x, gap_size ) );
        pad->SetY( pad->GetPos0().y + pad->GetPosition().y );
686 687
        break;

688
    case 2:     // Arc Stub created by a polygonal approach:
689 690 691
    {
        EDGE_MODULE* edge = new EDGE_MODULE( module );
        module->GraphicalItems().PushFront( edge );
692

693
        edge->SetShape( S_POLYGON );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
694
        edge->SetLayer( F_Cu );
695

696 697 698
        int numPoints = angle / 50 + 3;     // Note: angles are in 0.1 degrees
        std::vector<wxPoint> polyPoints = edge->GetPolyPoints();
        polyPoints.reserve( numPoints );
699

700
        edge->m_Start0.y = -pad->GetSize().y / 2;
701

702
        polyPoints.push_back( wxPoint( 0, 0 ) );
703

704
        int theta = -angle / 2;
705

706 707 708
        for( int ii = 1; ii<numPoints - 1; ii++ )
        {
            wxPoint pt( 0, -gap_size );
709

710
            RotatePoint( &pt.x, &pt.y, theta );
711

712
            polyPoints.push_back( pt );
713

714
            theta += 50;
715

716 717
            if( theta > angle / 2 )
                theta = angle / 2;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
718
        }
719 720 721 722

        // Close the polygon:
        polyPoints.push_back( polyPoints[0] );
    }
Dick Hollenbeck's avatar
Dick Hollenbeck committed
723
        break;
724 725 726 727 728

    default:
        break;
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
729
    module->CalculateBoundingBox();
730
    GetBoard()->m_Status_Pcb = 0;
731
    OnModify();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
732
    return module;
plyatov's avatar
plyatov committed
733 734 735 736 737
}


/**************** Polygon Shapes ***********************/

738
enum id_mw_cmd {
739
    ID_READ_SHAPE_FILE = 1000
plyatov's avatar
plyatov committed
740 741
};

742

743
/* Setting polynomial form parameters
744
 */
745
class WinEDA_SetParamShapeFrame : public wxDialog
plyatov's avatar
plyatov committed
746 747
{
private:
748
    PCB_EDIT_FRAME*  m_Parent;
749
    wxRadioBox*      m_ShapeOptionCtrl;
750
    EDA_SIZE_CTRL*   m_SizeCtrl;
plyatov's avatar
plyatov committed
751

752 753
public:
    WinEDA_SetParamShapeFrame( PCB_EDIT_FRAME* parent, const wxPoint& pos );
754
    ~WinEDA_SetParamShapeFrame() { };
plyatov's avatar
plyatov committed
755

756
private:
757 758
    void OnOkClick( wxCommandEvent& event );
    void OnCancelClick( wxCommandEvent& event );
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775

    /**
     * Function ReadDataShapeDescr
     * read a description shape file
     *  File format is
     *  Unit=MM
     *  XScale=271.501
     *  YScale=1.00133
     *
     *  $COORD
     *  0                      0.6112600148417837
     *  0.001851851851851852   0.6104800531118608
     *  ....
     *  $ENDCOORD
     *
     *  Each line is the X Y coord (normalized units from 0 to 1)
     */
776 777
    void ReadDataShapeDescr( wxCommandEvent& event );
    void AcceptOptions( wxCommandEvent& event );
plyatov's avatar
plyatov committed
778

779
    DECLARE_EVENT_TABLE()
plyatov's avatar
plyatov committed
780 781 782
};


783
BEGIN_EVENT_TABLE( WinEDA_SetParamShapeFrame, wxDialog )
784 785 786
    EVT_BUTTON( wxID_OK, WinEDA_SetParamShapeFrame::OnOkClick )
    EVT_BUTTON( wxID_CANCEL, WinEDA_SetParamShapeFrame::OnCancelClick )
    EVT_BUTTON( ID_READ_SHAPE_FILE, WinEDA_SetParamShapeFrame::ReadDataShapeDescr )
787
END_EVENT_TABLE()
plyatov's avatar
plyatov committed
788

789

790 791
WinEDA_SetParamShapeFrame::WinEDA_SetParamShapeFrame( PCB_EDIT_FRAME* parent,
                                                      const wxPoint&  framepos ) :
792 793
    wxDialog( parent, -1, _( "Complex shape" ), framepos, wxSize( 350, 280 ),
              wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
plyatov's avatar
plyatov committed
794
{
795 796
    m_Parent = parent;

797
    PolyEdges.clear();
798 799 800 801 802 803 804 805

    wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
    SetSizer( MainBoxSizer );
    wxBoxSizer* LeftBoxSizer  = new wxBoxSizer( wxVERTICAL );
    wxBoxSizer* RightBoxSizer = new wxBoxSizer( wxVERTICAL );
    MainBoxSizer->Add( LeftBoxSizer, 0, wxGROW | wxALL, 5 );
    MainBoxSizer->Add( RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );

806
    wxButton* Button = new wxButton( this, wxID_OK, _( "OK" ) );
807 808
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

809
    Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
810 811
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

812 813
    Button = new wxButton( this, ID_READ_SHAPE_FILE,
                           _( "Read Shape Description File..." ) );
814 815
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

816 817 818 819 820
    wxString shapelist[3] =
    {
        _( "Normal" ), _( "Symmetrical" ),
        _( "Mirrored" )
    };
821

822 823 824
    m_ShapeOptionCtrl = new wxRadioBox( this, -1, _( "Shape Option" ),
                                        wxDefaultPosition, wxDefaultSize, 3,
                                        shapelist, 1,
825 826 827
                                        wxRA_SPECIFY_COLS );
    LeftBoxSizer->Add( m_ShapeOptionCtrl, 0, wxGROW | wxALL, 5 );

828
    m_SizeCtrl = new EDA_SIZE_CTRL( this, _( "Size" ), ShapeSize, g_UserUnit, LeftBoxSizer );
829 830 831

    GetSizer()->Fit( this );
    GetSizer()->SetSizeHints( this );
plyatov's avatar
plyatov committed
832 833
}

834

835
void WinEDA_SetParamShapeFrame::OnCancelClick( wxCommandEvent& event )
plyatov's avatar
plyatov committed
836
{
837
    PolyEdges.clear();
838
    EndModal( -1 );
plyatov's avatar
plyatov committed
839 840 841
}


842
void WinEDA_SetParamShapeFrame::OnOkClick( wxCommandEvent& event )
plyatov's avatar
plyatov committed
843
{
844 845 846
    ShapeSize     = m_SizeCtrl->GetValue();
    PolyShapeType = m_ShapeOptionCtrl->GetSelection();
    EndModal( 1 );
plyatov's avatar
plyatov committed
847 848
}

849

850
void WinEDA_SetParamShapeFrame::ReadDataShapeDescr( wxCommandEvent& event )
plyatov's avatar
plyatov committed
851
{
852 853 854
    wxString FullFileName;
    wxString ext, mask;
    FILE*    File;
855
    char*    Line;
856 857 858 859 860 861
    double   unitconv = 10000;
    char*    param1, * param2;

    ext  = wxT( ".txt" );
    mask = wxT( "*" ) + ext;
    FullFileName = EDA_FileSelector( _( "Read descr shape file" ),
862 863 864 865
                                     wxEmptyString,
                                     FullFileName,
                                     ext,
                                     mask,
866 867
                                     this,
                                     wxFD_OPEN,
868
                                     true );
869 870 871 872 873 874 875 876 877 878 879
    if( FullFileName.IsEmpty() )
        return;

    File = wxFopen( FullFileName, wxT( "rt" ) );

    if( File == NULL )
    {
        DisplayError( this, _( "File not found" ) );
        return;
    }

880 881 882
    FILE_LINE_READER fileReader( File, FullFileName );

    FILTER_READER reader( fileReader );
883

Dick Hollenbeck's avatar
Dick Hollenbeck committed
884
    LOCALE_IO   toggle;
885

886
    while( reader.ReadLine() )
887
    {
888
        Line = reader.Line();
889 890 891 892 893 894 895
        param1 = strtok( Line, " =\n\r" );
        param2 = strtok( NULL, " \t\n\r" );

        if( strnicmp( param1, "Unit", 4 ) == 0 )
        {
            if( strnicmp( param2, "inch", 4 ) == 0 )
                unitconv = 10000;
896

897 898 899
            if( strnicmp( param2, "mm", 2 ) == 0 )
                unitconv = 10000 / 25.4;
        }
900

901 902
        if( strnicmp( param1, "$ENDCOORD", 8 ) == 0 )
            break;
903

904 905
        if( strnicmp( param1, "$COORD", 6 ) == 0 )
        {
906
            while( reader.ReadLine() )
907
            {
908
                Line = reader.Line();
909 910
                param1 = strtok( Line, " \t\n\r" );
                param2 = strtok( NULL, " \t\n\r" );
911

912 913
                if( strnicmp( param1, "$ENDCOORD", 8 ) == 0 )
                    break;
914

915 916
                PolyEdges.push_back( atof( param1 ) );
                PolyEdges.push_back( atof( param2 ) );
917 918
            }
        }
919

920 921 922 923
        if( strnicmp( Line, "XScale", 6 ) == 0 )
        {
            ShapeScaleX = atof( param2 );
        }
924

925 926 927 928 929 930 931 932 933 934
        if( strnicmp( Line, "YScale", 6 ) == 0 )
        {
            ShapeScaleY = atof( param2 );
        }
    }

    ShapeScaleX *= unitconv;
    ShapeScaleY *= unitconv;

    m_SizeCtrl->SetValue( (int) ShapeScaleX, (int) ShapeScaleY );
plyatov's avatar
plyatov committed
935 936 937
}


938
MODULE* PCB_EDIT_FRAME::Create_MuWavePolygonShape()
plyatov's avatar
plyatov committed
939
{
940
    D_PAD*       pad1, * pad2;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
941
    MODULE*      module;
942 943
    wxString     cmp_name;
    int          pad_count = 2;
944
    EDGE_MODULE* edge;
945

946
    WinEDA_SetParamShapeFrame* frame = new WinEDA_SetParamShapeFrame( this, wxPoint( -1, -1 ) );
947 948

    int ok = frame->ShowModal();
949

950
    frame->Destroy();
951

952
    m_canvas->MoveCursorToCrossHair();
953 954 955

    if( ok != 1 )
    {
956
        PolyEdges.clear();
957 958 959 960
    }

    if( PolyShapeType == 2 )  // mirrored
        ShapeScaleY = -ShapeScaleY;
961

962 963
    ShapeSize.x = KiROUND( ShapeScaleX );
    ShapeSize.y = KiROUND( ShapeScaleY );
964

965
    if( ( ShapeSize.x ) == 0 || ( ShapeSize.y == 0 ) )
966 967 968 969
    {
        DisplayError( this, _( "Shape has a null size!" ) );
        return NULL;
    }
970

971
    if( PolyEdges.size() == 0 )
972 973 974 975 976 977 978
    {
        DisplayError( this, _( "Shape has no points!" ) );
        return NULL;
    }

    cmp_name = wxT( "POLY" );

Dick Hollenbeck's avatar
Dick Hollenbeck committed
979
    module = Create_MuWaveBasicShape( cmp_name, pad_count );
980
    pad1   = module->Pads();
981

Dick Hollenbeck's avatar
Dick Hollenbeck committed
982 983
    pad1->SetX0( -ShapeSize.x / 2 );
    pad1->SetX( pad1->GetPos0().x + pad1->GetPosition().x );
984

985
    pad2 = (D_PAD*) pad1->Next();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
986 987
    pad2->SetX0( pad1->GetPos0().x + ShapeSize.x );
    pad2->SetX( pad2->GetPos0().x + pad2->GetPosition().x );
988

Dick Hollenbeck's avatar
Dick Hollenbeck committed
989
    edge = new EDGE_MODULE( module );
990

991
    module->GraphicalItems().PushFront( edge );
992

Dick Hollenbeck's avatar
Dick Hollenbeck committed
993
    edge->SetShape( S_POLYGON );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
994
    edge->SetLayer( F_Cu );
995

996
    std::vector<wxPoint> polyPoints = edge->GetPolyPoints();
997
    polyPoints.reserve( 2 * PolyEdges.size() + 2 );
998 999

    // Init start point coord:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1000
    polyPoints.push_back( wxPoint( pad1->GetPos0().x, 0 ) );
1001

1002
    wxPoint first_coordinate, last_coordinate;
1003

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1004
    for( unsigned ii = 0; ii < PolyEdges.size(); ii++ )  // Copy points
1005
    {
1006 1007
        last_coordinate.x = KiROUND( PolyEdges[ii] * ShapeScaleX ) + pad1->GetPos0().x;
        last_coordinate.y = -KiROUND( PolyEdges[ii] * ShapeScaleY );
1008
        polyPoints.push_back( last_coordinate );
1009 1010
    }

1011
    first_coordinate.y = polyPoints[1].y;
1012 1013 1014 1015 1016

    switch( PolyShapeType )
    {
    case 0:     // Single
    case 2:     // Single mirrored
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1017

1018
        // Init end point coord:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1019
        pad2->SetX0( last_coordinate.x );
1020
        polyPoints.push_back( wxPoint( last_coordinate.x, 0 ) );
1021

1022 1023 1024 1025
        pad1->SetSize( wxSize( std::abs( first_coordinate.y ),
                       std::abs( first_coordinate.y ) ) );
        pad2->SetSize( wxSize( std::abs( last_coordinate.y ),
                       std::abs( last_coordinate.y ) ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1026 1027 1028 1029 1030 1031

        pad1->SetY0( first_coordinate.y / 2 );
        pad2->SetY0( last_coordinate.y / 2 );

        pad1->SetY( pad1->GetPos0().y + module->GetPosition().y );
        pad2->SetY( pad2->GetPos0().y + module->GetPosition().y );
1032 1033
        break;

1034
    case 1:     // Symmetric
1035
        for( int ndx = polyPoints.size() - 1; ndx>=0; --ndx )
1036
        {
1037
            wxPoint pt = polyPoints[ndx];
1038

1039
            pt.y = -pt.y;   // mirror about X axis
1040

1041
            polyPoints.push_back( pt );
1042
        }
1043

1044 1045 1046 1047
        pad1->SetSize( wxSize( 2 * std::abs( first_coordinate.y ),
                       2 * std::abs( first_coordinate.y ) ) );
        pad2->SetSize( wxSize( 2 * std::abs( last_coordinate.y ),
                       2 * std::abs( last_coordinate.y ) ) );
1048 1049 1050
        break;
    }

1051
    PolyEdges.clear();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1052
    module->CalculateBoundingBox();
1053
    GetBoard()->m_Status_Pcb = 0;
1054
    OnModify();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1055
    return module;
plyatov's avatar
plyatov committed
1056 1057 1058
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
1059
void PCB_EDIT_FRAME::Edit_Gap( wxDC* DC, MODULE* aModule )
plyatov's avatar
plyatov committed
1060
{
1061 1062 1063 1064
    int      gap_size, oX;
    D_PAD*   pad, * next_pad;
    wxString msg;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1065
    if( aModule == NULL )
1066
        return;
1067

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1068
    // Test if module is a gap type (name begins with GAP, and has 2 pads).
1069
    msg = aModule->GetReference().Left( 3 );
1070

1071 1072 1073
    if( msg != wxT( "GAP" ) )
        return;

1074
    pad = aModule->Pads();
1075

1076 1077
    if( pad == NULL )
    {
1078
        DisplayError( this, _( "No pad for this footprint" ) );
1079
        return;
1080
    }
1081

1082
    next_pad = (D_PAD*) pad->Next();
1083

1084 1085
    if( next_pad == NULL )
    {
1086
        DisplayError( this, _( "Only one pad for this footprint" ) );
1087
        return;
1088 1089
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1090
    aModule->Draw( m_canvas, DC, GR_XOR );
1091

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1092 1093
    // Calculate the current dimension.
    gap_size = next_pad->GetPos0().x - pad->GetPos0().x - pad->GetSize().x;
1094

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1095
    // Entrer the desired length of the gap.
1096
    msg = StringFromValue( g_UserUnit, gap_size );
jean-pierre charras's avatar
jean-pierre charras committed
1097
    wxTextEntryDialog dlg( this, _( "Gap:" ), _( "Create Microwave Gap" ), msg );
1098

jean-pierre charras's avatar
jean-pierre charras committed
1099 1100
    if( dlg.ShowModal() != wxID_OK )
        return; // cancelled by user
1101

1102
    msg = dlg.GetValue();
1103
    gap_size = ValueFromString( g_UserUnit, msg );
1104

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1105
    // Updating sizes of pads forming the gap.
1106
    int tw = GetDesignSettings().GetCurrentTrackWidth();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1107 1108 1109 1110 1111 1112 1113 1114 1115
    pad->SetSize( wxSize( tw, tw ) );

    pad->SetY0( 0 );
    oX = -( gap_size + pad->GetSize().x ) / 2;
    pad->SetX0( oX );

    wxPoint padpos = pad->GetPos0() + aModule->GetPosition();

    RotatePoint( &padpos.x, &padpos.y,
1116
                 aModule->GetPosition().x, aModule->GetPosition().y, aModule->GetOrientation() );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1117 1118 1119

    pad->SetPosition( padpos );

1120
    tw = GetDesignSettings().GetCurrentTrackWidth();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1121 1122 1123 1124 1125 1126 1127 1128
    next_pad->SetSize( wxSize( tw, tw ) );

    next_pad->SetY0( 0 );
    next_pad->SetX0( oX + gap_size + next_pad->GetSize().x );

    padpos = next_pad->GetPos0() + aModule->GetPosition();

    RotatePoint( &padpos.x, &padpos.y,
1129
                 aModule->GetPosition().x, aModule->GetPosition().y, aModule->GetOrientation() );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1130 1131 1132 1133

    next_pad->SetPosition( padpos );

    aModule->Draw( m_canvas, DC, GR_OR );
plyatov's avatar
plyatov committed
1134
}