Пример #1
0
bool PCB_EDIT_FRAME::RemoveMisConnectedTracks()
{
     /* finds all track segments which are mis-connected (to more than one net).
     * When such a bad segment is found, it is flagged to be removed.
     * All tracks having at least one flagged segment are removed.
     */
    TRACK*          segment;
    TRACK*          other;
    TRACK*          next;
    int             net_code_s, net_code_e;
    bool            isModified = false;

    for( segment = GetBoard()->m_Track;  segment;  segment = (TRACK*) segment->Next() )
    {
        segment->SetState( FLAG0, false );

        // find the netcode for segment using anything connected to the "start" of "segment"
        net_code_s = -1;

        if( segment->start && segment->start->Type()==PCB_PAD_T )
        {
            // get the netcode of the pad to propagate.
            net_code_s = ((D_PAD*)(segment->start))->GetNet();
        }
        else
        {
            other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_START );

            if( other )
                net_code_s = other->GetNet();
        }

        if( net_code_s < 0 )
            continue;           // the "start" of segment is not connected

        // find the netcode for segment using anything connected to the "end" of "segment"
        net_code_e = -1;

        if( segment->end && segment->end->Type()==PCB_PAD_T )
        {
            net_code_e = ((D_PAD*)(segment->end))->GetNet();
        }
        else
        {
            other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_END );

            if( other )
                net_code_e = other->GetNet();
        }

        if( net_code_e < 0 )
            continue;           // the "end" of segment is not connected

        // Netcodes do not agree, so mark the segment as "to be removed"
        if( net_code_s != net_code_e )
        {
            segment->SetState( FLAG0, true );
        }
    }

    // Remove tracks having a flagged segment
    for( segment = GetBoard()->m_Track; segment; segment = next )
    {
        next = (TRACK*) segment->Next();

        if( segment->GetState( FLAG0 ) )    // Segment is flagged to be removed
        {
            segment->SetState( FLAG0, false );
            isModified = true;
            GetBoard()->m_Status_Pcb = 0;
            Remove_One_Track( NULL, segment );

            // the current segment is deleted,
            // we do not know the next "not yet tested" segment,
            // so restart to the beginning
            next = GetBoard()->m_Track;
        }
    }

    return isModified;
}
/**
 * Function Merge_SubNets_Connected_By_CopperAreas(BOARD* aPcb, int aNetcode)
 * Used after connections by tracks calculations
 * Merge subnets, in tracks ans pads when they are connected by a filled copper area
 * for pads, this is the .m_physical_connexion member which is tested and modified
 * for tracks, this is the .m_Subnet member which is tested and modified
 * these members are block numbers (or cluster numbers) for a given net,
 * calculated by Build_Pads_Info_Connections_By_Tracks()
 * The result is merging 2 blocks (or subnets)
 * @param aPcb = the current board
 * @param aNetcode = netcode to consider
 */
