class_drawsegment.cpp 10.3 KB
Newer Older
1 2 3 4 5 6 7 8
/***************************************************/
/* class and functions to handle a graphic segment */
/****************************************************/

#include "fctsys.h"
#include "wxstruct.h"
#include "gr_basic.h"
#include "common.h"
9 10 11
#include "class_drawpanel.h"
#include "kicad_string.h"

12 13 14 15 16 17 18 19 20
#include "pcbnew.h"

#ifdef CVPCB
#include "cvpcb.h"
#endif

#include "trigo.h"

/* DRAWSEGMENT: constructor */
21 22
DRAWSEGMENT::DRAWSEGMENT( BOARD_ITEM* aParent, KICAD_T idtype ) :
    BOARD_ITEM( aParent, idtype )
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
{
    m_Width = m_Flags = m_Shape = m_Type = m_Angle = 0;
}


/* destructor */
DRAWSEGMENT:: ~DRAWSEGMENT()
{
}


/*******************************************/
void DRAWSEGMENT::Copy( DRAWSEGMENT* source )
/*******************************************/
{
    m_Type      = source->m_Type;
    m_Layer     = source->m_Layer;
    m_Width     = source->m_Width;
    m_Start     = source->m_Start;
    m_End       = source->m_End;
    m_Shape     = source->m_Shape;
    m_Angle     = source->m_Angle;
    m_TimeStamp = source->m_TimeStamp;
}


bool DRAWSEGMENT::Save( FILE* aFile ) const
{
    if( GetState( DELETED ) )
        return true;

    bool rc = false;

    if( fprintf( aFile, "$DRAWSEGMENT\n" ) != sizeof("$DRAWSEGMENT\n") - 1 )
        goto out;

    fprintf( aFile, "Po %d %d %d %d %d %d\n",
             m_Shape,
             m_Start.x, m_Start.y,
             m_End.x, m_End.y, m_Width );

    fprintf( aFile, "De %d %d %d %lX %X\n",
            m_Layer, m_Type, m_Angle,
            m_TimeStamp, ReturnStatus() );

    if( fprintf( aFile, "$EndDRAWSEGMENT\n" ) != sizeof("$EndDRAWSEGMENT\n") - 1 )
        goto out;

    rc = true;

out:
    return rc;
}


/******************************************************************/
bool DRAWSEGMENT::ReadDrawSegmentDescr( FILE* File, int* LineNum )
/******************************************************************/

/* Read a DRAWSEGMENT from a file
 */
{
    char Line[2048];

    while( GetLine( File, Line, LineNum ) != NULL )
    {
        if( strnicmp( Line, "$End", 4 ) == 0 )
            return TRUE; /* End of description */
        if( Line[0] == 'P' )
        {
            sscanf( Line + 2, " %d %d %d %d %d %d",
                    &m_Shape, &m_Start.x, &m_Start.y,
                    &m_End.x, &m_End.y, &m_Width );
            if( m_Width < 0 )
                m_Width = 0;
        }

        if( Line[0] == 'D' )
        {
            int status;
            sscanf( Line + 2, " %d %d %d %lX %X",
                    &m_Layer, &m_Type, &m_Angle,
                    &m_TimeStamp, &status );

            if( m_Layer < FIRST_NO_COPPER_LAYER )
                m_Layer = FIRST_NO_COPPER_LAYER;
            if( m_Layer > LAST_NO_COPPER_LAYER )
                m_Layer = LAST_NO_COPPER_LAYER;

            SetState( status, ON );
        }
    }

    return FALSE;
}


120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
wxPoint DRAWSEGMENT::GetStart() const
{
    switch( m_Shape )
    {
    case S_ARC:
        return m_End;  // the start of the arc is held in field m_End, center point is in m_Start.

    case S_SEGMENT:
    default:
        return m_Start;
    }
}


wxPoint DRAWSEGMENT::GetEnd() const
{
136 137 138
    wxPoint center;        // center point of the arc
    wxPoint start;         // start of arc

139 140 141
    switch( m_Shape )
    {
    case S_ARC:
142 143 144 145 146
        // rotate the starting point of the arc, given by m_End, through the
        // angle m_Angle to get the ending point of the arc.
        center = m_Start;       // center point of the arc
        start  = m_End;         // start of arc
        RotatePoint( &start.x, &start.y, center.x, center.y, -m_Angle );
147

148
        return start;   // after rotation, the end of the arc.
149 150 151 152 153 154 155 156 157 158
        break;

    case S_SEGMENT:
    default:
        return m_End;
    }
}



