Example #1
0
PNS_PCBNEW_RULE_RESOLVER::PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter ) :
    m_router( aRouter ),
    m_board( aBoard )
{
    PNS::NODE* world = m_router->GetWorld();

    PNS::TOPOLOGY topo( world );
    m_netClearanceCache.resize( m_board->GetNetCount() );

    // Build clearance cache for net classes
    for( unsigned int i = 0; i < m_board->GetNetCount(); i++ )
    {
        NETINFO_ITEM* ni = m_board->FindNet( i );

        if( ni == NULL )
            continue;

        CLEARANCE_ENT ent;
        ent.coupledNet = DpCoupledNet( i );

        wxString netClassName = ni->GetClassName();
        NETCLASSPTR nc = m_board->GetDesignSettings().m_NetClasses.Find( netClassName );

        int clearance = nc->GetClearance();
        ent.clearance = clearance;
        m_netClearanceCache[i] = ent;

        wxLogTrace( "PNS", "Add net %u netclass %s clearance %d", i, netClassName.mb_str(), clearance );
    }

    // Build clearance cache for pads
    for( MODULE* mod = m_board->m_Modules; mod ; mod = mod->Next() )
    {
        auto moduleClearance = mod->GetLocalClearance();

        for( D_PAD* pad = mod->PadsList(); pad; pad = pad->Next() )
        {
            int padClearance = pad->GetLocalClearance();

            if( padClearance > 0 )
                m_localClearanceCache[ pad ] = padClearance;

            else if( moduleClearance > 0 )
                m_localClearanceCache[ pad ] = moduleClearance;
        }
    }

    //printf("DefaultCL : %d\n",  m_board->GetDesignSettings().m_NetClasses.Find ("Default clearance")->GetClearance());

    m_overrideEnabled = false;
    m_defaultClearance = Millimeter2iu( 0.254 );    // m_board->m_NetClasses.Find ("Default clearance")->GetClearance();
    m_overrideNetA = 0;
    m_overrideNetB = 0;
    m_overrideClearance = 0;
    m_useDpGap = false;
}
void BOARD::DrawHighLight( EDA_DRAW_PANEL* am_canvas, wxDC* DC, int aNetCode )
{
    GR_DRAWMODE draw_mode;

    if( IsHighLightNetON() )
        draw_mode = GR_HIGHLIGHT | GR_OR;
    else
        draw_mode = GR_AND | GR_HIGHLIGHT;

    // Redraw zones
    for( int ii = 0; ii < GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetArea( ii );

        if( zone->GetNetCode() == aNetCode )
        {
            zone->Draw( am_canvas, DC, draw_mode );
        }
    }

    // Redraw any pads that have aNetCode
    for( MODULE* module = m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->PadsList(); pad; pad = pad->Next() )
        {
            if( pad->GetNetCode() == aNetCode )
            {
                pad->Draw( am_canvas, DC, draw_mode );
            }
        }
    }

    // Redraw track and vias that have aNetCode
    for( TRACK* seg = m_Track; seg; seg = seg->Next() )
    {
        if( seg->GetNetCode() == aNetCode )
        {
            seg->Draw( am_canvas, DC, draw_mode );
        }
    }
}
Example #3
0
MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern,
                    PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage )
{
    /* Build a microwave inductor footprint.
     * - Length Mself.lng
     * - Extremities Mself.m_Start and Mself.m_End
     * We must determine:
     * Mself.nbrin = number of segments perpendicular to the direction
     * (The coil nbrin will demicercles + 1 + 2 1 / 4 circle)
     * Mself.lbrin = length of a strand
     * Mself.radius = radius of rounded parts of the coil
     * Mself.delta = segments extremities connection between him and the coil even
     *
     * The equations are
     * Mself.m_Size.x = 2 * Mself.radius + Mself.lbrin
     * Mself.m_Size.y * Mself.delta = 2 + 2 * Mself.nbrin * Mself.radius
     * Mself.lng = 2 * Mself.delta / / connections to the coil
     + (Mself.nbrin-2) * Mself.lbrin / / length of the strands except 1st and last
     + (Mself.nbrin 1) * (PI * Mself.radius) / / length of rounded
     * Mself.lbrin + / 2 - Melf.radius * 2) / / length of 1st and last bit
     *
     * The constraints are:
     * Nbrin >= 2
     * Mself.radius < Mself.m_Size.x
     * Mself.m_Size.y = Mself.radius * 4 + 2 * Mself.raccord
     * Mself.lbrin> Mself.radius * 2
     *
     * The calculation is conducted in the following way:
     * Initially:
     * Nbrin = 2
     * Radius = 4 * m_Size.x (arbitrarily fixed value)
     * Then:
     * Increasing the number of segments to the desired length
     * (Radius decreases if necessary)
     */

    D_PAD*   pad;
    int      ll;
    wxString msg;

    auto pt = inductorPattern.m_End - inductorPattern.m_Start;
    int     min_len = KiROUND( EuclideanNorm( pt ) );
    inductorPattern.m_length = min_len;

    // Enter the desired length.
    msg = StringFromValue( g_UserUnit, inductorPattern.m_length );
    wxTextEntryDialog dlg( nullptr, wxEmptyString, _( "Length of Trace:" ), msg );

    if( dlg.ShowModal() != wxID_OK )
        return nullptr; // canceled by user

    msg = dlg.GetValue();
    inductorPattern.m_length = ValueFromString( g_UserUnit, msg );

    // Control values (ii = minimum length)
    if( inductorPattern.m_length < min_len )
    {
        aErrorMessage = _( "Requested length < minimum length" );
        return nullptr;
    }

    // Calculate the elements.
    std::vector <wxPoint> buffer;
    ll = BuildCornersList_S_Shape( buffer, inductorPattern.m_Start,
                                   inductorPattern.m_End, inductorPattern.m_length,
                                   inductorPattern.m_Width );

    if( !ll )
    {
        aErrorMessage = _( "Requested length too large" );
        return nullptr;
    }

    // Generate footprint. the value is also used as footprint name.
    msg = "L";
    wxTextEntryDialog cmpdlg( nullptr, wxEmptyString, _( "Component Value:" ), msg );
    cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) );

    if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() )
        return nullptr;    //  Aborted by user

    MODULE* module = aPcbFrame->CreateNewModule( msg );

    // here the module is already in the BOARD, CreateNewModule() does that.
    module->SetFPID( LIB_ID( wxString( "mw_inductor" ) ) );
    module->SetAttributes( MOD_VIRTUAL | MOD_CMS );
    module->ClearFlags();
    module->SetPosition( inductorPattern.m_End );

    // Generate segments
    for( unsigned jj = 1; jj < buffer.size(); jj++ )
    {
        EDGE_MODULE* PtSegm;
        PtSegm = new EDGE_MODULE( module );
        PtSegm->SetStart( buffer[jj - 1] );
        PtSegm->SetEnd( buffer[jj] );
        PtSegm->SetWidth( inductorPattern.m_Width );
        PtSegm->SetLayer( module->GetLayer() );
        PtSegm->SetShape( S_SEGMENT );
        PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() );
        PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() );
        module->GraphicalItemsList().PushBack( PtSegm );
    }

    // Place a pad on each end of coil.
    pad = new D_PAD( module );

    module->PadsList().PushFront( pad );

    pad->SetName( "1" );
    pad->SetPosition( inductorPattern.m_End );
    pad->SetPos0( pad->GetPosition() - module->GetPosition() );

    pad->SetSize( wxSize( inductorPattern.m_Width, inductorPattern.m_Width ) );

    pad->SetLayerSet( LSET( module->GetLayer() ) );
    pad->SetAttribute( PAD_ATTRIB_SMD );
    pad->SetShape( PAD_SHAPE_CIRCLE );

    D_PAD* newpad = new D_PAD( *pad );

    module->PadsList().Insert( newpad, pad->Next() );

    pad = newpad;
    pad->SetName( "2" );
    pad->SetPosition( inductorPattern.m_Start );
    pad->SetPos0( pad->GetPosition() - module->GetPosition() );

    // Modify text positions.
    wxPoint refPos( ( inductorPattern.m_Start.x + inductorPattern.m_End.x ) / 2,
                    ( inductorPattern.m_Start.y + inductorPattern.m_End.y ) / 2 );

    wxPoint valPos = refPos;

    refPos.y -= module->Reference().GetTextSize().y;
    module->Reference().SetPosition( refPos );
    valPos.y += module->Value().GetTextSize().y;
    module->Value().SetPosition( valPos );

    module->CalculateBoundingBox();
    return module;
}
Example #4
0
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
                                         UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint )
{
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

    // First, filter unnecessary stuff from the list (i.e. for multiple pads / labels modified),
    // take the first occurence of the module (we save copies of modules when one of its subitems
    // is changed).
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        ITEM_PICKER curr_picker = aItemsList.GetItemWrapper(ii);
        BOARD_ITEM* item    = (BOARD_ITEM*) aItemsList.GetPickedItem( ii );

        // For items belonging to modules, we need to save state of the parent module
        if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_MODULE_EDGE_T
                || item->Type() == PCB_PAD_T )
        {
            // Item to be stored in the undo buffer is the parent module
            item = item->GetParent();
            wxASSERT( item && item->Type() == PCB_MODULE_T );

            if( item == NULL )
                continue;

            // Check if the parent module has already been saved in another entry
            bool found = false;

            for( unsigned j = 0; j < commandToUndo->GetCount(); j++ )
            {
                if( commandToUndo->GetPickedItem( j ) == item && commandToUndo->GetPickedItemStatus( j ) == UR_CHANGED )
                {
                    found = true;
                    break;
                }
            }

            if( !found )
            {
                // Create a clean copy of the parent module
                MODULE* orig = static_cast<MODULE*>( item );
                MODULE* clone = new MODULE( *orig );
                clone->SetParent( GetBoard() );

                // Clear current flags (which can be temporary set by a current edit command)
                for( EDA_ITEM* loc_item = clone->GraphicalItemsList(); loc_item;
                        loc_item = loc_item->Next() )
                    loc_item->ClearFlags();

                for( D_PAD* pad = clone->PadsList(); pad; pad = pad->Next() )
                    pad->ClearFlags();

                clone->Reference().ClearFlags();
                clone->Value().ClearFlags();

                ITEM_PICKER picker( item, UR_CHANGED );
                picker.SetLink( clone );
                commandToUndo->PushItem( picker );

                orig->SetLastEditTime();
            }
            else
            {
                continue;
            }
        }
        else
        {
            // Normal case: all other BOARD_ITEMs, are simply copied to the new list
            commandToUndo->PushItem( curr_picker );
        }
    }

    for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
    {
        BOARD_ITEM* item    = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );
        UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );

        if( command == UR_UNSPECIFIED )
        {
            command = aTypeCommand;
            commandToUndo->SetPickedItemStatus( command, ii );
        }

        wxASSERT( item );

        switch( command )
        {
        case UR_CHANGED:
        case UR_DRILLORIGIN:
        case UR_GRIDORIGIN:

            /* If needed, create a copy of item, and put in undo list
             * in the picker, as link
             * If this link is not null, the copy is already done
             */
            if( commandToUndo->GetPickedItemLink( ii ) == NULL )
            {
                EDA_ITEM* cloned = item->Clone();
                commandToUndo->SetPickedItemLink( cloned, ii );
            }
            break;

        case UR_MOVED:
        case UR_ROTATED:
        case UR_ROTATED_CLOCKWISE:
        case UR_FLIPPED:
        case UR_NEW:
        case UR_DELETED:
            break;

        default:
        {
            wxLogDebug( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), command );
        }
        break;

        }
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after a new command one cannot redo a command */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else
    {
        // Should not occur
        wxASSERT( false );
        delete commandToUndo;
    }
}
Example #5
0
void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
        SHAPE_POLY_SET& aFeatures ) const
{
    int segsPerCircle;
    double correctionFactor;

    // Set the number of segments in arc approximations
    if( aZone->GetArcSegmentCount() == 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 = aZone->GetMinThickness() / 2;

    // When removing holes, the holes must be expanded by outline_half_thickness
    // to take in account the thickness of the zone outlines
    int zone_clearance = aZone->GetClearance() + outline_half_thickness;

    // When holes are created by non copper items (edge cut items), use only
    // the m_ZoneClearance parameter (zone clearance with no netclass clearance)
    int zone_to_edgecut_clearance = aZone->GetZoneClearance() + 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 = aZone->GetBoundingBox();
    int biggest_clearance = m_board->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
     */

    /* Use a dummy pad to calculate hole clearance 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( m_board );   // Creates a dummy parent
    D_PAD   dummypad( &dummymodule );

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

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

            if( !pad->IsOnLayer( aZone->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() != aZone->GetNetCode() ) || ( pad->GetNetCode() <= 0 ) )
            {
                int 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_SHAPE_CUSTOM can have a specific keepout, to avoid to break the shape
                    if( pad->GetShape() == PAD_SHAPE_CUSTOM
                        && pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
                    {
                        // the pad shape in zone can be its convex hull or
                        // the shape itself
                        SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
                        outline.Inflate( KiROUND( clearance * correctionFactor ), segsPerCircle );
                        pad->CustomShapeAsPolygonToBoardPosition( &outline,
                                pad->GetPosition(), pad->GetOrientation() );

                        if( pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
                        {
                            std::vector<wxPoint> convex_hull;
                            BuildConvexHull( convex_hull, outline );

                            aFeatures.NewOutline();

                            for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
                                aFeatures.Append( convex_hull[ii] );
                        }
                        else
                            aFeatures.Append( outline );
                    }
                    else
                        pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                clearance,
                                segsPerCircle,
                                correctionFactor );
                }

                continue;
            }

            // Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
            // or if they have a custom shape, because a thermal relief will break
            // the shape
            if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_NONE
                || pad->GetShape() == PAD_SHAPE_CUSTOM )
            {
                int gap = zone_clearance;
                int thermalGap = aZone->GetThermalReliefGap( pad );
                gap = std::max( gap, thermalGap );
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( gap );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    // PAD_SHAPE_CUSTOM has a specific keepout, to avoid to break the shape
                    // the pad shape in zone can be its convex hull or the shape itself
                    if( pad->GetShape() == PAD_SHAPE_CUSTOM
                        && pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
                    {
                        // the pad shape in zone can be its convex hull or
                        // the shape itself
                        SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
                        outline.Inflate( KiROUND( gap * correctionFactor ), segsPerCircle );
                        pad->CustomShapeAsPolygonToBoardPosition( &outline,
                                pad->GetPosition(), pad->GetOrientation() );

                        std::vector<wxPoint> convex_hull;
                        BuildConvexHull( convex_hull, outline );

                        aFeatures.NewOutline();

                        for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
                            aFeatures.Append( convex_hull[ii] );
                    }
                    else
                        pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                gap, segsPerCircle, correctionFactor );
                }
            }
        }
    }

    /* Add holes (i.e. tracks and vias areas as polygons outlines)
     * in cornerBufferPolysToSubstract
     */
    for( auto track : m_board->Tracks() )
    {
        if( !track->IsOnLayer( aZone->GetLayer() ) )
            continue;

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

        int 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( auto module : m_board->Modules() )
    {
        for( auto item : module->GraphicalItems() )
        {
            if( !item->IsOnLayer( aZone->GetLayer() ) && !item->IsOnLayer( Edge_Cuts ) )
                continue;

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

            item_boundingbox = item->GetBoundingBox();

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                int zclearance = zone_clearance;

                if( item->IsOnLayer( Edge_Cuts ) )
                    // use only the m_ZoneClearance, not the clearance using
                    // the netclass value, because we do not have a copper item
                    zclearance = zone_to_edgecut_clearance;

                ( (EDGE_MODULE*) item )->TransformShapeWithClearanceToPolygon(
                        aFeatures, zclearance, segsPerCircle, correctionFactor );
            }
        }
    }

    // Add graphic items (copper texts) and board edges
    // Currently copper texts have no net, so only the zone_clearance
    // is used.
    for( auto item : m_board->Drawings() )
    {
        if( item->GetLayer() != aZone->GetLayer() && item->GetLayer() != Edge_Cuts )
            continue;

        int zclearance = zone_clearance;

        if( item->GetLayer() == Edge_Cuts )
            // use only the m_ZoneClearance, not the clearance using
            // the netclass value, because we do not have a copper item
            zclearance = zone_to_edgecut_clearance;

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

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

        default:
            break;
        }
    }

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

        // If the zones share no common layers
        if( !aZone->CommonLayerExists( zone->GetLayerSet() ) )
            continue;

        if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->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 = aZone->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( auto module : m_board->Modules() )
    {
        for( auto pad : module->Pads() )
        {
            // Rejects non-standard pads with tht-only thermal reliefs
            if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
                && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
                continue;

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

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

            if( pad->GetNetCode() != aZone->GetNetCode() )
                continue;

            item_boundingbox = pad->GetBoundingBox();
            int thermalGap = aZone->GetThermalReliefGap( pad );
            item_boundingbox.Inflate( thermalGap, thermalGap );

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                CreateThermalReliefPadPolygon( aFeatures,
                        *pad, thermalGap,
                        aZone->GetThermalReliefCopperBridge( pad ),
                        aZone->GetMinThickness(),
                        segsPerCircle,
                        correctionFactor, s_thermalRot );
            }
        }
    }
}
Example #6
0
/*
 * Function DoPushPadProperties
 * Function to change pad properties for the given footprint or all identical footprints
 * aPad is the pattern. The given footprint is the parent of this pad
 * aSameFootprints: if true, make changes on all identical footprints
 * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad
 * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad
 * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad
 * aSaveForUndo: if true: create an entry in the Undo/Redo list
 *        (usually: true in Schematic editor, false in Module editor)
 */