void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode )
{
    // Ensure a zone with the given netcode exists: examine all zones:
    bool found = false;

    for( int index = 0; index < aPcb->GetAreaCount(); index++ )
    {
        ZONE_CONTAINER* zone = aPcb->GetArea( index );

        if( aNetcode == zone->GetNetCode() )
        {
            found = true;
            break;
        }
    }

    if( !found )  // No zone with this netcode, therefore no connection by zone
        return;

    // list of pads and tracks candidates to test:
    // It is static to avoid multiple memory realloc.
    static std::vector <BOARD_CONNECTED_ITEM*> Candidates;
    Candidates.clear();

    // Build the list of pads candidates connected to the net:
    NETINFO_ITEM* net = aPcb->FindNet( aNetcode );
    wxASSERT( net );
    Candidates.reserve( net->m_PadInNetList.size() );
    for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ )
        Candidates.push_back( net->m_PadInNetList[ii] );

    // Build the list of track candidates connected to the net:
    TRACK* track;
    track = aPcb->m_Track.GetFirst()->GetStartNetCode( aNetcode );
    for( ; track; track = track->Next() )
    {
        if( track->GetNetCode() != aNetcode )
            break;
        Candidates.push_back( track );
    }

    if( Candidates.size() == 0 )
        return;

    int next_subnet_free_number = 0;
    for( unsigned ii = 0; ii < Candidates.size(); ii++ )
    {
        int subnet = Candidates[ii]->GetSubNet();
        next_subnet_free_number = std::max( next_subnet_free_number, subnet );
    }

    next_subnet_free_number++;     // This is a subnet we can use with not connected items
                                   // by tracks, but connected by zone.

    // Sort by zone_subnet:
    sort( Candidates.begin(), Candidates.end(), CmpZoneSubnetValue );

    // Some items can be not connected, but they can be connected to a filled area:
    // give them a subnet common to these items connected only by the area,
    // and not already used.
    // a value like next_subnet_free_number+zone_subnet is right
    for( unsigned jj = 0; jj < Candidates.size(); jj++ )
    {
        BOARD_CONNECTED_ITEM* item = Candidates[jj];
        if ( item->GetSubNet() == 0 && (item->GetZoneSubNet() > 0) )
        {
            item->SetSubNet( next_subnet_free_number + item->GetZoneSubNet() );
        }
    }

    // Now, for each zone subnet, we search for 2 items with different subnets.
    // if found, the 2 subnet are merged in the whole candidate list.
    int old_subnet      = 0;
    int old_zone_subnet = 0;
    for( unsigned ii = 0; ii < Candidates.size(); ii++ )
    {
        BOARD_CONNECTED_ITEM* item = Candidates[ii];
        int zone_subnet = item->GetZoneSubNet();

        if( zone_subnet == 0 )  // Not connected by a filled area, skip it
            continue;

        int subnet = item->GetSubNet();

        if( zone_subnet != old_zone_subnet )  // a new zone subnet is found
        {
            old_subnet = subnet;
            old_zone_subnet = zone_subnet;
            continue;
        }

        zone_subnet = old_zone_subnet;

        // 2 successive items already from the same cluster: nothing to do
        if( subnet == old_subnet )
            continue;

        // Here we have 2 items connected by the same area have 2 differents subnets: merge subnets
        if( (subnet > old_subnet) || ( subnet <= 0) )
            EXCHG( subnet, old_subnet );

        for( unsigned jj = 0; jj < Candidates.size(); jj++ )
        {
            BOARD_CONNECTED_ITEM * item_to_merge = Candidates[jj];

            if( item_to_merge->GetSubNet() == old_subnet )
                item_to_merge->SetSubNet( subnet );
        }

        old_subnet = subnet;
    }
}
bool DIALOG_TRACK_VIA_PROPERTIES::Apply()
{
    if( !check() )
        return false;

    for( int i = 0; i < m_items.Size(); ++i )
    {
        BOARD_ITEM* item = m_items.Item<BOARD_ITEM>( i );

        switch( item->Type() )
        {
            case PCB_TRACE_T:
            {
                assert( m_tracks );
                TRACK* t = static_cast<TRACK*>( item );

                if( m_trackStartX.Valid() || m_trackStartY.Valid() )
                {
                    wxPoint start = t->GetStart();

                    if( m_trackStartX.Valid() )
                        start.x = m_trackStartX.GetValue();

                    if( m_trackStartY.Valid() )
                        start.y = m_trackStartY.GetValue();

                    t->SetStart( start );
                }

                if( m_trackEndX.Valid() || m_trackEndY.Valid() )
                {
                    wxPoint end = t->GetEnd();

                    if( m_trackEndX.Valid() )
                        end.x = m_trackEndX.GetValue();

                    if( m_trackEndY.Valid() )
                        end.y = m_trackEndY.GetValue();

                    t->SetEnd( end );
                }

                if( m_trackNetclass->IsChecked() )
                {
                    t->SetWidth( t->GetNetClass()->GetTrackWidth() );
                }
                else if( m_trackWidth.Valid() )
                {
                    t->SetWidth( m_trackWidth.GetValue() );
                }

                LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection();

                if( layer != UNDEFINED_LAYER )
                    t->SetLayer( (LAYER_ID) layer );

                break;
            }

            case PCB_VIA_T:
            {
                assert( m_vias );

                VIA* v = static_cast<VIA*>( item );

                if( m_viaX.Valid() || m_viaY.Valid() )
                {
                    wxPoint pos = v->GetPosition();

                    if( m_viaX.Valid() )
                        pos.x = m_viaX.GetValue();

                    if( m_viaY.Valid() )
                        pos.y = m_viaY.GetValue();

                    v->SetPosition( pos );
                }

                if( m_viaNetclass->IsChecked() )
                {
                    v->SetWidth( v->GetNetClass()->GetViaDiameter() );
                    v->SetDrill( v->GetNetClass()->GetViaDrill() );
                }
                else
                {
                    if( m_viaDiameter.Valid() )
                        v->SetWidth( m_viaDiameter.GetValue() );

                    if( m_viaDrill.Valid() )
                        v->SetDrill( m_viaDrill.GetValue() );
                }

                break;
            }

            default:
                assert( false );
                break;
        }
    }

    return true;
}
Пример #4
0
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
{
    if( aImage == NULL )
        return;

    // Remark: to create images of edited items to undo, we are using Clone method
    // which can duplication of items foe copy, but does not clone all members
    // mainly pointers in chain and time stamp, which is set to new, unique value.
    // So we have to use the current values of these parameters.

    EDA_ITEM * pnext = Next();
    EDA_ITEM * pback = Back();
    DHEAD* mylist    = m_List;
    time_t timestamp = GetTimeStamp();

    switch( Type() )
    {
    case PCB_MODULE_T:
    {
        MODULE* tmp = (MODULE*) aImage->Clone();
        ( (MODULE*) aImage )->Copy( (MODULE*) this );
        ( (MODULE*) this )->Copy( tmp );
        delete tmp;
    }
        break;

    case PCB_ZONE_AREA_T:
    {
        ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone();
        ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this );
        ( (ZONE_CONTAINER*) this )->Copy( tmp );
        delete tmp;
    }
        break;

    case PCB_LINE_T:
        std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) );
        break;

    case PCB_TRACE_T:
    case PCB_VIA_T:
    {
        TRACK* track = (TRACK*) this;
        TRACK* image = (TRACK*) aImage;

        std::swap(track->m_Layer, image->m_Layer );

        // swap start, end, width and shape for track and image.
        wxPoint exchp = track->GetStart();
        track->SetStart( image->GetStart() );
        image->SetStart( exchp );
        exchp = track->GetEnd();
        track->SetEnd( image->GetEnd() );
        image->SetEnd( exchp );

        int atmp = track->GetWidth();
        track->SetWidth( image->GetWidth() );
        image->SetWidth( atmp );

        if( Type() == PCB_VIA_T )
        {
            VIA *via = static_cast<VIA*>( this );
            VIA *viaimage = static_cast<VIA*>( aImage );

            VIATYPE_T viatmp = via->GetViaType();
            via->SetViaType( viaimage->GetViaType() );
            viaimage->SetViaType( viatmp );

            int drilltmp = via->GetDrillValue();

            if( via->IsDrillDefault() )
                drilltmp = -1;

            int itmp = viaimage->GetDrillValue();

            if( viaimage->IsDrillDefault() )
                itmp = -1;

            std::swap(itmp, drilltmp );

            if( drilltmp > 0 )
                via->SetDrill( drilltmp );
            else
                via->SetDrillDefault();

            if( itmp > 0 )
                viaimage->SetDrill( itmp );
            else
                viaimage->SetDrillDefault();
        }
    }
        break;

    case PCB_TEXT_T:
        std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) );
        break;

    case PCB_TARGET_T:
        std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) );
        break;

    case PCB_DIMENSION_T:
        std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) );
        break;

    case PCB_ZONE_T:
    default:
        wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() );
        break;
    }

    // Restore pointers and time stamp, to be sure they are not broken
    Pnext = pnext;
    Pback = pback;
    m_List = mylist;
    SetTimeStamp( timestamp );
}
int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent )
{
    int open_ctl;
    wxString fileName;

    PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
    BOARD* board = getModel<BOARD>();
    BOARD_COMMIT commit( editFrame );

    if( !editFrame )
        return 0;

    // Pick a file to append
    if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) )
        return 0;

    IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl );
    PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

    // keep track of existing items, in order to know what are the new items
    // (for undo command for instance)

    // Tracks are inserted, not appended, so mark the existing tracks to know what are the new tracks
    for( TRACK* track = board->m_Track; track; track = track->Next() )
        track->SetFlags( FLAG0 );

    // Other items are appended to the item list, so keep trace to the last existing item is enough
    MODULE* module = board->m_Modules.GetLast();
    BOARD_ITEM* drawing = board->m_Drawings.GetLast();
    int zonescount = board->GetAreaCount();

    // Keep also the count of copper layers, to adjust if necessary
    int initialCopperLayerCount = board->GetCopperLayerCount();
    LSET initialEnabledLayers = board->GetEnabledLayers();

    // Load the data
    try
    {
        PROPERTIES  props;
        char        xbuf[30];
        char        ybuf[30];

        // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
        sprintf( xbuf, "%d", editFrame->GetPageSizeIU().x );
        sprintf( ybuf, "%d", editFrame->GetPageSizeIU().y );

        props["page_width"]  = xbuf;
        props["page_height"] = ybuf;

        editFrame->GetDesignSettings().m_NetClasses.Clear();
        pi->Load( fileName, board, &props );
    }
    catch( const IO_ERROR& ioe )
    {
        wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.What() ));
        DisplayError( editFrame, msg );

        return 0;
    }

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

    // Process the new items
    for( TRACK* track = board->m_Track; track; track = track->Next() )
    {
        if( track->GetFlags() & FLAG0 )
        {
            track->ClearFlags( FLAG0 );
            continue;
        }

        commit.Added( track );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, track );
    }

    module = module ? module->Next() : board->m_Modules;

    for( ; module; module = module->Next() )
    {
        commit.Added( module );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, module );
    }

    drawing = drawing ? drawing->Next() : board->m_Drawings;

    for( ; drawing; drawing = drawing->Next() )
    {
        commit.Added( drawing );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, drawing );
    }

    for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone;
         zone = board->GetArea( zonescount ) )
    {
        ++zonescount;
        commit.Added( zone );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, zone );
    }

    if( commit.Empty() )
        return 0;

    commit.Push( _( "Append a board" ) );

    // Synchronize layers
    // we should not ask PLUGINs to do these items:
    int copperLayerCount = board->GetCopperLayerCount();

    if( copperLayerCount > initialCopperLayerCount )
        board->SetCopperLayerCount( copperLayerCount );

    // Enable all used layers, and make them visible:
    LSET enabledLayers = board->GetEnabledLayers();
    enabledLayers |= initialEnabledLayers;
    board->SetEnabledLayers( enabledLayers );
    board->SetVisibleLayers( enabledLayers );
    editFrame->ReCreateLayerBox();
    editFrame->ReFillLayerWidget();
    static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board );

    // Ratsnest
    board->BuildListOfNets();
    board->SynchronizeNetsAndNetClasses();
    board->GetRatsnest()->ProcessBoard();

    // Start dragging the appended board
    SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
    const SELECTION& selection = selectionTool->GetSelection();
    VECTOR2D v( selection.Item<BOARD_ITEM>( 0 )->GetPosition() );
    getViewControls()->WarpCursor( v, true, true );
    m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" );

    return 0;
}
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{
    TRACK*    track;
    wxPoint   delta;           // lenght on X and Y axis of segments
    LSET layerMask;
    int       net_code_ref;
    wxPoint   shape_pos;

    NETCLASSPTR netclass = aRefSeg->GetNetClass();
    BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();

    /* In order to make some calculations more easier or faster,
     * pads and tracks coordinates will be made relative to the reference segment origin
     */
    wxPoint origin = aRefSeg->GetStart();  // origin will be the origin of other coordinates

    m_segmEnd   = delta = aRefSeg->GetEnd() - origin;
    m_segmAngle = 0;

    layerMask    = aRefSeg->GetLayerSet();
    net_code_ref = aRefSeg->GetNetCode();

    // Phase 0 : Test vias
    if( aRefSeg->Type() == PCB_VIA_T )
    {
        const VIA *refvia = static_cast<const VIA*>( aRefSeg );
        // test if the via size is smaller than minimum
        if( refvia->GetViaType() == VIA_MICROVIA )
        {
            if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_MICROVIA, m_currentMarker );
                return false;
            }
        }
        else
        {
            if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_VIA, m_currentMarker );
                return false;
            }
        }

        // test if via's hole is bigger than its diameter
        // This test is necessary since the via hole size and width can be modified
        // and a default via hole can be bigger than some vias sizes
        if( refvia->GetDrillValue() > refvia->GetWidth() )
        {
            m_currentMarker = fillMarker( refvia, NULL,
                                          DRCE_VIA_HOLE_BIGGER, m_currentMarker );
            return false;
        }

        // For microvias: test if they are blind vias and only between 2 layers
        // because they are used for very small drill size and are drill by laser
        // and **only one layer** can be drilled
        if( refvia->GetViaType() == VIA_MICROVIA )
        {
            LAYER_ID    layer1, layer2;
            bool        err = true;

            refvia->LayerPair( &layer1, &layer2 );

            if( layer1 > layer2 )
                EXCHG( layer1, layer2 );

#if 0   // was:
            // test:
            if( layer1 == B_Cu && layer2 == LAYER_N_2 )
                err = false;

            if( layer1 == (m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 )
                && layer2 == F_Cu )
                err = false;
#else
            if( layer2 == B_Cu && layer1 == m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 )
                err = false;

            else if( layer1 == F_Cu  &&  layer2 == In1_Cu  )
                err = false;
#endif

            if( err )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker );
                return false;
            }
        }
    }
    else    // This is a track segment
    {
        if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
        {
            m_currentMarker = fillMarker( aRefSeg, NULL,
                                          DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker );
            return false;
        }
    }

    // for a non horizontal or vertical segment Compute the segment angle
    // in tenths of degrees and its length
    if( delta.x || delta.y )
    {
        // Compute the segment angle in 0,1 degrees
        m_segmAngle = ArcTangente( delta.y, delta.x );

        // Compute the segment length: we build an equivalent rotated segment,
        // this segment is horizontal, therefore dx = length
        RotatePoint( &delta, m_segmAngle );    // delta.x = length, delta.y = 0
    }

    m_segmLength = delta.x;

    /******************************************/
    /* Phase 1 : test DRC track to pads :     */
    /******************************************/

    /* Use a dummy pad to test DRC tracks versus holes, for pads not on all copper layers
     * but having a hole
     * This dummy pad has the size and shape of the hole
     * to test tracks to pad hole DRC, using checkClearanceSegmToPad test function.
     * Therefore, this dummy pad is a circle or an oval.
     * A pad must have a parent because some functions expect a non null parent
     * to find the parent board, and some other data
     */
    MODULE  dummymodule( m_pcb );    // Creates a dummy parent
    D_PAD   dummypad( &dummymodule );

    dummypad.SetLayerSet( LSET::AllCuMask() );     // Ensure the hole is on all layers

    // Compute the min distance to pads
    if( testPads )
    {
        for( unsigned ii = 0;  ii<m_pcb->GetPadCount();  ++ii )
        {
            D_PAD* pad = m_pcb->GetPad( ii );

            /* No problem if pads are on an other layer,
             * But if a drill hole exists	(a pad on a single layer can have a hole!)
             * we must test the hole
             */
            if( !( pad->GetLayerSet() & layerMask ).any() )
            {
                /* We must test the pad hole. In order to use the function
                 * checkClearanceSegmToPad(),a pseudo pad is used, with a shape and a
                 * size like the hole
                 */
                if( pad->GetDrillSize().x == 0 )
                    continue;

                dummypad.SetSize( pad->GetDrillSize() );
                dummypad.SetPosition( pad->GetPosition() );
                dummypad.SetShape( pad->GetDrillShape()  == PAD_DRILL_OBLONG ?
                                   PAD_OVAL : PAD_CIRCLE );
                dummypad.SetOrientation( pad->GetOrientation() );

                m_padToTestPos = dummypad.GetPosition() - origin;

                if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
                                              netclass->GetClearance() ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, pad,
                                                  DRCE_TRACK_NEAR_THROUGH_HOLE, m_currentMarker );
                    return false;
                }

                continue;
            }

            // The pad must be in a net (i.e pt_pad->GetNet() != 0 )
            // but no problem if the pad netcode is the current netcode (same net)
            if( pad->GetNetCode()                       // the pad must be connected
               && net_code_ref == pad->GetNetCode() )   // the pad net is the same as current net -> Ok
                continue;

            // DRC for the pad
            shape_pos = pad->ShapePos();
            m_padToTestPos = shape_pos - origin;

            if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
            {
                m_currentMarker = fillMarker( aRefSeg, pad,
                                              DRCE_TRACK_NEAR_PAD, m_currentMarker );
                return false;
            }
        }
    }

    /***********************************************/
    /* Phase 2: test DRC with other track segments */
    /***********************************************/

    // At this point the reference segment is the X axis

    // Test the reference segment with other track segments
    wxPoint segStartPoint;
    wxPoint segEndPoint;
    for( track = aStart; track; track = track->Next() )
    {
        // No problem if segments have the same net code:
        if( net_code_ref == track->GetNetCode() )
            continue;

        // No problem if segment are on different layers :
        if( !( layerMask & track->GetLayerSet() ).any() )
            continue;

        // the minimum distance = clearance plus half the reference track
        // width plus half the other track's width
        int w_dist = aRefSeg->GetClearance( track );
        w_dist += (aRefSeg->GetWidth() + track->GetWidth()) / 2;

        // If the reference segment is a via, we test it here
        if( aRefSeg->Type() == PCB_VIA_T )
        {
            delta = track->GetEnd() - track->GetStart();
            segStartPoint = aRefSeg->GetStart() - track->GetStart();

            if( track->Type() == PCB_VIA_T )
            {
                // Test distance between two vias, i.e. two circles, trivial case
                if( EuclideanNorm( segStartPoint ) < w_dist )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_VIA_NEAR_VIA, m_currentMarker );
                    return false;
                }
            }
            else    // test via to segment
            {
                // Compute l'angle du segment a tester;
                double angle = ArcTangente( delta.y, delta.x );

                // Compute new coordinates ( the segment become horizontal)
                RotatePoint( &delta, angle );
                RotatePoint( &segStartPoint, angle );

                if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) )
                {
                    m_currentMarker = fillMarker( track, aRefSeg,
                                                  DRCE_VIA_NEAR_TRACK, m_currentMarker );
                    return false;
                }
            }

            continue;
        }

        /* We compute segStartPoint, segEndPoint = starting and ending point coordinates for
         * the segment to test in the new axis : the new X axis is the
         * reference segment.  We must translate and rotate the segment to test
         */
        segStartPoint = track->GetStart() - origin;
        segEndPoint   = track->GetEnd() - origin;
        RotatePoint( &segStartPoint, m_segmAngle );
        RotatePoint( &segEndPoint, m_segmAngle );
        if( track->Type() == PCB_VIA_T )
        {
            if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
                continue;

            m_currentMarker = fillMarker( aRefSeg, track,
                                          DRCE_TRACK_NEAR_VIA, m_currentMarker );
            return false;
        }

        /*	We have changed axis:
         *  the reference segment is Horizontal.
         *  3 cases : the segment to test can be parallel, perpendicular or have an other direction
         */
        if( segStartPoint.y == segEndPoint.y ) // parallel segments
        {
            if( abs( segStartPoint.y ) >= w_dist )
                continue;

            // Ensure segStartPoint.x <= segEndPoint.x
            if( segStartPoint.x > segEndPoint.x )
                EXCHG( segStartPoint.x, segEndPoint.x );

            if( segStartPoint.x > (-w_dist) && segStartPoint.x < (m_segmLength + w_dist) )    /* possible error drc */
            {
                // the start point is inside the reference range
                //      X........
                //    O--REF--+

                // Fine test : we consider the rounded shape of each end of the track segment:
                if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS1, m_currentMarker );
                    return false;
                }

                if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS2, m_currentMarker );
                    return false;
                }
            }

            if( segEndPoint.x > (-w_dist) && segEndPoint.x < (m_segmLength + w_dist) )
            {
                // the end point is inside the reference range
                //  .....X
                //    O--REF--+
                // Fine test : we consider the rounded shape of the ends
                if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS3, m_currentMarker );
                    return false;
                }

                if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS4, m_currentMarker );
                    return false;
                }
            }

            if( segStartPoint.x <=0 && segEndPoint.x >= 0 )
            {
            // the segment straddles the reference range (this actually only
            // checks if it straddles the origin, because the other cases where already
            // handled)
            //  X.............X
            //    O--REF--+
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker );
                return false;
            }
        }
        else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments
        {
            if( ( segStartPoint.x <= (-w_dist) ) || ( segStartPoint.x >= (m_segmLength + w_dist) ) )
                continue;

            // Test if segments are crossing
            if( segStartPoint.y > segEndPoint.y )
                EXCHG( segStartPoint.y, segEndPoint.y );

            if( (segStartPoint.y < 0) && (segEndPoint.y > 0) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_TRACKS_CROSSING, m_currentMarker );
                return false;
            }

            // At this point the drc error is due to an end near a reference segm end
            if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_ENDS_PROBLEM1, m_currentMarker );
                return false;
            }
            if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_ENDS_PROBLEM2, m_currentMarker );
                return false;
            }
        }
        else    // segments quelconques entre eux
        {
            // calcul de la "surface de securite du segment de reference
            // First rought 'and fast) test : the track segment is like a rectangle

            m_xcliplo = m_ycliplo = -w_dist;
            m_xcliphi = m_segmLength + w_dist;
            m_ycliphi = w_dist;

            // A fine test is needed because a serment is not exactly a
            // rectangle, it has rounded ends
            if( !checkLine( segStartPoint, segEndPoint ) )
            {
                /* 2eme passe : the track has rounded ends.
                 * we must a fine test for each rounded end and the
                 * rectangular zone
                 */

                m_xcliplo = 0;
                m_xcliphi = m_segmLength;

                if( !checkLine( segStartPoint, segEndPoint ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_ENDS_PROBLEM3, m_currentMarker );
                    return false;
                }
                else    // The drc error is due to the starting or the ending point of the reference segment
                {
                    // Test the starting and the ending point
                    segStartPoint = track->GetStart();
                    segEndPoint   = track->GetEnd();
                    delta = segEndPoint - segStartPoint;

                    // Compute the segment orientation (angle) en 0,1 degre
                    double angle = ArcTangente( delta.y, delta.x );

                    // Compute the segment lenght: delta.x = lenght after rotation
                    RotatePoint( &delta, angle );

                    /* Comute the reference segment coordinates relatives to a
                     *  X axis = current tested segment
                     */
                    wxPoint relStartPos = aRefSeg->GetStart() - segStartPoint;
                    wxPoint relEndPos   = aRefSeg->GetEnd() - segStartPoint;

                    RotatePoint( &relStartPos, angle );
                    RotatePoint( &relEndPos, angle );

                    if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) )
                    {
                        m_currentMarker = fillMarker( aRefSeg, track,
                                                      DRCE_ENDS_PROBLEM4, m_currentMarker );
                        return false;
                    }

                    if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) )
                    {
                        m_currentMarker = fillMarker( aRefSeg, track,
                                                      DRCE_ENDS_PROBLEM5, m_currentMarker );
                        return false;
                    }
                }
            }
        }
    }

    return true;
}
Пример #7
0
void DIALOG_GENDRILL::InitDisplayParams()
{
    wxString msg;

    m_Choice_Unit->SetSelection( m_UnitDrillIsInch ? 1 : 0 );
    m_Choice_Zeros_Format->SetSelection( m_ZerosFormat );
    UpdatePrecisionOptions();
    m_Check_Minimal->SetValue( m_MinimalHeader );

    if( m_DrillOriginIsAuxAxis )
        m_Choice_Drill_Offset->SetSelection( 1 );

    m_Check_Mirror->SetValue( m_Mirror );
    m_Check_Merge_PTH_NPTH->SetValue( m_Merge_PTH_NPTH );
    m_Choice_Drill_Map->SetSelection( m_mapFileType );
    m_ViaDrillValue->SetLabel( _( "Use Netclasses values" ) );
    m_MicroViaDrillValue->SetLabel( _( "Use Netclasses values" ) );

    // See if we have some buried vias or/and microvias, and display
    // microvias drill value if so
    m_throughViasCount = 0;
    m_microViasCount   = 0;
    m_blindOrBuriedViasCount = 0;

    for( TRACK* track = m_parent->GetBoard()->m_Track; track != NULL; track = track->Next() )
    {
        if( track->Type() != PCB_VIA_T )
            continue;

        if( track->GetShape() == VIA_THROUGH )
            m_throughViasCount++;
        else if( track->GetShape() == VIA_MICROVIA )
            m_microViasCount++;
        else if( track->GetShape() == VIA_BLIND_BURIED )
            m_blindOrBuriedViasCount++;
    }

    m_MicroViaDrillValue->Enable( m_microViasCount );

    // Count plated pad holes and not plated pad holes:
    m_platedPadsHoleCount    = 0;
    m_notplatedPadsHoleCount = 0;

    for( MODULE* module = m_parent->GetBoard()->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
        {
            if( pad->GetDrillShape() == PAD_DRILL_CIRCLE )
            {
                if( pad->GetDrillSize().x != 0 )
                {
                    if( pad->GetAttribute() == PAD_HOLE_NOT_PLATED )
                        m_notplatedPadsHoleCount++;
                    else
                        m_platedPadsHoleCount++;
                }
            }
            else
            {
                if( pad->GetDrillSize().x != 0 && pad->GetDrillSize().y != 0 )
                {
                    if( pad->GetAttribute() == PAD_HOLE_NOT_PLATED )
                        m_notplatedPadsHoleCount++;
                    else
                        m_platedPadsHoleCount++;
                }
            }
        }
    }

    // Display hole counts:
    msg = m_PlatedPadsCountInfoMsg->GetLabel();
    msg << wxT( " " ) << m_platedPadsHoleCount;
    m_PlatedPadsCountInfoMsg->SetLabel( msg );

    msg = m_NotPlatedPadsCountInfoMsg->GetLabel();
    msg << wxT( " " ) << m_notplatedPadsHoleCount;
    m_NotPlatedPadsCountInfoMsg->SetLabel( msg );

    msg = m_ThroughViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_throughViasCount;
    m_ThroughViasInfoMsg->SetLabel( msg );

    msg = m_MicroViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_microViasCount;
    m_MicroViasInfoMsg->SetLabel( msg );

    msg = m_BuriedViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_blindOrBuriedViasCount;
    m_BuriedViasInfoMsg->SetLabel( msg );

    // Output directory
    m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
}
void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( )
{
    bool gen_rastnest = false;

    m_Parent->SetCurItem( NULL );

    if( m_DelAlls->GetValue() )
    {
        m_Parent->Clear_Pcb( true );
    }
    else
    {
        if( !IsOK( this, _( "Are you sure you want to delete the selected items?" ) ) )
            return;

        BOARD*            pcb = m_Parent->GetBoard();
        PICKED_ITEMS_LIST pickersList;
        ITEM_PICKER       itemPicker( NULL, UR_DELETED );
        BOARD_ITEM*       item;
        BOARD_ITEM*       nextitem;
        RN_DATA*          ratsnest = pcb->GetRatsnest();

        LSET layers_filter = LSET().set();

        if( m_rbLayersOption->GetSelection() != 0 )     // Use current layer only
            layers_filter = LSET( ToLAYER_ID( m_currentLayer ) );

        if( m_DelZones->GetValue() )
        {
            int area_index = 0;
            item = pcb->GetArea( area_index );

            while( item )
            {
                if( layers_filter[item->GetLayer()] )
                {
                    itemPicker.SetItem( item );
                    pickersList.PushItem( itemPicker );
                    pcb->Remove( item );
                    item->ViewRelease();
                    ratsnest->Remove( item );
                    gen_rastnest = true;
                }
                else
                {
                    area_index++;
                }

                item = pcb->GetArea( area_index );
            }
        }

        if( m_DelDrawings->GetValue() || m_DelBoardEdges->GetValue() )
        {
            LSET masque_layer;

            if( m_DelDrawings->GetValue() )
                 masque_layer = LSET::AllNonCuMask().set( Edge_Cuts, false );

            if( m_DelBoardEdges->GetValue() )
                 masque_layer.set( Edge_Cuts );

            masque_layer &= layers_filter;

            for( item = pcb->m_Drawings; item; item = nextitem )
            {
                nextitem = item->Next();

                if( item->Type() == PCB_LINE_T  &&  masque_layer[item->GetLayer()] )
                {
                    itemPicker.SetItem( item );
                    pickersList.PushItem( itemPicker );
                    item->ViewRelease();
                    item->UnLink();
                }
            }
        }

        if( m_DelTexts->GetValue() )
        {
            LSET del_text_layers = layers_filter;

            for( item = pcb->m_Drawings; item; item = nextitem )
            {
                nextitem = item->Next();

                if( item->Type() == PCB_TEXT_T  &&  del_text_layers[item->GetLayer()] )
                {
                    itemPicker.SetItem( item );
                    pickersList.PushItem( itemPicker );
                    item->ViewRelease();
                    item->UnLink();
                }
            }
        }

        if( m_DelModules->GetValue() )
        {
            for( item = pcb->m_Modules; item; item = nextitem )
            {
                nextitem = item->Next();

                if( layers_filter[item->GetLayer()] &&
                    ( ( m_ModuleFilterNormal->GetValue() && !item->IsLocked() ) ||
                      ( m_ModuleFilterLocked->GetValue() && item->IsLocked() ) ) )
                {
                    itemPicker.SetItem( item );
                    pickersList.PushItem( itemPicker );
                    static_cast<MODULE*>( item )->RunOnChildren(
                            boost::bind( &KIGFX::VIEW_ITEM::ViewRelease, _1 ) );
                    ratsnest->Remove( item );
                    item->ViewRelease();
                    item->UnLink();
                    gen_rastnest = true;
                }
            }
        }

        if( m_DelTracks->GetValue() )
        {
            STATUS_FLAGS track_mask_filter = 0;

            if( !m_TrackFilterLocked->GetValue() )
                track_mask_filter |= TRACK_LOCKED;

            if( !m_TrackFilterAR->GetValue() )
                track_mask_filter |= TRACK_AR;

            TRACK* nexttrack;

            for( TRACK *track = pcb->m_Track; track; track = nexttrack )
            {
                nexttrack = track->Next();

                if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) & track_mask_filter ) != 0 )
                    continue;

                if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) == 0 ) &&
                    !m_TrackFilterNormal->GetValue() )
                    continue;

                if( ( track->Type() == PCB_VIA_T ) && !m_TrackFilterVias->GetValue() )
                    continue;

                if( ( track->GetLayerSet() & layers_filter ) == 0 )
                    continue;

                itemPicker.SetItem( track );
                pickersList.PushItem( itemPicker );
                track->ViewRelease();
                ratsnest->Remove( track );
                track->UnLink();
                gen_rastnest = true;
            }
        }

        if( pickersList.GetCount() )
            m_Parent->SaveCopyInUndoList( pickersList, UR_DELETED );

        if( m_DelMarkers->GetValue() )
            pcb->DeleteMARKERs();

        if( gen_rastnest )
            m_Parent->Compile_Ratsnest( NULL, true );

        if( m_Parent->IsGalCanvasActive() )
            pcb->GetRatsnest()->Recalculate();

    }

    m_Parent->GetCanvas()->Refresh();
    m_Parent->OnModify();

    EndModal( 1 );
}
Пример #9
0
// Handles the selection of command events.
void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
{
    int         id = event.GetId();
    LAYER_NUM itmp;
    INSTALL_UNBUFFERED_DC( dc, m_canvas );
    MODULE* module;

    m_canvas->CrossHairOff( &dc );

    switch( id )   // Some (not all ) edit commands must be finished or aborted
    {
    case wxID_CUT:
    case wxID_COPY:
    case ID_PCB_USER_GRID_SETUP:
    case ID_TOOLBARH_PCB_SELECT_LAYER:
    case ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR:
    case ID_POPUP_PCB_ROTATE_TEXTEPCB:
    case ID_POPUP_PCB_FLIP_TEXTEPCB:
    case ID_POPUP_PCB_COPY_TEXTEPCB:
    case ID_POPUP_PCB_EDIT_TEXTEPCB:
    case ID_POPUP_PCB_EDIT_MIRE:
    case ID_POPUP_PCB_ROTATE_TEXTMODULE:
    case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE:
    case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE:
    case ID_POPUP_PCB_CHANGE_SIDE_MODULE:
    case ID_POPUP_PCB_EDIT_MODULE_PRMS:
    case ID_POPUP_PCB_EDIT_MODULE_WITH_MODEDIT:
    case ID_POPUP_PCB_EDIT_TEXTMODULE:
    case ID_POPUP_PCB_STOP_CURRENT_DRAWING:
    case ID_POPUP_PCB_BEGIN_TRACK:
    case ID_POPUP_PCB_END_TRACK:
    case ID_POPUP_PCB_PLACE_THROUGH_VIA:
    case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA:
    case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA:
    case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA:
    case ID_POPUP_PCB_PLACE_MICROVIA:
    case ID_POPUP_PCB_SWITCH_TRACK_POSTURE:
    case ID_POPUP_PCB_IMPORT_PAD_SETTINGS:
    case ID_POPUP_PCB_EXPORT_PAD_SETTINGS:
    case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS:
    case ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE:
    case ID_POPUP_PCB_DELETE_ZONE_LAST_CREATED_CORNER:
    case ID_POPUP_PCB_FILL_ALL_ZONES:
    case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES:
    case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_CURRENT_ZONE:
    case ID_POPUP_PCB_PLACE_ZONE_CORNER:
    case ID_POPUP_PCB_PLACE_ZONE_OUTLINES:
    case ID_POPUP_PCB_EDIT_ZONE_PARAMS:
    case ID_POPUP_PCB_DELETE_ZONE:
    case ID_POPUP_PCB_MOVE_ZONE_CORNER:
    case ID_POPUP_PCB_DRAG_ZONE_OUTLINE_SEGMENT:
    case ID_POPUP_PCB_MOVE_ZONE_OUTLINES:
    case ID_POPUP_PCB_ADD_ZONE_CORNER:
    case ID_POPUP_PCB_DELETE_TRACKSEG:
    case ID_POPUP_PCB_DELETE_TRACK:
    case ID_POPUP_PCB_DELETE_TRACKNET:
    case ID_POPUP_PCB_FILL_ZONE:
    case ID_POPUP_PCB_SELECT_LAYER:
    case ID_POPUP_PCB_SELECT_CU_LAYER:
    case ID_POPUP_PCB_SELECT_LAYER_PAIR:
    case ID_POPUP_PCB_SELECT_NO_CU_LAYER:
    case ID_POPUP_PCB_MOVE_TRACK_NODE:
    case ID_POPUP_PCB_MOVE_TEXTEPCB_REQUEST:
    case ID_POPUP_PCB_DRAG_TRACK_SEGMENT_KEEP_SLOPE:
    case ID_POPUP_PCB_DRAG_TRACK_SEGMENT:
    case ID_POPUP_PCB_MOVE_TRACK_SEGMENT:
    case ID_POPUP_PCB_PLACE_MOVED_TRACK_NODE:
    case ID_POPUP_PCB_BREAK_TRACK:
    case ID_POPUP_PCB_EDIT_NET:
    case ID_POPUP_PCB_EDIT_TRACK:
    case ID_POPUP_PCB_EDIT_TRACKSEG:
    case ID_POPUP_PCB_LOCK_ON_TRACKSEG:
    case ID_POPUP_PCB_LOCK_OFF_TRACKSEG:
    case ID_POPUP_PCB_LOCK_ON_TRACK:
    case ID_POPUP_PCB_LOCK_OFF_TRACK:
    case ID_POPUP_PCB_LOCK_ON_NET:
    case ID_POPUP_PCB_LOCK_OFF_NET:
    case ID_POPUP_DELETE_BLOCK:
    case ID_POPUP_PLACE_BLOCK:
    case ID_POPUP_ZOOM_BLOCK:
    case ID_POPUP_FLIP_BLOCK:
    case ID_POPUP_ROTATE_BLOCK:
    case ID_POPUP_COPY_BLOCK:
    case ID_POPUP_PCB_EDIT_DRAWING:
    case ID_POPUP_PCB_GETINFO_MARKER:
    case ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST:
    case ID_POPUP_PCB_DRAG_MODULE_REQUEST:
    case ID_POPUP_PCB_MOVE_MODULE_REQUEST:
    case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST:
    case ID_POPUP_PCB_MOVE_MIRE_REQUEST:
        break;

    case ID_POPUP_CANCEL_CURRENT_COMMAND:
        if( m_canvas->IsMouseCaptured() )
        {
            m_canvas->EndMouseCapture();
        }

        // Should not be executed, just in case
        if( GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE )
        {
            GetScreen()->m_BlockLocate.SetCommand( BLOCK_IDLE );
            GetScreen()->m_BlockLocate.SetState( STATE_NO_BLOCK );
            GetScreen()->m_BlockLocate.ClearItemsList();
        }

        if( GetToolId() == ID_NO_TOOL_SELECTED )
            SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        else
            SetCursor( (wxStockCursor) m_canvas->GetDefaultCursor() );

        break;

    default:        // Finish (abort) the command
        if( m_canvas->IsMouseCaptured() )
            m_canvas->CallEndMouseCapture( &dc );

        if( GetToolId() != id )
        {
            if( m_lastDrawToolId != GetToolId() )
                m_lastDrawToolId = GetToolId();

            SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        }
        break;
    }

    switch( id )   // Execute command
    {
    case 0:
        break;

    case ID_OPEN_MODULE_EDITOR:
        {
            FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, false );

            if( !editor )
            {
                editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, true );

                editor->Show( true );
                editor->Zoom_Automatique( false );
            }
            else
            {
                /* not needed on linux, other platforms need this?
                if( editor->IsIconized() )
                     editor->Iconize( false );
                */

                editor->Raise();

                // Raising the window does not set the focus on Linux.  This should work on
                // any platform.
                if( wxWindow::FindFocus() != editor )
                    editor->SetFocus();
            }
        }
        break;

    case ID_OPEN_MODULE_VIEWER:
        {
            FOOTPRINT_VIEWER_FRAME* viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, false );

            if( !viewer )
            {
                viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, true );

                viewer->Show( true );
                viewer->Zoom_Automatique( false );
            }
            else
            {
                /* not needed on linux, other platforms need this?
                if( viewer->IsIconized() )
                     viewer->Iconize( false );
                */

                viewer->Raise();

                // Raising the window does not set the focus on Linux.  This should work on
                // any platform.
                if( wxWindow::FindFocus() != viewer )
                    viewer->SetFocus();
            }
        }
        break;

    case ID_PCB_GLOBAL_DELETE:
        InstallPcbGlobalDeleteFrame( wxDefaultPosition );
        break;

    case ID_POPUP_PLACE_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_MOVE );
        m_canvas->SetAutoPanRequest( false );
        HandleBlockPlace( &dc );
        break;

    case ID_POPUP_COPY_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_COPY );
        GetScreen()->m_BlockLocate.SetMessageBlock( this );
        m_canvas->SetAutoPanRequest( false );
        HandleBlockPlace( &dc );
        break;

    case ID_POPUP_ZOOM_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_ZOOM );
        GetScreen()->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_DELETE_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_DELETE );
        GetScreen()->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_ROTATE_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_ROTATE );
        GetScreen()->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_FLIP_BLOCK:
        GetScreen()->m_BlockLocate.SetCommand( BLOCK_FLIP );
        GetScreen()->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_DRC_CONTROL:
        m_drc->ShowDialog();
        break;

    case ID_GET_NETLIST:
        InstallNetlistFrame( &dc );
        break;

    case ID_FIND_ITEMS:
        InstallFindFrame();
        break;

    case ID_POPUP_CLOSE_CURRENT_TOOL:
        SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        break;

    case ID_POPUP_CANCEL_CURRENT_COMMAND:
        break;

    case ID_POPUP_PCB_END_LINE:
        m_canvas->MoveCursorToCrossHair();

        //  EndSegment(&dc);
        break;

    case ID_POPUP_PCB_EDIT_TRACK:
        if( GetCurItem() == NULL )
            break;
        Edit_Track_Width( &dc, (TRACK*) GetCurItem() );
        m_canvas->MoveCursorToCrossHair();
        OnModify();
        break;

    case ID_POPUP_PCB_EDIT_TRACKSEG:
        if( GetCurItem() == NULL )
            break;
        Edit_TrackSegm_Width( &dc, (TRACK*) GetCurItem() );
        m_canvas->MoveCursorToCrossHair();
        OnModify();
        break;

    case ID_POPUP_PCB_EDIT_ALL_VIAS_AND_TRACK_SIZE:
        if( GetCurItem() == NULL )
            break;
        {
        int type = GetCurItem()->Type();

        if( type == PCB_TRACE_T || type == PCB_VIA_T )
        {
            BOARD_CONNECTED_ITEM*item = (BOARD_CONNECTED_ITEM*) GetCurItem();
            DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS dlg( this, item->GetNetCode() );
            dlg.ShowModal();
        }

        }
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_BEGIN_TRACK:
        m_canvas->MoveCursorToCrossHair();
        OnHotkeyBeginRoute( &dc );
        break;

    case ID_POPUP_PCB_END_TRACK:
        m_canvas->MoveCursorToCrossHair();
        End_Route( (TRACK*) GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_PLACE_MOVED_TRACK_NODE:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem()->IsDragging() )
        {
            PlaceDraggedOrMovedTrackSegment( (TRACK*) GetCurItem(), &dc );
        }

        break;

    case ID_POPUP_PCB_SWITCH_TRACK_POSTURE:
        /* change the position of initial segment when creating new tracks
         * switch from _/  to -\ .
         * If a track is in progress, it will be redrawn
        */
        if( m_canvas->IsMouseCaptured() )
            m_canvas->CallMouseCapture( &dc, wxDefaultPosition, false );

        g_Alternate_Track_Posture = !g_Alternate_Track_Posture;

        if( m_canvas->IsMouseCaptured() )
            m_canvas->CallMouseCapture( &dc, wxDefaultPosition, false );

        break;

    case ID_POPUP_PCB_PLACE_MICROVIA:
        if( !IsMicroViaAcceptable() )
            break;
        // fall through
    case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA:
    case ID_POPUP_PCB_PLACE_THROUGH_VIA:
    case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA:
    case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem()->IsDragging() )
        {
            PlaceDraggedOrMovedTrackSegment( (TRACK*) GetCurItem(), &dc );
        }
        else
        {
            BOARD_DESIGN_SETTINGS &settings = GetDesignSettings();
            VIATYPE_T v_type = settings.m_CurrentViaType;
            switch( id )
            {
            case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA:
            case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA:
                settings.m_CurrentViaType = VIA_BLIND_BURIED;
                break;

            case ID_POPUP_PCB_PLACE_MICROVIA:
                settings.m_CurrentViaType = VIA_MICROVIA;
                break;

            default:
                settings.m_CurrentViaType = VIA_THROUGH;
                break;
            }

            // place via and switch layer.
            if( id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA ||
                id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA )
            {
                m_canvas->SetIgnoreMouseEvents( true );
                wxPoint dlgPosition;
                wxGetMousePosition( &dlgPosition.x, &dlgPosition.y );
                LAYER_NUM layer = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS,
                                               dlgPosition );
                m_canvas->SetIgnoreMouseEvents( false );
                m_canvas->MoveCursorToCrossHair();

                if( getActiveLayer() != layer )
                {
                    GetScreen()->m_Route_Layer_TOP    = getActiveLayer();
                    GetScreen()->m_Route_Layer_BOTTOM = layer;
                    Other_Layer_Route( (TRACK*) GetCurItem(), &dc );
                }
            }

            else
                Other_Layer_Route( (TRACK*) GetCurItem(), &dc );

            settings.m_CurrentViaType = v_type;

            if( DisplayOpt.ContrastModeDisplay )
                m_canvas->Refresh();
        }
        break;

    case ID_POPUP_PCB_DELETE_TRACKSEG:
        if( GetCurItem() == NULL )
            break;

        m_canvas->MoveCursorToCrossHair();
        SetCurItem( Delete_Segment( &dc, (TRACK*) GetCurItem() ) );
        OnModify();
        break;

    case ID_POPUP_PCB_DELETE_TRACK:
        if( GetCurItem() == NULL )
            break;
        m_canvas->MoveCursorToCrossHair();
        Delete_Track( &dc, (TRACK*) GetCurItem() );
        SetCurItem( NULL );
        OnModify();
        break;

    case ID_POPUP_PCB_DELETE_TRACKNET:
        m_canvas->MoveCursorToCrossHair();
        Delete_net( &dc, (TRACK*) GetCurItem() );
        SetCurItem( NULL );
        OnModify();
        break;

    case ID_POPUP_PCB_LOCK_ON_TRACKSEG:
        Attribut_Segment( (TRACK*) GetCurItem(), &dc, true );
        break;

    case ID_POPUP_PCB_LOCK_OFF_TRACKSEG:
        Attribut_Segment( (TRACK*) GetCurItem(), &dc, false );
        break;

    case ID_POPUP_PCB_LOCK_ON_TRACK:
        Attribut_Track( (TRACK*) GetCurItem(), &dc, true );
        break;

    case ID_POPUP_PCB_LOCK_OFF_TRACK:
        Attribut_Track( (TRACK*) GetCurItem(), &dc, false );
        break;

    case ID_POPUP_PCB_LOCK_ON_NET:
        Attribut_net( &dc, ( (TRACK*) GetCurItem() )->GetNetCode(), true );
        break;

    case ID_POPUP_PCB_LOCK_OFF_NET:
        Attribut_net( &dc, ( (TRACK*) GetCurItem() )->GetNetCode(), false );
        break;

    case ID_POPUP_PCB_SETFLAGS_TRACK_MNU:
        break;

    case ID_POPUP_PCB_DELETE_ZONE:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem() == NULL )
            break;

        {
            SEGZONE* zsegm   = (SEGZONE*) GetCurItem();
            int      netcode = zsegm->GetNetCode();
            Delete_OldZone_Fill( zsegm );
            SetCurItem( NULL );
            TestNetConnection( NULL, netcode );
            OnModify();
            SetMsgPanel( GetBoard() );
        }
        break;

    case ID_POPUP_PCB_EDIT_ZONE_PARAMS:
        Edit_Zone_Params( &dc, (ZONE_CONTAINER*) GetCurItem() );
        SetCurItem( NULL ); // Outlines can have changed
        break;

    case ID_POPUP_PCB_ZONE_DUPLICATE:
    {
        ZONE_CONTAINER* zone = (ZONE_CONTAINER*) GetCurItem();
        duplicateZone( &dc, zone );
    }
    break;

    case ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE:
        m_canvas->MoveCursorToCrossHair();
        m_canvas->SetAutoPanRequest( true );
        Add_Similar_Zone( &dc, (ZONE_CONTAINER*) GetCurItem() );
        break;

    case ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE:
        m_canvas->MoveCursorToCrossHair();
        m_canvas->SetAutoPanRequest( true );
        Add_Zone_Cutout( &dc, (ZONE_CONTAINER*) GetCurItem() );
        break;

    case ID_POPUP_PCB_DELETE_ZONE_CONTAINER:
    case ID_POPUP_PCB_DELETE_ZONE_CUTOUT:
        m_canvas->MoveCursorToCrossHair();
        {
            int netcode = ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode();
            Delete_Zone_Contour( &dc, (ZONE_CONTAINER*) GetCurItem() );
            SetCurItem( NULL );
            TestNetConnection( NULL, netcode );
            SetMsgPanel( GetBoard() );
        }
        break;

    case ID_POPUP_PCB_DELETE_ZONE_CORNER:
        Remove_Zone_Corner( &dc, (ZONE_CONTAINER*) GetCurItem() );
        SetCurItem( NULL );
        break;

    case ID_POPUP_PCB_MOVE_ZONE_CORNER:
    {
        m_canvas->MoveCursorToCrossHair();
        ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem();
        m_canvas->SetAutoPanRequest( true );
        Start_Move_Zone_Corner( &dc, zone_cont, zone_cont->GetSelectedCorner(), false );
        break;
    }

    case ID_POPUP_PCB_DRAG_ZONE_OUTLINE_SEGMENT:
    {
        m_canvas->MoveCursorToCrossHair();
        ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem();
        m_canvas->SetAutoPanRequest( true );
        Start_Move_Zone_Drag_Outline_Edge( &dc, zone_cont, zone_cont->GetSelectedCorner() );
        break;
    }

    case ID_POPUP_PCB_MOVE_ZONE_OUTLINES:
    {
        m_canvas->MoveCursorToCrossHair();
        ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem();
        m_canvas->SetAutoPanRequest( true );
        Start_Move_Zone_Outlines( &dc, zone_cont );
        break;
    }

    case ID_POPUP_PCB_ADD_ZONE_CORNER:
    {
        m_canvas->MoveCursorToCrossHair();
        ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem();
        wxPoint         pos = GetCrossHairPosition();

        /* add corner between zone_cont->m_CornerSelection
         * and zone_cont->m_CornerSelection+1
         * and start move the new corner
         */
        zone_cont->Draw( m_canvas, &dc, GR_XOR );
        zone_cont->Outline()->InsertCorner( zone_cont->GetSelectedCorner(), pos.x, pos.y );
        zone_cont->SetSelectedCorner( zone_cont->GetSelectedCorner() + 1 );
        zone_cont->Draw( m_canvas, &dc, GR_XOR );
        m_canvas->SetAutoPanRequest( true );
        Start_Move_Zone_Corner( &dc, zone_cont, zone_cont->GetSelectedCorner(), true );
        break;
    }

    case ID_POPUP_PCB_PLACE_ZONE_OUTLINES:
    case ID_POPUP_PCB_PLACE_ZONE_CORNER:
    {
        m_canvas->MoveCursorToCrossHair();
        ZONE_CONTAINER* zone_cont = (ZONE_CONTAINER*) GetCurItem();
        End_Move_Zone_Corner_Or_Outlines( &dc, zone_cont );
        m_canvas->SetAutoPanRequest( false );
        break;
    }

    case ID_POPUP_PCB_FILL_ALL_ZONES:
        m_canvas->MoveCursorToCrossHair();
        Fill_All_Zones( this );
        m_canvas->Refresh();
        SetMsgPanel( GetBoard() );
        break;

    case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_CURRENT_ZONE:
        if( ( GetCurItem() )->Type() == PCB_ZONE_AREA_T )
        {
            ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) GetCurItem();
            zone_container->UnFill();
            TestNetConnection( NULL, zone_container->GetNetCode() );
            OnModify();
            SetMsgPanel( GetBoard() );
            m_canvas->Refresh();
        }
        SetCurItem( NULL );
        break;

    case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES: // Remove all zones :
        GetBoard()->m_Zone.DeleteAll();                 // remove zone segments used to fill zones.

        for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
        {
            // Remove filled areas in zone
            ZONE_CONTAINER* zone_container = GetBoard()->GetArea( ii );
            zone_container->ClearFilledPolysList();
        }

        SetCurItem( NULL );        // CurItem might be deleted by this command, clear the pointer
        TestConnections();
        TestForActiveLinksInRatsnest( 0 );   // Recalculate the active ratsnest, i.e. the unconnected links
        OnModify();
        SetMsgPanel( GetBoard() );
        m_canvas->Refresh();
        break;

    case ID_POPUP_PCB_FILL_ZONE:
        m_canvas->MoveCursorToCrossHair();
        Fill_Zone( (ZONE_CONTAINER*) GetCurItem() );
        TestNetConnection( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode() );
        SetMsgPanel( GetBoard() );
        m_canvas->Refresh();
        break;

    case ID_POPUP_PCB_MOVE_TEXTEPCB_REQUEST:
        StartMoveTextePcb( (TEXTE_PCB*) GetCurItem(), &dc );
        m_canvas->SetAutoPanRequest( true );
        break;

    case ID_POPUP_PCB_DRAG_MODULE_REQUEST:
    case ID_POPUP_PCB_MOVE_MODULE_REQUEST:
        if( GetCurItem() == NULL )
            break;

        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        module = (MODULE*) GetCurItem();

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "Footprint %s found, but it is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        SendMessageToEESCHEMA( module );
        SetCrossHairPosition( module->GetPosition() );
        m_canvas->MoveCursorToCrossHair();
        StartMoveModule( module, &dc, id == ID_POPUP_PCB_DRAG_MODULE_REQUEST );
        break;

    case ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST:      // get module by name and move it
        SetCurItem( GetModuleByName() );
        module = (MODULE*) GetCurItem();

        if( module == NULL )
            break;

        if( module->IsLocked() )
        {
            wxString msg = wxString::Format(
                _( "Footprint %s found, but it is locked" ),
                module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        SendMessageToEESCHEMA( module );
        m_canvas->MoveCursorToCrossHair();
        StartMoveModule( module, &dc, false );
        break;

    case ID_POPUP_PCB_DELETE_MODULE:
        m_canvas->MoveCursorToCrossHair();

        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        module = (MODULE*) GetCurItem();

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "Footprint %s found, but it is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        if( Delete_Module( (MODULE*) GetCurItem(), &dc, true ) )
        {
            SetCurItem( NULL );
        }

        break;

    case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE:
        m_canvas->MoveCursorToCrossHair();

        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        module = (MODULE*) GetCurItem();

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "Footprint %s found, but it is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        // This is a simple rotation, no other editing in progress
        if( !GetCurItem()->IsMoving() )
            SaveCopyInUndoList( GetCurItem(), UR_CHANGED, ((MODULE*)GetCurItem())->GetPosition() );

        Rotate_Module( &dc, (MODULE*) GetCurItem(), m_rotationAngle, true );
        break;

    case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE:
        m_canvas->MoveCursorToCrossHair();

        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        module = (MODULE*) GetCurItem();

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "Footprint %s found, but it is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        // This is a simple rotation, no other editing in progress
        if( !GetCurItem()->IsMoving() )
            SaveCopyInUndoList( GetCurItem(), UR_CHANGED, ((MODULE*)GetCurItem())->GetPosition() );

        Rotate_Module( &dc, (MODULE*) GetCurItem(), -m_rotationAngle, true );
        break;

    case ID_POPUP_PCB_CHANGE_SIDE_MODULE:
        m_canvas->MoveCursorToCrossHair();

        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        module = (MODULE*) GetCurItem();

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "Footprint %s found, but it is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        // This is a simple flip, no other editing in progress
        if( !GetCurItem()->IsMoving() )
            SaveCopyInUndoList( GetCurItem(), UR_FLIPPED, ((MODULE*)GetCurItem())->GetPosition() );

        Change_Side_Module( (MODULE*) GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_EDIT_MODULE_PRMS:
        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        InstallModuleOptionsFrame( (MODULE*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_EDIT_MODULE_WITH_MODEDIT:
        // If the current Item is a pad, text module ...: Get its parent
        if( GetCurItem()->Type() != PCB_MODULE_T )
            SetCurItem( GetCurItem()->GetParent() );

        if( !GetCurItem() || GetCurItem()->Type() != PCB_MODULE_T )
            break;

        if( GetCurItem()->GetTimeStamp() == 0 )    // Module Editor needs a non null timestamp
        {
            GetCurItem()->SetTimeStamp( GetNewTimeStamp() );
            OnModify();
        }

        {
            FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) Kiway().Player( FRAME_PCB_MODULE_EDITOR, true );

            editor->Load_Module_From_BOARD( (MODULE*)GetCurItem() );
            SetCurItem( NULL );     // the current module could be deleted by

            editor->Show( true );

            editor->Raise();        // Iconize( false );
        }
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DRAG_PAD_REQUEST:
        module = (MODULE*) GetCurItem()->GetParent();

        if( !module || module->Type() != PCB_MODULE_T )
            break;

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "The parent (%s) of the pad is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        m_canvas->MoveCursorToCrossHair();
        StartMovePad( (D_PAD*) GetCurItem(), &dc, true );
        break;

    case ID_POPUP_PCB_MOVE_PAD_REQUEST:
        module = (MODULE*) GetCurItem()->GetParent();

        if( !module || module->Type() != PCB_MODULE_T )
            break;

        if( module->IsLocked() )
        {
            wxString msg;
            msg.Printf( _( "The parent (%s) of the pad is locked" ),
                        module->GetReference().GetData() );
            DisplayInfoMessage( this, msg );
            break;
        }

        m_canvas->MoveCursorToCrossHair();
        StartMovePad( (D_PAD*) GetCurItem(), &dc, false );
        break;

    case ID_POPUP_PCB_EDIT_PAD:
        InstallPadOptionsFrame( (D_PAD*) GetCurItem() );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_IMPORT_PAD_SETTINGS:
        m_canvas->MoveCursorToCrossHair();
        SaveCopyInUndoList( GetCurItem()->GetParent(), UR_CHANGED );
        Import_Pad_Settings( (D_PAD*) GetCurItem(), true );
        break;

    case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS:
        m_canvas->MoveCursorToCrossHair();
        DlgGlobalChange_PadSettings( (D_PAD*) GetCurItem(), true );
        break;

    case ID_POPUP_PCB_EXPORT_PAD_SETTINGS:
        m_canvas->MoveCursorToCrossHair();
        Export_Pad_Settings( (D_PAD*) GetCurItem() );
        break;

    case ID_POPUP_PCB_DELETE_PAD:
        SaveCopyInUndoList( GetCurItem()->GetParent(), UR_CHANGED );
        DeletePad( (D_PAD*) GetCurItem() );
        SetCurItem( NULL );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_EDIT_TEXTMODULE:
        InstallTextModOptionsFrame( (TEXTE_MODULE*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_RESET_TEXT_SIZE:
        ResetTextSize( GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST:
        m_canvas->MoveCursorToCrossHair();
        StartMoveTexteModule( (TEXTE_MODULE*) GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_ROTATE_TEXTMODULE:
        RotateTextModule( (TEXTE_MODULE*) GetCurItem(),
                         &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DELETE_TEXTMODULE:
        DeleteTextModule( (TEXTE_MODULE*) GetCurItem() );
        SetCurItem( NULL );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_SELECT_LAYER:
        itmp = SelectLayer( getActiveLayer() );

        if( itmp >= 0 )
        {
            // if user changed colors and we are in high contrast mode, then redraw
            // because the PAD_SMD pads may change color.
            if( DisplayOpt.ContrastModeDisplay && getActiveLayer() != itmp )
            {
                m_canvas->Refresh();
            }
            setActiveLayer( itmp );
        }

        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR:
        SelectCopperLayerPair();
        break;

    case ID_POPUP_PCB_SELECT_NO_CU_LAYER:
        itmp = SelectLayer( getActiveLayer(), ALL_CU_LAYERS );

        if( itmp >= 0 )
            setActiveLayer( itmp );

        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_SELECT_CU_LAYER:
        itmp = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS );

        if( itmp >= 0 )
            setActiveLayer( itmp );

        break;

    case ID_POPUP_PCB_SELECT_LAYER_PAIR:
        SelectCopperLayerPair();
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_TOOLBARH_PCB_SELECT_LAYER:
        setActiveLayer( m_SelLayerBox->GetLayerSelection() );

        if( DisplayOpt.ContrastModeDisplay )
            m_canvas->Refresh( true );

        break;

    case ID_POPUP_PCB_EDIT_TEXTEPCB:
        InstallTextPCBOptionsFrame( (TEXTE_PCB*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_ROTATE_TEXTEPCB:
        Rotate_Texte_Pcb( (TEXTE_PCB*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_COPY_TEXTEPCB:
        CreateTextePcb( &dc, (TEXTE_PCB*) GetCurItem() );
        m_canvas->MoveCursorToCrossHair();
        m_canvas->SetAutoPanRequest( true );
        break;

    case ID_POPUP_PCB_FLIP_TEXTEPCB:
        FlipTextePcb( (TEXTE_PCB*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DELETE_TEXTEPCB:
        Delete_Texte_Pcb( (TEXTE_PCB*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_MOVE_MIRE_REQUEST:
        BeginMoveTarget( (PCB_TARGET*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_EDIT_MIRE:
        ShowTargetOptionsDialog( (PCB_TARGET*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DELETE_MIRE:
        m_canvas->MoveCursorToCrossHair();
        DeleteTarget( (PCB_TARGET*) GetCurItem(), &dc );
        SetCurItem( NULL );
        break;

    case ID_POPUP_PCB_DELETE_DIMENSION:
        m_canvas->MoveCursorToCrossHair();
        DeleteDimension( (DIMENSION*) GetCurItem(), &dc );
        SetCurItem( NULL );
        break;

    case ID_POPUP_PCB_EDIT_DIMENSION:
        ShowDimensionPropertyDialog( (DIMENSION*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST:
        BeginMoveDimensionText( (DIMENSION*) GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_DELETE_DRAWING:
        Delete_Segment_Edge( (DRAWSEGMENT*) GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DELETE_MARKER:
        RemoveStruct( GetCurItem(), &dc );
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_GETINFO_MARKER:
        if( GetCurItem() && GetCurItem()->Type() == PCB_MARKER_T )
            ( (MARKER_PCB*) GetCurItem() )->DisplayMarkerInfo( this );

        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_DELETE_DRAWING_LAYER:
        if( GetCurItem()->GetFlags() != 0 )
            break;

        Delete_Drawings_All_Layer( GetCurItem()->GetLayer() );
        SetCurItem( NULL );
        m_canvas->MoveCursorToCrossHair();
        m_canvas->Refresh();
        break;

    case ID_POPUP_PCB_EDIT_DRAWING:
#ifndef USE_WX_OVERLAY
        InstallGraphicItemPropertiesDialog( (DRAWSEGMENT*) GetCurItem(), &dc );
#else
        // #1277772 - Draw into dialog converted in refresh request
        InstallGraphicItemPropertiesDialog( (DRAWSEGMENT*) GetCurItem(), NULL );
        m_canvas->Refresh();
#endif
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_PCB_MOVE_DRAWING_REQUEST:
        m_canvas->MoveCursorToCrossHair();
        Start_Move_DrawItem( (DRAWSEGMENT*) GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_STOP_CURRENT_DRAWING:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem() && (GetCurItem()->IsNew()) )
        {
            End_Edge( (DRAWSEGMENT*) GetCurItem(), &dc );
            SetCurItem( NULL );
        }

        break;

    case ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem() && (GetCurItem()->IsNew()) )
        {
            if( End_Zone( &dc ) )
                SetCurItem( NULL );
        }

        m_canvas->SetAutoPanRequest( false );
        break;

    case ID_POPUP_PCB_DELETE_ZONE_LAST_CREATED_CORNER:
        m_canvas->MoveCursorToCrossHair();

        if( GetCurItem() && (GetCurItem()->IsNew()) )
        {
            if( Delete_LastCreatedCorner( &dc ) == 0 )  // No more segment in outline,
                SetCurItem( NULL );
        }

        break;


    case ID_POPUP_PCB_MOVE_TRACK_SEGMENT:
        m_canvas->MoveCursorToCrossHair();
        StartMoveOneNodeOrSegment( (TRACK*) GetScreen()->GetCurItem(), &dc, id );
        break;

    case ID_POPUP_PCB_DRAG_TRACK_SEGMENT:
    case ID_POPUP_PCB_MOVE_TRACK_NODE:
        m_canvas->MoveCursorToCrossHair();
        StartMoveOneNodeOrSegment( (TRACK*) GetScreen()->GetCurItem(), &dc, id );
        break;

    case ID_POPUP_PCB_DRAG_TRACK_SEGMENT_KEEP_SLOPE:
        m_canvas->MoveCursorToCrossHair();
        Start_DragTrackSegmentAndKeepSlope( (TRACK*) GetScreen()->GetCurItem(), &dc );
        break;

    case ID_POPUP_PCB_BREAK_TRACK:
        m_canvas->MoveCursorToCrossHair();
        {
            TRACK*  track = (TRACK*) GetScreen()->GetCurItem();
            wxPoint pos   = GetCrossHairPosition();

            track->Draw( m_canvas, &dc, GR_XOR );
            PICKED_ITEMS_LIST itemsListPicker;

            TRACK*  newtrack = GetBoard()->CreateLockPoint( pos, track, &itemsListPicker );

            SaveCopyInUndoList( itemsListPicker, UR_UNSPECIFIED );
            track->Draw( m_canvas, &dc, GR_XOR );
            newtrack->Draw( m_canvas, &dc, GR_XOR );

            // compute the new ratsnest, because connectivity could change
            TestNetConnection( &dc, track->GetNetCode() );
        }
        break;

    case ID_MENU_PCB_CLEAN:
        Clean_Pcb();
        break;

    case ID_MENU_PCB_SWAP_LAYERS:
        Swap_Layers( event );
        break;

    case ID_PCB_USER_GRID_SETUP:
        InvokeDialogGrid();
        break;

    case ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC:
        {
            wxConfigBase* cfg = Pgm().CommonSettings();
            cfg->Read( wxT( "module_doc_file" ), g_DocModulesFileName );
            GetAssociatedDocument( this, g_DocModulesFileName, &Kiface().KifaceSearch() );
        }
        break;

    case ID_MENU_ARCHIVE_NEW_MODULES:
        ArchiveModulesOnBoard( true );
        break;

    case ID_MENU_ARCHIVE_ALL_MODULES:
        ArchiveModulesOnBoard( false );
        break;

    case ID_GEN_IMPORT_DXF_FILE:
        InvokeDXFDialogImport( this );
        m_canvas->Refresh();
        break;

    default:
        wxString msg;
        msg.Printf( wxT( "PCB_EDIT_FRAME::Process_Special_Functions() unknown event id %d" ),
                    id );
        DisplayError( this, msg );
        break;
    }

    m_canvas->CrossHairOn( &dc );
    m_canvas->SetIgnoreMouseEvents( false );
}
Пример #10
0
void PCB_EDIT_FRAME::StartMoveOneNodeOrSegment( TRACK* aTrack, wxDC* aDC, int aCommand )
{
    if( !aTrack )
        return;

    EraseDragList();

    // Change highlighted net: the new one will be highlighted
    GetBoard()->PushHighLight();

    if( GetBoard()->IsHighLightNetON() )
        HighLight( aDC );

    PosInit = GetCrossHairPosition();

    if( aTrack->Type() == PCB_VIA_T )
    {
        aTrack->SetFlags( IS_DRAGGED | STARTPOINT | ENDPOINT );
        AddSegmentToDragList( aTrack->GetFlags(), aTrack );

        if( aCommand != ID_POPUP_PCB_MOVE_TRACK_SEGMENT )
        {
            Collect_TrackSegmentsToDrag( GetBoard(), aTrack->GetStart(),
                                         aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
        }

        PosInit = aTrack->GetStart();
    }
    else
    {
        STATUS_FLAGS diag = aTrack->IsPointOnEnds( GetCrossHairPosition(), -1 );
        wxPoint pos;

        switch( aCommand )
        {
        case ID_POPUP_PCB_MOVE_TRACK_SEGMENT:   // Move segment
            aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
            AddSegmentToDragList( aTrack->GetFlags(), aTrack );
            break;

        case ID_POPUP_PCB_DRAG_TRACK_SEGMENT:   // drag a segment
            pos = aTrack->GetStart();
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            pos = aTrack->GetEnd();
            aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            break;

        case ID_POPUP_PCB_MOVE_TRACK_NODE:  // Drag via or move node
            pos = (diag & STARTPOINT) ? aTrack->GetStart() : aTrack->GetEnd();
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            PosInit = pos;
            break;
        }

        aTrack->SetFlags( IS_DRAGGED );
    }

    // Prepare the Undo command
    ITEM_PICKER picker( aTrack, UR_CHANGED );
    picker.SetLink( aTrack->Clone() );
    s_ItemsListPicker.PushItem( picker );

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
        picker.SetItem( draggedtrack );
        picker.SetLink( draggedtrack->Clone() );
        s_ItemsListPicker.PushItem( picker );
        draggedtrack = (TRACK*) picker.GetLink();
        draggedtrack->SetStatus( 0 );
        draggedtrack->ClearFlags();
    }

    s_LastPos = PosInit;
    m_canvas->SetMouseCapture( Show_MoveNode, Abort_MoveTrack );

    GetBoard()->SetHighLightNet( aTrack->GetNetCode() );
    GetBoard()->HighLightON();

    GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
    m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );

    UndrawAndMarkSegmentsToDrag( m_canvas, aDC );
}
Пример #11
0
void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC*  DC )
{
    TRACK* TrackToStartPoint = NULL;
    TRACK* TrackToEndPoint   = NULL;
    bool   error = false;

    if( !track )
        return;

    // TODO: Use cleanup functions to merge collinear segments if track
    // is connected to a collinear segment.

    s_StartSegmentPresent = s_EndSegmentPresent = true;

    if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
        TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToStartPoint )
    {
        TrackToStartPoint->SetState( BUSY, true );

        if( ( TrackToStartPoint->Type() == PCB_VIA_T )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
            error = true;

        TrackToStartPoint->SetState( BUSY, false );
    }

    if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
        TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToEndPoint )
    {
        TrackToEndPoint->SetState( BUSY, true );

        if( (TrackToEndPoint->Type() == PCB_VIA_T)
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
            error = true;

        TrackToEndPoint->SetState( BUSY, false );
    }

    if( error )
    {
        DisplayError( this,
                      _( "Unable to drag this segment: too many segments connected" ) );
        return;
    }

    if( !TrackToStartPoint || ( TrackToStartPoint->Type() != PCB_TRACE_T ) )
        s_StartSegmentPresent = false;

    if( !TrackToEndPoint || ( TrackToEndPoint->Type() != PCB_TRACE_T ) )
        s_EndSegmentPresent = false;

    // Change high light net: the new one will be highlighted
    GetBoard()->PushHighLight();

    if( GetBoard()->IsHighLightNetON() )
        HighLight( DC );

    EraseDragList();

    track->SetFlags( IS_DRAGGED );

    if( TrackToStartPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetStart() != TrackToStartPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToStartPoint );
        track->SetFlags( STARTPOINT );
    }

    if( TrackToEndPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetEnd() != TrackToEndPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToEndPoint );
        track->SetFlags( ENDPOINT );
    }

    AddSegmentToDragList( track->GetFlags(), track );

    UndrawAndMarkSegmentsToDrag( m_canvas, DC );


    PosInit   = GetCrossHairPosition();
    s_LastPos = GetCrossHairPosition();
    m_canvas->SetMouseCapture( Show_Drag_Track_Segment_With_Cte_Slope, Abort_MoveTrack );

    GetBoard()->SetHighLightNet( track->GetNetCode() );
    GetBoard()->HighLightON();
    GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );

    // Prepare the Undo command
    ITEM_PICKER picker( NULL, UR_CHANGED );

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
        picker.SetItem( draggedtrack);
        picker.SetLink ( draggedtrack->Clone() );
        s_ItemsListPicker.PushItem( picker );
        draggedtrack = (TRACK*) picker.GetLink();
        draggedtrack->SetStatus( 0 );
        draggedtrack->ClearFlags();
    }

    if( !InitialiseDragParameters() )
    {
        DisplayError( this, _( "Unable to drag this segment: two collinear segments" ) );
        m_canvas->SetMouseCaptureCallback( NULL );
        Abort_MoveTrack( m_canvas, DC );
        return;
    }
}
Пример #12
0
/* Init variables (slope, Y intersect point, flags) for
 * Show_Drag_Track_Segment_With_Cte_Slope()
 *  return true if Ok, false if dragging is not possible
 *  (2 colinear segments)
 */
bool InitialiseDragParameters()
{
    double     tx1, tx2, ty1, ty2; // temporary storage of points
    TRACK*     Track;
    TRACK*     tSegmentToStart = NULL, * tSegmentToEnd = NULL;

    if( g_DragSegmentList.size() == 0 )
        return false;

    /* get the segments :
     * from last to first in list are:
     * the segment to move
     * the segment connected to its end point (if exists)
     * the segment connected to its start point (if exists)
     */
    int ii = g_DragSegmentList.size() - 1;
    Track = g_DragSegmentList[ii].m_Track;
    if( Track == NULL )
        return false;

    ii--;

    if( ii >= 0)
    {
        if( s_EndSegmentPresent )
        {
            tSegmentToEnd = g_DragSegmentList[ii].m_Track;  // Get the segment connected to
                                                           // the end point
            ii--;
        }

        if( s_StartSegmentPresent )
        {
            if( ii  >= 0 )
                tSegmentToStart = g_DragSegmentList[ii].m_Track;  // Get the segment connected to
                                                                 // the start point
        }
    }

    // would be nice to eliminate collinear segments here, so we don't
    // have to deal with that annoying "Unable to drag this segment: two
    // collinear segments"

    s_StartPointVertical = false;
    s_EndPointVertical   = false;
    s_MovingSegmentVertical   = false;
    s_StartPointHorizontal    = false;
    s_EndPointHorizontal      = false;
    s_MovingSegmentHorizontal = false;

    // Init parameters for the starting point of the moved segment
    if( tSegmentToStart )
    {
        if( tSegmentToStart->GetFlags() & ENDPOINT )
        {
            tx1 = (double) tSegmentToStart->GetStart().x;
            ty1 = (double) tSegmentToStart->GetStart().y;
            tx2 = (double) tSegmentToStart->GetEnd().x;
            ty2 = (double) tSegmentToStart->GetEnd().y;
        }
        else
        {
            tx1 = (double) tSegmentToStart->GetEnd().x;
            ty1 = (double) tSegmentToStart->GetEnd().y;
            tx2 = (double) tSegmentToStart->GetStart().x;
            ty2 = (double) tSegmentToStart->GetStart().y;
        }
    }
    else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track
    {
        tx1 = (double) Track->GetStart().x;
        ty1 = (double) Track->GetStart().y;
        tx2 = (double) Track->GetEnd().x;
        ty2 = (double) Track->GetEnd().y;
        RotatePoint( &tx2, &ty2, tx1, ty1, 900 );
    }

    if( tx1 != tx2 )
    {
        s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
        s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
    }
    else
    {
        s_StartPointVertical = true;            //signal first segment vertical
    }

    if( ty1 == ty2 )
    {
        s_StartPointHorizontal = true;
    }

    // Init parameters for the ending point of the moved segment
    if( tSegmentToEnd )
    {
        //check if second line is vertical
        if( tSegmentToEnd->GetFlags() & STARTPOINT )
        {
            tx1 = (double) tSegmentToEnd->GetStart().x;
            ty1 = (double) tSegmentToEnd->GetStart().y;
            tx2 = (double) tSegmentToEnd->GetEnd().x;
            ty2 = (double) tSegmentToEnd->GetEnd().y;
        }
        else
        {
            tx1 = (double) tSegmentToEnd->GetEnd().x;
            ty1 = (double) tSegmentToEnd->GetEnd().y;
            tx2 = (double) tSegmentToEnd->GetStart().x;
            ty2 = (double) tSegmentToEnd->GetStart().y;
        }
    }
    else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track
    {
        tx1 = (double) Track->GetEnd().x;
        ty1 = (double) Track->GetEnd().y;
        tx2 = (double) Track->GetStart().x;
        ty2 = (double) Track->GetStart().y;
        RotatePoint( &tx2, &ty2, tx1, ty1, -900 );
    }

    if( tx2 != tx1 )
    {
        s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
        s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
    }
    else
    {
        s_EndPointVertical = true;      //signal second segment vertical
    }

    if( ty1 == ty2 )
    {
        s_EndPointHorizontal = true;
    }

    // Init parameters for the moved segment
    tx1 = (double) Track->GetStart().x;
    ty1 = (double) Track->GetStart().y;
    tx2 = (double) Track->GetEnd().x;
    ty2 = (double) Track->GetEnd().y;

    if( tx2 != tx1 )
    {
        s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
    }
    else
    {
        s_MovingSegmentVertical = true;      // signal vertical line
    }

    if( ty1 == ty2 )
    {
        s_MovingSegmentHorizontal = true;
    }

    // Test if drag is possible:
    if( s_MovingSegmentVertical )
    {
        if( s_EndPointVertical || s_StartPointVertical )
            return false;
    }
    else
    {
        if( !s_EndPointVertical && ( s_MovingSegmentSlope == s_EndSegmentSlope ) )
            return false;

        if( !s_StartPointVertical && ( s_MovingSegmentSlope == s_StartSegmentSlope ) )
            return false;
    }

    return true;
}
Пример #13
0
/* drawing the track segment movement
 *  > s_MovingSegmentSlope slope = moving track segment slope
 *  > s_StartSegmentSlope slope = slope of the segment connected to the start
 * point of the moving segment
 *  > s_EndSegmentSlope slope = slope of the segment connected to the end point
 * of the moving segment
 *
 *  moved segment function :
 *      yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg
 *
 *  segment connected to moved segment's start:
 *      y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg
 *
 *  segment connected to moved segment's end:
 *      y2=s_EndSegmentSlope * x + s_EndSegment_Yorg
 *
 *  first intersection point will be located at
 *      y1=yt ->
 *
 * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope)
 *      yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg
 *      or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg
 *
 *  second intersection point
 *      y2=yt ->
 *
 * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope)
 *      yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg
 *      or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *  !!!!!    special attention to vertical segments because
 *  !!!!!    their slope=infinite
 *  !!!!!    intersection point will be calculated using the
 *  !!!!!    segment intersecting it
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *
 *  Slope parameters are computed once, because they can become undetermined
 * when moving segments
 *  (i.e. when a segment length is 0) and we want keep them constant
 */
static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                                    const wxPoint& aPosition, bool aErase )
{
    double       xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0;    // calculated intersection points
    double       tx1, tx2, ty1, ty2;                    // temporary storage of points
    int          dx, dy;
    bool         update = true;
    TRACK*       Track;
    TRACK*       tSegmentToStart = NULL, * tSegmentToEnd = NULL;

    if( g_DragSegmentList.size() == 0 )
        return;

    /* get the segments :
     * from last to first in list are:
     * the segment to move
     * the segment connected to its end point (if exists)
     * the segment connected to its start point (if exists)
     */
    int ii = g_DragSegmentList.size() - 1;
    Track = g_DragSegmentList[ii].m_Track;

    if( Track == NULL )
        return;

    ii--;

    if( ii >= 0)
    {
        if( s_EndSegmentPresent )
        {
            // Get the segment connected to the end point
            tSegmentToEnd   = g_DragSegmentList[ii].m_Track;
            ii--;
        }

        if( s_StartSegmentPresent )
        {
            // Get the segment connected to the start point
            if( ii >= 0 )
                tSegmentToStart = g_DragSegmentList[ii].m_Track;
        }
    }

    GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;

    // Undraw the current moved track segments before modification

#ifndef USE_WX_OVERLAY
//  if( erase )
    {
        Track->Draw( aPanel, aDC, draw_mode );

        if( tSegmentToStart )
            tSegmentToStart->Draw( aPanel, aDC, draw_mode );

        if( tSegmentToEnd )
            tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
    }
#endif

    // Compute the new track segment position
    wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();

    dx = Pos.x - s_LastPos.x;
    dy = Pos.y - s_LastPos.y;

    // move the line by dx and dy
    tx1 = (double) ( Track->GetStart().x + dx );
    ty1 = (double) ( Track->GetStart().y + dy );
    tx2 = (double) ( Track->GetEnd().x + dx );
    ty2 = (double) ( Track->GetEnd().y + dy );

    // recalculate the segments new parameters and intersection points
    // only the intercept will change, segment slopes does not change
    // because we are moving parallel with is initial state
    if( !s_MovingSegmentVertical )
        s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 );

    if( ( !s_EndPointVertical ) && ( !s_MovingSegmentVertical ) )
    {
        xi2 = ( s_MovingSegment_Yorg - s_EndSegment_Yorg )
            / ( s_EndSegmentSlope - s_MovingSegmentSlope );
    }
    else
    {
        if( !s_EndPointVertical )
            xi2 = tx2;
        else
        {
            //P1=P2
            if( !s_EndPointHorizontal )
                xi2 = tx2 - dx;
            else
                update = false;
        }
    }

    if( !s_MovingSegmentVertical )
        yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
    else
    {
        if( !s_EndPointVertical )
            yi2 = ( s_EndSegmentSlope * xi2 ) + s_EndSegment_Yorg;
        else
        {
            if( !s_EndPointHorizontal )
                update = false;
             else
                yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
        }
    }

    if( ( !s_StartPointVertical ) && ( !s_MovingSegmentVertical ) )
    {
        xi1 = ( s_MovingSegment_Yorg - s_StartSegment_Yorg )
            / ( s_StartSegmentSlope - s_MovingSegmentSlope );
    }
    else
    {
        if( !s_StartPointVertical )
            xi1 = tx1;
        else
        {
            //P1=P2
            if( !s_StartPointHorizontal )
                xi1 = tx1 - dx;
            else
            {
                if( !s_StartPointHorizontal )
                    update = false;
            }
        }
    }

    if( !s_MovingSegmentVertical )
        yi1 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
    else
    {
        if( !s_StartPointVertical )
            yi1 = ( s_StartSegmentSlope * xi1 ) + s_StartSegment_Yorg;
        else
        {
            if( !s_StartPointHorizontal )
                update = false;
            else
                yi2 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
        }
    }

    // update the segment coordinates (if possible)
    if( tSegmentToStart == NULL )
    {
        xi1 = tx1;
        yi1 = ty1;
    }

    if( tSegmentToEnd == NULL )
    {
        xi2 = tx2;
        yi2 = ty2;
    }

    if( update )
    {
        s_LastPos = Pos;
        Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) );
        Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) );

        if( tSegmentToEnd )
        {
            if( tSegmentToEnd->GetFlags() & STARTPOINT )
                tSegmentToEnd->SetStart( Track->GetEnd() );
            else
                tSegmentToEnd->SetEnd( Track->GetEnd() );
        }

        if( tSegmentToStart )
        {
            if( tSegmentToStart->GetFlags() & STARTPOINT )
                tSegmentToStart->SetStart( Track->GetStart() );
            else
                tSegmentToStart->SetEnd( Track->GetStart() );
        }
    }

    Track->Draw( aPanel, aDC, draw_mode );

    if( tSegmentToStart )
        tSegmentToStart->Draw( aPanel, aDC, draw_mode );

    if( tSegmentToEnd )
        tSegmentToEnd->Draw( aPanel, aDC, draw_mode );

    // Display track length
    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
    frame->SetMsgPanel( Track );
}
Пример #14
0
// Redraw the moved node according to the mouse cursor position
static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
                           bool aErase )
{
    auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions();
    wxPoint      moveVector;
    int          tmp = displ_opts->m_DisplayPcbTrackFill;
    GR_DRAWMODE  draw_mode = GR_XOR | GR_HIGHLIGHT;

    displ_opts->m_DisplayPcbTrackFill = false;

#ifndef USE_WX_OVERLAY
    aErase = true;
#else
    aErase = false;
#endif

    // set the new track coordinates
    wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();

    moveVector = Pos - s_LastPos;
    s_LastPos  = Pos;

    TRACK *track = NULL;

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        track = g_DragSegmentList[ii].m_Track;

        if( aErase )
            track->Draw( aPanel, aDC, draw_mode );

        if( track->GetFlags() & STARTPOINT )
            track->SetStart( track->GetStart() + moveVector );

        if( track->GetFlags() & ENDPOINT )
            track->SetEnd( track->GetEnd() + moveVector );

        if( track->Type() == PCB_VIA_T )
            track->SetEnd( track->GetStart() );

        track->Draw( aPanel, aDC, draw_mode );
    }

    displ_opts->m_DisplayPcbTrackFill = tmp;

    // Display track length
    if( track )
    {
        PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
        frame->SetMsgPanel( track );
    }
}
void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeatures )
{
    int segsPerCircle;
    double correctionFactor;

    // Set the number of segments in arc approximations
    if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF  )
        segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
    else
        segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;

    /* calculates the coeff to compensate radius reduction of holes clearance
     * due to the segment approx.
     * For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
     * s_Correction is 1 /cos( PI/s_CircleToSegmentsCount  )
     */
    correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );

    aFeatures.RemoveAllContours();

    int outline_half_thickness = m_ZoneMinThickness / 2;

    int zone_clearance = std::max( m_ZoneClearance, GetClearance() );
    zone_clearance += outline_half_thickness;

    /* store holes (i.e. tracks and pads areas as polygons outlines)
     * in a polygon list
     */

    /* items ouside the zone bounding box are skipped
     * the bounding box is the zone bounding box + the biggest clearance found in Netclass list
     */
    EDA_RECT item_boundingbox;
    EDA_RECT zone_boundingbox  = GetBoundingBox();
    int      biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue();
    biggest_clearance = std::max( biggest_clearance, zone_clearance );
    zone_boundingbox.Inflate( biggest_clearance );

    /*
     * First : Add pads. Note: pads having the same net as zone are left in zone.
     * Thermal shapes will be created later if necessary
     */
    int item_clearance;

    /* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers
     * and this pad has a hole
     * This dummy pad has the size and shape of the hole
    * Therefore, this dummy pad is a circle or an oval.
     * A pad must have a parent because some functions expect a non null parent
     * to find the parent board, and some other data
     */
    MODULE dummymodule( aPcb );    // Creates a dummy parent
    D_PAD dummypad( &dummymodule );

    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        D_PAD* nextpad;

        for( D_PAD* pad = module->Pads(); pad != NULL; pad = nextpad )
        {
            nextpad = pad->Next();  // pad pointer can be modified by next code, so
                                    // calculate the next pad here

            if( !pad->IsOnLayer( GetLayer() ) )
            {
                /* Test for pads that are on top or bottom only and have a hole.
                 * There are curious pads but they can be used for some components that are
                 * inside the board (in fact inside the hole. Some photo diodes and Leds are
                 * like this)
                 */
                if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
                    continue;

                // Use a dummy pad to calculate a hole shape that have the same dimension as
                // the pad hole
                dummypad.SetSize( pad->GetDrillSize() );
                dummypad.SetOrientation( pad->GetOrientation() );
                dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
                                   PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
                dummypad.SetPosition( pad->GetPosition() );

                pad = &dummypad;
            }

            // Note: netcode <=0 means not connected item
            if( ( pad->GetNetCode() != GetNetCode() ) || ( pad->GetNetCode() <= 0 ) )
            {
                item_clearance   = pad->GetClearance() + outline_half_thickness;
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( item_clearance );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    int clearance = std::max( zone_clearance, item_clearance );
                    pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                                               clearance,
                                                               segsPerCircle,
                                                               correctionFactor );
                }

                continue;
            }

            // Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
            if( GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
            {
                int gap = zone_clearance;
                int thermalGap = GetThermalReliefGap( pad );
                gap = std::max( gap, thermalGap );
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( gap );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                                               gap,
                                                               segsPerCircle,
                                                               correctionFactor );
                }
            }
        }
    }

    /* Add holes (i.e. tracks and vias areas as polygons outlines)
     * in cornerBufferPolysToSubstract
     */
    for( TRACK* track = aPcb->m_Track;  track;  track = track->Next() )
    {
        if( !track->IsOnLayer( GetLayer() ) )
            continue;

        if( track->GetNetCode() == GetNetCode()  && (GetNetCode() != 0) )
            continue;

        item_clearance   = track->GetClearance() + outline_half_thickness;
        item_boundingbox = track->GetBoundingBox();

        if( item_boundingbox.Intersects( zone_boundingbox ) )
        {
            int clearance = std::max( zone_clearance, item_clearance );
            track->TransformShapeWithClearanceToPolygon( aFeatures,
                                                         clearance,
                                                         segsPerCircle,
                                                         correctionFactor );
        }
    }

    /* Add module edge items that are on copper layers
     * Pcbnew allows these items to be on copper layers in microwave applictions
     * This is a bad thing, but must be handled here, until a better way is found
     */
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( BOARD_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
        {
            if( !item->IsOnLayer( GetLayer() ) && !item->IsOnLayer( Edge_Cuts ) )
                continue;

            if( item->Type() != PCB_MODULE_EDGE_T )
                continue;

            item_boundingbox = item->GetBoundingBox();

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                ( (EDGE_MODULE*) item )->TransformShapeWithClearanceToPolygon(
                    aFeatures, zone_clearance,
                    segsPerCircle, correctionFactor );
            }
        }
    }

    // Add graphic items (copper texts) and board edges
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
    {
        if( item->GetLayer() != GetLayer() && item->GetLayer() != Edge_Cuts )
            continue;

        switch( item->Type() )
        {
        case PCB_LINE_T:
            ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                aFeatures,
                zone_clearance, segsPerCircle, correctionFactor );
            break;

        case PCB_TEXT_T:
            ( (TEXTE_PCB*) item )->TransformBoundingBoxWithClearanceToPolygon(
                aFeatures, zone_clearance );
            break;

        default:
            break;
        }
    }

    // Add zones outlines having an higher priority and keepout
    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
        if( zone->GetLayer() != GetLayer() )
            continue;

        if( !zone->GetIsKeepout() && zone->GetPriority() <= GetPriority() )
            continue;

        if( zone->GetIsKeepout() && ! zone->GetDoNotAllowCopperPour() )
            continue;

        // A highter priority zone or keepout area is found: remove this area
        item_boundingbox = zone->GetBoundingBox();
        if( !item_boundingbox.Intersects( zone_boundingbox ) )
            continue;

        // Add the zone outline area.
        // However if the zone has the same net as the current zone,
        // do not add any clearance.
        // the zone will be connected to the current zone, but filled areas
        // will use different parameters (clearance, thermal shapes )
        bool same_net = GetNetCode() == zone->GetNetCode();
        bool use_net_clearance = true;
        int min_clearance = zone_clearance;

        // Do not forget to make room to draw the thick outlines
        // of the hole created by the area of the zone to remove
        int holeclearance = zone->GetClearance() + outline_half_thickness;

        // The final clearance is obviously the max value of each zone clearance
        min_clearance = std::max( min_clearance, holeclearance );

        if( zone->GetIsKeepout() || same_net )
        {
            // Just take in account the fact the outline has a thickness, so
            // the actual area to substract is inflated to take in account this fact
            min_clearance = outline_half_thickness;
            use_net_clearance = false;
        }

        zone->TransformOutlinesShapeWithClearanceToPolygon(
                    aFeatures,
                    min_clearance, use_net_clearance );
    }

   // Remove thermal symbols
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
        {
            // Rejects non-standard pads with tht-only thermal reliefs
            if( GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
             && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
                continue;

            if( GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
             && GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
                continue;

            if( !pad->IsOnLayer( GetLayer() ) )
                continue;

            if( pad->GetNetCode() != GetNetCode() )
                continue;
            item_boundingbox = pad->GetBoundingBox();
            int thermalGap = GetThermalReliefGap( pad );
            item_boundingbox.Inflate( thermalGap, thermalGap );

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                CreateThermalReliefPadPolygon( aFeatures,
                                               *pad, thermalGap,
                                               GetThermalReliefCopperBridge( pad ),
                                               m_ZoneMinThickness,
                                               segsPerCircle,
                                               correctionFactor, s_thermalRot );
            }
        }
    }

}
/**
 * Function AddClearanceAreasPolygonsToPolysList
 * Supports a min thickness area constraint.
 * Add non copper areas polygons (pads and tracks with clearance)
 * to the filled copper area found
 * in BuildFilledPolysListData after calculating filled areas in a zone
 * Non filled copper areas are pads and track and their clearance areas
 * The filled copper area must be computed just before.
 * BuildFilledPolysListData() call this function just after creating the
 *  filled copper area polygon (without clearance areas)
 * to do that this function:
 * 1 - Creates the main outline (zone outline) using a correction to shrink the resulting area
 *     with m_ZoneMinThickness/2 value.
 *     The result is areas with a margin of m_ZoneMinThickness/2
 *     When drawing outline with segments having a thickness of m_ZoneMinThickness, the
 *      outlines will match exactly the initial outlines
 * 3 - Add all non filled areas (pads, tracks) in group B with a clearance of m_Clearance +
 *     m_ZoneMinThickness/2
 *     in a buffer
 *   - If Thermal shapes are wanted, add non filled area, in order to create these thermal shapes
 * 4 - calculates the polygon A - B
 * 5 - put resulting list of polygons (filled areas) in m_FilledPolysList
 *     This zone contains pads with the same net.
 * 6 - Remove insulated copper islands
 * 7 - If Thermal shapes are wanted, remove unconnected stubs in thermal shapes:
 *     creates a buffer of polygons corresponding to stubs to remove
 *     sub them to the filled areas.
 *     Remove new insulated copper islands
 */
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
    // Set the number of segments in arc approximations
    if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF  )
        s_CircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
    else
        s_CircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;

    /* calculates the coeff to compensate radius reduction of holes clearance
     * due to the segment approx.
     * For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
     * s_Correction is 1 /cos( PI/s_CircleToSegmentsCount  )
     */
    s_Correction = 1.0 / cos( M_PI / s_CircleToSegmentsCount );

    // This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
    KI_POLYGON_SET polyset_zone_solid_areas;
    int         margin = m_ZoneMinThickness / 2;

    /* First, creates the main polygon (i.e. the filled area using only one outline)
     * to reserve a m_ZoneMinThickness/2 margin around the outlines and holes
     * this margin is the room to redraw outlines with segments having a width set to
     * m_ZoneMinThickness
     * so m_ZoneMinThickness is the min thickness of the filled zones areas
     * the main polygon is stored in polyset_zone_solid_areas
     */

    CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas );
    polyset_zone_solid_areas -= margin;

    if( polyset_zone_solid_areas.size() == 0 )
        return;

    /* Calculates the clearance value that meet DRC requirements
     * from m_ZoneClearance and clearance from the corresponding netclass
     * We have a "local" clearance in zones because most of time
     * clearance between a zone and others items is bigger than the netclass clearance
     * this is more true for small clearance values
     * Note also the "local" clearance is used for clearance between non copper items
     *    or items like texts on copper layers
     */
    int zone_clearance = std::max( m_ZoneClearance, GetClearance() );
    zone_clearance += margin;

    /* store holes (i.e. tracks and pads areas as polygons outlines)
     * in a polygon list
     */

    /* items ouside the zone bounding box are skipped
     * the bounding box is the zone bounding box + the biggest clearance found in Netclass list
     */
    EDA_RECT item_boundingbox;
    EDA_RECT zone_boundingbox  = GetBoundingBox();
    int      biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue();
    biggest_clearance = std::max( biggest_clearance, zone_clearance );
    zone_boundingbox.Inflate( biggest_clearance );

    /*
     * First : Add pads. Note: pads having the same net as zone are left in zone.
     * Thermal shapes will be created later if necessary
     */
    int item_clearance;

    // static to avoid unnecessary memory allocation when filling many zones.
    static CPOLYGONS_LIST cornerBufferPolysToSubstract;
    cornerBufferPolysToSubstract.RemoveAllContours();

    /* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers
     * and this pad has a hole
     * This dummy pad has the size and shape of the hole
    * Therefore, this dummy pad is a circle or an oval.
     * A pad must have a parent because some functions expect a non null parent
     * to find the parent board, and some other data
     */
    MODULE dummymodule( aPcb );    // Creates a dummy parent
    D_PAD dummypad( &dummymodule );

    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        D_PAD* nextpad;

        for( D_PAD* pad = module->Pads(); pad != NULL; pad = nextpad )
        {
            nextpad = pad->Next();  // pad pointer can be modified by next code, so
                                    // calculate the next pad here

            if( !pad->IsOnLayer( GetLayer() ) )
            {
                /* Test for pads that are on top or bottom only and have a hole.
                 * There are curious pads but they can be used for some components that are
                 * inside the board (in fact inside the hole. Some photo diodes and Leds are
                 * like this)
                 */
                if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
                    continue;

                // Use a dummy pad to calculate a hole shape that have the same dimension as
                // the pad hole
                dummypad.SetSize( pad->GetDrillSize() );
                dummypad.SetOrientation( pad->GetOrientation() );
                dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_OBLONG ?
                                   PAD_OVAL : PAD_CIRCLE );
                dummypad.SetPosition( pad->GetPosition() );

                pad = &dummypad;
            }

            // Note: netcode <=0 means not connected item
            if( ( pad->GetNetCode() != GetNetCode() ) || ( pad->GetNetCode() <= 0 ) )
            {
                item_clearance   = pad->GetClearance() + margin;
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( item_clearance );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    int clearance = std::max( zone_clearance, item_clearance );
                    pad->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
                                                               clearance,
                                                               s_CircleToSegmentsCount,
                                                               s_Correction );
                }

                continue;
            }

            if( ( GetPadConnection( pad ) == PAD_NOT_IN_ZONE )
                || ( pad->GetShape() == PAD_TRAPEZOID ) )

            // PAD_TRAPEZOID shapes are not in zones because they are used in microwave apps
            // and i think it is good that shapes are not changed by thermal pads or others
            {
                int gap = zone_clearance;
                int thermalGap = GetThermalReliefGap( pad );
                gap = std::max( gap, thermalGap );
                item_boundingbox = pad->GetBoundingBox();

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    pad->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
                                                               gap,
                                                               s_CircleToSegmentsCount,
                                                               s_Correction );
                }
            }
        }
    }

    /* Add holes (i.e. tracks and vias areas as polygons outlines)
     * in cornerBufferPolysToSubstract
     */
    for( TRACK* track = aPcb->m_Track;  track;  track = track->Next() )
    {
        if( !track->IsOnLayer( GetLayer() ) )
            continue;

        if( track->GetNetCode() == GetNetCode()  && (GetNetCode() != 0) )
            continue;

        item_clearance   = track->GetClearance() + margin;
        item_boundingbox = track->GetBoundingBox();

        if( item_boundingbox.Intersects( zone_boundingbox ) )
        {
            int clearance = std::max( zone_clearance, item_clearance );
            track->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
                                                         clearance,
                                                         s_CircleToSegmentsCount,
                                                         s_Correction );
        }
    }

    /* Add module edge items that are on copper layers
     * Pcbnew allows these items to be on copper layers in microwave applictions
     * This is a bad thing, but must be handled here, until a better way is found
     */
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( BOARD_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
        {
            if( !item->IsOnLayer( GetLayer() ) && !item->IsOnLayer( Edge_Cuts ) )
                continue;

            if( item->Type() != PCB_MODULE_EDGE_T )
                continue;

            item_boundingbox = item->GetBoundingBox();

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                ( (EDGE_MODULE*) item )->TransformShapeWithClearanceToPolygon(
                    cornerBufferPolysToSubstract, zone_clearance,
                    s_CircleToSegmentsCount, s_Correction );
            }
        }
    }

    // Add graphic items (copper texts) and board edges
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
    {
        if( item->GetLayer() != GetLayer() && item->GetLayer() != Edge_Cuts )
            continue;

        switch( item->Type() )
        {
        case PCB_LINE_T:
            ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                cornerBufferPolysToSubstract,
                zone_clearance, s_CircleToSegmentsCount, s_Correction );
            break;

        case PCB_TEXT_T:
            ( (TEXTE_PCB*) item )->TransformBoundingBoxWithClearanceToPolygon(
                cornerBufferPolysToSubstract, zone_clearance );
            break;

        default:
            break;
        }
    }

    // Add zones outlines having an higher priority and keepout
    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
        if( zone->GetLayer() != GetLayer() )
            continue;

        if( !zone->GetIsKeepout() && zone->GetPriority() <= GetPriority() )
            continue;

        if( zone->GetIsKeepout() && ! zone->GetDoNotAllowCopperPour() )
            continue;

        // A highter priority zone or keepout area is found: remove its area
        item_boundingbox = zone->GetBoundingBox();
        if( !item_boundingbox.Intersects( zone_boundingbox ) )
            continue;

        // Add the zone outline area.
        // However if the zone has the same net as the current zone,
        // do not add clearance.
        // the zone will be connected to the current zone, but filled areas
        // will use different parameters (clearance, thermal shapes )
        bool addclearance = GetNetCode() != zone->GetNetCode();
        int clearance = zone_clearance;

        if( zone->GetIsKeepout() )
        {
            addclearance = true;
            clearance = m_ZoneMinThickness / 2;
        }

        zone->TransformOutlinesShapeWithClearanceToPolygon(
                    cornerBufferPolysToSubstract,
                    clearance, addclearance );
    }

   // Remove thermal symbols
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
        {
            // Rejects non-standard pads with tht-only thermal reliefs
            if( GetPadConnection( pad ) == THT_THERMAL
             && pad->GetAttribute() != PAD_STANDARD )
                continue;

            if( GetPadConnection( pad ) != THERMAL_PAD
             && GetPadConnection( pad ) != THT_THERMAL )
                continue;

            if( !pad->IsOnLayer( GetLayer() ) )
                continue;

            if( pad->GetNetCode() != GetNetCode() )
                continue;
            item_boundingbox = pad->GetBoundingBox();
            int thermalGap = GetThermalReliefGap( pad );
            item_boundingbox.Inflate( thermalGap, thermalGap );

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                CreateThermalReliefPadPolygon( cornerBufferPolysToSubstract,
                                               *pad, thermalGap,
                                               GetThermalReliefCopperBridge( pad ),
                                               m_ZoneMinThickness,
                                               s_CircleToSegmentsCount,
                                               s_Correction, s_thermalRot );
            }
        }
    }

    // cornerBufferPolysToSubstract contains polygons to substract.
    // polyset_zone_solid_areas contains the main filled area
    // Calculate now actual solid areas
    if( cornerBufferPolysToSubstract.GetCornersCount() > 0 )
    {
        KI_POLYGON_SET polyset_holes;
        cornerBufferPolysToSubstract.ExportTo( polyset_holes );
        // Remove holes from initial area.:
        polyset_zone_solid_areas -= polyset_holes;
    }

    // put solid areas in m_FilledPolysList:
    m_FilledPolysList.RemoveAllContours();
    CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );

    // Remove insulated islands:
    if( GetNetCode() > 0 )
        TestForCopperIslandAndRemoveInsulatedIslands( aPcb );

    // Now we remove all unused thermal stubs.
    cornerBufferPolysToSubstract.RemoveAllContours();

    // Test thermal stubs connections and add polygons to remove unconnected stubs.
    // (this is a refinement for thermal relief shapes)
    if( GetNetCode() > 0 )
        BuildUnconnectedThermalStubsPolygonList( cornerBufferPolysToSubstract, aPcb, this,
                                                 s_Correction, s_thermalRot );

    // remove copper areas corresponding to not connected stubs
    if( cornerBufferPolysToSubstract.GetCornersCount() )
    {
        KI_POLYGON_SET polyset_holes;
        cornerBufferPolysToSubstract.ExportTo( polyset_holes );

        // Remove unconnected stubs
        polyset_zone_solid_areas -= polyset_holes;

        // put these areas in m_FilledPolysList
        m_FilledPolysList.RemoveAllContours();
        CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );

        if( GetNetCode() > 0 )
            TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
    }

    cornerBufferPolysToSubstract.RemoveAllContours();
}
bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl )
{
    IO_MGR::PCB_FILE_T  pluginType = plugin_type( aFullFileName, aCtl );
    PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

    // keep trace of existing items, in order to know what are the new items
    // (for undo command for instance)

    // Tracks are inserted, not append, so mark existing tracks to know what are
    // the new tracks
    for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
        track->SetFlags( FLAG0 );

    // Other items are append to the item list, so keep trace to the
    // last existing item is enough
    MODULE* module = GetBoard()->m_Modules.GetLast();
    BOARD_ITEM* drawing = GetBoard()->m_Drawings.GetLast();
    int zonescount = GetBoard()->GetAreaCount();

    // Keep also the count of copper layers, because we can happen boards
    // with different copper layers counts,
    // and the enabled layers
    int initialCopperLayerCount = GetBoard()->GetCopperLayerCount();
    LSET initialEnabledLayers = GetBoard()->GetEnabledLayers();

    try
    {
        PROPERTIES  props;
        char        xbuf[30];
        char        ybuf[30];

        // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
        sprintf( xbuf, "%d", GetPageSizeIU().x );
        sprintf( ybuf, "%d", GetPageSizeIU().y );

        props["page_width"]  = xbuf;
        props["page_height"] = ybuf;

        GetDesignSettings().m_NetClasses.Clear();
        pi->Load( aFullFileName, GetBoard(), &props );
    }
    catch( const IO_ERROR& ioe )
    {
        for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
            track->ClearFlags( FLAG0 );

        wxString msg = wxString::Format( _(
                "Error loading board.\n%s" ),
                GetChars( ioe.errorText )
                );
        DisplayError( this, msg );

        return false;
    }

    // Now prepare a block move command to place the new items, and
    // prepare the undo command.
    BLOCK_SELECTOR& blockmove = GetScreen()->m_BlockLocate;
    HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) );
    PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems();
    PICKED_ITEMS_LIST undoListPicker;
    ITEM_PICKER picker( NULL, UR_NEW );

    EDA_RECT bbox;          // the new items bounding box, for block move
    bool bboxInit = true;   // true until the bounding box is initialized

    for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
    {
        if( track->GetFlags() & FLAG0  )
        {
            track->ClearFlags( FLAG0 );
            continue;
        }

        track->SetFlags( IS_MOVED );
        picker.SetItem( track );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = track->GetBoundingBox();
        else
            bbox.Merge( track->GetBoundingBox() );

        bboxInit = false;
    }

    if( module )
        module = module->Next();
    else
        module = GetBoard()->m_Modules;

    for( ; module; module = module->Next() )
    {
        module->SetFlags( IS_MOVED );
        picker.SetItem( module );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = module->GetBoundingBox();
        else
            bbox.Merge( module->GetBoundingBox() );

        bboxInit = false;
    }

    if( drawing )
        drawing = drawing->Next();
    else
        drawing = GetBoard()->m_Drawings;

    for( ; drawing; drawing = drawing->Next() )
    {
        drawing->SetFlags( IS_MOVED );
        picker.SetItem( drawing );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = drawing->GetBoundingBox();
        else
            bbox.Merge( drawing->GetBoundingBox() );

        bboxInit = false;
    }

    for( ZONE_CONTAINER* zone = GetBoard()->GetArea( zonescount ); zone;
         zone = GetBoard()->GetArea( zonescount ) )
    {
        zone->SetFlags( IS_MOVED );
        picker.SetItem( zone );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );
        zonescount++;

        if( bboxInit )
            bbox = zone->GetBoundingBox();
        else
            bbox.Merge( zone->GetBoundingBox() );

        bboxInit = false;
    }

    SaveCopyInUndoList( undoListPicker, UR_NEW );

    // we should not ask PLUGINs to do these items:
    int copperLayerCount = GetBoard()->GetCopperLayerCount();

    if( copperLayerCount > initialCopperLayerCount )
        GetBoard()->SetCopperLayerCount( copperLayerCount );

    // Enable all used layers, and make them visible:
    LSET enabledLayers = GetBoard()->GetEnabledLayers();
    enabledLayers |= initialEnabledLayers;
    GetBoard()->SetEnabledLayers( enabledLayers );
    GetBoard()->SetVisibleLayers( enabledLayers );
    ReCreateLayerBox();
    ReFillLayerWidget();

    if( IsGalCanvasActive() )
        static_cast<PCB_DRAW_PANEL_GAL*>( GetGalCanvas() )->SyncLayersVisibility( GetBoard() );

    GetBoard()->BuildListOfNets();
    GetBoard()->SynchronizeNetsAndNetClasses();

    SetStatusText( wxEmptyString );
    BestZoom();

    // Finish block move command:
    wxPoint cpos = GetNearestGridPosition( bbox.Centre() );
    blockmove.SetOrigin( bbox.GetOrigin() );
    blockmove.SetSize( bbox.GetSize() );
    blockmove.SetLastCursorPosition( cpos );
    HandleBlockEnd( NULL );

    return true;
}
Пример #18
0
/* Here goes our drawing code */
int drawGLScene()
{
	#ifdef PERFORMANCE_PROFILE
	suseconds_t t1, t2;
	t1 = GetMicroSeconds();
	t1 = GetMicroSeconds();
	#endif
	
	//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "RenderReflectedScene() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	gluPerspective( 45.0f, (float)SCREEN_WIDTH/SCREEN_HEIGHT, 0.1f, settings.GetViewDistance() );
	glMatrixMode( GL_MODELVIEW );
	
	glSetup();
	
	glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); 
	//glClearColor( 255.0f, 0.0f, 0.0f, 0.0f ); 
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "glSetup() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	utility.Tex2D(3, false);
	utility.Tex2D(2, false);
	utility.Tex2D(1, false);
	utility.Tex2D(0, true);
	
	glStencilMask(~0);
	glClearStencil(0);
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);		// Clear Screen And Depth Buffer
	
	glDisable(GL_STENCIL_TEST);

	
	GLdouble temp_matrix[16];
	int i;
	
	

	cam.PutTransformInto(temp_matrix);
	glLoadMatrixd(temp_matrix);
	
	//reset sun position so it's in the correct frame
	float lp[4];
	lp[0] = LightPosition[0];
	lp[1] = LightPosition[1];
	lp[2] = LightPosition[2];
	lp[3] = 0;
	
	//lighting hardcoded to reasonable position
	lp[0] = 3;
	lp[1] = 3;
	lp[2] = 3;
	lp[3] = 0;
	glLightfv( GL_LIGHT1, GL_POSITION, lp );
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "Matrix setup and light setup ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	// model the highlighted vertex belongs to
	OBJECTMODEL * highlighted_model = NULL;
	//if (state.GetGameState() != STATE_INITIALMENU)
	{
		
//		bool normal = true;
		
		glClear (GL_DEPTH_BUFFER_BIT);
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "DrawSky() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		glTranslatef(cam.GetPosition().x,cam.GetPosition().y,cam.GetPosition().z);
	
		/*GLdouble equation[4];
		VERTEX earthnormal = temp - cam.position;
		earthnormal.y += EARTH_RADIUS;
		earthnormal = earthnormal.normalize();
		equation[0] = earthnormal.x;
		equation[1] = -earthnormal.y;
		equation[2] = earthnormal.z;
		equation[3] = (waterheight);
		glClipPlane(GL_CLIP_PLANE1, equation);
		if (underwater)
			glEnable(GL_CLIP_PLANE1);
		else
			glDisable(GL_CLIP_PLANE1);
		*/
		
				
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "terrain.SetFrustum() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		//glPolygonOffset(1.0,1.0);
		//glPolygonOffset(0.0,10.0);
		//glEnable(GL_POLYGON_OFFSET_FILL);
	
		/*if (normal)
		{
			//GLfloat LightAmbient2[]  = { 0.3f, 0.3f, 0.3f, 1.0f };
			//glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient2 );
			glDisable(GL_STENCIL_TEST);
			
			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "terrain.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			
			utility.SelectTU(3);
			glDisable(GL_TEXTURE_2D);
			utility.SelectTU(0);
			glEnable(GL_TEXTURE_2D);

			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "trees.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			objects.Draw();
			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "objects.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			
			//glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );
		}
		
		glDisable(GL_POLYGON_OFFSET_FILL);*/
		
		//glClear (GL_DEPTH_BUFFER_BIT);
		
		//glDisable(GL_LIGHTING);
		objects.Draw();
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "normal draw done" << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
	
		/*
		//draw trees
		foliage.Draw(terrain, cam);
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "foliage.Draw() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
	
		//glDisable(GL_CLIP_PLANE1);
		ships.Draw(false);
	
		terrain.Draw(cam, 1.0f, false, false, true, false, timefactor, fps, day_time);
		//terrain.Draw(cam, 1.0f, false, false, true, false, timefactor, fps, day_time);
		
		//rain is drawn over everything else
		if (!underwater)
			backdrop.DrawRain(day_time);
	
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "DrawRain() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		
		glDisable(GL_CLIP_PLANE1);
	*/	
	
		
		//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		/*if (0)
		{	
			//experimental bezier stuff
			BEZIER patch;
			VERTEX fl, fr, bl, br;
			//fl.Set(20,40,0);
			fl.Set(5,10,0);
			fr = fl;
			bl = fl;
			br = fl;
			
			fr.x += 15;
			fr.y += 3;
			
			br.x += 12;
			br.z += 8;
			
			bl.z += 10;
			bl.y -= 2;
			
			patch.SetFromCorners(fl, fr, bl, br);
			
			BEZIER nextpatch;
			VERTEX offset;
			offset.x += -7;
			offset.z += -10;
			fl = fl + offset;
			fr = fr + offset;
			bl = bl + offset;
			br = br + offset;
			
			nextpatch.SetFromCorners(fl, fr, bl, br);
			
			//patch.Attach(nextpatch);
			
			BEZIER thirdpatch;
			offset.zero();
			offset.y += -3;
			offset.z += -10;
			fl = fl + offset;
			fr = fr + offset;
			bl = bl + offset;
			br = br + offset;
			
			thirdpatch.SetFromCorners(fl, fr, bl, br);
			
			//nextpatch.Attach(thirdpatch);
			
			TRACK track;
			ROADSTRIP * teststrip = track.AddNewRoad();
			teststrip->Add(patch);
			teststrip->Add(nextpatch);
			teststrip->Add(thirdpatch);
			
			//teststrip.DeleteLastPatch();
					
			track.VisualizeRoads(true, true);
			
			VERTEX down;
			down.y = -1;
			VERTEX colpoint;
			if (patch.Collide(cam.position.ScaleR(-1.0), down, colpoint))
			{
				//colpoint.DebugPrint();
			}
		}*/
		
		VERTEX camray;
		camray.z = -1;
		camray = cam.dir.ReturnConjugate().RotateVec(camray);
		/*camray.z = 1;
		camray = cam.dir.RotateVec(camray);*/
		VERTEX selvert;
		bool highlightedvert = false;
		if (objects.FindClosestVert(cam.position.ScaleR(-1.0), camray, selvert, highlighted_model))
		{
			/*cam.position.ScaleR(-1.0).DebugPrint();
			selvert.DebugPrint();
			cout << endl;*/
			
			//draw a highlighted vert
			
			highlightedvert = true;
			
			glPushAttrib(GL_ALL_ATTRIB_BITS);
			glDisable(GL_LIGHTING);
			glDisable(GL_TEXTURE_2D);
			glDisable(GL_DEPTH_TEST);
			//glEnable(GL_BLEND);
			//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
			glPointSize(4.0);
			//glColor4f(1,1,0,0.75);
			glColor4f(1,1,0,1);
			glBegin(GL_POINTS);
			glVertex3fv(selvert.v3());
			glEnd();
			glDisable(GL_BLEND);
			glColor4f(1,1,1,1);
			glPopAttrib();
		}
		
		//left click
		if (highlightedvert && mouse.ButtonDown(1) && !editordata.mousebounce[1])
		{
			int oldnumbezinput = editordata.numbezinput;
			
			//left click on a highlighted vert
			if (vertmode == TWOVERTS)
			{
				if (editordata.numbezinput == 0)
					editordata.numbezinput = 3;
				else if (editordata.numbezinput <= 3)
					editordata.numbezinput = 4;
				else if (editordata.numbezinput <= 4)
					editordata.numbezinput = 7;
				else if (editordata.numbezinput <= 7)
					editordata.numbezinput = 8;
			}
			else
			{
				editordata.numbezinput++;
				if (vertmode == THREEVERTS && (editordata.numbezinput == 2 || editordata.numbezinput == 6))
					editordata.numbezinput++;
			}
			
			if (editordata.numbezinput >= 8)
			{
				//create bezier patch
				BEZIER patch;
				
				if (vertmode == TWOVERTS)
					patch.SetFromCorners(editordata.bezinput[4], selvert, editordata.bezinput[0], editordata.bezinput[3]);
				else
				{
					//copy the front and back selected rows to the patch, then tell it to do the math to find the other points
					// plus center and radius calculations
					
					editordata.bezinput[7] = selvert;
					
					for (int i = 0; i < 4; i++)
						patch.points[3][i] = editordata.bezinput[i];
					for (int i = 0; i < 4; i++)
						patch.points[0][i] = editordata.bezinput[i+4];
					
					/*if (vertmode == THREEVERTS)
					{
						//recalculate the middle two verts
						for (int i = 0; i < 4; i += 3)
						{
							if ((patch.points[i][1] - patch.points[i][2]).len() < 0.0001)
							{
								VERTEX leftslope = patch.points[i][1] - patch.points[i][0];
								VERTEX rightslope = patch.points[i][2] - patch.points[i][3];
								patch.points[i][1] = patch.points[i][0] + leftslope.ScaleR(0.5);
								patch.points[i][2] = patch.points[i][3] + rightslope.ScaleR(0.5);
							}
						}
					}*/
					
					patch.CalculateMiddleRows();
				}
				
				if (activestrip == NULL)
				{
					activestrip = track.AddNewRoad();
					mq1.AddMessage("New road created to hold new patch.");
				}
				
				activestrip->Add(patch);
				
				//editordata.numbezinput = 0;
				editordata.numbezinput = 4;
				
				editordata.bezinput[0] = patch.points[0][0];
				editordata.bezinput[1] = patch.points[0][1];
				editordata.bezinput[2] = patch.points[0][2];
				editordata.bezinput[3] = patch.points[0][3];
			}
			else
			{
				editordata.bezinput[oldnumbezinput] = selvert;
				if (vertmode == THREEVERTS && (oldnumbezinput == 1 || oldnumbezinput == 5))
					editordata.bezinput[oldnumbezinput+1] = selvert;
			}
		}
		
		editordata.mousebounce[1] = mouse.ButtonDown(1);
		
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glDisable(GL_LIGHTING);
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_DEPTH_TEST);
		glPointSize(4.0);
		glColor4f(1,0,0,1);
		glBegin(GL_POINTS);
		for (i = 0; i < editordata.numbezinput; i++)
		{
			if (vertmode != TWOVERTS || i == 0 || i == 3 || i == 4 || i == 7)
			{
				glVertex3fv(editordata.bezinput[i].v3());
			}
		}
		glEnd();
		glColor4f(1,1,1,1);
		glPopAttrib();
		
		track.VisualizeRoads(true, false, activestrip);
		
		for (int l = 0; l < track.NumLapSeqs(); l++)
		{
			BEZIER * lapbez = track.GetLapSeq(l);
			if (lapbez != NULL)
			{
				VERTEX reddish;
				reddish.x = 0.5;
				reddish.y = 0.2;
				reddish.z = 0.2;
				lapbez->Visualize(true, false, reddish);
			}
		}
		
		
		//image in the framebuffer is now complete.
		
		
		/*//add a brightness/contrast adjustment
		glClear (GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glDisable(GL_FOG);
		glDisable(GL_LIGHTING);
		glTranslatef(0,0,-40.0f);
		glBlendFunc(GL_ONE, GL_SRC_ALPHA);
		
		float rd = (float) weathersystem.GetRainDrops();
		
		float rainscale = 0.7f;
		float clearscale = 1.1f;
		float rainbias = 0.035f;
		float clearbias = 0.0f;
		float rainmax = 50.0f;
		
		float rainfactor = (rd/rainmax);
		if (rainfactor > 1.0f)
			rainfactor = 1.0f;
	
		float scale = rainfactor*rainscale+(1.0f-rainfactor)*clearscale;
		float bias = rainfactor*rainbias+(1.0f-rainfactor)*clearbias;
	
	
		glColor4f(bias, bias, bias, scale);
		float x1, y1, x2, y2;
		x1 = -30;
		y1 = -30;
		x2 = 30;
		y2 = 30;
		
		if (scale > 1.0) 
		{
			float remainingScale;
			
			remainingScale = scale;
			glBlendFunc(GL_DST_COLOR, GL_ONE);
			if (remainingScale > 2.0) 
			{
				glColor4f(1, 1, 1, 1);
				while (remainingScale > 2.0) 
				{
					glRectf(x1,y1,x2,y2);
					remainingScale /= 2.0;
				}
			}
			glColor4f(remainingScale - 1,
				remainingScale - 1, remainingScale - 1, 1);
			glRectf(x1,y1,x2,y2);
			glBlendFunc(GL_ONE, GL_ONE);
			if (bias != 0)
			{
				if (bias > 0) 
				{
					glColor4f(bias, bias, bias, 0.0);
				} 
				else 
				{
					glColor4f(-bias, -bias, -bias, 0.0);
					//can't do bias < 0
				}
				glRectf(x1,y1,x2,y2);
			}
		}
		else 
		{
			if (bias > 0) 
			{
				glColor4f(bias, bias, bias, scale);
			}
			else 
			{
				glColor4f(-bias, -bias, -bias, scale);
				//can't do bias < 0
			}
			glBlendFunc(GL_ONE, GL_SRC_ALPHA);
			glRectf(x1,y1,x2,y2);
		}
		
		glPopAttrib();*/
	
		//timer.Draw();
	}
	
	float w, h;
	w = 0.02;
	h = w*(4/3.0);
	utility.Tex2D(0,true);
	utility.Draw2D(0.5-w, 0.5-h, 0.5+w, 0.5+h, editordata.cursortex);
	
	if (fps > 0.0f)
		mq1.Draw(timefactor, fps, font);
	
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "Brightness/contrast adjustment ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif

	
	
    Frames++;
	frameno++;
	if (frameno >= 30011)
		frameno -= 30011;
	lfps[lfpspos] = pfps;
	lfpspos++;
	if (lfpspos >= AVERAGEFRAMES)
	{
		lfpspos = lfpspos % AVERAGEFRAMES;
		lfpsfull = true;
	}
	
	float tfps = 0.0f;
	int tnum = 0;
	for (i = 0; i < AVERAGEFRAMES; i++)
	{
		if (!(!lfpsfull && i >= lfpspos))
		{
			tfps += lfps[i];
			tnum++;
		}
	}
	fps = std::min(1000.0f,tfps / (float) tnum);
	
	/*lfps += pfps;
    {
		//const int freq = (int) MIN_FPS;
		const int freq = 60;
		if (Frames >= freq)
		{
			fps = lfps / freq;
			Frames = 0;
			lfps = 0;
		}
	}*/
	
	char tempchar[1024];
	sprintf(tempchar, "Frames per second: %f\n", fps);
	
	//font.Print(0.5,0,tempchar,0,0,1,1,0);
	if (showfps)
		font.Print( 0.75, 0.0, tempchar, 1, 5, 1.0 );
	
	// print camera position
	VERTEX pos = cam.GetPosition();
	sprintf(tempchar, "Position: %0.2f, %0.2f, %0.2f\n", -pos.x, -pos.y, -pos.z);
	font.Print( 0.75, 0.025, tempchar, 1, 5, 1.0 );
	
	//VERTEX ang = cam.dir.GetEulerZYX();
	//sprintf(tempchar, "Angle: %0.2f, %0.2f, %0.2f\n", 180/M_PI*ang.x, -180/M_PI*ang.y, 180/M_PI*ang.z);
	//font.Print( 0.75, 0.05, tempchar, 1, 5, 1.0 );
	
	// print object name the highlighted vertex belongs to
	if (highlighted_model)
	{
		string modelname = highlighted_model->name;
		sprintf(tempchar, "Model: %s\n", modelname.c_str());
		font.Print( 0.75, 0.05, tempchar, 1, 5, 1.0 );
	}
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "font.Print() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	
	//draw help screen(s)
	if (editordata.helppage > 2)
		editordata.helppage = 0;
	if (editordata.helppage == 1)
	{
		font.Print(0.1, 0.1, "VDrift Track Editor Keys (press H again for more help)\n"
	"Mouse left click\n"
	"Arrow keys\n"
	"Page Up\n"
	"A, F\n"
	"L\n"
	"K\n"
	"N\n"
	"R\n"
	"S\n"
	"I\n"
	"E\n"
	"- (minus)\n"
	"2, 3, 4\n"
	"BACKSPACE\n"
	"ESCAPE\n"
	, 1, 5, 1.0);
		font.Print(0.3, 0.1, "\n"
	"Select highligted vertex\n"
	"Move around\n"
	"Move forward very fast\n"
	"Automatically try to create the next bezier patch on this road (F: 25 at a time)\n"
	"Add the current camera position to the list of car start locations\n"
	"Remove the last start location from the list\n"
	"Create a new road (the new road is created once you add patches to it)\n"
	"Select the road under the cursor\n"
	"Save the track\n"
	"Print the object that owns the selected vertex to the console\n"
	"Mark a road segment as part of a lap sequence\n"
	"Clear all lap sequences\n"
	"Select vertices 2 at a time, 3 at a time, 4 at a time\n"
	"Delete the last bezier patch on this road\n"
	"Quit the editor\n"
	, 1, 5, 1.0);
	}
	if (editordata.helppage == 2)
		font.Print(0.1, 0.1, "VDrift Track Editor Textual Help\n"
	"The editor starts in vertex selection mode.  Vertices are highlighted yellow as the mouse pointer\n"
	"gets close to them.  Press the left mouse button to select the highlighted vertex.  It will turn\n"
	"red.  Select a vertex on the left side of the road, then a vertex on the right side of the road,\n"
	"with left and right determined by the direction you'd like to create the road in.  You can now select\n"
	"the next two vertices (left and then right), and a green box will be created to indicate a bezier\n"
	"patch has been created there.  Notice that the last two vertices you select are still colored red\n"
	"(selected).  You can now select the next two vertices (left and right), and continue to create bezier\n"
	"patches around the track.  Once you have created a bezier patch, you can alternatively press A to\n"
	"have the editor try to automatically select the next two vertices and auto-create the next patch.\n"
	"This works well in straight areas, not so well in curvy areas.  Press BACKSPACE at any time to delete\n"
	"the last patch that was created."
	, 1, 5, 1.0);


	/* Draw it to the screen */
    SDL_GL_SwapBuffers( );

    
		GLint t = SDL_GetTicks();
		//if (t - T0 >= 50) 
		{
			GLfloat seconds = (t - T0) / 1000.0;
			pfps = 1 / seconds;
			//printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
			T0 = t;
			//Frames = 0;
		}
		
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "SwapBuffers() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	cout << endl;
	#endif
		
    return( TRUE );
}
void BOARD::ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, CPOLYGONS_LIST& aOutlines )
{
    // Number of segments to convert a circle to a polygon
    const int       segcountforcircle   = 18;
    double          correctionFactor    = 1.0 / cos( M_PI / (segcountforcircle * 2) );

    // convert tracks and vias:
    for( TRACK* track = m_Track; track != NULL; track = track->Next() )
    {
        if( !track->IsOnLayer( aLayer ) )
            continue;

        track->TransformShapeWithClearanceToPolygon( aOutlines,
                0, segcountforcircle, correctionFactor );
    }

    // convert pads
    for( MODULE* module = m_Modules; module != NULL; module = module->Next() )
    {
        module->TransformPadsShapesWithClearanceToPolygon( aLayer,
                aOutlines, 0, segcountforcircle, correctionFactor );

        // Micro-wave modules may have items on copper layers
        module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer,
                aOutlines, 0, segcountforcircle, correctionFactor );
    }

    // convert copper zones
    for( int ii = 0; ii < GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetArea( ii );
        LAYER_ID        zonelayer = zone->GetLayer();

        if( zonelayer == aLayer )
            zone->TransformSolidAreasShapesToPolygonSet(
                aOutlines, segcountforcircle, correctionFactor );
    }

    // convert graphic items on copper layers (texts)
    for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
    {
        if( !item->IsOnLayer( aLayer ) )
            continue;

        switch( item->Type() )
        {
        case PCB_LINE_T:    // should not exist on copper layers
            ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                aOutlines, 0, segcountforcircle, correctionFactor );
            break;

        case PCB_TEXT_T:
            ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
                aOutlines, 0, segcountforcircle, correctionFactor );
            break;

        default:
            break;
        }
    }
}
Пример #20
0
/* function to handle key press events */
void handleKeyPress( SDL_keysym *keysym )
{
	VERTEX tvec1, tvec2, fr, fl, bl, br, camray, selvert;
	QUATERNION trot;
	BEZIER * lastbez;
	BEZIER * colbez;
	ROADSTRIP * tempstrip;
	BEZIER patch;
	bool l;
	int i;
	string tstr;
	
	//else if (timefactor == 0 && !menu.InMenu()) timefactor = 0;
		//		else timefactor = 1.0;
//	else
	{
		switch ( keysym->sym )
		{
		case SDLK_ESCAPE:
			/* ESC key was pressed */
			Quit( 0 );
			//menu.MainMenu();
			break;
		/*case SDLK_F7:
			
			tvec1 = tvec1.rotate(0,0,6.21652);
			cout << tvec1[0] << "," << tvec1[1] << endl;
		
			
			tvec2.Set(44.464,-126.8737,0);
			
			trot.Rotate(6.21652, 0, 0, 1);
			tvec2 = trot.RotateVec(tvec2);
			tvec2.DebugPrint();
			break;*/
		/*case SDLK_F7:
			if (timefactor != 100.0f)
				timefactor = 100.0f;
			else
				timefactor = 1.0f;
			break;*/
		/*case SDLK_PAGEUP:
			//tmpvert = cam.GetVelocity();
			cam.MoveRelative(0.0f, 0.0f, -2.0f);
			//cam.Update();
			//cam.LoadVelocityIdentity();
			break;
		case SDLK_PAGEDOWN:
			//tmpvert = cam.GetVelocity();
			cam.MoveRelative(0.0f, 0.0f, 2.0f);
			//cam.Update();
			//cam.LoadVelocityIdentity();
			break;*/
			
		case SDLK_BACKSPACE:
			if (activestrip != NULL)
			{
				if (activestrip->DeleteLastPatch())
				{
					if (activestrip->NumPatches() == 0)
					{
						mq1.AddMessage("Deleted patch and empty road");
						track.Delete(activestrip);
						activestrip = NULL;
						editordata.numbezinput = 0;
					}
					else
					{
						mq1.AddMessage("Deleted patch");
						lastbez = activestrip->GetLastPatch();
						if (lastbez != NULL)
						{
							editordata.bezinput[0] = lastbez->points[0][0];
							editordata.bezinput[1] = lastbez->points[0][1];
							editordata.bezinput[2] = lastbez->points[0][2];
							editordata.bezinput[3] = lastbez->points[0][3];
						}
						else
							editordata.numbezinput = 0;
					}
				}
				else
					mq1.AddMessage("Can't delete patch: no patches on this road");
			}
			else
			{
				mq1.AddMessage("Can't delete patch: no road selected");
			}
			break;
			
		case 'h':
			editordata.helppage++;
			break;
		
		case 'd':
			if (activestrip != NULL)
			{
				track.Delete(activestrip);
				mq1.AddMessage("Deleted road.");
			}
			else
			{
				mq1.AddMessage("Can't delete road: no road selected.");
			}
			activestrip = NULL;
			editordata.numbezinput = 0;
			break;
		
		case 'n':
			//create a new road
			mq1.AddMessage("Ready to create new road, add patches.");
			activestrip = NULL;
			editordata.numbezinput = 0;
			break;
			
		case 's':
			mq1.AddMessage("Saved to file");
			track.Write(editordata.activetrack);
			break;
		
		case 'l':
			track.SetStart(cam.position.ScaleR(-1));
			track.SetStartOrientation(cam.dir.ReturnConjugate());
			mq1.AddMessage("Added start location");
			break;
		
		case 'k':
			track.RemoveStart();
			track.RemoveStartOrientation();
			mq1.AddMessage("Removed start location");
			break;
		
		case 'r':
			//mq1.AddMessage("Saved to file");
			tvec1.zero();
			tvec1.z = -1;
			tvec2 = cam.dir.ReturnConjugate().RotateVec(tvec1);
			l = track.Collide(cam.position.ScaleR(-1.0), tvec2, tvec1, true, activestrip, colbez);
			if (!l)
			{
				mq1.AddMessage("Can't select road: no road found under cursor");
			}
			break;
		
		case 'a':
			AutoTrace();
			break;
			
		case 'f':
			for (i = 0; i < 25; i++)
			{
				AutoTrace();
			}
			break;
		
		case 'i':
			camray.z = -1;
			camray = cam.dir.ReturnConjugate().RotateVec(camray);
			if (objects.FindClosestVert(cam.position.ScaleR(-1.0), camray, selvert, tstr))
				cout << tstr << endl;
			break;
			
		case '-':
			track.ClearLapSequence();
			mq1.AddMessage("All lap sequence markers cleared");
			break;
		
		case 'e':
			//mq1.AddMessage("Saved to file");
			tvec1.zero();
			tvec1.z = -1;
			tvec2 = cam.dir.ReturnConjugate().RotateVec(tvec1);
			l = track.Collide(cam.position.ScaleR(-1.0), tvec2, tvec1, true, tempstrip, colbez);
			if (!l)
			{
				mq1.AddMessage("Can't create lap sequence marker: no road found under cursor");
			}
			else
			{
				track.AddLapSequence(colbez);
			}
			break;
			
		case '2':
			mq1.AddMessage("Two-vertex selection mode");
			vertmode = TWOVERTS;
			break;
			
		case '3':
			mq1.AddMessage("Three-vertex selection mode");
			vertmode = THREEVERTS;
			break;
			
		case '4':
			mq1.AddMessage("Four-vertex selection mode");
			vertmode = FOURVERTS;
			break;
		
		//case SDLK_F11:
			//SDL_WM_ToggleFullScreen( surface );
			//ChangeDisplay(1280,1024,32,true);
			//menu.DisplayMenu();//DisplaySelect();
			//break;
		
		//case SDLK_F12:
			//menu.MainMenu();
			//break;
		
		default:
			keyman.OneTime(keysym->sym);
			break;
		}
	}
	
    return;
}
Пример #21
0
TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint,
        bool aSameNetOnly, bool aSequential )
{
    const   wxPoint& position = GetEndPoint( aEndPoint );
    LSET    refLayers = GetLayerSet();
    TRACK*  previousSegment;
    TRACK*  nextSegment;

    if( aSequential )
    {
        // Simple sequential search: from aStartTrace forward to aEndTrace
        previousSegment = NULL;
        nextSegment = aStartTrace;
    }
    else
    {
        /* Local bidirectional search: from this backward to aStartTrace
         * AND forward to aEndTrace. The idea is that nearest segments
         * are found (on average) faster in this way. In fact same-net
         * segments are almost guaranteed to be found faster, in a global
         * search, since they are grouped together in the track list */
        previousSegment = this;
        nextSegment = this;
    }

    while( nextSegment || previousSegment )
    {
        // Terminate the search in the direction if the netcode mismatches
        if( aSameNetOnly )
        {
            if( nextSegment && (nextSegment->GetNetCode() != GetNetCode()) )
                nextSegment = NULL;
            if( previousSegment && (previousSegment->GetNetCode() != GetNetCode()) )
                previousSegment = NULL;
        }

        if( nextSegment )
        {
            if ( (nextSegment != this) &&
                 !nextSegment->GetState( BUSY | IS_DELETED ) &&
                 ( refLayers & nextSegment->GetLayerSet() ).any() )
            {
                if( (position == nextSegment->m_Start) ||
                    (position == nextSegment->m_End) )
                    return nextSegment;
            }

            // Keep looking forward
            if( nextSegment == aEndTrace )
                nextSegment = NULL;
            else
                nextSegment = nextSegment->Next();
        }

        // Same as above, looking back. During sequential search this branch is inactive
        if( previousSegment )
        {
            if( (previousSegment != this) &&
                !previousSegment->GetState( BUSY | IS_DELETED ) &&
                ( refLayers & previousSegment->GetLayerSet() ).any()
                )
            {
                if( (position == previousSegment->m_Start) ||
                    (position == previousSegment->m_End) )
                    return previousSegment;
            }

            if( previousSegment == aStartTrace )
                previousSegment = NULL;
            else
                previousSegment = previousSegment->Back();
        }
    }

    return NULL;
}
Пример #22
0
bool LoadWorld()
{
	UnloadWorld();
	
	editordata.helppage = 0;
	editordata.numbezinput = 0;
	editordata.mousebounce[1] = false;
	
	//teststrip = track.AddNewRoad();
	
	//begin loading world
	
	LoadingScreen("Loading...\nConfiguration files");
	
	CONFIGFILE setupfile;
	setupfile.Load(settings.GetDataDir() + "/tracks/editor.config");
	setupfile.GetParam("active track", editordata.activetrack);
	if (editordata.activetrack == "")
		editordata.activetrack = "default";
	
	objects.LoadObjectsFromFolder(settings.GetDataDir() + "/tracks/" + 
			editordata.activetrack + "/objects/");
	
	track.Load(editordata.activetrack);
	
	//float aangle[] = {0, 1, 0, 0};
	//track.GetStartOrientation(0).GetAxisAngle(aangle);
	//cam.Rotate(aangle[0], aangle[1], aangle[2], aangle[3]);
	VERTEX start = track.GetStart(0);
	cam.Move(-start.x, -start.y, -start.z);
	cam.Update();
	cam.LoadVelocityIdentity();
	
	//car_file = "s2000";
	//ifstream csfile;
	//car_file = "";
	//csfile.open((settings.GetSettingsDir() + "/selected_car").c_str());
	//car_paint = 0;
/*	if (csfile)
	{
		state.SetCarName(0, utility.sGetLine(csfile));
		state.SetCarPaint(0, utility.iGetParam(csfile));
		csfile.close();
	}
*/
	
	//LoadingScreen("Loading...\nLoading scenery objects");
	//objects.LoadObjectsFromFolder(settings.GetDataDir() + "/tracks/" + state.GetTrackName() + "/objects");
	
	/*trees.DeleteAll();
	int numtrees = 200;
	for (i = 0; i < numtrees/2; i++)
	{
		VERTEX tp;
		tp.x = ((float) rand()/RAND_MAX)*(param[0]/2.0)+param[0]/4.0;
		tp.z = ((float) rand()/RAND_MAX)*(param[2]/2.0)+param[2]/4.0;
		tp.x += param[3];
		tp.z += param[4];
		tp.y = terrain.GetHeight(tp.x, tp.z);
		trees.Add(tp, 40.0, 0, 5);
	}
	
	for (i = 0; i < numtrees/2; i++)
	{
		VERTEX tp;
		tp.x = ((float) rand()/RAND_MAX)*(param[0]/2.0)+param[0]/4.0;
		tp.z = ((float) rand()/RAND_MAX)*(param[2]/2.0)+param[2]/4.0;
		tp.x += param[3];
		tp.z += param[4];
		tp.y = terrain.GetHeight(tp.x, tp.z);
		trees.Add(tp, 60.0, 1, 5);
	}*/
	
	LoadingScreen("Loading...\nDone");
	
	mq1.AddMessage("Editor started, press H for help");
	
	return true;
}
Пример #23
0
/* Function BuildAirWiresTargetsList
 * Build a list of candidates that can be a coonection point
 * when a track is started.
 * This functions prepares data to show airwires to nearest connecting points (pads)
 * from the current new track to candidates during track creation
 */
