Commit fa472950 authored by charras's avatar charras
Browse files

pcbnew: better protection against malformed zones

parent 55bc5be7
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@
/* ioascii.cpp */

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "pcbnew.h"
@@ -22,8 +21,6 @@
#include "cvpcb.h"
#endif

#include "protos.h"

/* Format des structures de sauvegarde type ASCII :

 Structure PAD:
@@ -859,7 +856,9 @@ int WinEDA_PcbFrame::ReadPcbFile( FILE* File, bool Append )
        {
            ZONE_CONTAINER * zone_descr = new ZONE_CONTAINER(m_Pcb);
            zone_descr->ReadDescr( File, &LineNum );
            if ( zone_descr->GetNumCorners( ) > 2 )     // should not occur
                m_Pcb->Add(zone_descr);
            else delete zone_descr;
            continue;
        }

+62 −0
Original line number Diff line number Diff line
@@ -21,6 +21,68 @@ static void Genere_Segments_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code
static bool          Zone_Debug = false;
static unsigned long s_TimeStamp; /* Time stamp common to all segments relative to the new created zone */




/***********************************************************/
int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb )
/***********************************************************/
/** function BuildFilledPolysListData
 * Build m_FilledPolysList data from real outlines (m_Poly)
 * in order to have drawable (and plottable) filled polygons
 * drawable filled polygons are polygons without hole
 * @param aPcb: the current board (can be NULL for non copper zones)
 * @return number of polygons
 * This function does not add holes for pads and tracks but calls
 * AddClearanceAreasPolygonsToPolysList() to do that for copper layers
 */
{

    // Currently, for copper zones,  we can use segment filling or filling by polygon areas
    // if m_GridFillValue == 0 polygon areas will be used (No Grid)
    if ( IsOnCopperLayer() && ( m_GridFillValue != 0 ) )
        return 0;

    m_FilledPolysList.clear();
    /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
    * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building this zone
    */

    if ( GetNumCorners( ) <= 2 )    // malformed zone. Kbool does not like it ...
        return 0;

    m_Poly->MakeKboolPoly( -1, -1, NULL, true );
    int count = 0;
    while( m_Poly->GetKboolEngine()->StartPolygonGet() )
    {
        CPolyPt corner(0,0,false);
        while( m_Poly->GetKboolEngine()->PolygonHasMorePoints() )
        {
            corner.x = (int)m_Poly->GetKboolEngine()->GetPolygonXPoint();
            corner.y = (int)m_Poly->GetKboolEngine()->GetPolygonYPoint();
            corner.end_contour = false;
            m_FilledPolysList.push_back(corner);
            count ++;
        }
        corner.end_contour = true;
        m_FilledPolysList.pop_back();
        m_FilledPolysList.push_back(corner);
        m_Poly->GetKboolEngine()->EndPolygonGet();
    }

    m_Poly->FreeKboolEngine();

    /* For copper layers, we now must add holes in the Polygon list.
    holes are pads and tracks with their clearance area
    */

    if ( IsOnCopperLayer() )
        AddClearanceAreasPolygonsToPolysList( aPcb );

    return count;
}