dickelbeck's avatar
dickelbeck committed
159
void DRAWSEGMENT::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
160
                        int draw_mode, const wxPoint& notUsed )
dickelbeck's avatar
dickelbeck committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
{
    int ux0, uy0, dx, dy;
    int l_piste;
    int color, mode;
    int rayon;

    color = g_DesignSettings.m_LayerColor[GetLayer()];
    if( color & ITEM_NOT_SHOW )
        return;

    GRSetDrawMode( DC, draw_mode );
    l_piste = m_Width >> 1;  /* l_piste = demi largeur piste */

    /* coord de depart */
    ux0 = m_Start.x;
    uy0 = m_Start.y;

    /* coord d'arrivee */
    dx = m_End.x;
    dy = m_End.y;

    mode = DisplayOpt.DisplayDrawItems;
    if( m_Flags & FORCE_SKETCH )
        mode = SKETCH;
185
    if( l_piste < panel->GetScreen()->Unscale( L_MIN_DESSIN ) )
dickelbeck's avatar
dickelbeck committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
        mode = FILAIRE;

    switch( m_Shape )
    {
    case S_CIRCLE:
        rayon = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
        if( mode == FILAIRE )
        {
            GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon, color );
        }
        else if( mode == SKETCH )
        {
            GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon - l_piste, color );
            GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon + l_piste, color );
        }
        else
        {
            GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon, m_Width, color );
        }
        break;

    case S_ARC:
208 209 210 211
        int StAngle, EndAngle;
        rayon    = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
        StAngle  = (int) ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;
dickelbeck's avatar
dickelbeck committed
212

213 214 215 216 217 218 219 220 221 222
        if ( ! panel->m_PrintIsMirrored)
        {
            if( StAngle > EndAngle )
                EXCHG( StAngle, EndAngle );
        }
        else    //Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                EXCHG( StAngle, EndAngle );
        }
223

dickelbeck's avatar
dickelbeck committed
224

225 226 227
        if( mode == FILAIRE )
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon, color );
dickelbeck's avatar
dickelbeck committed
228

229 230 231 232 233 234 235 236 237 238 239
        else if( mode == SKETCH )
        {
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon - l_piste, color );
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon + l_piste, color );
        }
        else
        {
            GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
                   rayon, m_Width, color );
dickelbeck's avatar
dickelbeck committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
        }
        break;

    default:
        if( mode == FILAIRE )
            GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, 0, color );
        else if( mode == SKETCH )
        {
            GRCSegm( &panel->m_ClipBox, DC, ux0, uy0, dx, dy,
                     m_Width, color );
        }
        else
        {
            GRFillCSegm( &panel->m_ClipBox, DC, ux0, uy0, dx, dy,
                         m_Width, color );
        }
        break;
    }
}


261 262 263 264 265
// see pcbstruct.h
void DRAWSEGMENT::Display_Infos( WinEDA_DrawFrame* frame )
{
    int      itype;
    wxString msg;
266
    wxString coords;
267

dickelbeck's avatar
dickelbeck committed
268 269 270
    BOARD*   board = (BOARD*) m_Parent;
    wxASSERT( board );

271 272 273 274 275 276 277 278
    frame->MsgPanel->EraseMsgBox();

    itype = m_Type & 0x0F;

    msg = wxT( "DRAWING" );

    Affiche_1_Parametre( frame, 1, _( "Type" ), msg, DARKCYAN );

279
    wxString    shape = _( "Shape" );
280 281

    if( m_Shape == S_CIRCLE )
282
        Affiche_1_Parametre( frame, 10, shape, _( "Circle" ), RED );
283 284 285

    else if( m_Shape == S_ARC )
    {
286 287 288 289
        Affiche_1_Parametre( frame, 10, shape, _( "Arc" ), RED );

        msg.Printf( wxT( "%d.%d" ), m_Angle/10, m_Angle % 10 );
        Affiche_1_Parametre( frame, 18, _("Angle"), msg, RED );
290 291
    }
    else
292 293 294 295
        Affiche_1_Parametre( frame, 10, shape, _( "Segment" ), RED );

    wxString start;
    start << GetStart();
296

297 298 299 300 301 302
    wxString end;
    end << GetEnd();

    Affiche_1_Parametre( frame, 22, start, end, BLACK );

    Affiche_1_Parametre( frame, 36, _( "Layer" ),
dickelbeck's avatar
dickelbeck committed
303
                         board->GetLayerName( m_Layer ), BROWN );
304 305

    valeur_param( (unsigned) m_Width, msg );
306 307

    Affiche_1_Parametre( frame, 50, _( "Width" ), msg, DARKCYAN );
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
}