void PCB_BASE_FRAME::BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
                                               const wxPoint& aPosition, bool aInit )
{
    if( ( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
       || ( ( m_Pcb->m_Status_Pcb & LISTE_PAD_OK ) == 0 )
       || ( ( m_Pcb->m_Status_Pcb & NET_CODES_OK ) == 0 ) )
    {
        s_TargetsLocations.clear();
        return;
    }

    s_CursorPos = aPosition;    // needed for sort_by_distance

    if( aInit )
    {
        s_TargetsLocations.clear();

        if( aItemRef == NULL )
            return;

        int net_code = aItemRef->GetNet();
        int subnet = aItemRef->GetSubNet();

        if( net_code <= 0 )
            return;

        NETINFO_ITEM* net = m_Pcb->FindNet( net_code );

        if( net == NULL )        // Should not occur
        {
            wxMessageBox( wxT( "BuildAirWiresTargetsList() error: net not found" ) );
            return;
        }

        // Create a list of pads candidates ( pads not already connected to the
        // current track ):
        for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ )
        {
            D_PAD* pad = net->m_PadInNetList[ii];

            if( pad == aItemRef )
                continue;

            if( !pad->GetSubNet() || (pad->GetSubNet() != subnet) )
                s_TargetsLocations.push_back( pad->GetPosition() );
        }

        // Create a list of tracks ends candidates, not already connected to the
        // current track:
        for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
        {
            if( track->GetNet() < net_code )
                continue;
            if( track->GetNet() > net_code )
                break;;

            if( !track->GetSubNet() || (track->GetSubNet() != subnet) )
            {
                if( aPosition != track->GetStart() )
                    s_TargetsLocations.push_back( track->GetStart() );
                if( aPosition != track->GetEnd() && track->GetStart() != track->GetEnd() )
                    s_TargetsLocations.push_back( track->GetEnd() );
            }
        }

        // Remove duplicate targets, using the C++ unique algorithm
        sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_point );
        std::vector< wxPoint >::iterator it = unique( s_TargetsLocations.begin(), s_TargetsLocations.end() );

        // Using the C++ unique algorithm only moves the duplicate entries to the end of
        // of the array.  This removes the duplicate entries from the array.
        s_TargetsLocations.resize( it - s_TargetsLocations.begin() );
    }   // end if Init

    // in all cases, sort by distances:
    sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_distance );
}
Пример #24
0
/* Insere la nouvelle piste creee dans la liste standard des pistes.
	Modifie les points de debut et fin de piste pour qu'ils soient relies
	au centre des pads corresponadants, meme hors grille
*/
static void Place_Piste_en_Buffer(WinEDA_PcbFrame * pcbframe, wxDC * DC)
{
TRACK* pt_track;
int dx0, dy0, dx1,dy1;
int marge, via_marge;
WinEDA_DrawPanel * panel = pcbframe->DrawPanel;

	marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth /2);
	via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize /2);

	/* tst point d'arrivee : doit etre sur pad start */

	dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
	dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
	/* Replacement sur le centre du pad si hors grille */

	dx0 = pt_cur_ch->pad_start->m_Pos.x - g_CurrentTrackSegment->m_Start.x;
	dy0 = pt_cur_ch->pad_start->m_Pos.y - g_CurrentTrackSegment->m_Start.y;

	/* si aligne: modif du point origine */
	if(abs(dx0*dy1) == abs(dx1*dy0) ) /* Alignes ! */
		{
		g_CurrentTrackSegment->m_End.x = pt_cur_ch->pad_start->m_Pos.x;
		g_CurrentTrackSegment->m_End.y = pt_cur_ch->pad_start->m_Pos.y;
		}
	else /* Creation d'un segment suppl raccord */
		{
		TRACK * NewTrack = g_CurrentTrackSegment->Copy();
		NewTrack->Insert(pcbframe->m_Pcb, g_CurrentTrackSegment);

		NewTrack->m_End.x = pt_cur_ch->pad_start->m_Pos.x;
		NewTrack->m_End.y = pt_cur_ch->pad_start->m_Pos.y;
		NewTrack->m_Start.x = g_CurrentTrackSegment->m_End.x;
		NewTrack->m_Start.y = g_CurrentTrackSegment->m_End.y;

		g_CurrentTrackSegment = NewTrack; g_TrackSegmentCount++;
		}


	g_FirstTrackSegment->start = Locate_Pad_Connecte(pcbframe->m_Pcb, g_FirstTrackSegment,START);
	if(g_FirstTrackSegment->start) g_FirstTrackSegment->SetState(BEGIN_ONPAD,ON);

	g_CurrentTrackSegment->end = Locate_Pad_Connecte(pcbframe->m_Pcb, g_CurrentTrackSegment,END);
	if(g_CurrentTrackSegment->end) g_CurrentTrackSegment->SetState(END_ONPAD,ON);

	/* recherche de la zone de rangement et insertion de la nouvelle piste */
	pt_track = g_FirstTrackSegment->GetBestInsertPoint(pcbframe->m_Pcb);
	g_FirstTrackSegment->Insert(pcbframe->m_Pcb, pt_track);

	Trace_Une_Piste(panel, DC, g_FirstTrackSegment,g_TrackSegmentCount,GR_OR) ;

	pcbframe->test_1_net_connexion(DC, g_FirstTrackSegment->m_NetCode );

	/* Trace de la forme exacte de la piste en BOARD */
	for ( pt_track = g_FirstTrackSegment; ; pt_track = (TRACK*)pt_track->Pnext)
		{
		TraceSegmentPcb(pcbframe->m_Pcb,pt_track,HOLE,marge,WRITE_CELL);
		TraceSegmentPcb(pcbframe->m_Pcb,pt_track,VIA_IMPOSSIBLE,via_marge,WRITE_OR_CELL);
		if(pt_track == g_CurrentTrackSegment ) break;
		}

	ActiveScreen->SetModify();
}
Пример #25
0
/*
 * Function BuildHolesList
 * Create the list of holes and tools for a given board
 * The list is sorted by increasing drill values
 * Only holes from aFirstLayer to aLastLayer copper layers  are listed (for vias, because pad holes are always through holes)
 * param aPcb : the given board
 * param aHoleListBuffer : the std::vector<HOLE_INFO> to fill with pcb holes info
 * param aToolListBuffer : the std::vector<DRILL_TOOL> to fill with tools to use
 * param aFirstLayer = first layer to consider. if < 0 aFirstLayer is ignored   (used to creates report file)
 * param aLastLayer = last layer to consider. if < 0 aLastLayer is ignored
 * param aExcludeThroughHoles : if true, exclude through holes ( pads and vias through )
 * param aGenerateNPTH_list :
 *       true to create NPTH only list (with no plated holes)
 *       false to created plated holes list (with no NPTH )
 */
