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.

951 lines
31 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
18 years ago
14 years ago
18 years ago
18 years ago
14 years ago
18 years ago
14 years ago
14 years ago
18 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
18 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
18 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 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) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. /**
  27. * @file zones_by_polygon.cpp
  28. */
  29. #include <fctsys.h>
  30. #include <appl_wxstruct.h>
  31. #include <class_drawpanel.h>
  32. #include <confirm.h>
  33. #include <wxPcbStruct.h>
  34. #include <class_board.h>
  35. #include <class_zone.h>
  36. #include <pcbnew.h>
  37. #include <zones.h>
  38. #include <pcbnew_id.h>
  39. #include <protos.h>
  40. #include <zones_functions_for_undo_redo.h>
  41. #include <drc_stuff.h>
  42. // Outline creation:
  43. static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC );
  44. static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  45. const wxPoint& aPosition, bool aErase );
  46. // Corner moving
  47. static void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC );
  48. static void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel,
  49. wxDC* aDC,
  50. const wxPoint& aPosition,
  51. bool aErase );
  52. // Local variables
  53. static wxPoint s_CornerInitialPosition; // Used to abort a move corner command
  54. static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted)
  55. static bool s_AddCutoutToCurrentZone; // if true, the next outline will be added to s_CurrentZone
  56. static ZONE_CONTAINER* s_CurrentZone; // if != NULL, these ZONE_CONTAINER params will be used for the next zone
  57. static wxPoint s_CursorLastPosition; // in move zone outline, last cursor position. Used to calculate the move vector
  58. static PICKED_ITEMS_LIST s_PickedList; // a picked list to save zones for undo/redo command
  59. static PICKED_ITEMS_LIST s_AuxiliaryList; // a picked list to store zones that are deleted or added when combined
  60. void PCB_EDIT_FRAME::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* aZone )
  61. {
  62. if( !aZone )
  63. return;
  64. s_AddCutoutToCurrentZone = false;
  65. s_CurrentZone = aZone;
  66. // set zone settings to the current zone
  67. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  68. zoneInfo << *aZone;
  69. SetZoneSettings( zoneInfo );
  70. // Use the general event handler to set others params (like toolbar)
  71. wxCommandEvent evt;
  72. evt.SetId( aZone->GetIsKeepout() ? ID_PCB_KEEPOUT_AREA_BUTT : ID_PCB_ZONES_BUTT );
  73. OnSelectTool( evt );
  74. }
  75. void PCB_EDIT_FRAME::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* aZone )
  76. {
  77. if( !aZone )
  78. return;
  79. s_AddCutoutToCurrentZone = true;
  80. s_CurrentZone = aZone;
  81. // set zones setup to the current zone
  82. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  83. zoneInfo << *aZone;
  84. SetZoneSettings( zoneInfo );
  85. // Use the general event handle to set others params (like toolbar)
  86. wxCommandEvent evt;
  87. evt.SetId( aZone->GetIsKeepout() ? ID_PCB_KEEPOUT_AREA_BUTT : ID_PCB_ZONES_BUTT );
  88. OnSelectTool( evt );
  89. }
  90. void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone )
  91. {
  92. ZONE_CONTAINER* newZone = new ZONE_CONTAINER( GetBoard() );
  93. newZone->Copy( aZone );
  94. newZone->UnFill();
  95. ZONE_SETTINGS zoneSettings;
  96. zoneSettings << *aZone;
  97. bool success;
  98. if( aZone->GetIsKeepout() )
  99. success = InvokeKeepoutAreaEditor( this, &zoneSettings );
  100. else if( aZone->IsOnCopperLayer() )
  101. success = InvokeCopperZonesEditor( this, &zoneSettings );
  102. else
  103. success = InvokeNonCopperZonesEditor( this, aZone, &zoneSettings );
  104. if( success )
  105. {
  106. zoneSettings.ExportSetting( *newZone );
  107. newZone->Outline()->Hatch();
  108. s_AuxiliaryList.ClearListAndDeleteItems();
  109. s_PickedList.ClearListAndDeleteItems();
  110. SaveCopyOfZones( s_PickedList, GetBoard(), newZone->GetNet(), newZone->GetLayer() );
  111. GetBoard()->Add( newZone );
  112. ITEM_PICKER picker( newZone, UR_NEW );
  113. s_PickedList.PushItem( picker );
  114. GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines
  115. // Combine zones if possible
  116. GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, newZone );
  117. // Redraw zones
  118. GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() );
  119. GetBoard()->RedrawFilledAreas( m_canvas, aDC, GR_OR, newZone->GetLayer() );
  120. if( GetBoard()->GetAreaIndex( newZone ) >= 0
  121. && GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( newZone, true ) )
  122. {
  123. DisplayError( this, _( "Duplicate Zone: The outline of the duplicated zone fails DRC check!" ) );
  124. }
  125. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  126. SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
  127. s_PickedList.ClearItemsList();
  128. OnModify();
  129. }
  130. else
  131. delete newZone;
  132. }
  133. int PCB_EDIT_FRAME::Delete_LastCreatedCorner( wxDC* DC )
  134. {
  135. ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
  136. if( !zone )
  137. return 0;
  138. if( !zone->GetNumCorners() )
  139. return 0;
  140. zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );
  141. if( zone->GetNumCorners() > 2 )
  142. {
  143. zone->Outline()->DeleteCorner( zone->GetNumCorners() - 1 );
  144. if( m_canvas->IsMouseCaptured() )
  145. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  146. }
  147. else
  148. {
  149. m_canvas->SetMouseCapture( NULL, NULL );
  150. SetCurItem( NULL );
  151. zone->RemoveAllContours();
  152. zone->ClearFlags();
  153. }
  154. return zone->GetNumCorners();
  155. }
  156. /**
  157. * Function Abort_Zone_Create_Outline
  158. * cancels the Begin_Zone command if at least one EDGE_ZONE was created.
  159. */
  160. static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC )
  161. {
  162. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
  163. ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;
  164. if( zone )
  165. {
  166. zone->DrawWhileCreateOutline( Panel, DC, GR_XOR );
  167. zone->ClearFlags();
  168. zone->RemoveAllContours();
  169. }
  170. pcbframe->SetCurItem( NULL );
  171. s_AddCutoutToCurrentZone = false;
  172. s_CurrentZone = NULL;
  173. Panel->SetMouseCapture( NULL, NULL );
  174. }
  175. void PCB_EDIT_FRAME::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone,
  176. int corner_id, bool IsNewCorner )
  177. {
  178. if( aZone->IsOnCopperLayer() ) // Show the Net
  179. {
  180. if( GetBoard()->IsHighLightNetON() && DC )
  181. {
  182. HighLight( DC ); // Remove old highlight selection
  183. }
  184. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  185. zoneInfo.m_NetcodeSelection = aZone->GetNet();
  186. SetZoneSettings( zoneInfo );
  187. GetBoard()->SetHighLightNet( aZone->GetNet() );
  188. if( DC )
  189. HighLight( DC );
  190. }
  191. // Prepare copy of old zones, for undo/redo.
  192. // if the corner is new, remove it from list, save and insert it in list
  193. int cx = aZone->Outline()->GetX( corner_id );
  194. int cy = aZone->Outline()->GetY( corner_id );
  195. if ( IsNewCorner )
  196. aZone->Outline()->DeleteCorner( corner_id );
  197. s_AuxiliaryList.ClearListAndDeleteItems();
  198. s_PickedList.ClearListAndDeleteItems();
  199. SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(),
  200. aZone->GetLayer() );
  201. if ( IsNewCorner )
  202. aZone->Outline()->InsertCorner(corner_id-1, cx, cy );
  203. aZone->SetFlags( IN_EDIT );
  204. m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
  205. Abort_Zone_Move_Corner_Or_Outlines );
  206. s_CornerInitialPosition = aZone->GetCornerPosition( corner_id );
  207. s_CornerIsNew = IsNewCorner;
  208. s_AddCutoutToCurrentZone = false;
  209. s_CurrentZone = NULL;
  210. }
  211. void PCB_EDIT_FRAME::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC,
  212. ZONE_CONTAINER* aZone,
  213. int corner_id )
  214. {
  215. aZone->SetFlags( IS_DRAGGED );
  216. aZone->SetSelectedCorner( corner_id );
  217. m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
  218. Abort_Zone_Move_Corner_Or_Outlines );
  219. s_CursorLastPosition = s_CornerInitialPosition = GetCrossHairPosition();
  220. s_AddCutoutToCurrentZone = false;
  221. s_CurrentZone = NULL;
  222. s_PickedList.ClearListAndDeleteItems();
  223. s_AuxiliaryList.ClearListAndDeleteItems();
  224. SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(),
  225. aZone->GetLayer() );
  226. }
  227. void PCB_EDIT_FRAME::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* aZone )
  228. {
  229. // Show the Net
  230. if( aZone->IsOnCopperLayer() ) // Show the Net
  231. {
  232. if( GetBoard()->IsHighLightNetON() )
  233. {
  234. HighLight( DC ); // Remove old highlight selection
  235. }
  236. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  237. zoneInfo.m_NetcodeSelection = aZone->GetNet();
  238. SetZoneSettings( zoneInfo );
  239. GetBoard()->SetHighLightNet( aZone->GetNet() );
  240. HighLight( DC );
  241. }
  242. s_PickedList.ClearListAndDeleteItems();
  243. s_AuxiliaryList.ClearListAndDeleteItems();
  244. SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(),
  245. aZone->GetLayer() );
  246. aZone->SetFlags( IS_MOVED );
  247. m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
  248. Abort_Zone_Move_Corner_Or_Outlines );
  249. s_CursorLastPosition = s_CornerInitialPosition = GetCrossHairPosition();
  250. s_CornerIsNew = false;
  251. s_AddCutoutToCurrentZone = false;
  252. s_CurrentZone = NULL;
  253. }
  254. void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* aZone )
  255. {
  256. aZone->ClearFlags();
  257. m_canvas->SetMouseCapture( NULL, NULL );
  258. if( DC )
  259. aZone->Draw( m_canvas, DC, GR_OR );
  260. OnModify();
  261. s_AddCutoutToCurrentZone = false;
  262. s_CurrentZone = NULL;
  263. SetCurItem( NULL ); // This outline can be deleted when merging outlines
  264. // Combine zones if possible
  265. wxBusyCursor dummy;
  266. GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
  267. m_canvas->Refresh();
  268. int ii = GetBoard()->GetAreaIndex( aZone ); // test if aZone exists
  269. if( ii < 0 )
  270. aZone = NULL; // was removed by combining zones
  271. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  272. SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
  273. s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  274. int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( aZone, true );
  275. if( error_count )
  276. {
  277. DisplayError( this, _( "Area: DRC outline error" ) );
  278. }
  279. }
  280. void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone )
  281. {
  282. OnModify();
  283. if( aZone->Outline()->GetCornersCount() <= 3 )
  284. {
  285. m_canvas->RefreshDrawingRect( aZone->GetBoundingBox() );
  286. if( DC )
  287. { // Remove the full zone because this is no more an area
  288. aZone->UnFill();
  289. aZone->DrawFilledArea( m_canvas, DC, GR_XOR );
  290. }
  291. GetBoard()->Delete( aZone );
  292. return;
  293. }
  294. LAYER_NUM layer = aZone->GetLayer();
  295. if( DC )
  296. {
  297. GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
  298. GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
  299. }
  300. s_AuxiliaryList.ClearListAndDeleteItems();
  301. s_PickedList. ClearListAndDeleteItems();
  302. SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(), aZone->GetLayer() );
  303. aZone->Outline()->DeleteCorner( aZone->GetSelectedCorner() );
  304. // modify zones outlines according to the new aZone shape
  305. GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
  306. if( DC )
  307. {
  308. GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
  309. GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
  310. }
  311. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  312. SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
  313. s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  314. int ii = GetBoard()->GetAreaIndex( aZone ); // test if aZone exists
  315. if( ii < 0 )
  316. aZone = NULL; // aZone does not exist anymore, after combining zones
  317. int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( aZone, true );
  318. if( error_count )
  319. {
  320. DisplayError( this, _( "Area: DRC outline error" ) );
  321. }
  322. }
  323. /**
  324. * Function Abort_Zone_Move_Corner_Or_Outlines
  325. * cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
  326. */
  327. void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC )
  328. {
  329. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
  330. ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem();
  331. if( zone->IsMoving() )
  332. {
  333. wxPoint offset;
  334. offset = s_CornerInitialPosition - s_CursorLastPosition;
  335. zone->Move( offset );
  336. }
  337. else if( zone->IsDragging() )
  338. {
  339. wxPoint offset;
  340. offset = s_CornerInitialPosition - s_CursorLastPosition;
  341. zone->MoveEdge( offset );
  342. }
  343. else
  344. {
  345. if( s_CornerIsNew )
  346. {
  347. zone->Outline()->DeleteCorner( zone->GetSelectedCorner() );
  348. }
  349. else
  350. {
  351. wxPoint pos = s_CornerInitialPosition;
  352. zone->Outline()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y );
  353. }
  354. }
  355. Panel->SetMouseCapture( NULL, NULL );
  356. s_AuxiliaryList.ClearListAndDeleteItems();
  357. s_PickedList. ClearListAndDeleteItems();
  358. Panel->Refresh();
  359. pcbframe->SetCurItem( NULL );
  360. zone->ClearFlags();
  361. s_AddCutoutToCurrentZone = false;
  362. s_CurrentZone = NULL;
  363. }
  364. /// Redraws the zone outline when moving a corner according to the cursor position
  365. void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  366. const wxPoint& aPosition, bool aErase )
  367. {
  368. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
  369. ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem();
  370. if( aErase ) // Undraw edge in old position
  371. {
  372. zone->Draw( aPanel, aDC, GR_XOR );
  373. }
  374. wxPoint pos = pcbframe->GetCrossHairPosition();
  375. if( zone->IsMoving() )
  376. {
  377. wxPoint offset;
  378. offset = pos - s_CursorLastPosition;
  379. zone->Move( offset );
  380. s_CursorLastPosition = pos;
  381. }
  382. else if( zone->IsDragging() )
  383. {
  384. wxPoint offset;
  385. offset = pos - s_CursorLastPosition;
  386. zone->MoveEdge( offset );
  387. s_CursorLastPosition = pos;
  388. }
  389. else
  390. {
  391. zone->Outline()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y );
  392. }
  393. zone->Draw( aPanel, aDC, GR_XOR );
  394. }
  395. int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC )
  396. {
  397. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  398. // verify if s_CurrentZone exists (could be deleted since last selection) :
  399. int ii;
  400. for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
  401. {
  402. if( s_CurrentZone == GetBoard()->GetArea( ii ) )
  403. break;
  404. }
  405. if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection
  406. {
  407. s_AddCutoutToCurrentZone = false;
  408. s_CurrentZone = NULL;
  409. }
  410. // If no zone contour in progress, a new zone is being created:
  411. if( !GetBoard()->m_CurrentZoneContour )
  412. {
  413. if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT &&
  414. getActiveLayer() >= FIRST_NON_COPPER_LAYER )
  415. {
  416. DisplayError( this,
  417. _( "Error: a keepout area is allowed only on copper layers" ) );
  418. return 0;
  419. }
  420. else
  421. GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() );
  422. }
  423. ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
  424. if( zone->GetNumCorners() == 0 ) // Start a new contour: init zone params (net, layer ...)
  425. {
  426. if( !s_CurrentZone ) // A new outline is created, from scratch
  427. {
  428. ZONE_EDIT_T edited;
  429. // Init zone params to reasonable values
  430. zone->SetLayer( getActiveLayer() );
  431. // Prompt user for parameters:
  432. m_canvas->SetIgnoreMouseEvents( true );
  433. if( zone->IsOnCopperLayer() )
  434. {
  435. // Put a zone on a copper layer
  436. if( GetBoard()->GetHighLightNetCode() > 0 )
  437. {
  438. zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode();
  439. zone->SetNet( zoneInfo.m_NetcodeSelection );
  440. zone->SetNetNameFromNetCode( );
  441. }
  442. double tmp = ZONE_THERMAL_RELIEF_GAP_MIL;
  443. wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp );
  444. zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS);
  445. tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL;
  446. wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY,
  447. &tmp );
  448. zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS );
  449. tmp = ZONE_CLEARANCE_MIL;
  450. wxGetApp().GetSettings()->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY,
  451. &tmp );
  452. zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS );
  453. tmp = ZONE_THICKNESS_MIL;
  454. wxGetApp().GetSettings()->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY,
  455. &tmp );
  456. zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS );
  457. zoneInfo.m_CurrentZone_Layer = zone->GetLayer();
  458. if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT )
  459. {
  460. zoneInfo.SetIsKeepout( true );
  461. // Netcode and netname are irrelevant,
  462. // so ensure they are cleared
  463. zone->SetNet( 0 );
  464. zone->SetNetName( wxEmptyString );
  465. edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
  466. }
  467. else
  468. {
  469. zoneInfo.SetIsKeepout( false );
  470. edited = InvokeCopperZonesEditor( this, &zoneInfo );
  471. }
  472. }
  473. else // Put a zone on a non copper layer (technical layer)
  474. {
  475. zoneInfo.SetIsKeepout( false );
  476. zoneInfo.m_NetcodeSelection = 0; // No net for non copper zones
  477. edited = InvokeNonCopperZonesEditor( this, zone, &zoneInfo );
  478. }
  479. m_canvas->MoveCursorToCrossHair();
  480. m_canvas->SetIgnoreMouseEvents( false );
  481. if( edited == ZONE_ABORT )
  482. return 0;
  483. // Switch active layer to the selected zone layer
  484. setActiveLayer( zoneInfo.m_CurrentZone_Layer );
  485. SetZoneSettings( zoneInfo );
  486. }
  487. else
  488. {
  489. // Start a new contour: init zone params (net and layer) from an existing
  490. // zone (add cutout or similar zone)
  491. zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer();
  492. setActiveLayer( s_CurrentZone->GetLayer() );
  493. zoneInfo << *s_CurrentZone;
  494. SetZoneSettings( zoneInfo );
  495. }
  496. // Show the Net for zones on copper layers
  497. if( zoneInfo.m_CurrentZone_Layer < FIRST_NON_COPPER_LAYER &&
  498. ! zoneInfo.GetIsKeepout() )
  499. {
  500. if( s_CurrentZone )
  501. {
  502. zoneInfo.m_NetcodeSelection = s_CurrentZone->GetNet();
  503. GetBoard()->SetZoneSettings( zoneInfo );
  504. }
  505. if( GetBoard()->IsHighLightNetON() )
  506. {
  507. HighLight( DC ); // Remove old highlight selection
  508. }
  509. GetBoard()->SetHighLightNet( zoneInfo.m_NetcodeSelection );
  510. HighLight( DC );
  511. }
  512. if( !s_AddCutoutToCurrentZone )
  513. s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command)
  514. }
  515. // if first segment
  516. if( zone->GetNumCorners() == 0 )
  517. {
  518. zone->SetFlags( IS_NEW );
  519. zone->SetTimeStamp( GetNewTimeStamp() );
  520. zoneInfo.ExportSetting( *zone );
  521. zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer,
  522. GetCrossHairPosition().x,
  523. GetCrossHairPosition().y,
  524. zone->GetHatchStyle() );
  525. zone->AppendCorner( GetCrossHairPosition() );
  526. if( g_Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() )
  527. {
  528. zone->ClearFlags();
  529. zone->RemoveAllContours();
  530. // use the form of SetCurItem() which does not write to the msg panel,
  531. // SCREEN::SetCurItem(), so the DRC error remains on screen.
  532. // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo().
  533. GetScreen()->SetCurItem( NULL );
  534. DisplayError( this,
  535. _( "DRC error: this start point is inside or too close an other area" ) );
  536. return 0;
  537. }
  538. SetCurItem( zone );
  539. m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline );
  540. }
  541. else // edge in progress:
  542. {
  543. ii = zone->GetNumCorners() - 1;
  544. // edge in progress : the current corner coordinate was set
  545. // by Show_New_Edge_While_Move_Mouse
  546. if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) )
  547. {
  548. if( !g_Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) )
  549. {
  550. // Ok, we can add a new corner
  551. if( m_canvas->IsMouseCaptured() )
  552. m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
  553. zone->AppendCorner( GetCrossHairPosition() );
  554. SetCurItem( zone ); // calls DisplayInfo().
  555. if( m_canvas->IsMouseCaptured() )
  556. m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
  557. }
  558. }
  559. }
  560. return zone->GetNumCorners();
  561. }
  562. bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
  563. {
  564. ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
  565. if( !zone )
  566. return true;
  567. // Validate the current outline:
  568. if( zone->GetNumCorners() <= 2 ) // An outline must have 3 corners or more
  569. {
  570. Abort_Zone_Create_Outline( m_canvas, DC );
  571. return true;
  572. }
  573. // Remove the last corner if is is at the same location as the prevoius corner
  574. zone->Outline()->RemoveNullSegments();
  575. // Validate the current edge:
  576. int icorner = zone->GetNumCorners() - 1;
  577. if( zone->IsOnCopperLayer() )
  578. {
  579. if( g_Drc_On && m_drc->Drc( zone, icorner - 1 ) == BAD_DRC ) // we can't validate last edge
  580. return false;
  581. if( g_Drc_On && m_drc->Drc( zone, icorner ) == BAD_DRC ) // we can't validate the closing edge
  582. {
  583. DisplayError( this,
  584. _( "DRC error: closing this area creates a drc error with an other area" ) );
  585. m_canvas->MoveCursorToCrossHair();
  586. return false;
  587. }
  588. }
  589. zone->ClearFlags();
  590. zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );
  591. m_canvas->SetMouseCapture( NULL, NULL );
  592. // Undraw old drawings, because they can have important changes
  593. LAYER_NUM layer = zone->GetLayer();
  594. GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
  595. GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
  596. // Save initial zones configuration, for undo/redo, before adding new zone
  597. s_AuxiliaryList.ClearListAndDeleteItems();
  598. s_PickedList.ClearListAndDeleteItems();
  599. SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() );
  600. // Put new zone in list
  601. if( !s_CurrentZone )
  602. {
  603. zone->Outline()->CloseLastContour(); // Close the current corner list
  604. GetBoard()->Add( zone );
  605. GetBoard()->m_CurrentZoneContour = NULL;
  606. // Add this zone in picked list, as new item
  607. ITEM_PICKER picker( zone, UR_NEW );
  608. s_PickedList.PushItem( picker );
  609. }
  610. else // Append this outline as a cutout to an existing zone
  611. {
  612. for( int ii = 0; ii < zone->GetNumCorners(); ii++ )
  613. {
  614. s_CurrentZone->AppendCorner( zone->GetCornerPosition( ii ) );
  615. }
  616. s_CurrentZone->Outline()->CloseLastContour(); // Close the current corner list
  617. zone->RemoveAllContours(); // All corners are copied in s_CurrentZone. Free corner list.
  618. zone = s_CurrentZone;
  619. }
  620. s_AddCutoutToCurrentZone = false;
  621. s_CurrentZone = NULL;
  622. GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines
  623. // Combine zones if possible :
  624. GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, zone );
  625. // Redraw the real edge zone :
  626. GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
  627. GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
  628. int ii = GetBoard()->GetAreaIndex( zone ); // test if zone exists
  629. if( ii < 0 )
  630. zone = NULL; // was removed by combining zones
  631. int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true );
  632. if( error_count )
  633. {
  634. DisplayError( this, _( "Area: DRC outline error" ) );
  635. }
  636. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  637. SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
  638. s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  639. OnModify();
  640. return true;
  641. }
  642. /* Redraws the zone outlines when moving mouse
  643. */
  644. static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  645. const wxPoint& aPosition, bool aErase )
  646. {
  647. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
  648. wxPoint c_pos = pcbframe->GetCrossHairPosition();
  649. ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;
  650. if( !zone )
  651. return;
  652. int icorner = zone->GetNumCorners() - 1;
  653. if( icorner < 1 )
  654. return; // We must have 2 (or more) corners
  655. if( aErase ) // Undraw edge in old position
  656. {
  657. zone->DrawWhileCreateOutline( aPanel, aDC );
  658. }
  659. // Redraw the current edge in its new position
  660. if( pcbframe->GetZoneSettings().m_Zone_45_Only )
  661. {
  662. // calculate the new position as allowed
  663. wxPoint StartPoint = zone->GetCornerPosition( icorner - 1 );
  664. CalculateSegmentEndPoint( c_pos, StartPoint.x, StartPoint.y, &c_pos.x, &c_pos.y );
  665. }
  666. zone->SetCornerPosition( icorner, c_pos );
  667. zone->DrawWhileCreateOutline( aPanel, aDC );
  668. }
  669. void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
  670. {
  671. ZONE_EDIT_T edited;
  672. ZONE_SETTINGS zoneInfo = GetZoneSettings();
  673. m_canvas->SetIgnoreMouseEvents( true );
  674. // Save initial zones configuration, for undo/redo, before adding new zone
  675. // note the net name and the layer can be changed, so we must save all zones
  676. s_AuxiliaryList.ClearListAndDeleteItems();
  677. s_PickedList.ClearListAndDeleteItems();
  678. SaveCopyOfZones(s_PickedList, GetBoard(), -1, UNDEFINED_LAYER );
  679. if( aZone->GetIsKeepout() )
  680. {
  681. // edit a keepout area on a copper layer
  682. zoneInfo << *aZone;
  683. edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
  684. }
  685. else if( aZone->GetLayer() < FIRST_NON_COPPER_LAYER )
  686. {
  687. // edit a zone on a copper layer
  688. zoneInfo << *aZone;
  689. edited = InvokeCopperZonesEditor( this, &zoneInfo );
  690. }
  691. else
  692. {
  693. edited = InvokeNonCopperZonesEditor( this, aZone, &zoneInfo );
  694. }
  695. m_canvas->MoveCursorToCrossHair();
  696. m_canvas->SetIgnoreMouseEvents( false );
  697. if( edited == ZONE_ABORT )
  698. {
  699. s_AuxiliaryList.ClearListAndDeleteItems();
  700. s_PickedList.ClearListAndDeleteItems();
  701. return;
  702. }
  703. SetZoneSettings( zoneInfo );
  704. if( edited == ZONE_EXPORT_VALUES )
  705. {
  706. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  707. SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
  708. s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  709. return;
  710. }
  711. // Undraw old zone outlines
  712. for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
  713. {
  714. ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii );
  715. edge_zone->Draw( m_canvas, DC, GR_XOR );
  716. }
  717. zoneInfo.ExportSetting( *aZone );
  718. NETINFO_ITEM* net = GetBoard()->FindNet( zoneInfo.m_NetcodeSelection );
  719. if( net ) // net == NULL should not occur
  720. aZone->SetNetName( net->GetNetname() );
  721. // Combine zones if possible
  722. GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
  723. // Redraw the real new zone outlines
  724. GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, UNDEFINED_LAYER );
  725. UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
  726. SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
  727. s_PickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items
  728. OnModify();
  729. }
  730. void PCB_EDIT_FRAME::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* aZone )
  731. {
  732. int ncont = aZone->Outline()->GetContour( aZone->GetSelectedCorner() );
  733. EDA_RECT dirty = aZone->GetBoundingBox();
  734. // For compatibility with old boards: remove old SEGZONE fill segments
  735. Delete_OldZone_Fill( NULL, aZone->GetTimeStamp() );
  736. // Remove current filling:
  737. aZone->UnFill();
  738. if( ncont == 0 ) // This is the main outline: remove all
  739. {
  740. SaveCopyInUndoList( aZone, UR_DELETED );
  741. GetBoard()->Remove( aZone );
  742. }
  743. else
  744. {
  745. SaveCopyInUndoList( aZone, UR_CHANGED );
  746. aZone->Outline()->RemoveContour( ncont );
  747. }
  748. m_canvas->RefreshDrawingRect( dirty );
  749. OnModify();
  750. }