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.

1609 lines
56 KiB

  1. /****************************/
  2. /* DRC control */
  3. /****************************/
  4. #include "fctsys.h"
  5. #include "gr_basic.h"
  6. #include "common.h"
  7. #include "pcbnew.h"
  8. #include "autorout.h"
  9. #include "trigo.h"
  10. #include "protos.h"
  11. /* variables locales */
  12. class WinEDA_DrcFrame;
  13. WinEDA_DrcFrame* DrcFrame;
  14. /* saving drc options */
  15. static bool s_Pad2PadTestOpt = true;
  16. static bool s_UnconnectedTestOpt = true;
  17. static bool s_ZonesTestOpt = false;
  18. static bool s_CreateRptFileOpt = false;
  19. static FILE* s_RptFile = NULL;
  20. static wxString s_RptFilename;
  21. static int ErrorsDRC_Count;
  22. static MARQUEUR* current_marqueur; /* Pour gestion des marqueurs sur pcb */
  23. static bool AbortDrc, DrcInProgress = FALSE;
  24. static int spot_cX, spot_cY; /* position d'elements a tester */
  25. static int finx, finy; // coord relatives de l'extremite du segm de reference
  26. static int segm_angle; // angle d'inclinaison du segment de reference en 0,1 degre
  27. static int segm_long; // longueur du segment de reference
  28. static int xcliplo, ycliplo, xcliphi, ycliphi; /* coord de la surface de securite du segment a comparer */
  29. /* Routines Locales */
  30. static int Pad_to_Pad_Isol( D_PAD* pad_ref, D_PAD* pad, const int dist_min );
  31. static bool Test_Pad_to_Pads_Drc( WinEDA_BasePcbFrame* frame,
  32. wxDC* DC,
  33. D_PAD* pad_ref,
  34. LISTE_PAD* start_buffer,
  35. LISTE_PAD* end_buffer,
  36. int max_size,
  37. bool show_err );
  38. static int TestClearanceSegmToPad( const D_PAD* pad_to_test, int seg_width, int isol );
  39. static int TestMarginToCircle( int cx, int cy, int rayon, int longueur );
  40. static int Tst_Ligne( int x1, int y1, int x2, int y2 );
  41. static void Affiche_Erreur_DRC( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb,
  42. TRACK* pt_ref, BOARD_ITEM* pt_item, int errnumber );
  43. static void Affiche_Erreur_DRC( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb,
  44. D_PAD* pad1, D_PAD* pad2 );
  45. /*******************************************/
  46. /* function relatives to the DRC control */
  47. /*******************************************/
  48. #include "dialog_drc.cpp"
  49. /***************************************************************/
  50. void WinEDA_DrcFrame::ListUnconnectedPads( wxCommandEvent& event )
  51. /***************************************************************/
  52. {
  53. if( (m_Parent->m_Pcb->m_Status_Pcb & LISTE_CHEVELU_OK) == 0 )
  54. {
  55. m_Parent->Compile_Ratsnest( m_DC, TRUE );
  56. }
  57. if( m_Parent->m_Pcb->m_Ratsnest == NULL )
  58. return;
  59. CHEVELU* Ratsnest = m_Parent->m_Pcb->m_Ratsnest;
  60. int draw_mode = GR_SURBRILL | GR_OR;
  61. WinEDA_DrawPanel* panel = m_Parent->DrawPanel;
  62. int ii;
  63. wxString msg;
  64. float convert = 0.0001;
  65. msg = _( "Look for active routes\n" );
  66. m_logWindow->AppendText( msg );
  67. if( s_RptFile )
  68. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  69. m_UnconnectedCount = 0;
  70. for( ii = m_Parent->m_Pcb->GetNumRatsnests(); ii > 0; Ratsnest++, ii-- )
  71. {
  72. if( (Ratsnest->status & CH_ACTIF) == 0 )
  73. continue;
  74. m_UnconnectedCount++;
  75. if( m_UnconnectedCount == 1 )
  76. m_logWindow->AppendText( _( "Unconnected found:\n" ) );
  77. D_PAD* pad = Ratsnest->pad_start;
  78. pad->Draw( panel, m_DC, wxPoint( 0, 0 ), draw_mode );
  79. wxString pad_name = pad->ReturnStringPadName();
  80. wxString module_name = ( (MODULE*) (pad->m_Parent) )->m_Reference->m_Text;
  81. msg.Printf( _( "%d > Pad %s (%s) @ %.4f,%.4f and " ), m_UnconnectedCount,
  82. pad_name.GetData(), module_name.GetData(
  83. ), pad->m_Pos.x * convert, pad->m_Pos.y * convert );
  84. m_logWindow->AppendText( msg );
  85. if( s_RptFile )
  86. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  87. pad = Ratsnest->pad_end;
  88. pad->Draw( panel, m_DC, wxPoint( 0, 0 ), draw_mode );
  89. pad_name = pad->ReturnStringPadName();
  90. module_name = ( (MODULE*) (pad->m_Parent) )->m_Reference->m_Text;
  91. msg.Printf( _( "Pad %s (%s) @ %.4f,%.4f\n" ),
  92. pad_name.GetData(), module_name.GetData(
  93. ), pad->m_Pos.x * convert, pad->m_Pos.y * convert );
  94. m_logWindow->AppendText( msg );
  95. if( s_RptFile )
  96. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  97. }
  98. if( m_UnconnectedCount )
  99. msg.Printf( _( "Active routes: %d\n" ), m_UnconnectedCount );
  100. else
  101. msg = _( "OK! (No active routes)\n" );
  102. m_logWindow->AppendText( msg );
  103. if( s_RptFile )
  104. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  105. }
  106. /****************************************************/
  107. void WinEDA_DrcFrame::TestDrc( wxCommandEvent& event )
  108. /****************************************************/
  109. {
  110. int errors;
  111. wxString msg;
  112. if( !DrcInProgress )
  113. {
  114. if( m_CreateRptCtrl->IsChecked() ) // Create a file rpt
  115. {
  116. s_RptFilename = m_RptFilenameCtrl->GetValue();
  117. if( s_RptFilename.IsEmpty() )
  118. OnButtonBrowseRptFileClick( event );
  119. if( !s_RptFilename.IsEmpty() )
  120. s_RptFile = wxFopen( s_RptFilename, wxT( "w" ) );
  121. else
  122. s_RptFile = NULL;
  123. }
  124. if( s_RptFile )
  125. {
  126. fprintf( s_RptFile, "Drc report for %s\n",
  127. CONV_TO_UTF8( m_Parent->m_CurrentScreen->m_FileName ) );
  128. char line[256];
  129. fprintf( s_RptFile, "Created on %s\n", DateAndTime( line ) );
  130. }
  131. s_Pad2PadTestOpt = m_Pad2PadTestCtrl->IsChecked();
  132. s_UnconnectedTestOpt = m_UnconnectedTestCtrl->IsChecked();
  133. s_ZonesTestOpt = m_ZonesTestCtrl->IsChecked();
  134. AbortDrc = FALSE;
  135. m_logWindow->Clear();
  136. g_DesignSettings.m_TrackClearence =
  137. ReturnValueFromTextCtrl( *m_SetClearance, m_Parent->m_InternalUnits );
  138. /* Test DRC errors (clearance errors, bad connections .. */
  139. errors = m_Parent->Test_DRC( m_DC, m_Pad2PadTestCtrl->IsChecked(
  140. ), m_ZonesTestCtrl->IsChecked() );
  141. /* Search for active routes (unconnected pads) */
  142. if( m_UnconnectedTestCtrl->IsChecked() )
  143. ListUnconnectedPads( event );
  144. else
  145. m_UnconnectedCount = 0;
  146. if( errors )
  147. msg.Printf( _( "** End Drc: %d errors **\n" ), errors );
  148. else if( m_UnconnectedCount == 0 )
  149. msg = _( "** End Drc: No Error **\n" );
  150. m_logWindow->AppendText( msg );
  151. if( s_RptFile )
  152. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  153. if( s_RptFile )
  154. {
  155. msg.Printf( _( "Report file <%s> created\n" ), s_RptFilename.GetData() );
  156. m_logWindow->AppendText( msg );
  157. fclose( s_RptFile );
  158. s_RptFile = NULL;
  159. }
  160. }
  161. else
  162. wxBell();
  163. }
  164. /*********************************************************/
  165. void WinEDA_DrcFrame::DelDRCMarkers( wxCommandEvent& event )
  166. /*********************************************************/
  167. {
  168. if( !DrcInProgress )
  169. {
  170. m_Parent->Erase_Marqueurs();
  171. m_Parent->DrawPanel->ReDraw( m_DC, TRUE );
  172. }
  173. else
  174. wxBell();
  175. }
  176. /******************************************************/
  177. void WinEDA_PcbFrame::Install_Test_DRC_Frame( wxDC* DC )
  178. /******************************************************/
  179. /* install a dialog box to handle the general DRC control
  180. */
  181. {
  182. AbortDrc = FALSE;
  183. DrcFrame = new WinEDA_DrcFrame( this, DC );
  184. DrcFrame->ShowModal(); DrcFrame->Destroy();
  185. DrcFrame = NULL;
  186. }
  187. /************************************************************************/
  188. int WinEDA_PcbFrame::Test_DRC( wxDC* DC, bool TestPad2Pad, bool TestZone )
  189. /************************************************************************/
  190. /* Test DRC :
  191. * Run a drc control for each pad and track segment
  192. * Put a marker on pad or track end which have a drc problem
  193. */
  194. {
  195. int ii, jj, old_net;
  196. int flag_err_Drc;
  197. TRACK* pt_segm;
  198. D_PAD* pad;
  199. MARQUEUR* Marqueur;
  200. EDA_BaseStruct* PtStruct;
  201. wxString Line;
  202. #define PRINT_NB_PAD_POS 42
  203. #define PRINT_PAD_ERR_POS 48
  204. #define PRINT_TST_POS 20
  205. #define PRINT_NB_SEGM_POS 26
  206. #define PRINT_TRACK_ERR_POS 32
  207. #define PRINT_NB_ZONESEGM_POS 60
  208. #define PRINT_ZONE_ERR_POS 70
  209. DrcInProgress = TRUE;
  210. ErrorsDRC_Count = 0;
  211. Compile_Ratsnest( DC, TRUE );
  212. MsgPanel->EraseMsgBox();
  213. m_CurrentScreen->SetRefreshReq();
  214. /* Delete previous markers */
  215. Erase_Marqueurs();
  216. if( TestPad2Pad ) /* First test: Test DRC between pads (no track)*/
  217. {
  218. Line.Printf( wxT( "%d" ), m_Pcb->m_NbPads );
  219. Affiche_1_Parametre( this, PRINT_NB_PAD_POS, wxT( "NbPad" ), Line, RED );
  220. Affiche_1_Parametre( this, PRINT_PAD_ERR_POS, wxT( "Pad Err" ), wxT( "0" ), LIGHTRED );
  221. if( DrcFrame )
  222. DrcFrame->m_logWindow->AppendText( _( "Tst Pad to Pad\n" ) );
  223. LISTE_PAD* pad_list_start = CreateSortedPadListByXCoord( m_Pcb );
  224. LISTE_PAD* pad_list_limit = &pad_list_start[m_Pcb->m_NbPads];
  225. int max_size = 0;
  226. LISTE_PAD* pad_list;
  227. /* Compute the max size of the pads ( used to stop the test) */
  228. for( pad_list = pad_list_start; pad_list < pad_list_limit; pad_list++ )
  229. {
  230. pad = *pad_list;
  231. if( pad->m_Rayon > max_size )
  232. max_size = pad->m_Rayon;
  233. }
  234. /* Test the pads */
  235. for( pad_list = pad_list_start; pad_list < pad_list_limit; pad_list++ )
  236. {
  237. pad = *pad_list;
  238. if( Test_Pad_to_Pads_Drc( this, DC, pad, pad_list, pad_list_limit, max_size,
  239. TRUE ) == BAD_DRC )
  240. {
  241. Marqueur = current_marqueur;
  242. current_marqueur = NULL;
  243. if( Marqueur == NULL )
  244. {
  245. DisplayError( this, wxT( "Test_Drc(): internal err" ) );
  246. return ErrorsDRC_Count;
  247. }
  248. Line.Printf( wxT( "%d" ), ErrorsDRC_Count );
  249. Affiche_1_Parametre( this, PRINT_PAD_ERR_POS, wxEmptyString, Line, LIGHTRED );
  250. Marqueur->Pnext = m_Pcb->m_Drawings;
  251. Marqueur->Pback = m_Pcb;
  252. PtStruct = m_Pcb->m_Drawings;
  253. if( PtStruct )
  254. PtStruct->Pback = Marqueur;
  255. m_Pcb->m_Drawings = Marqueur;
  256. }
  257. }
  258. free( pad_list_start );
  259. }
  260. /* Test track segments */
  261. Line.Printf( wxT( "%d" ), m_Pcb->m_NbSegmTrack );
  262. Affiche_1_Parametre( this, PRINT_NB_SEGM_POS, _( "SegmNb" ), Line, RED );
  263. Affiche_1_Parametre( this, PRINT_TRACK_ERR_POS, _( "Track Err" ), wxT( "0" ), LIGHTRED );
  264. pt_segm = m_Pcb->m_Track;
  265. if( DrcFrame )
  266. DrcFrame->m_logWindow->AppendText( _( "Tst Tracks\n" ) );
  267. for( ii = 0, old_net = -1, jj = 0;
  268. pt_segm != NULL;
  269. pt_segm = (TRACK*) pt_segm->Pnext, ii++, jj-- )
  270. {
  271. if( pt_segm->Pnext == NULL )
  272. break;
  273. if( jj == 0 )
  274. {
  275. jj = 10;
  276. wxYield();
  277. if( AbortDrc )
  278. {
  279. AbortDrc = FALSE; break;
  280. }
  281. /* Print stats */
  282. Line.Printf( wxT( "%d" ), ii );
  283. Affiche_1_Parametre( this, PRINT_TST_POS, wxT( "Test" ), Line, CYAN );
  284. }
  285. if( old_net != pt_segm->m_NetCode )
  286. {
  287. wxString msg;
  288. jj = 1;
  289. EQUIPOT* equipot = m_Pcb->FindNet( pt_segm->m_NetCode );
  290. if( equipot )
  291. msg = equipot->m_Netname + wxT( " " );
  292. else
  293. msg = wxT( "<noname>" );
  294. Affiche_1_Parametre( this, 0, _( "Netname" ), msg, YELLOW );
  295. old_net = pt_segm->m_NetCode;
  296. }
  297. g_HightLigth_NetCode = pt_segm->m_NetCode;
  298. flag_err_Drc = Drc( this, DC, pt_segm, (TRACK*) pt_segm->Pnext, 1 );
  299. if( flag_err_Drc == BAD_DRC )
  300. {
  301. Marqueur = current_marqueur;
  302. current_marqueur = NULL;
  303. if( Marqueur == NULL )
  304. {
  305. DisplayError( this, wxT( "Test_Drc(): internal err" ) );
  306. return ErrorsDRC_Count;
  307. }
  308. Marqueur->Pnext = m_Pcb->m_Drawings;
  309. Marqueur->Pback = m_Pcb;
  310. PtStruct = m_Pcb->m_Drawings;
  311. if( PtStruct )
  312. PtStruct->Pback = Marqueur;
  313. m_Pcb->m_Drawings = Marqueur;
  314. GRSetDrawMode( DC, GR_OR );
  315. pt_segm->Draw( DrawPanel, DC, RED ^ LIGHTRED );
  316. Line.Printf( wxT( "%d" ), ErrorsDRC_Count );
  317. Affiche_1_Parametre( this, PRINT_TRACK_ERR_POS, wxEmptyString, Line, LIGHTRED );
  318. }
  319. }
  320. /* Test zone segments */
  321. if( TestZone )
  322. {
  323. m_Pcb->m_NbSegmZone = 0;
  324. for( pt_segm = (TRACK*) m_Pcb->m_Zone; pt_segm != NULL; pt_segm = (TRACK*) pt_segm->Pnext )
  325. m_Pcb->m_NbSegmZone++;
  326. Line.Printf( wxT( "%d" ), m_Pcb->m_NbSegmZone );
  327. Affiche_1_Parametre( this, PRINT_NB_ZONESEGM_POS, _( "SegmNb" ), Line, RED );
  328. Affiche_1_Parametre( this, PRINT_ZONE_ERR_POS, _( "Zone Err" ), wxT( "0" ), LIGHTRED );
  329. if( DrcFrame )
  330. DrcFrame->m_logWindow->AppendText( _( "Tst Zones\n" ) );
  331. pt_segm = (TRACK*) m_Pcb->m_Zone;
  332. for( ii = 0, old_net = -1, jj = 0;
  333. pt_segm != NULL;
  334. pt_segm = (TRACK*) pt_segm->Pnext, ii++, jj-- )
  335. {
  336. if( pt_segm->Pnext == NULL )
  337. break;
  338. if( jj == 0 )
  339. {
  340. jj = 100;
  341. wxYield();
  342. if( AbortDrc )
  343. {
  344. AbortDrc = FALSE; break;
  345. }
  346. /* Print stats */
  347. Line.Printf( wxT( "%d" ), ii );
  348. Affiche_1_Parametre( this, PRINT_TST_POS, wxT( "Test" ), Line, CYAN );
  349. }
  350. if( old_net != pt_segm->m_NetCode )
  351. {
  352. jj = 1;
  353. wxString msg;
  354. EQUIPOT* equipot = m_Pcb->FindNet( pt_segm->m_NetCode );
  355. if( equipot )
  356. msg = equipot->m_Netname + wxT( " " );
  357. else
  358. msg = wxT( "<noname>" );
  359. Affiche_1_Parametre( this, 0, _( "Netname" ), msg, YELLOW );
  360. old_net = pt_segm->m_NetCode;
  361. }
  362. g_HightLigth_NetCode = pt_segm->m_NetCode;
  363. /* Test drc with other zone segments, and pads */
  364. flag_err_Drc = Drc( this, DC, pt_segm, (TRACK*) pt_segm->Pnext, 1 );
  365. if( flag_err_Drc == BAD_DRC )
  366. {
  367. Marqueur = current_marqueur;
  368. current_marqueur = NULL;
  369. if( Marqueur == NULL )
  370. {
  371. DisplayError( this, wxT( "Test_Drc(): internal err" ) );
  372. return ErrorsDRC_Count;
  373. }
  374. Marqueur->Pnext = m_Pcb->m_Drawings;
  375. Marqueur->Pback = m_Pcb;
  376. PtStruct = m_Pcb->m_Drawings;
  377. if( PtStruct )
  378. PtStruct->Pback = Marqueur;
  379. m_Pcb->m_Drawings = Marqueur;
  380. GRSetDrawMode( DC, GR_OR );
  381. pt_segm->Draw( DrawPanel, DC, RED ^ LIGHTRED );
  382. Line.Printf( wxT( "%d" ), ErrorsDRC_Count );
  383. Affiche_1_Parametre( this, PRINT_ZONE_ERR_POS, wxEmptyString, Line, LIGHTRED );
  384. }
  385. /* Test drc with track segments */
  386. int tmp = m_Pcb->m_NbPads;
  387. m_Pcb->m_NbPads = 0; // Pads already tested: disable pad test
  388. flag_err_Drc = Drc( this, DC, pt_segm, m_Pcb->m_Track, 1 );
  389. m_Pcb->m_NbPads = tmp;
  390. if( flag_err_Drc == BAD_DRC )
  391. {
  392. Marqueur = current_marqueur;
  393. current_marqueur = NULL;
  394. if( Marqueur == NULL )
  395. {
  396. DisplayError( this, wxT( "Test_Drc(): internal err" ) );
  397. return ErrorsDRC_Count;
  398. }
  399. Marqueur->Pnext = m_Pcb->m_Drawings;
  400. Marqueur->Pback = m_Pcb;
  401. PtStruct = m_Pcb->m_Drawings;
  402. if( PtStruct )
  403. PtStruct->Pback = Marqueur;
  404. m_Pcb->m_Drawings = Marqueur;
  405. GRSetDrawMode( DC, GR_OR );
  406. pt_segm->Draw( DrawPanel, DC, RED ^ LIGHTRED );
  407. Line.Printf( wxT( "%d" ), ErrorsDRC_Count );
  408. Affiche_1_Parametre( this, PRINT_ZONE_ERR_POS, wxEmptyString, Line, LIGHTRED );
  409. }
  410. }
  411. }
  412. AbortDrc = FALSE;
  413. DrcInProgress = FALSE;
  414. return ErrorsDRC_Count;
  415. }
  416. /***********************************************************************/
  417. int Drc( WinEDA_BasePcbFrame* frame, wxDC* DC,
  418. TRACK* pt_segment, TRACK* StartBuffer, int show_err )
  419. /***********************************************************************/
  420. /**
  421. * Test the current segment:
  422. * @param pt_segment = current segment to test
  423. * @param StartBuffer = track buffer to test (usually m_Pcb->m_Track)
  424. * @param show_err (flag) si 0 pas d'affichage d'erreur sur ecran
  425. * @return : BAD_DRC (1) if DRC error or OK_DRC (0) if OK
  426. */
  427. {
  428. int ii;
  429. TRACK* pttrack;
  430. int x0, y0, xf, yf; // coord des extremites du segment teste dans le repere modifie
  431. int dx, dy; // utilise pour calcul des dim x et dim y des segments
  432. int w_dist;
  433. int MaskLayer;
  434. int net_code_ref;
  435. int org_X, org_Y; // Origine sur le PCB des axes du repere centre sur
  436. // l'origine du segment de reference
  437. wxPoint shape_pos;
  438. org_X = pt_segment->m_Start.x;
  439. org_Y = pt_segment->m_Start.y;
  440. finx = dx = pt_segment->m_End.x - org_X;
  441. finy = dy = pt_segment->m_End.y - org_Y;
  442. MaskLayer = pt_segment->ReturnMaskLayer();
  443. net_code_ref = pt_segment->m_NetCode;
  444. segm_angle = 0;
  445. /* for a non horizontal or vertical segment Compute the segment angle
  446. in 0,1 degrees and its lenght */
  447. if( dx || dy )
  448. {
  449. /* Compute the segment angle in 0,1 degrees */
  450. segm_angle = ArcTangente( dy, dx );
  451. /* Compute the segment lenght: we build an equivalent rotated segment,
  452. this segment is horizontal, therefore dx = lenght */
  453. RotatePoint( &dx, &dy, segm_angle ); /* dx = lenght, dy = 0 */
  454. }
  455. segm_long = dx;
  456. /******************************************/
  457. /* Phase 1 : test DRC track to pads :*/
  458. /******************************************/
  459. /* Compute the min distance to pads : */
  460. w_dist = (unsigned) (pt_segment->m_Width >> 1 );
  461. for( ii = 0; ii < frame->m_Pcb->m_NbPads; ii++ )
  462. {
  463. D_PAD* pt_pad = frame->m_Pcb->m_Pads[ii];
  464. /* No problem if pads are on an other layer,
  465. * But if a drill hole exists (a pad on a single layer can have a hole!)
  466. * we must test the hole
  467. */
  468. if( (pt_pad->m_Masque_Layer & MaskLayer ) == 0 )
  469. {
  470. /* We must test the pad hole. In order to use the function "TestClearanceSegmToPad",
  471. * a pseudo pad is used, with a shape and a size like the hole */
  472. if( pt_pad->m_Drill.x == 0 )
  473. continue;
  474. D_PAD pseudo_pad( (MODULE*) NULL );
  475. pseudo_pad.m_Size = pt_pad->m_Drill;
  476. pseudo_pad.m_Pos = pt_pad->m_Pos;
  477. pseudo_pad.m_PadShape = pt_pad->m_DrillShape;
  478. pseudo_pad.m_Orient = pt_pad->m_Orient;
  479. pseudo_pad.ComputeRayon();
  480. spot_cX = pseudo_pad.m_Pos.x - org_X;
  481. spot_cY = pseudo_pad.m_Pos.y - org_Y;
  482. if( TestClearanceSegmToPad( &pseudo_pad, w_dist,
  483. g_DesignSettings.m_TrackClearence ) != OK_DRC )
  484. {
  485. ErrorsDRC_Count++;
  486. if( show_err )
  487. Affiche_Erreur_DRC( frame->DrawPanel, DC,
  488. frame->m_Pcb, pt_segment, pt_pad, 0 );
  489. return BAD_DRC;
  490. }
  491. continue;
  492. }
  493. /* The pad must be in a net (i.e pt_pad->m_NetCode != 0 )
  494. * but no problem if the pad netcode is the current netcode (same net) */
  495. if( pt_pad->m_NetCode && // the pad must be connected
  496. net_code_ref == pt_pad->m_NetCode ) // the pad net is the same as current net -> Ok
  497. continue;
  498. /* Test DRC pour les pads */
  499. shape_pos = pt_pad->ReturnShapePos();
  500. spot_cX = shape_pos.x - org_X;
  501. spot_cY = shape_pos.y - org_Y;
  502. if( TestClearanceSegmToPad( pt_pad, w_dist, g_DesignSettings.m_TrackClearence ) == OK_DRC )
  503. continue;
  504. /* Drc error found! */
  505. else
  506. {
  507. ErrorsDRC_Count++;
  508. if( show_err )
  509. Affiche_Erreur_DRC( frame->DrawPanel, DC,
  510. frame->m_Pcb, pt_segment, pt_pad, 1 );
  511. return BAD_DRC;
  512. }
  513. }
  514. /**********************************************/
  515. /* Phase 2: test DRC with other track segments */
  516. /**********************************************/
  517. /* At this point the reference segment is the X axis */
  518. /* Test the reference segment with other track segments */
  519. pttrack = StartBuffer;
  520. for( ; pttrack != NULL; pttrack = (TRACK*) pttrack->Pnext )
  521. {
  522. //No problem if segments have the meme net code:
  523. if( net_code_ref == pttrack->m_NetCode )
  524. continue;
  525. // No problem if segment are on different layers :
  526. if( ( MaskLayer & pttrack->ReturnMaskLayer() ) == 0 )
  527. continue;
  528. /* calcul de la Distance mini = Isol+ rayon ou demi largeur seg ref
  529. + rayon ou demi largeur seg a comparer */
  530. w_dist = pt_segment->m_Width >> 1;
  531. w_dist += pttrack->m_Width >> 1;
  532. w_dist += g_DesignSettings.m_TrackClearence;
  533. /* If the reference segment is a via, we test it here */
  534. if( pt_segment->Type() == TYPEVIA )
  535. {
  536. int orgx, orgy; // origine du repere d'axe X = segment a comparer
  537. int angle = 0; // angle du segment a tester;
  538. orgx = pttrack->m_Start.x; orgy = pttrack->m_Start.y;
  539. dx = pttrack->m_End.x - orgx; dy = pttrack->m_End.y - orgy;
  540. x0 = pt_segment->m_Start.x - orgx; y0 = pt_segment->m_Start.y - orgy;
  541. if( pttrack->Type() == TYPEVIA ) /* Tst distance entre 2 vias */
  542. {
  543. if( (int) hypot( (float) x0, (float) y0 ) < w_dist )
  544. {
  545. ErrorsDRC_Count++;
  546. if( show_err )
  547. Affiche_Erreur_DRC( frame->DrawPanel,
  548. DC,
  549. frame->m_Pcb,
  550. pt_segment,
  551. pttrack,
  552. 21 );
  553. return BAD_DRC;
  554. }
  555. }
  556. else /* Tst drc via / segment */
  557. {
  558. /* Compute l'angle */
  559. angle = ArcTangente( dy, dx );
  560. /* Compute new coordinates ( the segment become horizontal) */
  561. RotatePoint( &dx, &dy, angle );
  562. RotatePoint( &x0, &y0, angle );
  563. if( TestMarginToCircle( x0, y0, w_dist, dx ) == BAD_DRC )
  564. {
  565. ErrorsDRC_Count++;
  566. if( show_err )
  567. Affiche_Erreur_DRC( frame->DrawPanel,
  568. DC,
  569. frame->m_Pcb,
  570. pt_segment,
  571. pttrack,
  572. 20 );
  573. return BAD_DRC;
  574. }
  575. }
  576. continue;
  577. }
  578. /* We compute x0,y0, xf,yf = starting and ending point coordinates for the segment to test
  579. * in the new axis : the new X axis is the reference segment
  580. * We must translate and rotate the segment to test
  581. */
  582. x0 = pttrack->m_Start.x - org_X;
  583. y0 = pttrack->m_Start.y - org_Y;
  584. xf = pttrack->m_End.x - org_X;
  585. yf = pttrack->m_End.y - org_Y;
  586. RotatePoint( &x0, &y0, segm_angle );
  587. RotatePoint( &xf, &yf, segm_angle );
  588. if( pttrack->Type() == TYPEVIA )
  589. {
  590. if( TestMarginToCircle( x0, y0, w_dist, segm_long ) == OK_DRC )
  591. continue;
  592. ErrorsDRC_Count++;
  593. if( show_err )
  594. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pt_segment, pttrack, 21 );
  595. return BAD_DRC;
  596. }
  597. /* We have changed axis:
  598. * the reference segment is Horizontal.
  599. * 3 cases : the segment to test can be parallel, perpendicular or have an other direction
  600. */
  601. if( y0 == yf ) // parallel segments
  602. {
  603. if( abs( y0 ) >= w_dist )
  604. continue;
  605. if( x0 > xf )
  606. EXCHG( x0, xf ); /* pour que x0 <= xf */
  607. if( x0 > (-w_dist) && x0 < (segm_long + w_dist) ) /* possible error drc */
  608. {
  609. /* Fine test : we consider the rounded shape of the ends */
  610. if( x0 >= 0 && x0 <= segm_long )
  611. {
  612. ErrorsDRC_Count++;
  613. if( show_err )
  614. Affiche_Erreur_DRC( frame->DrawPanel,
  615. DC,
  616. frame->m_Pcb,
  617. pt_segment,
  618. pttrack,
  619. 2 );
  620. return BAD_DRC;
  621. }
  622. if( TestMarginToCircle( x0, y0, w_dist, segm_long ) == BAD_DRC )
  623. {
  624. ErrorsDRC_Count++;
  625. if( show_err )
  626. Affiche_Erreur_DRC( frame->DrawPanel,
  627. DC,
  628. frame->m_Pcb,
  629. pt_segment,
  630. pttrack,
  631. 2 );
  632. return BAD_DRC;
  633. }
  634. }
  635. if( xf > (-w_dist) && xf < (segm_long + w_dist) )
  636. {
  637. /* Fine test : we consider the rounded shape of the ends */
  638. if( xf >= 0 && xf <= segm_long )
  639. {
  640. ErrorsDRC_Count++;
  641. if( show_err )
  642. Affiche_Erreur_DRC( frame->DrawPanel,
  643. DC,
  644. frame->m_Pcb,
  645. pt_segment,
  646. pttrack,
  647. 3 );
  648. return BAD_DRC;
  649. }
  650. if( TestMarginToCircle( xf, yf, w_dist, segm_long ) == BAD_DRC )
  651. {
  652. ErrorsDRC_Count++;
  653. if( show_err )
  654. Affiche_Erreur_DRC( frame->DrawPanel,
  655. DC,
  656. frame->m_Pcb,
  657. pt_segment,
  658. pttrack,
  659. 3 );
  660. return BAD_DRC;
  661. }
  662. }
  663. if( x0 <=0 && xf >= 0 )
  664. {
  665. ErrorsDRC_Count++;
  666. if( show_err )
  667. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pt_segment, pttrack, 4 );
  668. return BAD_DRC;
  669. }
  670. }
  671. else if( x0 == xf ) // perpendicular segments
  672. {
  673. if( ( x0 <= (-w_dist) ) || ( x0 >= (segm_long + w_dist) ) )
  674. continue;
  675. /* Test is segments are crossing */
  676. if( y0 > yf )
  677. EXCHG( y0, yf );
  678. if( (y0 < 0) && (yf > 0) )
  679. {
  680. ErrorsDRC_Count++;
  681. if( show_err )
  682. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pt_segment, pttrack, 6 );
  683. return BAD_DRC;
  684. }
  685. /* At this point the drc error is due to an end near a reference segm end */
  686. if( TestMarginToCircle( x0, y0, w_dist, segm_long ) == BAD_DRC )
  687. {
  688. ErrorsDRC_Count++;
  689. if( show_err )
  690. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pt_segment, pttrack, 7 );
  691. return BAD_DRC;
  692. }
  693. if( TestMarginToCircle( xf, yf, w_dist, segm_long ) == BAD_DRC )
  694. {
  695. ErrorsDRC_Count++;
  696. if( show_err )
  697. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pt_segment, pttrack, 8 );
  698. return BAD_DRC;
  699. }
  700. }
  701. else // segments quelconques entre eux */
  702. {
  703. int bflag = OK_DRC;
  704. /* calcul de la "surface de securite du segment de reference */
  705. /* First rought 'and fast) test : the track segment is like a rectangle */
  706. xcliplo = ycliplo = -w_dist;
  707. xcliphi = segm_long + w_dist; ycliphi = w_dist;
  708. bflag = Tst_Ligne( x0, y0, xf, yf );
  709. if( bflag == BAD_DRC ) /* A fine test is needed because a serment is not exactly a rectangle
  710. it has rounded ends */
  711. {
  712. /* 2eme passe : the track has rounded ends.
  713. * we must a fine test for each rounded end and the rectangular zone */
  714. xcliplo = 0; xcliphi = segm_long;
  715. bflag = Tst_Ligne( x0, y0, xf, yf );
  716. if( bflag == BAD_DRC )
  717. {
  718. ErrorsDRC_Count++;
  719. if( show_err )
  720. Affiche_Erreur_DRC( frame->DrawPanel,
  721. DC,
  722. frame->m_Pcb,
  723. pt_segment,
  724. pttrack,
  725. 9 );
  726. return BAD_DRC;
  727. }
  728. else // The drc error is due to the starting or the ending point of the reference segment
  729. {
  730. // Test the starting and the ending point
  731. int angle, rx0, ry0, rxf, ryf;
  732. x0 = pttrack->m_Start.x;
  733. y0 = pttrack->m_Start.y;
  734. xf = pttrack->m_End.x;
  735. yf = pttrack->m_End.y;
  736. dx = xf - x0;
  737. dy = yf - y0;
  738. /* Compute the segment orientation (angle) en 0,1 degre */
  739. angle = ArcTangente( dy, dx );
  740. /* Compute the segment lenght: dx = longueur */
  741. RotatePoint( &dx, &dy, angle );
  742. /* Comute the reference segment coordinates relatives to a
  743. * X axis = current tested segment */
  744. rx0 = pt_segment->m_Start.x - x0;
  745. ry0 = pt_segment->m_Start.y - y0;
  746. rxf = pt_segment->m_End.x - x0;
  747. ryf = pt_segment->m_End.y - y0;
  748. RotatePoint( &rx0, &ry0, angle );
  749. RotatePoint( &rxf, &ryf, angle );
  750. if( TestMarginToCircle( rx0, ry0, w_dist, dx ) == BAD_DRC )
  751. {
  752. ErrorsDRC_Count++;
  753. if( show_err )
  754. Affiche_Erreur_DRC( frame->DrawPanel,
  755. DC,
  756. frame->m_Pcb,
  757. pt_segment,
  758. pttrack,
  759. 10 );
  760. return BAD_DRC;
  761. }
  762. if( TestMarginToCircle( rxf, ryf, w_dist, dx ) == BAD_DRC )
  763. {
  764. ErrorsDRC_Count++;
  765. if( show_err )
  766. Affiche_Erreur_DRC( frame->DrawPanel,
  767. DC,
  768. frame->m_Pcb,
  769. pt_segment,
  770. pttrack,
  771. 11 );
  772. return BAD_DRC;
  773. }
  774. }
  775. }
  776. }
  777. }
  778. return OK_DRC;
  779. }
  780. /*****************************************************************************/
  781. static bool Test_Pad_to_Pads_Drc( WinEDA_BasePcbFrame* frame,
  782. wxDC* DC,
  783. D_PAD* pad_ref,
  784. LISTE_PAD* start_buffer,
  785. LISTE_PAD* end_buffer,
  786. int max_size,
  787. bool show_err )
  788. /*****************************************************************************/
  789. /** Test the drc between pad_ref and other pads.
  790. * the pad list must be sorted by x coordinate
  791. * @param frame = current active frame
  792. * @param DC = current DC
  793. * @param pad_ref = pad to test
  794. * @param end_buffer = upper limit of the pad list.
  795. * @param max_size = size of the biggest pad (used to stop the test when the X distance is > max_size)
  796. * @param show_err if true, display a marker and amessage.
  797. */
  798. {
  799. int MaskLayer;
  800. D_PAD* pad;
  801. LISTE_PAD* pad_list = start_buffer;
  802. MaskLayer = pad_ref->m_Masque_Layer & ALL_CU_LAYERS;
  803. int x_limite = max_size + g_DesignSettings.m_TrackClearence +
  804. pad_ref->m_Rayon + pad_ref->m_Pos.x;
  805. for( ; pad_list < end_buffer; pad_list++ )
  806. {
  807. pad = *pad_list;
  808. if( pad == pad_ref )
  809. continue;
  810. /* We can stop the test when pad->m_Pos.x > x_limite
  811. * because the list is sorted by X values */
  812. if( pad->m_Pos.x > x_limite )
  813. break;
  814. /* No probleme if pads are on different copper layers */
  815. if( (pad->m_Masque_Layer & MaskLayer ) == 0 )
  816. continue;
  817. /* The pad must be in a net (i.e pt_pad->m_NetCode != 0 ),
  818. * But no problem if pads have the same netcode (same net)*/
  819. if( pad->m_NetCode && (pad_ref->m_NetCode == pad->m_NetCode) )
  820. continue;
  821. /* No problem if pads are from the same footprint
  822. * and have the same pad number ( equivalent pads ) */
  823. if( (pad->m_Parent == pad_ref->m_Parent) && (pad->m_NumPadName == pad_ref->m_NumPadName) )
  824. continue;
  825. if( Pad_to_Pad_Isol( pad_ref, pad, g_DesignSettings.m_TrackClearence ) == OK_DRC )
  826. continue;
  827. else /* here we have a drc error! */
  828. {
  829. ErrorsDRC_Count++;
  830. if( show_err )
  831. Affiche_Erreur_DRC( frame->DrawPanel, DC, frame->m_Pcb, pad_ref, pad );
  832. return BAD_DRC;
  833. }
  834. }
  835. return OK_DRC;
  836. }
  837. /**************************************************************************************/
  838. static int Pad_to_Pad_Isol( D_PAD* pad_ref, D_PAD* pad, const int dist_min )
  839. /***************************************************************************************/
  840. /* Return OK_DRC si clearance between pad_ref and pad is >= dist_min
  841. * or BAD_DRC if not */
  842. {
  843. wxPoint rel_pos;
  844. int dist, diag;
  845. wxPoint shape_pos;
  846. int pad_angle;
  847. rel_pos = pad->ReturnShapePos();
  848. shape_pos = pad_ref->ReturnShapePos();
  849. // rel_pos is pad position relative to the pad_ref position
  850. rel_pos.x -= shape_pos.x;
  851. rel_pos.y -= shape_pos.y;
  852. dist = (int) hypot( (double) rel_pos.x, (double) rel_pos.y );
  853. diag = OK_DRC;
  854. /* tst rapide: si les cercles exinscrits sont distants de dist_min au moins,
  855. * il n'y a pas de risque: */
  856. if( (dist - pad_ref->m_Rayon - pad->m_Rayon) >= dist_min )
  857. return OK_DRC;
  858. /* Ici les pads sont proches et les cercles exinxcrits sont trop proches
  859. * Selon les formes relatives il peut y avoir ou non erreur */
  860. bool swap_pads = false;
  861. if( (pad_ref->m_PadShape != CIRCLE) && (pad->m_PadShape == CIRCLE) )
  862. swap_pads = true;
  863. else if( (pad_ref->m_PadShape != OVALE) && (pad->m_PadShape == OVALE) )
  864. swap_pads = true;
  865. if( swap_pads )
  866. {
  867. EXCHG( pad_ref, pad );
  868. rel_pos.x = -rel_pos.x;
  869. rel_pos.y = -rel_pos.y;
  870. }
  871. switch( pad_ref->m_PadShape )
  872. {
  873. case CIRCLE: // pad_ref is like a track segment with a null lenght
  874. segm_long = 0;
  875. segm_angle = 0;
  876. finx = finy = 0;
  877. spot_cX = rel_pos.x;
  878. spot_cY = rel_pos.y;
  879. diag = TestClearanceSegmToPad( pad, pad_ref->m_Rayon, dist_min );
  880. break;
  881. case RECT:
  882. RotatePoint( &rel_pos.x, &rel_pos.y, pad_ref->m_Orient );
  883. pad_angle = pad_ref->m_Orient + pad->m_Orient; // pad_angle = pad orient relative to the pad_ref orient
  884. NORMALIZE_ANGLE_POS( pad_angle );
  885. if( pad->m_PadShape == RECT )
  886. {
  887. wxSize size = pad->m_Size;
  888. if( (pad_angle == 0) || (pad_angle == 900) || (pad_angle == 1800) ||
  889. (pad_angle == 2700) )
  890. {
  891. if( (pad_angle == 900) || (pad_angle == 2700) )
  892. {
  893. EXCHG( size.x, size.y );
  894. }
  895. // Test DRC:
  896. diag = BAD_DRC;
  897. rel_pos.x = ABS( rel_pos.x );
  898. rel_pos.y = ABS( rel_pos.y );
  899. if( ( rel_pos.x - ( (size.x + pad_ref->m_Size.x) / 2 ) ) >= dist_min )
  900. diag = OK_DRC;
  901. if( ( rel_pos.y - ( (size.y + pad_ref->m_Size.y) / 2 ) ) >= dist_min )
  902. diag = OK_DRC;
  903. }
  904. else // Any other orient
  905. {
  906. /* TODO : any orient ... */
  907. }
  908. }
  909. break;
  910. case OVALE: /* an oval pad is like a track segment */
  911. {
  912. /* Create and test a track segment with same dimensions */
  913. int segm_width;
  914. segm_angle = pad_ref->m_Orient; // Segment orient.
  915. if( pad_ref->m_Size.y < pad_ref->m_Size.x ) /* We suppose the pad is an horizontal oval */
  916. {
  917. segm_width = pad_ref->m_Size.y;
  918. segm_long = pad_ref->m_Size.x - pad_ref->m_Size.y;
  919. }
  920. else // it was a vertical oval, change to a rotated horizontal one
  921. {
  922. segm_width = pad_ref->m_Size.x;
  923. segm_long = pad_ref->m_Size.y - pad_ref->m_Size.x;
  924. segm_angle += 900;
  925. }
  926. /* the start point must be 0,0 and currently rel_pos is relative the center of pad coordinate */
  927. int sx = -segm_long / 2, sy = 0; // Start point coordinate of the horizontal equivalent segment
  928. RotatePoint( &sx, &sy, segm_angle ); // True start point coordinate of the equivalent segment
  929. spot_cX = rel_pos.x + sx;
  930. spot_cY = rel_pos.y + sy; // pad position / segment origin
  931. finx = -sx;
  932. finy = -sy; // end of segment coordinate
  933. diag = TestClearanceSegmToPad( pad, segm_width / 2, dist_min );
  934. break;
  935. }
  936. default:
  937. /* TODO...*/
  938. break;
  939. }
  940. return diag;
  941. }
  942. /***************************************************************************/
  943. static int TestClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int dist_min )
  944. /****************************************************************************/
  945. /*
  946. * Routine adaptee de la "distance()" (LOCATE.CPP)
  947. * teste la distance du pad au segment de droite en cours
  948. *
  949. * retourne:
  950. * 0 si distance >= dist_min
  951. * 1 si distance < dist_min
  952. * Parametres d'appel:
  953. * pad_to_test = pointeur sur le pad a tester
  954. * w_segm = demi largeur du segment a tester
  955. * dist_min = marge a respecter
  956. *
  957. * en variables globales
  958. * segm_long = longueur du segment en test
  959. * segm_angle = angle d'inclinaison du segment;
  960. * finx, finy = coord fin du segment / origine
  961. * spot_cX, spot_cY = position du pad / origine du segment
  962. */
  963. {
  964. int p_dimx, p_dimy; /* demi - dimensions X et Y du pad a controler */
  965. int bflag;
  966. int orient;
  967. int x0, y0, xf, yf;
  968. int seuil;
  969. int deltay;
  970. seuil = w_segm + dist_min;
  971. p_dimx = pad_to_test->m_Size.x >> 1;
  972. p_dimy = pad_to_test->m_Size.y >> 1;
  973. if( pad_to_test->m_PadShape == CIRCLE )
  974. {
  975. /* calcul des coord centre du pad dans le repere axe X confondu
  976. * avec le segment en tst */
  977. RotatePoint( &spot_cX, &spot_cY, segm_angle );
  978. return TestMarginToCircle( spot_cX, spot_cY, seuil + p_dimx, segm_long );
  979. }
  980. else
  981. {
  982. /* calcul de la "surface de securite" du pad de reference */
  983. xcliplo = spot_cX - seuil - p_dimx;
  984. ycliplo = spot_cY - seuil - p_dimy;
  985. xcliphi = spot_cX + seuil + p_dimx;
  986. ycliphi = spot_cY + seuil + p_dimy;
  987. x0 = y0 = 0;
  988. xf = finx;
  989. yf = finy;
  990. orient = pad_to_test->m_Orient;
  991. RotatePoint( &x0, &y0, spot_cX, spot_cY, -orient );
  992. RotatePoint( &xf, &yf, spot_cX, spot_cY, -orient );
  993. bflag = Tst_Ligne( x0, y0, xf, yf );
  994. if( bflag == OK_DRC )
  995. return OK_DRC;
  996. /* Erreur DRC : analyse fine de la forme de la pastille */
  997. switch( pad_to_test->m_PadShape )
  998. {
  999. default:
  1000. return BAD_DRC;
  1001. case OVALE:
  1002. /* test de la pastille ovale ramenee au type ovale vertical */
  1003. if( p_dimx > p_dimy )
  1004. {
  1005. EXCHG( p_dimx, p_dimy ); orient += 900;
  1006. if( orient >= 3600 )
  1007. orient -= 3600;
  1008. }
  1009. deltay = p_dimy - p_dimx;
  1010. /* ici: p_dimx = rayon,
  1011. * delta = dist centre cercles a centre pad */
  1012. /* Test du rectangle separant les 2 demi cercles */
  1013. xcliplo = spot_cX - seuil - p_dimx;
  1014. ycliplo = spot_cY - w_segm - deltay;
  1015. xcliphi = spot_cX + seuil + p_dimx;
  1016. ycliphi = spot_cY + w_segm + deltay;
  1017. bflag = Tst_Ligne( x0, y0, xf, yf );
  1018. if( bflag == BAD_DRC )
  1019. return BAD_DRC;
  1020. /* test des 2 cercles */
  1021. x0 = spot_cX; /* x0,y0 = centre du cercle superieur du pad ovale */
  1022. y0 = spot_cY + deltay;
  1023. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1024. RotatePoint( &x0, &y0, segm_angle );
  1025. bflag = TestMarginToCircle( x0, y0, p_dimx + seuil, segm_long );
  1026. if( bflag == BAD_DRC )
  1027. return BAD_DRC;
  1028. x0 = spot_cX; /* x0,y0 = centre du cercle inferieur du pad ovale */
  1029. y0 = spot_cY - deltay;
  1030. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1031. RotatePoint( &x0, &y0, segm_angle );
  1032. bflag = TestMarginToCircle( x0, y0, p_dimx + seuil, segm_long );
  1033. if( bflag == BAD_DRC )
  1034. return BAD_DRC;
  1035. break;
  1036. case RECT: /* 2 rectangle + 4 1/4 cercles a tester */
  1037. /* Test du rectangle dimx + seuil, dimy */
  1038. xcliplo = spot_cX - p_dimx - seuil;
  1039. ycliplo = spot_cY - p_dimy;
  1040. xcliphi = spot_cX + p_dimx + seuil;
  1041. ycliphi = spot_cY + p_dimy;
  1042. bflag = Tst_Ligne( x0, y0, xf, yf );
  1043. if( bflag == BAD_DRC )
  1044. {
  1045. return BAD_DRC;
  1046. }
  1047. /* Test du rectangle dimx , dimy + seuil */
  1048. xcliplo = spot_cX - p_dimx;
  1049. ycliplo = spot_cY - p_dimy - seuil;
  1050. xcliphi = spot_cX + p_dimx;
  1051. ycliphi = spot_cY + p_dimy + seuil;
  1052. bflag = Tst_Ligne( x0, y0, xf, yf );
  1053. if( bflag == BAD_DRC )
  1054. {
  1055. return BAD_DRC;
  1056. }
  1057. /* test des 4 cercles ( surface d'solation autour des sommets */
  1058. /* test du coin sup. gauche du pad */
  1059. x0 = spot_cX - p_dimx;
  1060. y0 = spot_cY - p_dimy;
  1061. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1062. RotatePoint( &x0, &y0, segm_angle );
  1063. bflag = TestMarginToCircle( x0, y0, seuil, segm_long );
  1064. if( bflag == BAD_DRC )
  1065. {
  1066. return BAD_DRC;
  1067. }
  1068. /* test du coin sup. droit du pad */
  1069. x0 = spot_cX + p_dimx;
  1070. y0 = spot_cY - p_dimy;
  1071. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1072. RotatePoint( &x0, &y0, segm_angle );
  1073. bflag = TestMarginToCircle( x0, y0, seuil, segm_long );
  1074. if( bflag == BAD_DRC )
  1075. {
  1076. return BAD_DRC;
  1077. }
  1078. /* test du coin inf. gauche du pad */
  1079. x0 = spot_cX - p_dimx;
  1080. y0 = spot_cY + p_dimy;
  1081. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1082. RotatePoint( &x0, &y0, segm_angle );
  1083. bflag = TestMarginToCircle( x0, y0, seuil, segm_long );
  1084. if( bflag == BAD_DRC )
  1085. {
  1086. return BAD_DRC;
  1087. }
  1088. /* test du coin inf. droit du pad */
  1089. x0 = spot_cX + p_dimx;
  1090. y0 = spot_cY + p_dimy;
  1091. RotatePoint( &x0, &y0, spot_cX, spot_cY, orient );
  1092. RotatePoint( &x0, &y0, segm_angle );
  1093. bflag = TestMarginToCircle( x0, y0, seuil, segm_long );
  1094. if( bflag == BAD_DRC )
  1095. {
  1096. return BAD_DRC;
  1097. }
  1098. break;
  1099. }
  1100. }
  1101. return OK_DRC;
  1102. }
  1103. /*******************************************************************/
  1104. static int TestMarginToCircle( int cx, int cy, int rayon, int longueur )
  1105. /*******************************************************************/
  1106. /*
  1107. * Routine analogue a TestClearanceSegmToPad.
  1108. * Calcul de la distance d'un cercle (via ronde, extremite de piste)
  1109. * au segment de droite en cours de controle (segment de reference dans
  1110. * son repere )
  1111. * parametres:
  1112. * cx, cy: centre du cercle (surface ronde) a tester, dans le repere
  1113. * segment de reference
  1114. * rayon = rayon du cercle
  1115. * longueur = longueur du segment dans son repere (i.e. coord de fin)
  1116. * retourne:
  1117. * OK_DRC si distance >= rayon
  1118. * BAD_DRC si distance < rayon
  1119. */
  1120. {
  1121. if( abs( cy ) > rayon )
  1122. return OK_DRC;
  1123. if( (cx >= -rayon ) && ( cx <= (longueur + rayon) ) )
  1124. {
  1125. if( (cx >= 0) && (cx <= longueur) )
  1126. return BAD_DRC;
  1127. if( cx > longueur )
  1128. cx -= longueur;
  1129. if( hypot( (double) cx, (double) cy ) < rayon )
  1130. return BAD_DRC;
  1131. }
  1132. return OK_DRC;
  1133. }
  1134. /******************************************************************************/
  1135. static void Affiche_Erreur_DRC( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb,
  1136. TRACK* pt_ref, BOARD_ITEM* pt_item, int errnumber )
  1137. /******************************************************************************/
  1138. /* affiche les erreurs de DRC :
  1139. * Message d'erreur
  1140. +
  1141. * Marqueur
  1142. * number = numero d'identification
  1143. */
  1144. {
  1145. wxPoint erc_pos;
  1146. TRACK* pt_segm;
  1147. wxString msg;
  1148. wxString tracktype, netname1, netname2;
  1149. EQUIPOT* equipot = Pcb->FindNet( pt_ref->m_NetCode );
  1150. if( equipot )
  1151. netname1 = equipot->m_Netname;
  1152. else
  1153. netname1 = wxT( "<noname>" );
  1154. netname2 = wxT( "<noname>" );
  1155. if( pt_ref->Type() == TYPEVIA )
  1156. tracktype = wxT( "Via" );
  1157. else if( pt_ref->Type() == TYPEZONE )
  1158. tracktype = wxT( "Zone" );
  1159. else
  1160. tracktype = wxT( "Track" );
  1161. if( pt_item->Type() == TYPEPAD )
  1162. {
  1163. D_PAD* pad = (D_PAD*) pt_item;
  1164. equipot = Pcb->FindNet( pad->m_NetCode );
  1165. if( equipot )
  1166. netname2 = equipot->m_Netname;
  1167. erc_pos = pad->m_Pos;
  1168. wxString pad_name = pad->ReturnStringPadName();
  1169. wxString module_name = ( (MODULE*) (pad->m_Parent) )->m_Reference->m_Text;
  1170. msg.Printf( _( "%d Drc Err %d %s (net %s) and PAD %s (%s) net %s @ %d,%d\n" ),
  1171. ErrorsDRC_Count, errnumber, tracktype.GetData(),
  1172. netname1.GetData(),
  1173. pad_name.GetData(), module_name.GetData(),
  1174. netname2.GetData(),
  1175. erc_pos.x, erc_pos.y );
  1176. }
  1177. else /* erreur sur segment de piste */
  1178. {
  1179. pt_segm = (TRACK*) pt_item;
  1180. equipot = Pcb->FindNet( pt_segm->m_NetCode );
  1181. if( equipot )
  1182. netname2 = equipot->m_Netname;
  1183. erc_pos = pt_segm->m_Start;
  1184. if( pt_segm->Type() == TYPEVIA )
  1185. {
  1186. msg.Printf( _( "%d Err type %d: %s (net %s) and VIA (net %s) @ %d,%d\n" ),
  1187. ErrorsDRC_Count, errnumber, tracktype.GetData(),
  1188. netname1.GetData(), netname2.GetData(),
  1189. erc_pos.x, erc_pos.y );
  1190. }
  1191. else
  1192. {
  1193. wxPoint erc_pos_f = pt_segm->m_End;
  1194. if( hypot( (double) (erc_pos_f.x - pt_ref->m_End.x),
  1195. (double) (erc_pos_f.y - pt_ref->m_End.y) )
  1196. < hypot( (double) (erc_pos.x - pt_ref->m_End.x),
  1197. (double) (erc_pos.y - pt_ref->m_End.y) ) )
  1198. {
  1199. EXCHG( erc_pos_f.x, erc_pos.x );
  1200. EXCHG( erc_pos_f.y, erc_pos.y );
  1201. }
  1202. msg.Printf( _( "%d Err type %d: %s (net %s) and track (net %s) @ %d,%d\n" ),
  1203. ErrorsDRC_Count, errnumber, tracktype.GetData(),
  1204. netname1.GetData(), netname2.GetData(),
  1205. erc_pos.x, erc_pos.y );
  1206. }
  1207. }
  1208. if( DrcFrame )
  1209. DrcFrame->m_logWindow->AppendText( msg );
  1210. else
  1211. panel->m_Parent->Affiche_Message( msg );
  1212. if( s_RptFile )
  1213. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  1214. if( current_marqueur == NULL )
  1215. current_marqueur = new MARQUEUR( Pcb );
  1216. current_marqueur->m_Pos = wxPoint( erc_pos.x, erc_pos.y );
  1217. current_marqueur->m_Color = WHITE;
  1218. current_marqueur->m_Diag = msg;
  1219. current_marqueur->Draw( panel, DC, GR_OR );
  1220. }
  1221. /******************************************************************************/
  1222. static void Affiche_Erreur_DRC( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb,
  1223. D_PAD* pad1, D_PAD* pad2 )
  1224. /******************************************************************************/
  1225. /* affiche les erreurs de DRC :
  1226. * Message d'erreur
  1227. +
  1228. * Marqueur
  1229. * number = numero d'identification
  1230. */
  1231. {
  1232. wxString msg;
  1233. wxString pad_name1 = pad1->ReturnStringPadName();
  1234. wxString module_name1 = ( (MODULE*) (pad1->m_Parent) )->m_Reference->m_Text;
  1235. wxString pad_name2 = pad2->ReturnStringPadName();
  1236. wxString module_name2 = ( (MODULE*) (pad2->m_Parent) )->m_Reference->m_Text;
  1237. wxString netname1, netname2;
  1238. EQUIPOT* equipot = Pcb->FindNet( pad1->m_NetCode );
  1239. if( equipot )
  1240. netname1 = equipot->m_Netname;
  1241. else
  1242. netname1 = wxT( "<noname>" );
  1243. equipot = Pcb->FindNet( pad2->m_NetCode );
  1244. if( equipot )
  1245. netname2 = equipot->m_Netname;
  1246. else
  1247. netname2 = wxT( "<noname>" );
  1248. msg.Printf( _( "%d Drc Err: PAD %s (%s) net %s @ %d,%d and PAD %s (%s) net %s @ %d,%d\n" ),
  1249. ErrorsDRC_Count,
  1250. pad_name1.GetData(), module_name1.GetData(), netname1.GetData(), pad1->m_Pos.x, pad1->m_Pos.y,
  1251. pad_name2.GetData(), module_name2.GetData(), netname2.GetData(), pad2->m_Pos.x, pad2->m_Pos.y );
  1252. if( DrcFrame )
  1253. DrcFrame->m_logWindow->AppendText( msg );
  1254. else
  1255. panel->m_Parent->Affiche_Message( msg );
  1256. if( s_RptFile )
  1257. fprintf( s_RptFile, "%s", CONV_TO_UTF8( msg ) );
  1258. if( current_marqueur == NULL )
  1259. current_marqueur = new MARQUEUR( Pcb );
  1260. current_marqueur->m_Pos = pad1->m_Pos;
  1261. current_marqueur->m_Color = WHITE;
  1262. current_marqueur->m_Diag = msg;
  1263. current_marqueur->Draw( panel, DC, GR_OR );
  1264. }
  1265. /**********************************************/
  1266. /* int Tst_Ligne(int x1,int y1,int x2,int y2) */
  1267. /**********************************************/
  1268. /* Routine utilisee pour tester si une piste est en contact avec une autre piste.
  1269. *
  1270. * Cette routine controle si la ligne (x1,y1 x2,y2) a une partie s'inscrivant
  1271. * dans le cadre (xcliplo,ycliplo xcliphi,ycliphi) (variables globales,
  1272. * locales a ce fichier)
  1273. *
  1274. * Retourne OK_DRC si aucune partie commune
  1275. * Retourne BAD_DRC si partie commune
  1276. */
  1277. #define us unsigned int
  1278. static inline int USCALE( us arg, us num, us den )
  1279. {
  1280. int ii;
  1281. ii = (int) ( ( (float) arg * num ) / den );
  1282. return ii;
  1283. }
  1284. #define WHEN_OUTSIDE return (OK_DRC)
  1285. #define WHEN_INSIDE
  1286. static int Tst_Ligne( int x1, int y1, int x2, int y2 )
  1287. {
  1288. int temp;
  1289. do {
  1290. if( x1 > x2 )
  1291. {
  1292. EXCHG( x1, x2 ); EXCHG( y1, y2 );
  1293. }
  1294. if( (x2 < xcliplo) || (x1 > xcliphi) )
  1295. {
  1296. WHEN_OUTSIDE;
  1297. }
  1298. if( y1 < y2 )
  1299. {
  1300. if( (y2 < ycliplo) || (y1 > ycliphi) )
  1301. {
  1302. WHEN_OUTSIDE;
  1303. }
  1304. if( y1 < ycliplo )
  1305. {
  1306. temp = USCALE( (x2 - x1), (ycliplo - y1), (y2 - y1) );
  1307. if( (x1 += temp) > xcliphi )
  1308. {
  1309. WHEN_OUTSIDE;
  1310. }
  1311. y1 = ycliplo;
  1312. WHEN_INSIDE;
  1313. }
  1314. if( y2 > ycliphi )
  1315. {
  1316. temp = USCALE( (x2 - x1), (y2 - ycliphi), (y2 - y1) );
  1317. if( (x2 -= temp) < xcliplo )
  1318. {
  1319. WHEN_OUTSIDE;
  1320. }
  1321. y2 = ycliphi;
  1322. WHEN_INSIDE;
  1323. }
  1324. if( x1 < xcliplo )
  1325. {
  1326. temp = USCALE( (y2 - y1), (xcliplo - x1), (x2 - x1) );
  1327. y1 += temp; x1 = xcliplo;
  1328. WHEN_INSIDE;
  1329. }
  1330. if( x2 > xcliphi )
  1331. {
  1332. temp = USCALE( (y2 - y1), (x2 - xcliphi), (x2 - x1) );
  1333. y2 -= temp; x2 = xcliphi;
  1334. WHEN_INSIDE;
  1335. }
  1336. }
  1337. else
  1338. {
  1339. if( (y1 < ycliplo) || (y2 > ycliphi) )
  1340. {
  1341. WHEN_OUTSIDE;
  1342. }
  1343. if( y1 > ycliphi )
  1344. {
  1345. temp = USCALE( (x2 - x1), (y1 - ycliphi), (y1 - y2) );
  1346. if( (x1 += temp) > xcliphi )
  1347. {
  1348. WHEN_OUTSIDE;
  1349. }
  1350. y1 = ycliphi;
  1351. WHEN_INSIDE;
  1352. }
  1353. if( y2 < ycliplo )
  1354. {
  1355. temp = USCALE( (x2 - x1), (ycliplo - y2), (y1 - y2) );
  1356. if( (x2 -= temp) < xcliplo )
  1357. {
  1358. WHEN_OUTSIDE;
  1359. }
  1360. y2 = ycliplo;
  1361. WHEN_INSIDE;
  1362. }
  1363. if( x1 < xcliplo )
  1364. {
  1365. temp = USCALE( (y1 - y2), (xcliplo - x1), (x2 - x1) );
  1366. y1 -= temp;
  1367. x1 = xcliplo;
  1368. WHEN_INSIDE;
  1369. }
  1370. if( x2 > xcliphi )
  1371. {
  1372. temp = USCALE( (y1 - y2), (x2 - xcliphi), (x2 - x1) );
  1373. y2 += temp;
  1374. x2 = xcliphi;
  1375. WHEN_INSIDE;
  1376. }
  1377. }
  1378. } while( 0 );
  1379. if( ( (x2 + x1)/2 <= xcliphi ) && ( (x2 + x1)/2 >= xcliplo ) \
  1380. && ( (y2 + y1)/2 <= ycliphi ) && ( (y2 + y1)/2 >= ycliplo ) )
  1381. {
  1382. return BAD_DRC;
  1383. }
  1384. else
  1385. return OK_DRC;
  1386. }