You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

855 lines
25 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
12 years ago
12 years ago
14 years ago
12 years ago
12 years ago
12 years ago
14 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file class_zone.cpp
  27. * @brief Implementation of class to handle copper zones.
  28. */
  29. #include <fctsys.h>
  30. #include <wxstruct.h>
  31. #include <trigo.h>
  32. #include <class_pcb_screen.h>
  33. #include <class_drawpanel.h>
  34. #include <kicad_string.h>
  35. #include <pcbcommon.h>
  36. #include <colors_selection.h>
  37. #include <richio.h>
  38. #include <macros.h>
  39. #include <wxBasePcbFrame.h>
  40. #include <msgpanel.h>
  41. #include <class_board.h>
  42. #include <class_zone.h>
  43. #include <pcbnew.h>
  44. #include <zones.h>
  45. #include <math_for_graphics.h>
  46. #include <polygon_test_point_inside.h>
  47. ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) :
  48. BOARD_CONNECTED_ITEM( aBoard, PCB_ZONE_AREA_T )
  49. {
  50. m_CornerSelection = -1;
  51. m_IsFilled = false; // fill status : true when the zone is filled
  52. m_FillMode = 0; // How to fill areas: 0 = use filled polygons, != 0 fill with segments
  53. m_priority = 0;
  54. m_smoothedPoly = NULL;
  55. m_cornerSmoothingType = ZONE_SETTINGS::SMOOTHING_NONE;
  56. SetIsKeepout( false );
  57. SetDoNotAllowCopperPour( false ); // has meaning only if m_isKeepout == true
  58. SetDoNotAllowVias( true ); // has meaning only if m_isKeepout == true
  59. SetDoNotAllowTracks( true ); // has meaning only if m_isKeepout == true
  60. m_cornerRadius = 0;
  61. SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
  62. m_Poly = new CPolyLine(); // Outlines
  63. aBoard->GetZoneSettings().ExportSetting( *this );
  64. }
  65. ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) :
  66. BOARD_CONNECTED_ITEM( aZone )
  67. {
  68. m_smoothedPoly = NULL;
  69. // Should the copy be on the same net?
  70. SetNetCode( aZone.GetNetCode() );
  71. m_Poly = new CPolyLine( *aZone.m_Poly );
  72. // For corner moving, corner index to drag, or -1 if no selection
  73. m_CornerSelection = -1;
  74. m_IsFilled = aZone.m_IsFilled;
  75. m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
  76. m_ZoneMinThickness = aZone.m_ZoneMinThickness;
  77. m_FillMode = aZone.m_FillMode; // Filling mode (segments/polygons)
  78. m_priority = aZone.m_priority;
  79. m_ArcToSegmentsCount = aZone.m_ArcToSegmentsCount;
  80. m_PadConnection = aZone.m_PadConnection;
  81. m_ThermalReliefGap = aZone.m_ThermalReliefGap;
  82. m_ThermalReliefCopperBridge = aZone.m_ThermalReliefCopperBridge;
  83. m_FilledPolysList.Append( aZone.m_FilledPolysList );
  84. m_FillSegmList = aZone.m_FillSegmList; // vector <> copy
  85. m_isKeepout = aZone.m_isKeepout;
  86. m_doNotAllowCopperPour = aZone.m_doNotAllowCopperPour;
  87. m_doNotAllowVias = aZone.m_doNotAllowVias;
  88. m_doNotAllowTracks = aZone.m_doNotAllowTracks;
  89. m_cornerSmoothingType = aZone.m_cornerSmoothingType;
  90. m_cornerRadius = aZone.m_cornerRadius;
  91. SetLocalFlags( aZone.GetLocalFlags() );
  92. }
  93. ZONE_CONTAINER& ZONE_CONTAINER::operator=( const ZONE_CONTAINER& aOther )
  94. {
  95. BOARD_CONNECTED_ITEM::operator=( aOther );
  96. m_Poly->RemoveAllContours();
  97. m_Poly->Copy( aOther.m_Poly ); // copy outlines
  98. m_CornerSelection = -1; // for corner moving, corner index to drag or -1 if no selection
  99. m_ZoneClearance = aOther.m_ZoneClearance; // clearance value
  100. m_ZoneMinThickness = aOther.m_ZoneMinThickness;
  101. m_FillMode = aOther.m_FillMode; // filling mode (segments/polygons)
  102. m_ArcToSegmentsCount = aOther.m_ArcToSegmentsCount;
  103. m_PadConnection = aOther.m_PadConnection;
  104. m_ThermalReliefGap = aOther.m_ThermalReliefGap;
  105. m_ThermalReliefCopperBridge = aOther.m_ThermalReliefCopperBridge;
  106. m_Poly->SetHatchStyle( aOther.m_Poly->GetHatchStyle() );
  107. m_Poly->SetHatchPitch( aOther.m_Poly->GetHatchPitch() );
  108. m_Poly->m_HatchLines = aOther.m_Poly->m_HatchLines; // copy vector <CSegment>
  109. m_FilledPolysList.RemoveAllContours();
  110. m_FilledPolysList.Append( aOther.m_FilledPolysList );
  111. m_FillSegmList.clear();
  112. m_FillSegmList = aOther.m_FillSegmList;
  113. return *this;
  114. }
  115. ZONE_CONTAINER::~ZONE_CONTAINER()
  116. {
  117. delete m_Poly;
  118. m_Poly = NULL;
  119. }
  120. EDA_ITEM* ZONE_CONTAINER::Clone() const
  121. {
  122. return new ZONE_CONTAINER( *this );
  123. }
  124. bool ZONE_CONTAINER::UnFill()
  125. {
  126. bool change = ( !m_FilledPolysList.IsEmpty() ) ||
  127. ( m_FillSegmList.size() > 0 );
  128. m_FilledPolysList.RemoveAllContours();
  129. m_FillSegmList.clear();
  130. m_IsFilled = false;
  131. return change;
  132. }
  133. const wxPoint& ZONE_CONTAINER::GetPosition() const
  134. {
  135. static const wxPoint dummy;
  136. return m_Poly ? GetCornerPosition( 0 ) : dummy;
  137. }
  138. void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode,
  139. const wxPoint& offset )
  140. {
  141. if( !DC )
  142. return;
  143. wxPoint seg_start, seg_end;
  144. LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
  145. BOARD* brd = GetBoard();
  146. EDA_COLOR_T color = brd->GetLayerColor( m_Layer );
  147. if( brd->IsLayerVisible( m_Layer ) == false && ( color & HIGHLIGHT_FLAG ) != HIGHLIGHT_FLAG )
  148. return;
  149. GRSetDrawMode( DC, aDrawMode );
  150. DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
  151. if( displ_opts->m_ContrastModeDisplay )
  152. {
  153. if( !IsOnLayer( curr_layer ) )
  154. ColorTurnToDarkDarkGray( &color );
  155. }
  156. if( aDrawMode & GR_HIGHLIGHT )
  157. ColorChangeHighlightFlag( &color, !(aDrawMode & GR_AND) );
  158. ColorApplyHighlightFlag( &color );
  159. SetAlpha( &color, 150 );
  160. // draw the lines
  161. int i_start_contour = 0;
  162. std::vector<wxPoint> lines;
  163. lines.reserve( (GetNumCorners() * 2) + 2 );
  164. for( int ic = 0; ic < GetNumCorners(); ic++ )
  165. {
  166. seg_start = GetCornerPosition( ic ) + offset;
  167. if( !m_Poly->m_CornersList.IsEndContour( ic ) && ic < GetNumCorners() - 1 )
  168. {
  169. seg_end = GetCornerPosition( ic + 1 ) + offset;
  170. }
  171. else
  172. {
  173. seg_end = GetCornerPosition( i_start_contour ) + offset;
  174. i_start_contour = ic + 1;
  175. }
  176. lines.push_back( seg_start );
  177. lines.push_back( seg_end );
  178. }
  179. GRLineArray( panel->GetClipBox(), DC, lines, 0, color );
  180. // draw hatches
  181. lines.clear();
  182. lines.reserve( (m_Poly->m_HatchLines.size() * 2) + 2 );
  183. for( unsigned ic = 0; ic < m_Poly->m_HatchLines.size(); ic++ )
  184. {
  185. seg_start = m_Poly->m_HatchLines[ic].m_Start + offset;
  186. seg_end = m_Poly->m_HatchLines[ic].m_End + offset;
  187. lines.push_back( seg_start );
  188. lines.push_back( seg_end );
  189. }
  190. GRLineArray( panel->GetClipBox(), DC, lines, 0, color );
  191. }
  192. void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
  193. wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset )
  194. {
  195. static std::vector <wxPoint> CornersBuffer;
  196. DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
  197. // outline_mode is false to show filled polys,
  198. // and true to show polygons outlines only (test and debug purposes)
  199. bool outline_mode = displ_opts->m_DisplayZonesMode == 2 ? true : false;
  200. if( DC == NULL )
  201. return;
  202. if( displ_opts->m_DisplayZonesMode == 1 ) // Do not show filled areas
  203. return;
  204. if( m_FilledPolysList.IsEmpty() ) // Nothing to draw
  205. return;
  206. BOARD* brd = GetBoard();
  207. LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
  208. EDA_COLOR_T color = brd->GetLayerColor( m_Layer );
  209. if( brd->IsLayerVisible( m_Layer ) == false && ( color & HIGHLIGHT_FLAG ) != HIGHLIGHT_FLAG )
  210. return;
  211. GRSetDrawMode( DC, aDrawMode );
  212. if( displ_opts->m_ContrastModeDisplay )
  213. {
  214. if( !IsOnLayer( curr_layer ) )
  215. ColorTurnToDarkDarkGray( &color );
  216. }
  217. if( aDrawMode & GR_HIGHLIGHT )
  218. ColorChangeHighlightFlag( &color, !(aDrawMode & GR_AND) );
  219. ColorApplyHighlightFlag( &color );
  220. SetAlpha( &color, 150 );
  221. for ( int ic = 0; ic < m_FilledPolysList.OutlineCount(); ic++ )
  222. {
  223. const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( ic );
  224. CornersBuffer.clear();
  225. wxPoint p0;
  226. for( int j = 0; j < path.PointCount(); j++ )
  227. {
  228. const VECTOR2I& corner = path.CPoint( j );
  229. wxPoint coord( corner.x + offset.x, corner.y + offset.y );
  230. if( j == 0 )
  231. p0 = coord;
  232. CornersBuffer.push_back( coord );
  233. }
  234. CornersBuffer.push_back( p0 );
  235. // Draw outlines:
  236. if( ( m_ZoneMinThickness > 1 ) || outline_mode )
  237. {
  238. int ilim = CornersBuffer.size() - 1;
  239. for( int is = 0, ie = ilim; is <= ilim; ie = is, is++ )
  240. {
  241. int x0 = CornersBuffer[is].x;
  242. int y0 = CornersBuffer[is].y;
  243. int x1 = CornersBuffer[ie].x;
  244. int y1 = CornersBuffer[ie].y;
  245. // Draw only basic outlines, not extra segments.
  246. if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
  247. GRCSegm( panel->GetClipBox(), DC,
  248. x0, y0, x1, y1,
  249. m_ZoneMinThickness, color );
  250. else
  251. GRFillCSegm( panel->GetClipBox(), DC,
  252. x0, y0, x1, y1,
  253. m_ZoneMinThickness, color );
  254. }
  255. }
  256. // Draw areas:
  257. if( m_FillMode == 0 && !outline_mode )
  258. GRPoly( panel->GetClipBox(), DC, CornersBuffer.size(), &CornersBuffer[0],
  259. true, 0, color, color );
  260. }
  261. if( m_FillMode == 1 && !outline_mode ) // filled with segments
  262. {
  263. for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
  264. {
  265. wxPoint start = m_FillSegmList[ic].m_Start + offset;
  266. wxPoint end = m_FillSegmList[ic].m_End + offset;
  267. if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
  268. GRCSegm( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y,
  269. m_ZoneMinThickness, color );
  270. else
  271. GRFillCSegm( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y,
  272. m_ZoneMinThickness, color );
  273. }
  274. }
  275. }
  276. const EDA_RECT ZONE_CONTAINER::GetBoundingBox() const
  277. {
  278. const int PRELOAD = 0x7FFFFFFF; // Biggest integer (32 bits)
  279. int ymax = -PRELOAD;
  280. int ymin = PRELOAD;
  281. int xmin = PRELOAD;
  282. int xmax = -PRELOAD;
  283. int count = GetNumCorners();
  284. for( int i = 0; i<count; ++i )
  285. {
  286. wxPoint corner = GetCornerPosition( i );
  287. ymax = std::max( ymax, corner.y );
  288. xmax = std::max( xmax, corner.x );
  289. ymin = std::min( ymin, corner.y );
  290. xmin = std::min( xmin, corner.x );
  291. }
  292. EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
  293. return ret;
  294. }
  295. void ZONE_CONTAINER::DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC,
  296. GR_DRAWMODE draw_mode )
  297. {
  298. GR_DRAWMODE current_gr_mode = draw_mode;
  299. bool is_close_segment = false;
  300. if( !DC )
  301. return;
  302. LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
  303. BOARD* brd = GetBoard();
  304. EDA_COLOR_T color = brd->GetLayerColor( m_Layer );
  305. DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
  306. if( displ_opts->m_ContrastModeDisplay )
  307. {
  308. if( !IsOnLayer( curr_layer ) )
  309. ColorTurnToDarkDarkGray( &color );
  310. }
  311. // draw the lines
  312. wxPoint start_contour_pos = GetCornerPosition( 0 );
  313. int icmax = GetNumCorners() - 1;
  314. for( int ic = 0; ic <= icmax; ic++ )
  315. {
  316. int xi = GetCornerPosition( ic ).x;
  317. int yi = GetCornerPosition( ic ).y;
  318. int xf, yf;
  319. if( !m_Poly->m_CornersList.IsEndContour( ic ) && ic < icmax )
  320. {
  321. is_close_segment = false;
  322. xf = GetCornerPosition( ic + 1 ).x;
  323. yf = GetCornerPosition( ic + 1 ).y;
  324. if( m_Poly->m_CornersList.IsEndContour( ic + 1 ) || (ic == icmax - 1) )
  325. current_gr_mode = GR_XOR;
  326. else
  327. current_gr_mode = draw_mode;
  328. }
  329. else // Draw the line from last corner to the first corner of the current contour
  330. {
  331. is_close_segment = true;
  332. current_gr_mode = GR_XOR;
  333. xf = start_contour_pos.x;
  334. yf = start_contour_pos.y;
  335. // Prepare the next contour for drawing, if exists
  336. if( ic < icmax )
  337. start_contour_pos = GetCornerPosition( ic + 1 );
  338. }
  339. GRSetDrawMode( DC, current_gr_mode );
  340. if( is_close_segment )
  341. GRLine( panel->GetClipBox(), DC, xi, yi, xf, yf, 0, WHITE );
  342. else
  343. GRLine( panel->GetClipBox(), DC, xi, yi, xf, yf, 0, color );
  344. }
  345. }
  346. int ZONE_CONTAINER::GetThermalReliefGap( D_PAD* aPad ) const
  347. {
  348. if( aPad == NULL || aPad->GetThermalGap() == 0 )
  349. return m_ThermalReliefGap;
  350. else
  351. return aPad->GetThermalGap();
  352. }
  353. int ZONE_CONTAINER::GetThermalReliefCopperBridge( D_PAD* aPad ) const
  354. {
  355. if( aPad == NULL || aPad->GetThermalWidth() == 0 )
  356. return m_ThermalReliefCopperBridge;
  357. else
  358. return aPad->GetThermalWidth();
  359. }
  360. void ZONE_CONTAINER::SetCornerRadius( unsigned int aRadius )
  361. {
  362. m_cornerRadius = aRadius;
  363. if( m_cornerRadius > (unsigned int) Mils2iu( MAX_ZONE_CORNER_RADIUS_MILS ) )
  364. m_cornerRadius = Mils2iu( MAX_ZONE_CORNER_RADIUS_MILS );
  365. };
  366. bool ZONE_CONTAINER::HitTest( const wxPoint& aPosition ) const
  367. {
  368. if( HitTestForCorner( aPosition ) >= 0 )
  369. return true;
  370. if( HitTestForEdge( aPosition ) >= 0 )
  371. return true;
  372. return false;
  373. }
  374. void ZONE_CONTAINER::SetSelectedCorner( const wxPoint& aPosition )
  375. {
  376. m_CornerSelection = HitTestForCorner( aPosition );
  377. if( m_CornerSelection < 0 )
  378. m_CornerSelection = HitTestForEdge( aPosition );
  379. }
  380. // Zones outlines have no thickness, so it Hit Test functions
  381. // we must have a default distance between the test point
  382. // and a corner or a zone edge:
  383. #define MAX_DIST_IN_MM 0.25
  384. int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos ) const
  385. {
  386. int distmax = Millimeter2iu( MAX_DIST_IN_MM );
  387. return m_Poly->HitTestForCorner( refPos, distmax );
  388. }
  389. int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) const
  390. {
  391. int distmax = Millimeter2iu( MAX_DIST_IN_MM );
  392. return m_Poly->HitTestForEdge( refPos, distmax );
  393. }
  394. bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  395. {
  396. EDA_RECT arect = aRect;
  397. arect.Inflate( aAccuracy );
  398. EDA_RECT bbox = m_Poly->GetBoundingBox();
  399. bbox.Normalize();
  400. if( aContained )
  401. return arect.Contains( bbox );
  402. else // Test for intersection between aRect and the polygon
  403. // For a polygon, using its bounding box has no sense here
  404. {
  405. // Fast test: if aRect is outside the polygon bounding box,
  406. // rectangles cannot intersect
  407. if( ! bbox.Intersects( arect ) )
  408. return false;
  409. // aRect is inside the polygon bounding box,
  410. // and can intersect the polygon: use a fine test.
  411. // aRect intersects the polygon if at least one aRect corner
  412. // is inside the polygon
  413. wxPoint corner = arect.GetOrigin();
  414. if( HitTestInsideZone( corner ) )
  415. return true;
  416. corner.x = arect.GetEnd().x;
  417. if( HitTestInsideZone( corner ) )
  418. return true;
  419. corner = arect.GetEnd();
  420. if( HitTestInsideZone( corner ) )
  421. return true;
  422. corner.x = arect.GetOrigin().x;
  423. if( HitTestInsideZone( corner ) )
  424. return true;
  425. // No corner inside arect, but outlines can intersect arect
  426. // if one of outline corners is inside arect
  427. int count = m_Poly->GetCornersCount();
  428. for( int ii =0; ii < count; ii++ )
  429. {
  430. if( arect.Contains( m_Poly->GetPos( ii ) ) )
  431. return true;
  432. }
  433. return false;
  434. }
  435. }
  436. int ZONE_CONTAINER::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const
  437. {
  438. int myClearance = m_ZoneClearance;
  439. #if 0 // Maybe the netclass clearance should not come into play for a zone?
  440. // At least the policy decision can be controlled by the zone
  441. // itself, i.e. here. On reasons of insufficient documentation,
  442. // the user will be less bewildered if we simply respect the
  443. // "zone clearance" setting in the zone properties dialog. (At least
  444. // until there is a UI boolean for this.)
  445. NETCLASSPTR myClass = GetNetClass();
  446. if( myClass )
  447. myClearance = std::max( myClearance, myClass->GetClearance() );
  448. #endif
  449. if( aItem )
  450. {
  451. int hisClearance = aItem->GetClearance( NULL );
  452. myClearance = std::max( hisClearance, myClearance );
  453. }
  454. return myClearance;
  455. }
  456. bool ZONE_CONTAINER::HitTestFilledArea( const wxPoint& aRefPos ) const
  457. {
  458. return m_FilledPolysList.Contains( VECTOR2I( aRefPos.x, aRefPos.y ) );
  459. }
  460. void ZONE_CONTAINER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
  461. {
  462. wxString msg;
  463. msg = _( "Zone Outline" );
  464. // Display Cutout instead of Outline for holes inside a zone
  465. // i.e. when num contour !=0
  466. int ncont = m_Poly->GetContour( m_CornerSelection );
  467. if( ncont )
  468. msg << wxT( " " ) << _( "(Cutout)" );
  469. aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
  470. if( GetIsKeepout() )
  471. {
  472. msg.Empty();
  473. if( GetDoNotAllowVias() )
  474. AccumulateDescription( msg, _( "No via" ) );
  475. if( GetDoNotAllowTracks() )
  476. AccumulateDescription( msg, _("No track") );
  477. if( GetDoNotAllowCopperPour() )
  478. AccumulateDescription( msg, _("No copper pour") );
  479. aList.push_back( MSG_PANEL_ITEM( _( "Keepout" ), msg, RED ) );
  480. }
  481. else if( IsOnCopperLayer() )
  482. {
  483. if( GetNetCode() >= 0 )
  484. {
  485. NETINFO_ITEM* net = GetNet();
  486. if( net )
  487. msg = net->GetNetname();
  488. else // Should not occur
  489. msg = _( "<unknown>" );
  490. }
  491. else // a netcode < 0 is an error
  492. msg = wxT( "<error>" );
  493. aList.push_back( MSG_PANEL_ITEM( _( "NetName" ), msg, RED ) );
  494. // Display net code : (useful in test or debug)
  495. msg.Printf( wxT( "%d" ), GetNetCode() );
  496. aList.push_back( MSG_PANEL_ITEM( _( "NetCode" ), msg, RED ) );
  497. // Display priority level
  498. msg.Printf( wxT( "%d" ), GetPriority() );
  499. aList.push_back( MSG_PANEL_ITEM( _( "Priority" ), msg, BLUE ) );
  500. }
  501. else
  502. {
  503. aList.push_back( MSG_PANEL_ITEM( _( "Non Copper Zone" ), wxEmptyString, RED ) );
  504. }
  505. aList.push_back( MSG_PANEL_ITEM( _( "Layer" ), GetLayerName(), BROWN ) );
  506. msg.Printf( wxT( "%d" ), (int) m_Poly->m_CornersList.GetCornersCount() );
  507. aList.push_back( MSG_PANEL_ITEM( _( "Corners" ), msg, BLUE ) );
  508. if( m_FillMode )
  509. msg = _( "Segments" );
  510. else
  511. msg = _( "Polygons" );
  512. aList.push_back( MSG_PANEL_ITEM( _( "Fill Mode" ), msg, BROWN ) );
  513. // Useful for statistics :
  514. msg.Printf( wxT( "%d" ), (int) m_Poly->m_HatchLines.size() );
  515. aList.push_back( MSG_PANEL_ITEM( _( "Hatch Lines" ), msg, BLUE ) );
  516. if( !m_FilledPolysList.IsEmpty() )
  517. {
  518. msg.Printf( wxT( "%d" ), m_FilledPolysList.TotalVertices() );
  519. aList.push_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg, BLUE ) );
  520. }
  521. }
  522. /* Geometric transforms: */
  523. void ZONE_CONTAINER::Move( const wxPoint& offset )
  524. {
  525. /* move outlines */
  526. for( unsigned ii = 0; ii < m_Poly->m_CornersList.GetCornersCount(); ii++ )
  527. {
  528. SetCornerPosition( ii, GetCornerPosition( ii ) + offset );
  529. }
  530. m_Poly->Hatch();
  531. m_FilledPolysList.Move( VECTOR2I( offset.x, offset.y ) );
  532. for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
  533. {
  534. m_FillSegmList[ic].m_Start += offset;
  535. m_FillSegmList[ic].m_End += offset;
  536. }
  537. }
  538. void ZONE_CONTAINER::MoveEdge( const wxPoint& offset, int aEdge )
  539. {
  540. // Move the start point of the selected edge:
  541. SetCornerPosition( aEdge, GetCornerPosition( aEdge ) + offset );
  542. // Move the end point of the selected edge:
  543. if( m_Poly->m_CornersList.IsEndContour( aEdge ) || aEdge == GetNumCorners() - 1 )
  544. {
  545. int icont = m_Poly->GetContour( aEdge );
  546. aEdge = m_Poly->GetContourStart( icont );
  547. }
  548. else
  549. {
  550. aEdge++;
  551. }
  552. SetCornerPosition( aEdge, GetCornerPosition( aEdge ) + offset );
  553. m_Poly->Hatch();
  554. }
  555. void ZONE_CONTAINER::Rotate( const wxPoint& centre, double angle )
  556. {
  557. wxPoint pos;
  558. for( unsigned ic = 0; ic < m_Poly->m_CornersList.GetCornersCount(); ic++ )
  559. {
  560. pos = m_Poly->m_CornersList.GetPos( ic );
  561. RotatePoint( &pos, centre, angle );
  562. m_Poly->SetX( ic, pos.x );
  563. m_Poly->SetY( ic, pos.y );
  564. }
  565. m_Poly->Hatch();
  566. /* rotate filled areas: */
  567. for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic )
  568. RotatePoint( &ic->x, &ic->y, centre.x, centre.y, angle );
  569. for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
  570. {
  571. RotatePoint( &m_FillSegmList[ic].m_Start, centre, angle );
  572. RotatePoint( &m_FillSegmList[ic].m_End, centre, angle );
  573. }
  574. }
  575. void ZONE_CONTAINER::Flip( const wxPoint& aCentre )
  576. {
  577. Mirror( aCentre );
  578. int copperLayerCount = GetBoard()->GetCopperLayerCount();
  579. SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
  580. }
  581. void ZONE_CONTAINER::Mirror( const wxPoint& mirror_ref )
  582. {
  583. for( unsigned ic = 0; ic < m_Poly->m_CornersList.GetCornersCount(); ic++ )
  584. {
  585. int py = mirror_ref.y - m_Poly->m_CornersList.GetY( ic );
  586. m_Poly->m_CornersList.SetY( ic, py + mirror_ref.y );
  587. }
  588. m_Poly->Hatch();
  589. for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic )
  590. {
  591. int py = mirror_ref.y - ic->y;
  592. ic->y = py + mirror_ref.y;
  593. }
  594. for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
  595. {
  596. MIRROR( m_FillSegmList[ic].m_Start.y, mirror_ref.y );
  597. MIRROR( m_FillSegmList[ic].m_End.y, mirror_ref.y );
  598. }
  599. }
  600. ZoneConnection ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const
  601. {
  602. if( aPad == NULL || aPad->GetZoneConnection() == PAD_ZONE_CONN_INHERITED )
  603. return m_PadConnection;
  604. else
  605. return aPad->GetZoneConnection();
  606. }
  607. void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon )
  608. {
  609. if( aPolygon.empty() )
  610. return;
  611. for( unsigned i = 0; i < aPolygon.size(); i++ )
  612. {
  613. if( i == 0 )
  614. m_Poly->Start( GetLayer(), aPolygon[i].x, aPolygon[i].y, GetHatchStyle() );
  615. else
  616. AppendCorner( aPolygon[i] );
  617. }
  618. m_Poly->CloseLastContour();
  619. }
  620. wxString ZONE_CONTAINER::GetSelectMenuText() const
  621. {
  622. wxString text;
  623. NETINFO_ITEM* net;
  624. BOARD* board = GetBoard();
  625. int ncont = m_Poly->GetContour( m_CornerSelection );
  626. if( ncont )
  627. text << wxT( " " ) << _( "(Cutout)" );
  628. if( GetIsKeepout() )
  629. text << wxT( " " ) << _( "(Keepout)" );
  630. text << wxString::Format( wxT( " (%08lX)" ), m_TimeStamp );
  631. // Display net name for copper zones
  632. if( !GetIsKeepout() )
  633. {
  634. if( GetNetCode() >= 0 )
  635. {
  636. if( board )
  637. {
  638. net = GetNet();
  639. if( net )
  640. {
  641. text << wxT( " [" ) << net->GetNetname() << wxT( "]" );
  642. }
  643. }
  644. else
  645. {
  646. text << _( "** NO BOARD DEFINED **" );
  647. }
  648. }
  649. else
  650. { // A netcode < 0 is an error:
  651. // Netname not found or area not initialised
  652. text << wxT( " [" ) << GetNetname() << wxT( "]" );
  653. text << wxT( " <" ) << _( "Not Found" ) << wxT( ">" );
  654. }
  655. }
  656. wxString msg;
  657. msg.Printf( _( "Zone Outline %s on %s" ), GetChars( text ),
  658. GetChars( GetLayerName() ) );
  659. return msg;
  660. }