void Build_Holes_List( BOARD* aPcb,
                       std::vector<HOLE_INFO>& aHoleListBuffer,
                       std::vector<DRILL_TOOL>& aToolListBuffer,
                       int aFirstLayer, int aLastLayer, bool aExcludeThroughHoles,
                       bool aGenerateNPTH_list )
{
    HOLE_INFO new_hole;
    int       hole_value;

    aHoleListBuffer.clear();
    aToolListBuffer.clear();

    if( (aFirstLayer >= 0) && (aLastLayer >= 0) )
    {
        if( aFirstLayer > aLastLayer )
            EXCHG( aFirstLayer, aLastLayer );
    }

    /* build hole list for vias
    */
    if( ! aGenerateNPTH_list )  // vias are always plated !
    {
        for( TRACK* track = aPcb->m_Track;  track;  track = track->Next() )
        {
            if( track->Type() != PCB_VIA_T )
                continue;

            SEGVIA* via = (SEGVIA*) track;
            hole_value = via->GetDrillValue();

            if( hole_value == 0 )
                continue;

            new_hole.m_Tool_Reference = -1;         // Flag value for Not initialized
            new_hole.m_Hole_Orient    = 0;
            new_hole.m_Hole_Diameter  = hole_value;
            new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

            new_hole.m_Hole_Shape = 0;              // hole shape: round
            new_hole.m_Hole_Pos = via->m_Start;
            via->ReturnLayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer );

            // ReturnLayerPair return params with m_Hole_Bottom_Layer < m_Hole_Top_Layer
            if( (new_hole.m_Hole_Bottom_Layer > aFirstLayer) && (aFirstLayer >= 0) )
                continue;

            if( (new_hole.m_Hole_Top_Layer < aLastLayer) && (aLastLayer >= 0) )
                continue;

            if( aExcludeThroughHoles  && (new_hole.m_Hole_Bottom_Layer == LAYER_N_BACK)
               && (new_hole.m_Hole_Top_Layer == LAYER_N_FRONT) )
                continue;

            aHoleListBuffer.push_back( new_hole );
        }
    }

    // build hole list for pads (assumed always through holes)
    if( !aExcludeThroughHoles || aGenerateNPTH_list )
    {
        for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
        {
            // Read and analyse pads
            for( D_PAD* pad = module->m_Pads;  pad;  pad = pad->Next() )
            {
                if( ! aGenerateNPTH_list && pad->GetAttribute() == PAD_HOLE_NOT_PLATED )
                    continue;

                if( aGenerateNPTH_list && pad->GetAttribute() != PAD_HOLE_NOT_PLATED )
                    continue;

                if( pad->GetDrillSize().x == 0 )
                    continue;

                new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED);
                new_hole.m_Tool_Reference = -1;         // Flag is: Not initialized
                new_hole.m_Hole_Orient    = pad->GetOrientation();
                new_hole.m_Hole_Shape    = 0;           // hole shape: round
                new_hole.m_Hole_Diameter = min( pad->GetDrillSize().x, pad->GetDrillSize().y );
                new_hole.m_Hole_Size.x    = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

                if( pad->GetDrillShape() != PAD_CIRCLE )
                    new_hole.m_Hole_Shape = 1; // oval flag set

                new_hole.m_Hole_Size = pad->GetDrillSize();
                new_hole.m_Hole_Pos = pad->GetPosition();               // hole position
                new_hole.m_Hole_Bottom_Layer = LAYER_N_BACK;
                new_hole.m_Hole_Top_Layer    = LAYER_N_FRONT;// pad holes are through holes
                aHoleListBuffer.push_back( new_hole );
            }
        }
    }

    // Sort holes per increasing diameter value
    sort( aHoleListBuffer.begin(), aHoleListBuffer.end(), CmpHoleDiameterValue );

    // build the tool list
    int        LastHole = -1; /* Set to not initialised (this is a value not used
                               * for aHoleListBuffer[ii].m_Hole_Diameter) */
    DRILL_TOOL new_tool( 0 );
    unsigned   jj;

    for( unsigned ii = 0; ii < aHoleListBuffer.size(); ii++ )
    {
        if( aHoleListBuffer[ii].m_Hole_Diameter != LastHole )
        {
            new_tool.m_Diameter = ( aHoleListBuffer[ii].m_Hole_Diameter );
            aToolListBuffer.push_back( new_tool );
            LastHole = new_tool.m_Diameter;
        }

        jj = aToolListBuffer.size();

        if( jj == 0 )
            continue;                                       // Should not occurs

        aHoleListBuffer[ii].m_Tool_Reference = jj;          // Tool value Initialized (value >= 1)

        aToolListBuffer.back().m_TotalCount++;

        if( aHoleListBuffer[ii].m_Hole_Shape )
            aToolListBuffer.back().m_OvalCount++;
    }
}
Пример #26
0
/* Creates the section "$TRACKS"
 *  This sections give the list of widths (tools) used in tracks and vias
 *  format:
 *  $TRACK
 *  TRACK <name> <width>
 *  $ENDTRACK
 *
 *  Each tool name is build like this: "TRACK" + track width.
 *  For instance for a width = 120 : name = "TRACK120".
 */
static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb )
{
    TRACK* track;
    int    last_width = -1;

    // Find thickness used for traces
    // XXX could use the same sorting approach used for pads

    std::vector <int> trackinfo;

    unsigned          ii;

    for( track = aPcb->m_Track; track; track = track->Next() )
    {
        if( last_width != track->GetWidth() ) // Find a thickness already used.
        {
            for( ii = 0; ii < trackinfo.size(); ii++ )
            {
                if( trackinfo[ii] == track->GetWidth() )
                    break;
            }

            if( ii == trackinfo.size() )    // not found
                trackinfo.push_back( track->GetWidth() );

            last_width = track->GetWidth();
        }
    }

    for( track = aPcb->m_Zone; track; track = track->Next() )
    {
        if( last_width != track->GetWidth() ) // Find a thickness already used.
        {
            for( ii = 0; ii < trackinfo.size(); ii++ )
            {
                if( trackinfo[ii] == track->GetWidth() )
                    break;
            }

            if( ii == trackinfo.size() )    // not found
                trackinfo.push_back( track->GetWidth() );

            last_width = track->GetWidth();
        }
    }

    // Write data
    fputs( "$TRACKS\n", aFile );

    for( ii = 0; ii < trackinfo.size(); ii++ )
    {
        fprintf( aFile, "TRACK TRACK%d %g\n", trackinfo[ii],
                 trackinfo[ii] / SCALE_FACTOR );
    }

    fputs( "$ENDTRACKS\n\n", aFile );
}
/**
 * Function Test_Connection_To_Copper_Areas
 * init .m_ZoneSubnet parameter in tracks and pads according to the connections to areas found
 * @param aNetcode = netcode to analyse. if -1, analyse all nets
 */