/*****************************************************************************/
int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
/*****************************************************************************/
+1 −1
Original line number Diff line number Diff line
@@ -356,7 +356,7 @@ void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_contain
    {
        DrawPanel->PostDirtyRect( zone_container->GetBoundingBox() );
        if( DC )
        {
        {  // Remove the full zone because this is no more an area
            Delete_Zone_Fill( DC, NULL, zone_container->m_TimeStamp );
            zone_container->DrawFilledArea( DrawPanel, DC, GR_XOR );
        }
+0 −55
Original line number Diff line number Diff line
@@ -164,58 +164,3 @@ void DialogNonCopperZonesEditor::OnCancelClick( wxCommandEvent& event )
    EndModal( ZONE_ABORT );
}


/***********************************************************/
int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb )
/***********************************************************/
/** function BuildFilledPolysListData
 * Build m_FilledPolysList data from real outlines (m_Poly)
 * in order to have drawable (and plottable) filled polygons
 * drawable filled polygons are polygons without hole
 * @param aPcb: the current board (can be NULL for non copper zones)
 * @return number of polygons
 * This function does not add holes for pads and tracks but calls
 * AddClearanceAreasPolygonsToPolysList() to do that for copper layers
 */
{

    // Currently, for copper zones,  we can use segment filling or filling by polygon areas
    // if m_GridFillValue == 0 polygon areas will be used (No Grid)
    if ( IsOnCopperLayer() && ( m_GridFillValue != 0 ) )
        return 0;

    m_FilledPolysList.clear();
    /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
    * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building this zone
    */
    m_Poly->MakeKboolPoly( -1, -1, NULL, true );
    int count = 0;
    while( m_Poly->GetKboolEngine()->StartPolygonGet() )
    {
        CPolyPt corner(0,0,false);
        while( m_Poly->GetKboolEngine()->PolygonHasMorePoints() )
        {
            corner.x = (int)m_Poly->GetKboolEngine()->GetPolygonXPoint();
            corner.y = (int)m_Poly->GetKboolEngine()->GetPolygonYPoint();
            corner.end_contour = false;
            m_FilledPolysList.push_back(corner);
            count ++;
        }
        corner.end_contour = true;
        m_FilledPolysList.pop_back();
        m_FilledPolysList.push_back(corner);
        m_Poly->GetKboolEngine()->EndPolygonGet();
    }

    m_Poly->FreeKboolEngine();

    /* For copper layers, we now must add holes in the Polygon list.
    holes are pads and tracks with their clearance area
    */

    if ( IsOnCopperLayer() )
        AddClearanceAreasPolygonsToPolysList( aPcb );

    return count;
}
+14 −82
Original line number Diff line number Diff line
@@ -335,6 +335,17 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
                if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
                    m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
        }
    }
    // Test for bad areas: all zones must have more than 2 corners:
    // Note: should not happen, but just in case.
    for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; )
    {
        ZONE_CONTAINER* zone = m_ZoneDescriptorList[ia1];
        if( zone->GetNumCorners( ) >= 3 )
            ia1++;
        // Remove zone because it is incorrect:
        else
            RemoveArea( zone );
    }
     return test;
}
@@ -387,21 +398,6 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit
                                ret = CombineAreas( curr_area, area2 );
                            if( ret == 1 )
                            {
                                if( bMessageBox && bDontShowIntersectionWarning == false )
                                {
                                    wxString str;
                                    str.Printf(
                                        wxT(
                                            "Areas %d and %d of net \"%s\" intersect and will be combined.\n" ),
                                        ia1 + 1,
                                        ia2 + 1,
                                        curr_area->m_Netname.GetData() );
                                    str += wxT(
                                        "If they are complex, this may take a few seconds." );
                                    wxMessageBox( str );

//                                    bDontShowIntersectionWarning = dlg.bDontShowBoxState;
                                }
                                mod_ia1 = true;
                            }
                            else if( ret == 2 )
@@ -428,6 +424,7 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit
                ia1--; // if modified, we need to check it again
        }
    }

   return 0;
}

@@ -683,13 +680,6 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
{
    if( area_ref == area_to_combine )
        ASSERT( 0 );
#if 0

    // test for intersection
    int test = TestAreaIntersection( area_ref, area_to_combine );
    if( test != 1 )
        return test; // no intersection
#endif

    // polygons intersect, combine them
    std::vector<CArc> arc_array1;
@@ -798,64 +788,6 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
}


#if 0   // Currently not used: work in progress

/**
 * Function Is_Area_Inside_Area
 * Test a given area to see if it is inside an other area, or an other area is inside the given area
 * an area is inside an other are if ALL its edges are inside the other area
 * @param Area_Ref: the given area to compare with other areas
 * used to remove redundant areas
 */
ZONE_CONTAINER* BOARD::Is_Area_Inside_Area( ZONE_CONTAINER* Area_Ref )
{
    int corners_inside_count;

    for( int ia = 0; ia < GetAreaCount(); ia++ )
    {
        ZONE_CONTAINER* Area_To_Test = GetArea( ia );

        if( Area_Ref == Area_To_Test )
            continue;

        // test for same layer
        if( Area_Ref->GetLayer() != Area_To_Test->GetLayer() )
            continue;

        // test if Area_Ref inside Area_To_Test
        corners_inside_count = Area_Ref->m_Poly->GetNumCorners();
        for( int ic = 0; ic < Area_Ref->m_Poly->GetNumCorners(); ic++ )
        {
            int x = Area_Ref->m_Poly->GetX( ic );
            int y = Area_Ref->m_Poly->GetY( ic );
            if( Area_To_Test->m_Poly->TestPointInside( x, y ) )
                corners_inside_count--;
        }

        if( corners_inside_count == 0 )
            return Area_Ref;

        // test if Area_To_Test inside Area_Ref
        corners_inside_count = Area_To_Test->m_Poly->GetNumCorners();
        for( int ic2 = 0; ic2 < Area_To_Test->m_Poly->GetNumCorners(); ic2++ )
        {
            int x = Area_To_Test->m_Poly->GetX( ic2 );
            int y = Area_To_Test->m_Poly->GetY( ic2 );
            if( Area_Ref->m_Poly->TestPointInside( x, y ) )
                corners_inside_count--;
        }

        if( corners_inside_count == 0 )
            return Area_Ref;
    }

    return NULL;
}


#endif


/**
 * Function Test_Drc_Areas_Outlines_To_Areas_Outlines
 * Test Areas outlines for DRC: