muonde.cpp 32.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
 * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
 * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
 *
 * 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
 */

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

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 <pcbcommon.h>
#include <macros.h>
44

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

49 50
#include <protos.h>
#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 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    wxPoint poly[5];
    wxPoint pt    = Mself.m_End - Mself.m_Start;
    int     angle = -wxRound( atan2( (double) pt.y, (double) pt.x ) * 1800.0 / M_PI );
    int     len   = wxRound( sqrt( (double) pt.x * pt.x + (double) pt.y * pt.y ) );

    // 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->GetScreen()->GetCrossHairPosition();
125 126 127
    pt    = Mself.m_End - Mself.m_Start;
    angle = -wxRound( atan2( (double) pt.y, (double) pt.x ) * 1800.0 / M_PI );
    len   = wxRound( sqrt( (double) pt.x * pt.x + (double) pt.y * pt.y ) );
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 = GetScreen()->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 = GetScreen()->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 = GetScreen()->GetCrossHairPosition();
dickelbeck's avatar
dickelbeck committed
194

195 196 197
    wxPoint pt = Mself.m_End - Mself.m_Start;
    int     min_len = wxRound( sqrt( (double) pt.x * pt.x + (double) pt.y * pt.y ) );
    Mself.lng = min_len;
dickelbeck's avatar
dickelbeck committed
198

Dick Hollenbeck's avatar
Dick Hollenbeck committed
199
    // Enter the desired length.
jean-pierre charras's avatar
jean-pierre charras committed
200 201
    msg = ReturnStringFromValue( g_UserUnit, Mself.lng, GetScreen()->GetInternalUnits() );
    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();
jean-pierre charras's avatar
jean-pierre charras committed
207
    Mself.lng = ReturnValueFromString( g_UserUnit, msg, GetScreen()->GetInternalUnits() );
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 = GetBoard()->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 236 237
    // here the module is already in the BOARD, Create_1_Module() does that.
    module->m_LibRef    = wxT( "MuSelf" );
    module->m_Attributs = MOD_VIRTUAL | MOD_CMS;
238
    module->ClearFlags();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
239
    module->m_Pos = 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 253
        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() );
        module->m_Drawings.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 259 260 261 262 263
    pad = new D_PAD( module );

    module->m_Pads.PushFront( pad );

    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 268 269
    pad->SetLayerMask( GetLayerMask( module->GetLayer() ) );
    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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
273
    module->m_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 281 282
    // Modify text positions.
    module->DisplayInfo( this );
    module->m_Value->m_Pos.x = module->m_Reference->m_Pos.x =
283
                               ( Mself.m_Start.x + Mself.m_End.x ) / 2;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
284
    module->m_Value->m_Pos.y = module->m_Reference->m_Pos.y =
285
                               ( Mself.m_Start.y + Mself.m_End.y ) / 2;
dickelbeck's avatar
dickelbeck committed
286

Dick Hollenbeck's avatar
Dick Hollenbeck committed
287 288 289 290
    module->m_Reference->m_Pos.y -= module->m_Reference->m_Size.y;
    module->m_Value->m_Pos.y     += module->m_Value->m_Size.y;
    module->m_Reference->SetPos0( module->m_Reference->m_Pos - module->m_Pos );
    module->m_Value->SetPos0( module->m_Value->m_Pos - module->m_Pos );
dickelbeck's avatar
dickelbeck committed
291

Dick Hollenbeck's avatar
Dick Hollenbeck committed
292
    module->CalculateBoundingBox();
293
    module->Draw( m_canvas, DC, GR_OR );
dickelbeck's avatar
dickelbeck committed
294

Dick Hollenbeck's avatar
Dick Hollenbeck committed
295
    return module;
dickelbeck's avatar
dickelbeck committed
296 297 298
}


299 300 301
/**
 * Function  gen_arc
 * generates an arc using arc approximation by lines:
302 303 304 305 306 307
 * 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
308
 */
309 310 311 312
static void gen_arc( std::vector <wxPoint>& aBuffer,
                     wxPoint                aStartPoint,
                     wxPoint                aCenter,
                     int                    a_ArcAngle )
dickelbeck's avatar
dickelbeck committed
313
{
314 315
    #define SEGM_COUNT_PER_360DEG 16
    wxPoint first_point = aStartPoint - aCenter;
316
    int     seg_count   = ( ( abs( a_ArcAngle ) ) * SEGM_COUNT_PER_360DEG ) / 3600;
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

    if( seg_count == 0 )
        seg_count = 1;

    double increment_angle = (double) a_ArcAngle * 3.14159 / 1800 / seg_count;

    // 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:
        currpt.x = wxRound( ( first_point.x * fcos + first_point.y * fsin ) );
        currpt.y = wxRound( ( first_point.y * fcos - first_point.x * fsin ) );

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


341 342
/**
 * Function BuildCornersList_S_Shape
343
 * Create a path like a S-shaped coil
344 345
 * @param  aBuffer =  a buffer where to store points (ends of segments)
 * @param  aStartPoint = starting point of the path
346 347
 * @param  aEndPoint = ending point of the path
 * @param  aLength = full lenght of the path
348
 * @param  aWidth = segment width
349 350 351 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
 */
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)
 */
383
    wxSize size;
384

Dick Hollenbeck's avatar
Dick Hollenbeck committed
385
    // This scale factor adjusts the arc length to handle
386 387 388
    // 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
389
    // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified
390 391 392 393 394 395 396 397
    // 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;
    int     angle    = -wxRound( atan2( (double) pt.y, (double) pt.x ) * 1800.0 / M_PI );
    int     min_len  = wxRound( sqrt( (double) pt.x * pt.x + (double) pt.y * pt.y ) );
398
    int     segm_len = 0;           // length of segments
399 400 401 402 403 404 405 406 407
    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.
     */
408

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

413 414
    // Choose a reasonable starting value for the radius of the arcs.
    int radius = MIN( aWidth * 5, size.x / 4 );
dickelbeck's avatar
dickelbeck committed
415

416 417 418
    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)
419

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

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

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

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

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

447 448
    // Adjust len by adjusting segm_len:
    int delta_size = full_len - aLength;
449

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

453 454 455 456 457
    // 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
458

459 460 461 462
    wxPoint centre = pt;
    centre.x -= radius;
    gen_arc( aBuffer, pt, centre, -900 );
    pt = aBuffer.back();
dickelbeck's avatar
dickelbeck committed
463

464
    int half_size_seg_len = segm_len / 2 - radius;
465

466 467 468 469 470 471
    if( half_size_seg_len )
    {
        pt.x -= half_size_seg_len;
        aBuffer.push_back( pt );
    }

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

477 478 479
    for( ii = 0; ii < segm_count; ii++ )
    {
        int arc_angle;
dickelbeck's avatar
dickelbeck committed
480

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

486 487 488 489 490 491 492 493 494 495 496 497 498 499
        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
500

501 502 503 504 505
    // 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
506

507 508
    // Rotate point
    angle += 900;
509

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

515 516 517 518
    // push last point (end point)
    aBuffer.push_back( aEndPoint );

    return 1;
dickelbeck's avatar
dickelbeck committed
519 520
}

plyatov's avatar
plyatov committed
521

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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
528
    module = Create_1_Module( name );
529

Dick Hollenbeck's avatar
Dick Hollenbeck committed
530
    if( module == NULL )
531 532
        return NULL;

533
    #define DEFAULT_SIZE 30
Dick Hollenbeck's avatar
Dick Hollenbeck committed
534
    module->SetTimeStamp( GetNewTimeStamp() );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
535

Dick Hollenbeck's avatar
Dick Hollenbeck committed
536
    module->m_Value->m_Size       = wxSize( DEFAULT_SIZE, DEFAULT_SIZE );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
537

Dick Hollenbeck's avatar
Dick Hollenbeck committed
538
    module->m_Value->SetPos0( wxPoint( 0, -DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
539

Dick Hollenbeck's avatar
Dick Hollenbeck committed
540
    module->m_Value->m_Pos.y     += module->m_Value->GetPos0().y;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
541

Dick Hollenbeck's avatar
Dick Hollenbeck committed
542
    module->m_Value->m_Thickness  = DEFAULT_SIZE / 4;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
543

Dick Hollenbeck's avatar
Dick Hollenbeck committed
544
    module->m_Reference->m_Size   = wxSize( DEFAULT_SIZE, DEFAULT_SIZE );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
545

Dick Hollenbeck's avatar
Dick Hollenbeck committed
546
    module->m_Reference->SetPos0( wxPoint( 0, DEFAULT_SIZE ) );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
547

Dick Hollenbeck's avatar
Dick Hollenbeck committed
548
    module->m_Reference->m_Pos.y += module->m_Reference->GetPos0().y;
Dick Hollenbeck's avatar
Dick Hollenbeck committed
549

Dick Hollenbeck's avatar
Dick Hollenbeck committed
550
    module->m_Reference->m_Thickness  = DEFAULT_SIZE / 4;
551

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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
558
        module->m_Pads.PushFront( pad );
559

Dick Hollenbeck's avatar
Dick Hollenbeck committed
560 561 562 563 564 565 566 567
        int tw = GetBoard()->GetCurrentTrackWidth();
        pad->SetSize( wxSize( tw, tw ) );

        pad->SetPosition( module->GetPosition() );
        pad->SetShape( PAD_RECT );
        pad->SetAttribute( PAD_SMD );
        pad->SetLayerMask( LAYER_FRONT );

568 569 570 571
        Line.Printf( wxT( "%d" ), pad_num );
        pad->SetPadName( Line );
        pad_num++;
    }
572

Dick Hollenbeck's avatar
Dick Hollenbeck committed
573
    return module;
plyatov's avatar
plyatov committed
574 575 576
}


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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
586
    // Enter the size of the gap or stub