void BOARD::Test_Connections_To_Copper_Areas( int aNetcode )
{
    // list of pads and tracks candidates on this layer and on this net.
    // It is static to avoid multiple memory realloc.
    static std::vector <BOARD_CONNECTED_ITEM*> candidates;

    // clear .m_ZoneSubnet parameter for pads
    for( MODULE* module = m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
            if( aNetcode < 0 || aNetcode == pad->GetNetCode() )
                pad->SetZoneSubNet( 0 );
    }

    // clear .m_ZoneSubnet parameter for tracks and vias
    for( TRACK* track = m_Track;  track;  track = track->Next() )
    {
        if( aNetcode < 0 || aNetcode == track->GetNetCode() )
            track->SetZoneSubNet( 0 );
    }

    // examine all zones, net by net:
    int subnet = 0;

    // Build zones candidates list
    std::vector<ZONE_CONTAINER*> zones_candidates;

    zones_candidates.reserve( GetAreaCount() );

    for( int index = 0; index < GetAreaCount(); index++ )
    {
        ZONE_CONTAINER* zone = GetArea( index );

        if( !zone->IsOnCopperLayer() )
            continue;

        if( aNetcode >= 0 &&  aNetcode != zone->GetNetCode() )
            continue;

        if( zone->GetFilledPolysList().GetCornersCount() == 0 )
            continue;

        zones_candidates.push_back( zone );
    }

    // sort them by netcode then vertices count.
    // For a given net, examine the smaller zones first slightly speed up calculation
    // (25% faster)
    // this is only noticeable with very large boards and depends on board zones topology
    // This is due to the fact some items are connected by small zones ares,
    // before examining large zones areas and these items are not tested after a connection is found
    sort( zones_candidates.begin(), zones_candidates.end(), sort_areas );

    int oldnetcode = -1;
    for( unsigned idx = 0; idx < zones_candidates.size(); idx++ )
    {
        ZONE_CONTAINER* zone = zones_candidates[idx];

        int netcode = zone->GetNetCode();

        // Build a list of candidates connected to the net:
        // At this point, layers are not considered, because areas on different layers can
        // be connected by a via or a pad.
        // (because zones are sorted by netcode, there is made only once per net)
        NETINFO_ITEM* net = FindNet( netcode );

        wxASSERT( net );
        if( net == NULL )
            continue;

        if( oldnetcode != netcode )
        {
            oldnetcode = netcode;
            candidates.clear();

            // Build the list of pads candidates connected to the net:
            candidates.reserve( net->m_PadInNetList.size() );

            for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ )
                candidates.push_back( net->m_PadInNetList[ii] );

            // Build the list of track candidates connected to the net:
            TRACK* track = m_Track.GetFirst()->GetStartNetCode( netcode );

            for( ; track; track = track->Next() )
            {
                if( track->GetNetCode() != netcode )
                    break;

                candidates.push_back( track );
            }
        }

        // test if a candidate is inside a filled area of this zone
        unsigned indexstart = 0, indexend;
        const CPOLYGONS_LIST& polysList = zone->GetFilledPolysList();

        for( indexend = 0; indexend < polysList.GetCornersCount(); indexend++ )
        {
            // end of a filled sub-area found
            if( polysList.IsEndContour( indexend ) )
            {
                subnet++;
                EDA_RECT bbox = zone->CalculateSubAreaBoundaryBox( indexstart, indexend );

                for( unsigned ic = 0; ic < candidates.size(); ic++ )
                {
                    // test if this area is connected to a board item:
                    BOARD_CONNECTED_ITEM* item = candidates[ic];

                    if( item->GetZoneSubNet() == subnet )   // Already merged
                        continue;

                   if( !item->IsOnLayer( zone->GetLayer() ) )
                        continue;

                    wxPoint pos1, pos2;

                    if( item->Type() == PCB_PAD_T )
                    {
                        // For pads we use the shape position instead of
                        // the pad position, because the zones are connected
                        // to the center of the shape, not the pad position
                        // (this is important for pads with thermal relief)
                        pos1 = pos2 = ( (D_PAD*) item )->ShapePos();
                    }
                    else if( item->Type() == PCB_VIA_T )
                    {
                        const VIA *via = static_cast<const VIA*>( item );
                        pos1 = via->GetStart();
                        pos2 = pos1;
                    }
                    else if( item->Type() == PCB_TRACE_T )
                    {
                        const TRACK *trk = static_cast<const TRACK*>( item );
                        pos1 = trk->GetStart();
                        pos2 = trk->GetEnd();
                    }
                    else
                    {
                        continue;
                    }

                    bool connected = false;

                    if( bbox.Contains( pos1 ) )
                    {
                        if( TestPointInsidePolygon( polysList, indexstart,
                                                    indexend, pos1.x, pos1.y ) )
                            connected = true;
                    }
                    if( !connected && (pos1 != pos2 ) )
                    {
                        if( bbox.Contains( pos2 ) )
                        {
                            if( TestPointInsidePolygon( polysList,
                                                        indexstart, indexend,
                                                        pos2.x, pos2.y ) )
                                connected = true;
                        }
                    }

                    if( connected )
                    {
                        // Set ZoneSubnet to the current subnet value.
                        // If the previous subnet is not 0, merge all items with old subnet
                        // to the new one
                        int old_subnet = item->GetZoneSubNet();
                        item->SetZoneSubNet( subnet );

                        // Merge previous subnet with the current
                        if( (old_subnet > 0) && (old_subnet != subnet) )
                        {
                            for( unsigned jj = 0; jj < candidates.size(); jj++ )
                            {
                                BOARD_CONNECTED_ITEM* item_to_merge = candidates[jj];

                                if( old_subnet == item_to_merge->GetZoneSubNet() )
                                {
                                    item_to_merge->SetZoneSubNet( subnet );
                                }
                            }
                        }   // End if ( old_subnet > 0 )
                    }       // End if( connected )
                }

                // End test candidates for the current filled area
                indexstart = indexend + 1;  // prepare test next area, starting at indexend+1
                                            // (if exists).  End read one area in
                                            // zone->m_FilledPolysList
            }
        } // End read all segments in zone
    } // End read all zones candidates
}
Пример #28
0
MARKER_PCB* DRC::fillMarker( TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe )
{
    wxString textA = aTrack->GetSelectMenuText();
    wxString textB;

    wxPoint  position;
    wxPoint  posB;

    if( aItem )     // aItem might be NULL
    {
        textB = aItem->GetSelectMenuText();

        if( aItem->Type() == PCB_PAD_T )
        {
            posB = position = ((D_PAD*)aItem)->GetPosition();
        }
        else if( aItem->Type() == PCB_VIA_T )
        {
            posB = position = ((SEGVIA*)aItem)->GetPosition();
        }
        else if( aItem->Type() == PCB_TRACE_T )
        {
            TRACK*  track  = (TRACK*) aItem;

            posB = track->GetPosition();

            wxPoint endPos = track->m_End;

            // either of aItem's start or end will be used for the marker position
            // first assume start, then switch at end if needed.  decision made on
            // distance from end of aTrack.
            position = track->m_Start;

            double dToEnd = hypot( endPos.x - aTrack->m_End.x,
                                   endPos.y - aTrack->m_End.y );
            double dToStart = hypot( position.x - aTrack->m_End.x,
                                     position.y - aTrack->m_End.y );

            if( dToEnd < dToStart )
                position = endPos;
        }
    }
    else
        position = aTrack->GetPosition();

    if( fillMe )
    {
        if( aItem )
            fillMe->SetData( aErrorCode, position,
                             textA, aTrack->GetPosition(),
                             textB, posB );
        else
            fillMe->SetData( aErrorCode, position,
                             textA, aTrack->GetPosition() );
    }
    else
    {
        if( aItem )
            fillMe = new MARKER_PCB( aErrorCode, position,
                                     textA, aTrack->GetPosition(),
                                     textB, posB );
        else
            fillMe = new MARKER_PCB( aErrorCode, position,
                                     textA, aTrack->GetPosition() );
    }

    return fillMe;
}
Пример #29
0
/* Populates .m_connected with tracks/vias connected to aTrack
 * param aTrack = track or via to use as reference
 * For calculation time reason, an exhaustive search cannot be made
 * and a proximity search is made:
 * Only tracks with one end near one end of aTrack are collected.
 * near means dist <= aTrack width / 2
 * because with this constraint we can make a fast search in track list
 * m_candidates is expected to be populated by the track candidates ends list
 */