/**
 * Function HitTest
 * tests if the given wxPoint is within the bounds of this object.
 * @param ref_pos A wxPoint to test
 * @return bool - true if a hit, else false
 */
bool DRAWSEGMENT::HitTest( const wxPoint& ref_pos )
{
    int ux0 = m_Start.x;
    int uy0 = m_Start.y;

    /* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
    int dx = m_End.x - ux0;
    int dy = m_End.y - uy0;

    int spot_cX = ref_pos.x - ux0;
    int spot_cY = ref_pos.y - uy0;

    if( m_Shape==S_CIRCLE || m_Shape==S_ARC )
    {
        int rayon, dist, stAngle, endAngle, mouseAngle;

        rayon = (int) hypot( (double) (dx), (double) (dy) );
        dist  = (int) hypot( (double) (spot_cX), (double) (spot_cY) );

336
        if( abs( rayon - dist ) <= ( m_Width / 2 ) )
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        {
            if( m_Shape == S_CIRCLE )
                return true;

            /* pour un arc, controle complementaire */
            mouseAngle = (int) ArcTangente( spot_cY, spot_cX );
            stAngle    = (int) ArcTangente( dy, dx );
            endAngle   = stAngle + m_Angle;

            if( endAngle > 3600 )
            {
                stAngle  -= 3600;
                endAngle -= 3600;
            }

352
            if( mouseAngle >= stAngle && mouseAngle <= endAngle )
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
                return true;
        }
    }
    else
    {
        if( DistanceTest( m_Width / 2, dx, dy, spot_cX, spot_cY ) )
            return true;
    }
    return false;
}


/**
 * Function HitTest (overlayed)
 * tests if the given EDA_Rect intersect this object.
 * For now, an ending point must be inside this rect.
 * @param refArea : the given EDA_Rect
 * @return bool - true if a hit, else false
 */
bool DRAWSEGMENT::HitTest( EDA_Rect& refArea )
{
    if( refArea.Inside( m_Start ) )
        return true;
    if( refArea.Inside( m_End ) )
        return true;
    return false;
}
dickelbeck's avatar
dickelbeck committed
380 381 382 383 384 385 386 387 388 389 390 391 392 393


#if defined(DEBUG)
/**
 * Function Show
 * is used to output the object tree, currently for debugging only.
 * @param nestLevel An aid to prettier tree indenting, and is the level
 *          of nesting of this object within the overall tree.
 * @param os The ostream& to output to.
 */
void DRAWSEGMENT::Show( int nestLevel, std::ostream& os )
{
    NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<

394 395
    " shape=\"" << m_Shape << '"' <<
/*
dickelbeck's avatar
dickelbeck committed
396 397
    " layer=\"" << GetLayer() << '"' <<
    " width=\"" << m_Width << '"' <<
398 399 400
    " angle=\"" << m_Angle << '"' <<  // Used only for Arcs: Arc angle in 1/10 deg
*/
    '>' <<
dickelbeck's avatar
dickelbeck committed
401
    "<start" << m_Start << "/>" <<
402 403 404 405
    "<end"   << m_End << "/>"
    "<GetStart" << GetStart() << "/>" <<
    "<GetEnd"   << GetEnd() << "/>"
    ;
dickelbeck's avatar
dickelbeck committed
406 407 408 409

    os << "</" << GetClass().Lower().mb_str() << ">\n";
}
#endif