587
    int      gap_size = GetBoard()->GetCurrentTrackWidth();
588 589 590 591

    switch( shape_type )
    {
    case 0:
592
        msg = _( "Gap" );
593 594 595 596
        cmp_name = wxT( "GAP" );
        break;

    case 1:
597
        msg = _( "Stub" );
598 599 600 601 602
        cmp_name  = wxT( "STUB" );
        pad_count = 2;
        break;

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

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

613
    wxString          value = ReturnStringFromValue( g_UserUnit, gap_size,
614
                                                     GetScreen()->GetInternalUnits() );
615
    wxTextEntryDialog dlg( this, msg, _( "Create microwave module" ), value );
616

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

623 624
    value    = dlg.GetValue();
    gap_size = ReturnValueFromString( g_UserUnit, value, GetScreen()->GetInternalUnits() );
625

jean-pierre charras's avatar
jean-pierre charras committed
626
    bool abort = false;
627

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

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

641
        msg = angledlg.GetValue();
642

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

649
        angle = ABS( wxRound( fval * fcoeff ) );
650

651 652 653 654 655 656
        if( angle > 1800 )
            angle = 1800;
    }

    if( abort )
    {
657
        m_canvas->MoveCursorToCrossHair();
658 659 660
        return NULL;
    }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
661 662
    module = Create_MuWaveBasicShape( cmp_name, pad_count );
    pad    = module->m_Pads;
663 664 665 666

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

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

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

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

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

686
    case 2:     // Arc Stub created by a polygonal approach:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
687 688 689
        {
            EDGE_MODULE* edge = new EDGE_MODULE( module );
            module->m_Drawings.PushFront( edge );
690

Dick Hollenbeck's avatar
Dick Hollenbeck committed
691 692
            edge->SetShape( S_POLYGON );
            edge->SetLayer( LAYER_N_FRONT );
693

Dick Hollenbeck's avatar
Dick Hollenbeck committed
694 695 696
            int numPoints = angle / 50 + 3;     // Note: angles are in 0.1 degrees
            std::vector<wxPoint> polyPoints = edge->GetPolyPoints();
            polyPoints.reserve( numPoints );
697

Dick Hollenbeck's avatar
Dick Hollenbeck committed
698
            edge->m_Start0.y = -pad->GetSize().y / 2;
699

Dick Hollenbeck's avatar
Dick Hollenbeck committed
700
            polyPoints.push_back( wxPoint( 0, 0 ) );
701

Dick Hollenbeck's avatar
Dick Hollenbeck committed
702
            int theta = -angle / 2;
703

Dick Hollenbeck's avatar
Dick Hollenbeck committed
704 705 706
            for( int ii = 1; ii<numPoints - 1; ii++ )
            {
                wxPoint pt( 0, -gap_size );
707

Dick Hollenbeck's avatar
Dick Hollenbeck committed
708
                RotatePoint( &pt.x, &pt.y, theta );
709

Dick Hollenbeck's avatar
Dick Hollenbeck committed
710
                polyPoints.push_back( pt );
711

Dick Hollenbeck's avatar
Dick Hollenbeck committed
712
                theta += 50;
713

Dick Hollenbeck's avatar
Dick Hollenbeck committed
714 715 716
                if( theta > angle / 2 )
                    theta = angle / 2;
            }
717

Dick Hollenbeck's avatar
Dick Hollenbeck committed
718 719 720 721
            // Close the polygon:
            polyPoints.push_back( polyPoints[0] );
        }
        break;
722 723 724 725 726

    default:
        break;
    }

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


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

736
enum id_mw_cmd {
737
    ID_READ_SHAPE_FILE = 1000
plyatov's avatar
plyatov committed
738 739
};

740

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

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

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

    /**
     * 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)
     */
773 774
    void ReadDataShapeDescr( wxCommandEvent& event );
    void AcceptOptions( wxCommandEvent& event );
plyatov's avatar
plyatov committed
775

776
    DECLARE_EVENT_TABLE()
plyatov's avatar
plyatov committed
777 778 779
};


780
BEGIN_EVENT_TABLE( WinEDA_SetParamShapeFrame, wxDialog )
781 782 783
    EVT_BUTTON( wxID_OK, WinEDA_SetParamShapeFrame::OnOkClick )
    EVT_BUTTON( wxID_CANCEL, WinEDA_SetParamShapeFrame::OnCancelClick )
    EVT_BUTTON( ID_READ_SHAPE_FILE, WinEDA_SetParamShapeFrame::ReadDataShapeDescr )
784
END_EVENT_TABLE()
plyatov's avatar
plyatov committed
785

786

787 788
WinEDA_SetParamShapeFrame::WinEDA_SetParamShapeFrame( PCB_EDIT_FRAME* parent,
                                                      const wxPoint&  framepos ) :
789
    wxDialog( parent, -1, _( "Complex shape" ), framepos, wxSize( 350, 280 ), DIALOG_STYLE )
plyatov's avatar
plyatov committed
790
{
791 792
    m_Parent = parent;

793
    PolyEdges.clear();
794 795 796 797 798 799 800 801

    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 );

802
    wxButton* Button = new wxButton( this, wxID_OK, _( "OK" ) );
803 804
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

805
    Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
806 807
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

808 809
    Button = new wxButton( this, ID_READ_SHAPE_FILE,
                           _( "Read Shape Description File..." ) );
810 811
    RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );

812 813 814 815 816
    wxString shapelist[3] =
    {
        _( "Normal" ), _( "Symmetrical" ),
        _( "Mirrored" )
    };
817

818 819 820
    m_ShapeOptionCtrl = new wxRadioBox( this, -1, _( "Shape Option" ),
                                        wxDefaultPosition, wxDefaultSize, 3,
                                        shapelist, 1,
821 822 823
                                        wxRA_SPECIFY_COLS );
    LeftBoxSizer->Add( m_ShapeOptionCtrl, 0, wxGROW | wxALL, 5 );

824 825 826
    m_SizeCtrl = new EDA_SIZE_CTRL( this, _( "Size" ), ShapeSize,
                                    g_UserUnit, LeftBoxSizer,
                                    PCB_INTERNAL_UNIT );
827 828 829

    GetSizer()->Fit( this );
    GetSizer()->SetSizeHints( this );
plyatov's avatar
plyatov committed
830 831
}

832

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


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

847

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

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

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

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

878 879 880
    FILE_LINE_READER fileReader( File, FullFileName );

    FILTER_READER reader( fileReader );
881

Dick Hollenbeck's avatar
Dick Hollenbeck committed
882
    LOCALE_IO   toggle;
883

884
    while( reader.ReadLine() )
885
    {
886
        Line = reader.Line();
887 888 889 890 891 892 893
        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;
894

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

899 900
        if( strnicmp( param1, "$ENDCOORD", 8 ) == 0 )
            break;
901

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

910 911
                if( strnicmp( param1, "$ENDCOORD", 8 ) == 0 )
                    break;
912

913 914
                PolyEdges.push_back( atof( param1 ) );
                PolyEdges.push_back( atof( param2 ) );
915 916
            }
        }
917

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

923 924 925 926 927 928 929 930 931 932
        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
933 934 935
}


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

944
    WinEDA_SetParamShapeFrame* frame = new WinEDA_SetParamShapeFrame( this, wxPoint( -1, -1 ) );
945 946

    int ok = frame->ShowModal();
947

948
    frame->Destroy();
949

950
    m_canvas->MoveCursorToCrossHair();
951 952 953

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

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

960 961
    ShapeSize.x = wxRound( ShapeScaleX );
    ShapeSize.y = wxRound( ShapeScaleY );
962

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

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

    cmp_name = wxT( "POLY" );