int CONNECTIONS::SearchConnectedTracks( const TRACK* aTrack )
{
    int count = 0;
    m_connected.clear();

    LSET layerMask = aTrack->GetLayerSet();

    // Search for connections to starting point:
#define USE_EXTENDED_SEARCH

#ifdef USE_EXTENDED_SEARCH
    int dist_max = aTrack->GetWidth() / 2;
    static std::vector<CONNECTED_POINT*> tracks_candidates;
#endif

    wxPoint position = aTrack->GetStart();

    for( int kk = 0; kk < 2; kk++ )
    {
#ifndef USE_EXTENDED_SEARCH
        int idx = searchEntryPointInCandidatesList( position );

        if( idx >= 0 )
        {
            // search after:
            for( unsigned ii = idx; ii < m_candidates.size(); ii ++ )
            {
                if( m_candidates[ii].GetTrack() == aTrack )
                    continue;

                if( m_candidates[ii].GetPoint() != position )
                    break;

                if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
                    m_connected.push_back( m_candidates[ii].GetTrack() );
            }

            // search before:
            for( int ii = idx-1; ii >= 0; ii -- )
            {
                if( m_candidates[ii].GetTrack() == aTrack )
                    continue;

                if( m_candidates[ii].GetPoint() != position )
                    break;

                if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
                    m_connected.push_back( m_candidates[ii].GetTrack() );
            }
        }
#else

        tracks_candidates.clear();

        CollectItemsNearTo( tracks_candidates, position, dist_max );

        for( unsigned ii = 0; ii < tracks_candidates.size(); ii++ )
        {
            TRACK* ctrack = tracks_candidates[ii]->GetTrack();

            if( !( ctrack->GetLayerSet() & layerMask ).any() )
                continue;

            if( ctrack == aTrack )
                continue;

            // We have a good candidate: calculate the actual distance
            // between ends, which should be <= dist max.
            wxPoint delta = tracks_candidates[ii]->GetPoint() - position;

            int dist = KiROUND( EuclideanNorm( delta ) );

            if( dist > dist_max )
                continue;

            m_connected.push_back( ctrack );
        }
#endif

        // Search for connections to ending point:
        if( aTrack->Type() == PCB_VIA_T )
            break;

        position = aTrack->GetEnd();
    }

    return count;
}
Пример #30
0
// Delete null length segments, and intermediate points ..
bool TRACKS_CLEANER::clean_segments()
{
    bool modified = false;
    TRACK*          segment, * nextsegment;
    TRACK*          other;
    int             flag, no_inc;


    // Delete null segments
    for( segment = m_Brd->m_Track; segment; segment = nextsegment )
    {
        nextsegment = segment->Next();

        if( segment->IsNull() )     // Length segment = 0; delete it
            segment->DeleteStructure();
    }

    // Delete redundant segments, i.e. segments having the same end points
    // and layers
    for( segment  = m_Brd->m_Track; segment; segment = segment->Next() )
    {
        for( other = segment->Next(); other; other = nextsegment )
        {
            nextsegment = other->Next();
            bool erase = false;

            if( segment->Type() != other->Type() )
                continue;

            if( segment->GetLayer() != other->GetLayer() )
                continue;

            if( segment->GetNet() != other->GetNet() )
                break;

            if( ( segment->GetStart() == other->GetStart() ) &&
                ( segment->GetEnd() == other->GetEnd() ) )
                erase = true;

            if( ( segment->GetStart() == other->GetEnd() ) &&
                ( segment->GetEnd() == other->GetStart() ) )
                erase = true;

            // Delete redundant point
            if( erase )
            {
                other->DeleteStructure();
                modified = true;
            }
        }
    }

    // merge collinear segments:
    for( segment = m_Brd->m_Track; segment; segment = nextsegment )
    {
        TRACK*  segStart;
        TRACK*  segEnd;
        TRACK*  segDelete;

        nextsegment = segment->Next();

        if( segment->Type() != PCB_TRACE_T )
            continue;

        flag = no_inc = 0;

        // search for a possible point connected to the START point of the current segment
        for( segStart = segment->Next(); ; )
        {
            segStart = segment->GetTrace( segStart, NULL, FLG_START );

            if( segStart )
            {
                // the two segments must have the same width
                if( segment->GetWidth() != segStart->GetWidth() )
                    break;

                // it cannot be a via
                if( segStart->Type() != PCB_TRACE_T )
                    break;

                // We must have only one segment connected
                segStart->SetState( BUSY, true );
                other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_START );
                segStart->SetState( BUSY, false );

                if( other == NULL )
                    flag = 1;           // OK

                break;
            }
            break;
        }

        if( flag )   // We have the starting point of the segment is connected to an other segment
        {
            segDelete = mergeCollinearSegmentIfPossible( segment, segStart, FLG_START );

            if( segDelete )
            {
                no_inc = 1;
                segDelete->DeleteStructure();
                modified = true;
            }
        }

        // search for a possible point connected to the END point of the current segment:
        for( segEnd = segment->Next(); ; )
        {
            segEnd = segment->GetTrace( segEnd, NULL, FLG_END );

            if( segEnd )
            {
                if( segment->GetWidth() != segEnd->GetWidth() )
                    break;

                if( segEnd->Type() != PCB_TRACE_T )
                    break;

                // We must have only one segment connected
                segEnd->SetState( BUSY, true );
                other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_END );
                segEnd->SetState( BUSY, false );

                if( other == NULL )
                    flag |= 2;          // Ok

                break;
            }
            else
            {
                break;
            }
        }

        if( flag & 2 )  // We have the ending point of the segment is connected to an other segment
        {
            segDelete = mergeCollinearSegmentIfPossible( segment, segEnd, FLG_END );

            if( segDelete )
            {
                no_inc = 1;
                segDelete->DeleteStructure();
                modified = true;
            }
        }

        if( no_inc ) // The current segment was modified, retry to merge it
            nextsegment = segment->Next();
    }

    return modified;
}