diff options
Diffstat (limited to 'pcbnew/class_zone.cpp')
-rw-r--r-- | pcbnew/class_zone.cpp | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp new file mode 100644 index 0000000..5a464fa --- /dev/null +++ b/pcbnew/class_zone.cpp @@ -0,0 +1,856 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file class_zone.cpp + * @brief Implementation of class to handle copper zones. + */ + +#include <fctsys.h> +#include <wxstruct.h> +#include <trigo.h> +#include <class_pcb_screen.h> +#include <class_drawpanel.h> +#include <kicad_string.h> +#include <pcbcommon.h> +#include <colors_selection.h> +#include <richio.h> +#include <macros.h> +#include <wxBasePcbFrame.h> +#include <msgpanel.h> + +#include <class_board.h> +#include <class_zone.h> + +#include <pcbnew.h> +#include <zones.h> +#include <math_for_graphics.h> +#include <polygon_test_point_inside.h> + + +ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) : + BOARD_CONNECTED_ITEM( aBoard, PCB_ZONE_AREA_T ) +{ + m_CornerSelection = -1; + m_IsFilled = false; // fill status : true when the zone is filled + m_FillMode = 0; // How to fill areas: 0 = use filled polygons, != 0 fill with segments + m_priority = 0; + m_smoothedPoly = NULL; + m_cornerSmoothingType = ZONE_SETTINGS::SMOOTHING_NONE; + SetIsKeepout( false ); + SetDoNotAllowCopperPour( false ); // has meaning only if m_isKeepout == true + SetDoNotAllowVias( true ); // has meaning only if m_isKeepout == true + SetDoNotAllowTracks( true ); // has meaning only if m_isKeepout == true + m_cornerRadius = 0; + SetLocalFlags( 0 ); // flags tempoarry used in zone calculations + m_Poly = new CPolyLine(); // Outlines + aBoard->GetZoneSettings().ExportSetting( *this ); +} + + +ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) : + BOARD_CONNECTED_ITEM( aZone ) +{ + m_smoothedPoly = NULL; + + // Should the copy be on the same net? + SetNetCode( aZone.GetNetCode() ); + m_Poly = new CPolyLine( *aZone.m_Poly ); + + // For corner moving, corner index to drag, or -1 if no selection + m_CornerSelection = -1; + m_IsFilled = aZone.m_IsFilled; + m_ZoneClearance = aZone.m_ZoneClearance; // clearance value + m_ZoneMinThickness = aZone.m_ZoneMinThickness; + m_FillMode = aZone.m_FillMode; // Filling mode (segments/polygons) + m_priority = aZone.m_priority; + m_ArcToSegmentsCount = aZone.m_ArcToSegmentsCount; + m_PadConnection = aZone.m_PadConnection; + m_ThermalReliefGap = aZone.m_ThermalReliefGap; + m_ThermalReliefCopperBridge = aZone.m_ThermalReliefCopperBridge; + m_FilledPolysList.Append( aZone.m_FilledPolysList ); + m_FillSegmList = aZone.m_FillSegmList; // vector <> copy + + m_isKeepout = aZone.m_isKeepout; + m_doNotAllowCopperPour = aZone.m_doNotAllowCopperPour; + m_doNotAllowVias = aZone.m_doNotAllowVias; + m_doNotAllowTracks = aZone.m_doNotAllowTracks; + + m_cornerSmoothingType = aZone.m_cornerSmoothingType; + m_cornerRadius = aZone.m_cornerRadius; + + SetLocalFlags( aZone.GetLocalFlags() ); +} + + +ZONE_CONTAINER::~ZONE_CONTAINER() +{ + delete m_Poly; + m_Poly = NULL; +} + + +EDA_ITEM* ZONE_CONTAINER::Clone() const +{ + return new ZONE_CONTAINER( *this ); +} + + +bool ZONE_CONTAINER::UnFill() +{ + bool change = ( !m_FilledPolysList.IsEmpty() ) || + ( m_FillSegmList.size() > 0 ); + + m_FilledPolysList.RemoveAllContours(); + m_FillSegmList.clear(); + m_IsFilled = false; + + return change; +} + + +const wxPoint& ZONE_CONTAINER::GetPosition() const +{ + static const wxPoint dummy; + + return m_Poly ? GetCornerPosition( 0 ) : dummy; +} + + +void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode, + const wxPoint& offset ) +{ + if( !DC ) + return; + + wxPoint seg_start, seg_end; + LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; + BOARD* brd = GetBoard(); + + EDA_COLOR_T color = brd->GetLayerColor( m_Layer ); + + if( brd->IsLayerVisible( m_Layer ) == false && ( color & HIGHLIGHT_FLAG ) != HIGHLIGHT_FLAG ) + return; + + GRSetDrawMode( DC, aDrawMode ); + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions(); + + if( displ_opts->m_ContrastModeDisplay ) + { + if( !IsOnLayer( curr_layer ) ) + ColorTurnToDarkDarkGray( &color ); + } + + if( aDrawMode & GR_HIGHLIGHT ) + ColorChangeHighlightFlag( &color, !(aDrawMode & GR_AND) ); + + ColorApplyHighlightFlag( &color ); + + SetAlpha( &color, 150 ); + + // draw the lines + int i_start_contour = 0; + std::vector<wxPoint> lines; + lines.reserve( (GetNumCorners() * 2) + 2 ); + + for( int ic = 0; ic < GetNumCorners(); ic++ ) + { + seg_start = GetCornerPosition( ic ) + offset; + + if( !m_Poly->m_CornersList.IsEndContour( ic ) && ic < GetNumCorners() - 1 ) + { + seg_end = GetCornerPosition( ic + 1 ) + offset; + } + else + { + seg_end = GetCornerPosition( i_start_contour ) + offset; + i_start_contour = ic + 1; + } + + lines.push_back( seg_start ); + lines.push_back( seg_end ); + } + + GRLineArray( panel->GetClipBox(), DC, lines, 0, color ); + + // draw hatches + lines.clear(); + lines.reserve( (m_Poly->m_HatchLines.size() * 2) + 2 ); + + for( unsigned ic = 0; ic < m_Poly->m_HatchLines.size(); ic++ ) + { + seg_start = m_Poly->m_HatchLines[ic].m_Start + offset; + seg_end = m_Poly->m_HatchLines[ic].m_End + offset; + lines.push_back( seg_start ); + lines.push_back( seg_end ); + } + + GRLineArray( panel->GetClipBox(), DC, lines, 0, color ); +} + + +void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel, + wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset ) +{ + static std::vector <wxPoint> CornersBuffer; + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions(); + + // outline_mode is false to show filled polys, + // and true to show polygons outlines only (test and debug purposes) + bool outline_mode = displ_opts->m_DisplayZonesMode == 2 ? true : false; + + if( DC == NULL ) + return; + + if( displ_opts->m_DisplayZonesMode == 1 ) // Do not show filled areas + return; + + if( m_FilledPolysList.IsEmpty() ) // Nothing to draw + return; + + BOARD* brd = GetBoard(); + LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; + EDA_COLOR_T color = brd->GetLayerColor( m_Layer ); + + if( brd->IsLayerVisible( m_Layer ) == false && ( color & HIGHLIGHT_FLAG ) != HIGHLIGHT_FLAG ) + return; + + GRSetDrawMode( DC, aDrawMode ); + + if( displ_opts->m_ContrastModeDisplay ) + { + if( !IsOnLayer( curr_layer ) ) + ColorTurnToDarkDarkGray( &color ); + } + + if( aDrawMode & GR_HIGHLIGHT ) + ColorChangeHighlightFlag( &color, !(aDrawMode & GR_AND) ); + + ColorApplyHighlightFlag( &color ); + + SetAlpha( &color, 150 ); + + + for ( int ic = 0; ic < m_FilledPolysList.OutlineCount(); ic++ ) + { + const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( ic ); + + CornersBuffer.clear(); + + wxPoint p0; + + for( int j = 0; j < path.PointCount(); j++ ) + { + const VECTOR2I& corner = path.CPoint( j ); + + wxPoint coord( corner.x + offset.x, corner.y + offset.y ); + + if( j == 0 ) + p0 = coord; + + CornersBuffer.push_back( coord ); + } + + CornersBuffer.push_back( p0 ); + + // Draw outlines: + if( ( m_ZoneMinThickness > 1 ) || outline_mode ) + { + int ilim = CornersBuffer.size() - 1; + + for( int is = 0, ie = ilim; is <= ilim; ie = is, is++ ) + { + int x0 = CornersBuffer[is].x; + int y0 = CornersBuffer[is].y; + int x1 = CornersBuffer[ie].x; + int y1 = CornersBuffer[ie].y; + + // Draw only basic outlines, not extra segments. + if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) ) + GRCSegm( panel->GetClipBox(), DC, + x0, y0, x1, y1, + m_ZoneMinThickness, color ); + else + GRFillCSegm( panel->GetClipBox(), DC, + x0, y0, x1, y1, + m_ZoneMinThickness, color ); + } + } + + // Draw areas: + if( m_FillMode == 0 && !outline_mode ) + GRPoly( panel->GetClipBox(), DC, CornersBuffer.size(), &CornersBuffer[0], + true, 0, color, color ); + } + + if( m_FillMode == 1 && !outline_mode ) // filled with segments + { + for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ ) + { + wxPoint start = m_FillSegmList[ic].m_Start + offset; + wxPoint end = m_FillSegmList[ic].m_End + offset; + + if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) ) + GRCSegm( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y, + m_ZoneMinThickness, color ); + else + GRFillCSegm( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y, + m_ZoneMinThickness, color ); + } + } +} + + +const EDA_RECT ZONE_CONTAINER::GetBoundingBox() const +{ + const int PRELOAD = 0x7FFFFFFF; // Biggest integer (32 bits) + + int ymax = -PRELOAD; + int ymin = PRELOAD; + int xmin = PRELOAD; + int xmax = -PRELOAD; + + int count = GetNumCorners(); + + for( int i = 0; i<count; ++i ) + { + wxPoint corner = GetCornerPosition( i ); + + ymax = std::max( ymax, corner.y ); + xmax = std::max( xmax, corner.x ); + ymin = std::min( ymin, corner.y ); + xmin = std::min( xmin, corner.x ); + } + + EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) ); + + return ret; +} + + +void ZONE_CONTAINER::DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC, + GR_DRAWMODE draw_mode ) +{ + GR_DRAWMODE current_gr_mode = draw_mode; + bool is_close_segment = false; + + if( !DC ) + return; + + LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; + BOARD* brd = GetBoard(); + EDA_COLOR_T color = brd->GetLayerColor( m_Layer ); + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions(); + + if( displ_opts->m_ContrastModeDisplay ) + { + if( !IsOnLayer( curr_layer ) ) + ColorTurnToDarkDarkGray( &color ); + } + + // draw the lines + wxPoint start_contour_pos = GetCornerPosition( 0 ); + int icmax = GetNumCorners() - 1; + + for( int ic = 0; ic <= icmax; ic++ ) + { + int xi = GetCornerPosition( ic ).x; + int yi = GetCornerPosition( ic ).y; + int xf, yf; + + if( !m_Poly->m_CornersList.IsEndContour( ic ) && ic < icmax ) + { + is_close_segment = false; + xf = GetCornerPosition( ic + 1 ).x; + yf = GetCornerPosition( ic + 1 ).y; + + if( m_Poly->m_CornersList.IsEndContour( ic + 1 ) || (ic == icmax - 1) ) + current_gr_mode = GR_XOR; + else + current_gr_mode = draw_mode; + } + else // Draw the line from last corner to the first corner of the current contour + { + is_close_segment = true; + current_gr_mode = GR_XOR; + xf = start_contour_pos.x; + yf = start_contour_pos.y; + + // Prepare the next contour for drawing, if exists + if( ic < icmax ) + start_contour_pos = GetCornerPosition( ic + 1 ); + } + + GRSetDrawMode( DC, current_gr_mode ); + + if( is_close_segment ) + GRLine( panel->GetClipBox(), DC, xi, yi, xf, yf, 0, WHITE ); + else + GRLine( panel->GetClipBox(), DC, xi, yi, xf, yf, 0, color ); + } +} + + +int ZONE_CONTAINER::GetThermalReliefGap( D_PAD* aPad ) const +{ + if( aPad == NULL || aPad->GetThermalGap() == 0 ) + return m_ThermalReliefGap; + else + return aPad->GetThermalGap(); +} + + +int ZONE_CONTAINER::GetThermalReliefCopperBridge( D_PAD* aPad ) const +{ + if( aPad == NULL || aPad->GetThermalWidth() == 0 ) + return m_ThermalReliefCopperBridge; + else + return aPad->GetThermalWidth(); +} + + +void ZONE_CONTAINER::SetCornerRadius( unsigned int aRadius ) +{ + m_cornerRadius = aRadius; + if( m_cornerRadius > (unsigned int) Mils2iu( MAX_ZONE_CORNER_RADIUS_MILS ) ) + m_cornerRadius = Mils2iu( MAX_ZONE_CORNER_RADIUS_MILS ); +}; + + +bool ZONE_CONTAINER::HitTest( const wxPoint& aPosition ) const +{ + if( HitTestForCorner( aPosition ) >= 0 ) + return true; + + if( HitTestForEdge( aPosition ) >= 0 ) + return true; + + return false; +} + +void ZONE_CONTAINER::SetSelectedCorner( const wxPoint& aPosition ) +{ + m_CornerSelection = HitTestForCorner( aPosition ); + + if( m_CornerSelection < 0 ) + m_CornerSelection = HitTestForEdge( aPosition ); +} + + +// Zones outlines have no thickness, so it Hit Test functions +// we must have a default distance between the test point +// and a corner or a zone edge: +#define MAX_DIST_IN_MM 0.25 + +int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos ) const +{ + int distmax = Millimeter2iu( MAX_DIST_IN_MM ); + return m_Poly->HitTestForCorner( refPos, distmax ); +} + + +int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) const +{ + int distmax = Millimeter2iu( MAX_DIST_IN_MM ); + return m_Poly->HitTestForEdge( refPos, distmax ); +} + + +bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); + EDA_RECT bbox = m_Poly->GetBoundingBox(); + bbox.Normalize(); + + if( aContained ) + return arect.Contains( bbox ); + else // Test for intersection between aRect and the polygon + // For a polygon, using its bounding box has no sense here + { + // Fast test: if aRect is outside the polygon bounding box, + // rectangles cannot intersect + if( ! bbox.Intersects( arect ) ) + return false; + + // aRect is inside the polygon bounding box, + // and can intersect the polygon: use a fine test. + // aRect intersects the polygon if at least one aRect corner + // is inside the polygon + wxPoint corner = arect.GetOrigin(); + + if( HitTestInsideZone( corner ) ) + return true; + + corner.x = arect.GetEnd().x; + + if( HitTestInsideZone( corner ) ) + return true; + + corner = arect.GetEnd(); + + if( HitTestInsideZone( corner ) ) + return true; + + corner.x = arect.GetOrigin().x; + + if( HitTestInsideZone( corner ) ) + return true; + + // No corner inside arect, but outlines can intersect arect + // if one of outline corners is inside arect + int count = m_Poly->GetCornersCount(); + for( int ii =0; ii < count; ii++ ) + { + if( arect.Contains( m_Poly->GetPos( ii ) ) ) + return true; + } + + return false; + } +} + + +int ZONE_CONTAINER::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const +{ + int myClearance = m_ZoneClearance; + +#if 0 // Maybe the netclass clearance should not come into play for a zone? + // At least the policy decision can be controlled by the zone + // itself, i.e. here. On reasons of insufficient documentation, + // the user will be less bewildered if we simply respect the + // "zone clearance" setting in the zone properties dialog. (At least + // until there is a UI boolean for this.) + + NETCLASSPTR myClass = GetNetClass(); + + if( myClass ) + myClearance = std::max( myClearance, myClass->GetClearance() ); +#endif + + if( aItem ) + { + int hisClearance = aItem->GetClearance( NULL ); + myClearance = std::max( hisClearance, myClearance ); + } + + return myClearance; +} + + +bool ZONE_CONTAINER::HitTestFilledArea( const wxPoint& aRefPos ) const +{ + return m_FilledPolysList.Contains( VECTOR2I( aRefPos.x, aRefPos.y ) ); +} + + +void ZONE_CONTAINER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) +{ + wxString msg; + + msg = _( "Zone Outline" ); + + // Display Cutout instead of Outline for holes inside a zone + // i.e. when num contour !=0 + int ncont = m_Poly->GetContour( m_CornerSelection ); + + if( ncont ) + msg << wxT( " " ) << _( "(Cutout)" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) ); + + if( GetIsKeepout() ) + { + msg.Empty(); + + if( GetDoNotAllowVias() ) + AccumulateDescription( msg, _( "No via" ) ); + + if( GetDoNotAllowTracks() ) + AccumulateDescription( msg, _("No track") ); + + if( GetDoNotAllowCopperPour() ) + AccumulateDescription( msg, _("No copper pour") ); + + aList.push_back( MSG_PANEL_ITEM( _( "Keepout" ), msg, RED ) ); + } + else if( IsOnCopperLayer() ) + { + if( GetNetCode() >= 0 ) + { + NETINFO_ITEM* net = GetNet(); + + if( net ) + msg = net->GetNetname(); + else // Should not occur + msg = _( "<unknown>" ); + } + else // a netcode < 0 is an error + msg = wxT( "<error>" ); + + aList.push_back( MSG_PANEL_ITEM( _( "NetName" ), msg, RED ) ); + + // Display net code : (useful in test or debug) + msg.Printf( wxT( "%d" ), GetNetCode() ); + aList.push_back( MSG_PANEL_ITEM( _( "NetCode" ), msg, RED ) ); + + // Display priority level + msg.Printf( wxT( "%d" ), GetPriority() ); + aList.push_back( MSG_PANEL_ITEM( _( "Priority" ), msg, BLUE ) ); + } + else + { + aList.push_back( MSG_PANEL_ITEM( _( "Non Copper Zone" ), wxEmptyString, RED ) ); + } + + aList.push_back( MSG_PANEL_ITEM( _( "Layer" ), GetLayerName(), BROWN ) ); + + msg.Printf( wxT( "%d" ), (int) m_Poly->m_CornersList.GetCornersCount() ); + aList.push_back( MSG_PANEL_ITEM( _( "Corners" ), msg, BLUE ) ); + + if( m_FillMode ) + msg = _( "Segments" ); + else + msg = _( "Polygons" ); + + aList.push_back( MSG_PANEL_ITEM( _( "Fill Mode" ), msg, BROWN ) ); + + // Useful for statistics : + msg.Printf( wxT( "%d" ), (int) m_Poly->m_HatchLines.size() ); + aList.push_back( MSG_PANEL_ITEM( _( "Hatch Lines" ), msg, BLUE ) ); + + if( !m_FilledPolysList.IsEmpty() ) + { + msg.Printf( wxT( "%d" ), m_FilledPolysList.TotalVertices() ); + aList.push_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg, BLUE ) ); + } +} + + +/* Geometric transforms: */ + +void ZONE_CONTAINER::Move( const wxPoint& offset ) +{ + /* move outlines */ + for( unsigned ii = 0; ii < m_Poly->m_CornersList.GetCornersCount(); ii++ ) + { + SetCornerPosition( ii, GetCornerPosition( ii ) + offset ); + } + + m_Poly->Hatch(); + + m_FilledPolysList.Move( VECTOR2I( offset.x, offset.y ) ); + + for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ ) + { + m_FillSegmList[ic].m_Start += offset; + m_FillSegmList[ic].m_End += offset; + } +} + + +void ZONE_CONTAINER::MoveEdge( const wxPoint& offset, int aEdge ) +{ + // Move the start point of the selected edge: + SetCornerPosition( aEdge, GetCornerPosition( aEdge ) + offset ); + + // Move the end point of the selected edge: + if( m_Poly->m_CornersList.IsEndContour( aEdge ) || aEdge == GetNumCorners() - 1 ) + { + int icont = m_Poly->GetContour( aEdge ); + aEdge = m_Poly->GetContourStart( icont ); + } + else + { + aEdge++; + } + + SetCornerPosition( aEdge, GetCornerPosition( aEdge ) + offset ); + + m_Poly->Hatch(); +} + + +void ZONE_CONTAINER::Rotate( const wxPoint& centre, double angle ) +{ + wxPoint pos; + + for( unsigned ic = 0; ic < m_Poly->m_CornersList.GetCornersCount(); ic++ ) + { + pos = m_Poly->m_CornersList.GetPos( ic ); + RotatePoint( &pos, centre, angle ); + m_Poly->SetX( ic, pos.x ); + m_Poly->SetY( ic, pos.y ); + } + + m_Poly->Hatch(); + + /* rotate filled areas: */ + for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic ) + RotatePoint( &ic->x, &ic->y, centre.x, centre.y, angle ); + + for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ ) + { + RotatePoint( &m_FillSegmList[ic].m_Start, centre, angle ); + RotatePoint( &m_FillSegmList[ic].m_End, centre, angle ); + } +} + + +void ZONE_CONTAINER::Flip( const wxPoint& aCentre ) +{ + Mirror( aCentre ); + int copperLayerCount = GetBoard()->GetCopperLayerCount(); + SetLayer( FlipLayer( GetLayer(), copperLayerCount ) ); +} + + +void ZONE_CONTAINER::Mirror( const wxPoint& mirror_ref ) +{ + for( unsigned ic = 0; ic < m_Poly->m_CornersList.GetCornersCount(); ic++ ) + { + int py = mirror_ref.y - m_Poly->m_CornersList.GetY( ic ); + m_Poly->m_CornersList.SetY( ic, py + mirror_ref.y ); + } + + m_Poly->Hatch(); + + for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic ) + { + int py = mirror_ref.y - ic->y; + ic->y = py + mirror_ref.y; + } + + for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ ) + { + MIRROR( m_FillSegmList[ic].m_Start.y, mirror_ref.y ); + MIRROR( m_FillSegmList[ic].m_End.y, mirror_ref.y ); + } +} + + +void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) +{ + m_Parent = src->m_Parent; + m_Layer = src->m_Layer; + SetNetCode( src->GetNetCode() ); + SetTimeStamp( src->m_TimeStamp ); + m_Poly->RemoveAllContours(); + m_Poly->Copy( src->m_Poly ); // copy outlines + m_CornerSelection = -1; // For corner moving, corner index to drag, + // or -1 if no selection + m_ZoneClearance = src->m_ZoneClearance; // clearance value + m_ZoneMinThickness = src->m_ZoneMinThickness; + m_FillMode = src->m_FillMode; // Filling mode (segments/polygons) + m_ArcToSegmentsCount = src->m_ArcToSegmentsCount; + m_PadConnection = src->m_PadConnection; + m_ThermalReliefGap = src->m_ThermalReliefGap; + m_ThermalReliefCopperBridge = src->m_ThermalReliefCopperBridge; + m_Poly->SetHatchStyle( src->m_Poly->GetHatchStyle() ); + m_Poly->SetHatchPitch( src->m_Poly->GetHatchPitch() ); + m_Poly->m_HatchLines = src->m_Poly->m_HatchLines; // Copy vector <CSegment> + m_FilledPolysList.RemoveAllContours(); + m_FilledPolysList.Append( src->m_FilledPolysList ); + m_FillSegmList.clear(); + m_FillSegmList = src->m_FillSegmList; +} + + +ZoneConnection ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const +{ + if( aPad == NULL || aPad->GetZoneConnection() == PAD_ZONE_CONN_INHERITED ) + return m_PadConnection; + else + return aPad->GetZoneConnection(); +} + + +void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon ) +{ + if( aPolygon.empty() ) + return; + + for( unsigned i = 0; i < aPolygon.size(); i++ ) + { + if( i == 0 ) + m_Poly->Start( GetLayer(), aPolygon[i].x, aPolygon[i].y, GetHatchStyle() ); + else + AppendCorner( aPolygon[i] ); + } + + m_Poly->CloseLastContour(); +} + + + +wxString ZONE_CONTAINER::GetSelectMenuText() const +{ + wxString text; + NETINFO_ITEM* net; + BOARD* board = GetBoard(); + + int ncont = m_Poly->GetContour( m_CornerSelection ); + + if( ncont ) + text << wxT( " " ) << _( "(Cutout)" ); + + if( GetIsKeepout() ) + text << wxT( " " ) << _( "(Keepout)" ); + + text << wxString::Format( wxT( " (%08lX)" ), m_TimeStamp ); + + // Display net name for copper zones + if( !GetIsKeepout() ) + { + if( GetNetCode() >= 0 ) + { + if( board ) + { + net = GetNet(); + + if( net ) + { + text << wxT( " [" ) << net->GetNetname() << wxT( "]" ); + } + } + else + { + text << _( "** NO BOARD DEFINED **" ); + } + } + else + { // A netcode < 0 is an error: + // Netname not found or area not initialised + text << wxT( " [" ) << GetNetname() << wxT( "]" ); + text << wxT( " <" ) << _( "Not Found" ) << wxT( ">" ); + } + } + + wxString msg; + msg.Printf( _( "Zone Outline %s on %s" ), GetChars( text ), + GetChars( GetLayerName() ) ); + + return msg; +} |