Dick Hollenbeck's avatar
Dick Hollenbeck committed
977 978
    module = Create_MuWaveBasicShape( cmp_name, pad_count );
    pad1   = module->m_Pads;
979

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

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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
987
    edge = new EDGE_MODULE( module );
988

Dick Hollenbeck's avatar
Dick Hollenbeck committed
989
    module->m_Drawings.PushFront( edge );
990

Dick Hollenbeck's avatar
Dick Hollenbeck committed
991
    edge->SetShape( S_POLYGON );
dickelbeck's avatar
dickelbeck committed
992
    edge->SetLayer( LAYER_N_FRONT );
993

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

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

1000
    wxPoint first_coordinate, last_coordinate;
1001

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

1009
    first_coordinate.y = polyPoints[1].y;
1010 1011 1012 1013 1014

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

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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1020 1021 1022 1023 1024 1025 1026 1027
        pad1->SetSize( wxSize( ABS( first_coordinate.y ), ABS( first_coordinate.y ) ) );
        pad2->SetSize( wxSize( ABS( last_coordinate.y ),  ABS( last_coordinate.y ) ) );

        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 );
1028 1029
        break;

1030
    case 1:     // Symmetric
1031
        for( int ndx = polyPoints.size() - 1; ndx>=0; --ndx )
1032
        {
1033
            wxPoint pt = polyPoints[ndx];
1034

1035
            pt.y = -pt.y;   // mirror about X axis
1036

1037
            polyPoints.push_back( pt );
1038
        }
1039

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1040 1041
        pad1->SetSize( wxSize( 2 * ABS( first_coordinate.y ), 2 * ABS( first_coordinate.y ) ) );
        pad2->SetSize( wxSize( 2 * ABS( last_coordinate.y ),  2 * ABS( last_coordinate.y ) ) );
1042 1043 1044
        break;
    }

1045
    PolyEdges.clear();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1046
    module->CalculateBoundingBox();
1047
    GetBoard()->m_Status_Pcb = 0;
1048
    OnModify();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
1049
    return module;
plyatov's avatar
plyatov committed
1050 1051 1052
}


Dick Hollenbeck's avatar
Dick Hollenbeck committed
1053
void PCB_EDIT_FRAME::Edit_Gap( wxDC* DC, MODULE* aModule )
plyatov's avatar
plyatov committed
1054
{
1055 1056 1057 1058
    int      gap_size, oX;
    D_PAD*   pad, * next_pad;
    wxString msg;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1059
    if( aModule == NULL )
1060
        return;
1061

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1062 1063
    // Test if module is a gap type (name begins with GAP, and has 2 pads).
    msg = aModule->m_Reference->m_Text.Left( 3 );
1064

1065 1066 1067
    if( msg != wxT( "GAP" ) )
        return;

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1068
    pad = aModule->m_Pads;
1069

1070 1071
    if( pad == NULL )
    {
1072 1073
        DisplayError( this, _( "No pad for this module" ) );
        return;
1074
    }
1075

1076
    next_pad = (D_PAD*) pad->Next();
1077

1078 1079
    if( next_pad == NULL )
    {
1080 1081
        DisplayError( this, _( "Only one pad for this module" ) );
        return;
1082 1083
    }

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

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

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1089
    // Entrer the desired length of the gap.
jean-pierre charras's avatar
jean-pierre charras committed
1090 1091
    msg = ReturnStringFromValue( g_UserUnit, gap_size, GetScreen()->GetInternalUnits() );
    wxTextEntryDialog dlg( this, _( "Gap:" ), _( "Create Microwave Gap" ), msg );
1092

jean-pierre charras's avatar
jean-pierre charras committed
1093 1094
    if( dlg.ShowModal() != wxID_OK )
        return; // cancelled by user
1095

1096
    msg = dlg.GetValue();
jean-pierre charras's avatar
jean-pierre charras committed
1097
    gap_size = ReturnValueFromString( g_UserUnit, msg, GetScreen()->GetInternalUnits() );
1098

Dick Hollenbeck's avatar
Dick Hollenbeck committed
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
    // Updating sizes of pads forming the gap.
    int tw = GetBoard()->GetCurrentTrackWidth();
    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,
                 aModule->m_Pos.x, aModule->m_Pos.y, aModule->GetOrientation() );

    pad->SetPosition( padpos );

    tw = GetBoard()->GetCurrentTrackWidth();
    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,
                 aModule->m_Pos.x, aModule->m_Pos.y, aModule->GetOrientation() );

    next_pad->SetPosition( padpos );

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