void PCB_BASE_FRAME::DoPushPadProperties( D_PAD* aPad, bool aSameFootprints,
                                          bool aPadShapeFilter,
                                          bool aPadOrientFilter,
                                          bool aPadLayerFilter,
                                          bool aSaveForUndo )
{
    MODULE* Module_Ref = aPad->GetParent();
    double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation();

    // Prepare an undo list:
    if( aSaveForUndo )
    {
        PICKED_ITEMS_LIST itemsList;

        if( aSameFootprints )
        {
            for( MODULE* module = m_Pcb->m_Modules;  module;  module = module->Next() )
            {
                if( module->GetFPID() == Module_Ref->GetFPID() )
                {
                    ITEM_PICKER itemWrapper( module, UR_CHANGED );
                    itemsList.PushItem( itemWrapper );
                }
            }
        }
        else
        {
            ITEM_PICKER itemWrapper( Module_Ref, UR_CHANGED );
            itemsList.PushItem( itemWrapper );
        }

        SaveCopyInUndoList( itemsList, UR_CHANGED );
    }

    // Update the current module and same others modules if requested.
    for( MODULE* module = m_Pcb->m_Modules;  module;  module = module->Next() )
    {
        if( !aSameFootprints && (module != Module_Ref) )
            continue;

        if( module->GetFPID() != Module_Ref->GetFPID() )
            continue;

        // Erase module on screen
        module->SetFlags( DO_NOT_DRAW );
        m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
        module->ClearFlags( DO_NOT_DRAW );

        for( D_PAD* pad = module->PadsList();  pad;  pad = pad->Next() )
        {
            if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
                continue;

            double currpad_orient = pad->GetOrientation() - module->GetOrientation();

            if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
                continue;

            if( aPadLayerFilter && ( pad->GetLayerSet() != aPad->GetLayerSet() ) )
                continue;

            // Do not copy pad to itself, it can create issues with custom pad primitives.
            if( pad == aPad )
                continue;

            pad->ImportSettingsFromMaster( *aPad );
        }

        module->CalculateBoundingBox();
        m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
    }

    OnModify();
}