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.

1265 lines
35 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
17 years ago
18 years ago
18 years ago
17 years ago
17 years ago
17 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
17 years ago
18 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
  1. /***********************************************************************/
  2. /* Functions relatives to tracks, vias and segments used to fill zones */
  3. /* (see class_track.h ) */
  4. /***********************************************************************/
  5. #include "fctsys.h"
  6. #include "gr_basic.h"
  7. #include "common.h"
  8. #include "trigo.h"
  9. #include "class_drawpanel.h"
  10. #include "drawtxt.h"
  11. #include "pcbnew.h"
  12. #include "class_board_design_settings.h"
  13. #include "colors_selection.h"
  14. #include "protos.h"
  15. /**
  16. * Function ShowClearance
  17. * tests to see if the clearance border is drawn on the given track.
  18. * @return bool - true if should draw clearance, else false.
  19. */
  20. static bool ShowClearance( const TRACK* aTrack )
  21. {
  22. // maybe return true for tracks and vias, not for zone segments
  23. return DisplayOpt.ShowTrackClearanceMode == SHOW_CLEARANCE_ALWAYS
  24. && aTrack->GetLayer() <= LAST_COPPER_LAYER
  25. && ( aTrack->Type() == TYPE_TRACK || aTrack->Type() == TYPE_VIA );
  26. }
  27. /**********************************************************/
  28. TRACK::TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) :
  29. BOARD_CONNECTED_ITEM( aParent, idtype )
  30. /**********************************************************/
  31. {
  32. m_Width = 0;
  33. m_Shape = S_SEGMENT;
  34. start = end = NULL;
  35. SetDrillDefault();
  36. m_Param = 0;
  37. }
  38. /***************************/
  39. wxString TRACK::ShowWidth()
  40. /***************************/
  41. {
  42. wxString msg;
  43. valeur_param( m_Width, msg );
  44. return msg;
  45. }
  46. SEGZONE::SEGZONE( BOARD_ITEM* aParent ) :
  47. TRACK( aParent, TYPE_ZONE )
  48. {
  49. }
  50. SEGVIA::SEGVIA( BOARD_ITEM* aParent ) :
  51. TRACK( aParent, TYPE_VIA )
  52. {
  53. }
  54. // Copy constructor
  55. TRACK::TRACK( const TRACK& Source ) :
  56. BOARD_CONNECTED_ITEM( Source )
  57. {
  58. m_Shape = Source.m_Shape;
  59. SetNet( Source.GetNet() );
  60. m_Flags = Source.m_Flags;
  61. m_TimeStamp = Source.m_TimeStamp;
  62. SetStatus( Source.ReturnStatus() );
  63. m_Start = Source.m_Start;
  64. m_End = Source.m_End;
  65. m_Width = Source.m_Width;
  66. m_Drill = Source.m_Drill;
  67. SetSubNet( Source.GetSubNet() );
  68. m_Param = Source.m_Param;
  69. }
  70. /* Because of the way SEGVIA and SEGZONE are derived from TRACK and because there are
  71. * virtual functions being used, we can no longer simply copy a TRACK and
  72. * expect it to be a via or zone. We must construct a true SEGVIA or SEGZONE so its constructor
  73. * can initialize the virtual function table properly. This factory type of
  74. * function called Copy() can duplicate either a TRACK, SEGVIA, or SEGZONE.
  75. */
  76. TRACK* TRACK::Copy() const
  77. {
  78. if( Type() == TYPE_TRACK )
  79. return new TRACK( *this );
  80. if( Type() == TYPE_VIA )
  81. return new SEGVIA( (const SEGVIA &) * this );
  82. if( Type() == TYPE_ZONE )
  83. return new SEGZONE( (const SEGZONE &) * this );
  84. return NULL; // should never happen
  85. }
  86. /**
  87. * Function GetClearance (virtual)
  88. * returns the clearance in internal units. If \a aItem is not NULL then the
  89. * returned clearance is the greater of this object's clearance and
  90. * aItem's clearance. If \a aItem is NULL, then this objects
  91. * clearance
  92. * is returned.
  93. * @param aItem is another BOARD_CONNECTED_ITEM or NULL
  94. * @return int - the clearance in internal units.
  95. */
  96. int TRACK::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const
  97. {
  98. // Currently tracks have no specific clearance parameter
  99. // on a per track or per segment basis.
  100. // the NETCLASS clearance is used
  101. return BOARD_CONNECTED_ITEM::GetClearance( aItem );
  102. }
  103. /**
  104. * Function GetDrillValue
  105. * calculate the drill value for vias (m_Drill if > 0, or default drill value for the Netclass
  106. * @return real drill_value
  107. */
  108. int TRACK::GetDrillValue() const
  109. {
  110. if( Type() != TYPE_VIA )
  111. return 0;
  112. if( m_Drill > 0 ) // Use the specific value.
  113. return m_Drill;
  114. // Use the default value from the Netclass
  115. NETCLASS* netclass = GetNetClass();
  116. if( m_Shape == VIA_MICROVIA )
  117. return netclass->GetuViaDrill();
  118. return netclass->GetViaDrill();
  119. }
  120. /***********************/
  121. bool TRACK::IsNull()
  122. /***********************/
  123. // return true if segment length = 0
  124. {
  125. if( ( Type() != TYPE_VIA ) && ( m_Start == m_End ) )
  126. return true;
  127. else
  128. return false;
  129. }
  130. /*************************************************************/
  131. int TRACK::IsPointOnEnds( const wxPoint& point, int min_dist )
  132. /*************************************************************/
  133. /* Return:
  134. * STARTPOINT if point if near (dist = min_dist) star point
  135. * ENDPOINT if point if near (dist = min_dist) end point
  136. * STARTPOINT|ENDPOINT if point if near (dist = min_dist) both ends
  137. * 0 if no
  138. * if min_dist < 0: min_dist = track_width/2
  139. */
  140. {
  141. int result = 0;
  142. if( min_dist < 0 )
  143. min_dist = m_Width / 2;
  144. int dx = m_Start.x - point.x;
  145. int dy = m_Start.y - point.y;
  146. if( min_dist == 0 )
  147. {
  148. if( (dx == 0) && (dy == 0 ) )
  149. result |= STARTPOINT;
  150. }
  151. else
  152. {
  153. double dist = ( (double) dx * dx ) + ( (double) dy * dy );
  154. dist = sqrt( dist );
  155. if( min_dist >= (int) dist )
  156. result |= STARTPOINT;
  157. }
  158. dx = m_End.x - point.x;
  159. dy = m_End.y - point.y;
  160. if( min_dist == 0 )
  161. {
  162. if( (dx == 0) && (dy == 0 ) )
  163. result |= ENDPOINT;
  164. }
  165. else
  166. {
  167. double dist = ( (double) dx * dx ) + ( (double) dy * dy );
  168. dist = sqrt( dist );
  169. if( min_dist >= (int) dist )
  170. result |= ENDPOINT;
  171. }
  172. return result;
  173. }
  174. EDA_RECT TRACK::GetBoundingBox() const
  175. {
  176. // end of track is round, this is its radius, rounded up
  177. int radius = ( m_Width + 1 ) / 2;
  178. int ymax;
  179. int xmax;
  180. int ymin;
  181. int xmin;
  182. if( Type() == TYPE_VIA )
  183. {
  184. // Because vias are sometimes drawn larger than their m_Width would
  185. // provide, erasing them using a dirty rect must also compensate for this
  186. // possibility (that the via is larger on screen than its m_Width would provide).
  187. // Because it is cheap to return a larger BoundingBox, do it so that
  188. // the via gets erased properly. Do not divide width by 2 for this reason.
  189. radius = m_Width;
  190. ymax = m_Start.y;
  191. xmax = m_Start.x;
  192. ymin = m_Start.y;
  193. xmin = m_Start.x;
  194. }
  195. else
  196. {
  197. radius = ( m_Width + 1 ) / 2;
  198. ymax = MAX( m_Start.y, m_End.y );
  199. xmax = MAX( m_Start.x, m_End.x );
  200. ymin = MIN( m_Start.y, m_End.y );
  201. xmin = MIN( m_Start.x, m_End.x );
  202. }
  203. if( ShowClearance( this ) )
  204. {
  205. // + 1 is for the clearance line itself.
  206. radius += GetClearance() + 1;
  207. }
  208. ymax += radius;
  209. xmax += radius;
  210. ymin -= radius;
  211. xmin -= radius;
  212. // return a rectangle which is [pos,dim) in nature. therefore the +1
  213. EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
  214. return ret;
  215. }
  216. /**
  217. * Function Rotate
  218. * Rotate this object.
  219. * @param aRotCentre - the rotation point.
  220. * @param aAngle - the rotation angle in 0.1 degree.
  221. */
  222. void TRACK::Rotate( const wxPoint& aRotCentre, int aAngle )
  223. {
  224. RotatePoint( &m_Start, aRotCentre, aAngle );
  225. RotatePoint( &m_End, aRotCentre, aAngle );
  226. }
  227. /**
  228. * Function Flip
  229. * Flip this object, i.e. change the board side for this object
  230. * @param aCentre - the rotation point.
  231. */
  232. void TRACK::Flip( const wxPoint& aCentre )
  233. {
  234. m_Start.y = aCentre.y - (m_Start.y - aCentre.y);
  235. m_End.y = aCentre.y - (m_End.y - aCentre.y);
  236. if( Type() == TYPE_VIA )
  237. {
  238. }
  239. else
  240. SetLayer( ChangeSideNumLayer( GetLayer() ) );
  241. }
  242. // see class_track.h
  243. // SEGVIA and SEGZONE inherit this version
  244. SEARCH_RESULT TRACK::Visit( INSPECTOR* inspector, const void* testData,
  245. const KICAD_T scanTypes[] )
  246. {
  247. KICAD_T stype = *scanTypes;
  248. #if 0 && defined(DEBUG)
  249. std::cout << GetClass().mb_str() << ' ';
  250. #endif
  251. // If caller wants to inspect my type
  252. if( stype == Type() )
  253. {
  254. if( SEARCH_QUIT == inspector->Inspect( this, testData ) )
  255. return SEARCH_QUIT;
  256. }
  257. return SEARCH_CONTINUE;
  258. }
  259. /***********************************************/
  260. bool SEGVIA::IsOnLayer( int layer_number ) const
  261. /***********************************************/
  262. {
  263. int bottom_layer, top_layer;
  264. ReturnLayerPair( &top_layer, &bottom_layer );
  265. if( bottom_layer <= layer_number && layer_number <= top_layer )
  266. return true;
  267. else
  268. return false;
  269. }
  270. /***********************************/
  271. int TRACK::ReturnMaskLayer()
  272. /***********************************/
  273. /* Return the mask layer for this.
  274. * for a via, there is more than one layer used
  275. */
  276. {
  277. if( Type() == TYPE_VIA )
  278. {
  279. int via_type = Shape();
  280. if( via_type == VIA_THROUGH )
  281. return ALL_CU_LAYERS;
  282. // VIA_BLIND_BURIED or VIA_MICRVIA:
  283. int bottom_layer, top_layer;
  284. // ReturnLayerPair() knows how layers are stored
  285. ( (SEGVIA*) this )->ReturnLayerPair( &top_layer, &bottom_layer );
  286. int layermask = 0;
  287. while( bottom_layer <= top_layer )
  288. {
  289. layermask |= g_TabOneLayerMask[bottom_layer++];
  290. }
  291. return layermask;
  292. }
  293. else
  294. return g_TabOneLayerMask[m_Layer];
  295. }
  296. /*********************************************************/
  297. void SEGVIA::SetLayerPair( int top_layer, int bottom_layer )
  298. /*********************************************************/
  299. /** Set the .m_Layer member param:
  300. * For a via m_Layer contains the 2 layers :
  301. * top layer and bottom layer used by the via.
  302. * The via connect all layers from top layer to bottom layer
  303. * 4 bits for the first layer and 4 next bits for the secaon layer
  304. * @param top_layer = first layer connected by the via
  305. * @param bottom_layer = last layer connected by the via
  306. */
  307. {
  308. if( Shape() == VIA_THROUGH )
  309. {
  310. top_layer = LAYER_N_FRONT;
  311. bottom_layer = LAYER_N_BACK;
  312. }
  313. if( bottom_layer > top_layer )
  314. EXCHG( bottom_layer, top_layer );
  315. m_Layer = (top_layer & 15) + ( (bottom_layer & 15) << 4 );
  316. }
  317. /*********************************************************************/
  318. void SEGVIA::ReturnLayerPair( int* top_layer, int* bottom_layer ) const
  319. /*********************************************************************/
  320. /**
  321. * Function ReturnLayerPair
  322. * Return the 2 layers used by the via (the via actually uses
  323. * all layers between these 2 layers)
  324. * @param top_layer = pointer to the first layer (can be null)
  325. * @param bottom_layer = pointer to the last layer (can be null)
  326. */
  327. {
  328. int b_layer = LAYER_N_BACK;
  329. int t_layer = LAYER_N_FRONT;
  330. if( Shape() != VIA_THROUGH )
  331. {
  332. b_layer = (m_Layer >> 4) & 15;
  333. t_layer = m_Layer & 15;
  334. if( b_layer > t_layer )
  335. EXCHG( b_layer, t_layer );
  336. }
  337. if( top_layer )
  338. *top_layer = t_layer;
  339. if( bottom_layer )
  340. *bottom_layer = b_layer;
  341. }
  342. /*
  343. * Function GetBestInsertPoint
  344. * Search the "best" insertion point within the track linked list
  345. * the best point is the of the corresponding net code section
  346. * return the item found in the linked list (or NULL if no track)
  347. */
  348. TRACK* TRACK::GetBestInsertPoint( BOARD* aPcb )
  349. {
  350. TRACK* track;
  351. if( Type() == TYPE_ZONE )
  352. track = aPcb->m_Zone;
  353. else
  354. track = aPcb->m_Track;
  355. for( ; track; track = track->Next() )
  356. {
  357. if( GetNet() <= track->GetNet() )
  358. return track;
  359. }
  360. return NULL;
  361. }
  362. /*******************************************/
  363. TRACK* TRACK::GetStartNetCode( int NetCode )
  364. /*******************************************/
  365. /* Search (within the track linked list) the first segment matching the netcode
  366. * ( the linked list is always sorted by net codes )
  367. */
  368. {
  369. TRACK* Track = this;
  370. int ii = 0;
  371. if( NetCode == -1 )
  372. NetCode = GetNet();
  373. while( Track != NULL )
  374. {
  375. if( Track->GetNet() > NetCode )
  376. break;
  377. if( Track->GetNet() == NetCode )
  378. {
  379. ii++;
  380. break;
  381. }
  382. Track = (TRACK*) Track->Pnext;
  383. }
  384. if( ii )
  385. return Track;
  386. else
  387. return NULL;
  388. }
  389. /*****************************************/
  390. TRACK* TRACK::GetEndNetCode( int NetCode )
  391. /*****************************************/
  392. /* Search (within the track linked list) the last segment matching the netcode
  393. * ( the linked list is always sorted by net codes )
  394. */
  395. {
  396. TRACK* NextS, * Track = this;
  397. int ii = 0;
  398. if( Track == NULL )
  399. return NULL;
  400. if( NetCode == -1 )
  401. NetCode = GetNet();
  402. while( Track != NULL )
  403. {
  404. NextS = (TRACK*) Track->Pnext;
  405. if( Track->GetNet() == NetCode )
  406. ii++;
  407. if( NextS == NULL )
  408. break;
  409. if( NextS->GetNet() > NetCode )
  410. break;
  411. Track = NextS;
  412. }
  413. if( ii )
  414. return Track;
  415. else
  416. return NULL;
  417. }
  418. bool TRACK::Save( FILE* aFile ) const
  419. {
  420. int type = 0;
  421. if( Type() == TYPE_VIA )
  422. type = 1;
  423. fprintf( aFile, "Po %d %d %d %d %d %d %d\n", m_Shape,
  424. m_Start.x, m_Start.y, m_End.x, m_End.y, m_Width, m_Drill );
  425. fprintf( aFile, "De %d %d %d %lX %X\n",
  426. m_Layer, type, GetNet(),
  427. m_TimeStamp, ReturnStatus() );
  428. return true;
  429. }
  430. /*********************************************************************/
  431. void TRACK::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, int draw_mode, const wxPoint& aOffset )
  432. /*********************************************************************/
  433. {
  434. int l_piste;
  435. int color;
  436. int rayon;
  437. int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
  438. if( Type() == TYPE_ZONE && DisplayOpt.DisplayZonesMode != 0 )
  439. return;
  440. BOARD * brd = GetBoard( );
  441. color = brd->GetLayerColor(m_Layer);
  442. if( brd->IsLayerVisible( m_Layer ) == false && ( color & HIGHLIGHT_FLAG ) !=
  443. HIGHLIGHT_FLAG )
  444. return;
  445. if( DisplayOpt.ContrastModeDisplay )
  446. {
  447. if( !IsOnLayer( curr_layer ) )
  448. {
  449. color &= ~MASKCOLOR;
  450. color |= DARKDARKGRAY;
  451. }
  452. }
  453. if( draw_mode & GR_SURBRILL )
  454. {
  455. if( draw_mode & GR_AND )
  456. color &= ~HIGHLIGHT_FLAG;
  457. else
  458. color |= HIGHLIGHT_FLAG;
  459. }
  460. if( color & HIGHLIGHT_FLAG )
  461. color = ColorRefs[color & MASKCOLOR].m_LightColor;
  462. SetAlpha( &color, 150 );
  463. GRSetDrawMode( DC, draw_mode );
  464. l_piste = m_Width >> 1;
  465. if( m_Shape == S_CIRCLE )
  466. {
  467. rayon = (int) hypot( (double) ( m_End.x - m_Start.x ),
  468. (double) ( m_End.y - m_Start.y ) );
  469. if( DC->LogicalToDeviceXRel( l_piste ) < L_MIN_DESSIN )
  470. {
  471. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  472. m_Start.y + aOffset.y, rayon, color );
  473. }
  474. else
  475. {
  476. if( DC->LogicalToDeviceXRel( l_piste ) <= 1 ) /* Sketch mode if l_piste/zoom <= 1 */
  477. {
  478. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  479. m_Start.y + aOffset.y, rayon, color );
  480. }
  481. else if( ( !DisplayOpt.DisplayPcbTrackFill) || GetState( FORCE_SKETCH ) )
  482. {
  483. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  484. m_Start.y + aOffset.y, rayon - l_piste, color );
  485. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  486. m_Start.y + aOffset.y, rayon + l_piste, color );
  487. }
  488. else
  489. {
  490. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  491. m_Start.y + aOffset.y, rayon,
  492. m_Width, color );
  493. }
  494. }
  495. return;
  496. }
  497. if( DC->LogicalToDeviceXRel( l_piste ) < L_MIN_DESSIN )
  498. {
  499. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  500. m_Start.y + aOffset.y,
  501. m_End.x + aOffset.x, m_End.y + aOffset.y, 0, color );
  502. return;
  503. }
  504. if( !DisplayOpt.DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
  505. {
  506. GRCSegm( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  507. m_Start.y + aOffset.y,
  508. m_End.x + aOffset.x, m_End.y + aOffset.y, m_Width, color );
  509. }
  510. else
  511. {
  512. GRFillCSegm( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  513. m_Start.y + aOffset.y,
  514. m_End.x + aOffset.x, m_End.y + aOffset.y, m_Width, color );
  515. }
  516. if( panel->GetScreen()->m_IsPrinting )
  517. return;
  518. // Show clearance for tracks, not for zone segments
  519. if( ShowClearance( this ) )
  520. {
  521. GRCSegm( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  522. m_Start.y + aOffset.y,
  523. m_End.x + aOffset.x, m_End.y + aOffset.y,
  524. m_Width + (GetClearance() * 2), color );
  525. }
  526. /* Display the short netname for tracks, not for zone segments.
  527. * we must filter tracks, to avoid a lot of texts.
  528. * - only horizontal or vertical tracks are eligible
  529. * - only tracks with a length > 10 * thickness are eligible
  530. * and, of course, if we are not printing the board
  531. */
  532. if( Type() == TYPE_ZONE )
  533. return;
  534. if( DisplayOpt.DisplayNetNamesMode == 0 || DisplayOpt.DisplayNetNamesMode == 1 )
  535. return;
  536. #define THRESHOLD 10
  537. if( (m_End.x - m_Start.x) != 0
  538. && (m_End.y - m_Start.y) != 0 )
  539. return;
  540. int len = ABS( (m_End.x - m_Start.x)
  541. + (m_End.y - m_Start.y) );
  542. if( len < THRESHOLD * m_Width )
  543. return;
  544. if( DC->LogicalToDeviceXRel( m_Width ) < 6 ) // no room to display a text inside track
  545. return;
  546. if( GetNet() == 0 )
  547. return;
  548. NETINFO_ITEM* net = ( (BOARD*) GetParent() )->FindNet( GetNet() );
  549. if( net == NULL )
  550. return;
  551. int textlen = net->GetShortNetname().Len();
  552. if( textlen > 0 )
  553. {
  554. // calculate a good size for the text
  555. int tsize = MIN( m_Width, len / textlen );
  556. wxPoint tpos = m_Start + m_End;
  557. tpos.x /= 2;
  558. tpos.y /= 2;
  559. // Calculate angle: if the track segment is vertical, angle = 90 degrees
  560. int angle = 0;
  561. if( (m_End.x - m_Start.x) == 0 ) // Vertical segment
  562. angle = 900; // angle is in 0.1 degree
  563. if( DC->LogicalToDeviceXRel( tsize ) >= 6 )
  564. {
  565. if( !(!IsOnLayer( curr_layer )&& DisplayOpt.ContrastModeDisplay) )
  566. {
  567. tsize = (tsize * 8) / 10; // small reduction to give a better look
  568. DrawGraphicText( panel, DC, tpos,
  569. WHITE, net->GetShortNetname(), angle, wxSize( tsize, tsize ),
  570. GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, tsize / 7,
  571. false, false );
  572. }
  573. }
  574. }
  575. }
  576. /*******************************************************************************************/
  577. void SEGVIA::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, int draw_mode, const wxPoint& aOffset )
  578. /*******************************************************************************************/
  579. {
  580. int color;
  581. int rayon;
  582. int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
  583. int fillvia = 0;
  584. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
  585. PCB_SCREEN* screen = frame->GetScreen();
  586. if( frame->m_DisplayViaFill == FILLED )
  587. fillvia = 1;
  588. GRSetDrawMode( DC, draw_mode );
  589. BOARD * brd = GetBoard( );
  590. color = brd->GetVisibleElementColor(VIAS_VISIBLE + m_Shape);
  591. if( brd->IsElementVisible( PCB_VISIBLE(VIAS_VISIBLE + m_Shape) ) == false
  592. && ( color & HIGHLIGHT_FLAG ) != HIGHLIGHT_FLAG )
  593. return;
  594. if( DisplayOpt.ContrastModeDisplay )
  595. {
  596. if( !IsOnLayer( curr_layer ) )
  597. {
  598. color &= ~MASKCOLOR;
  599. color |= DARKDARKGRAY;
  600. }
  601. }
  602. if( draw_mode & GR_SURBRILL )
  603. {
  604. if( draw_mode & GR_AND )
  605. color &= ~HIGHLIGHT_FLAG;
  606. else
  607. color |= HIGHLIGHT_FLAG;
  608. }
  609. if( color & HIGHLIGHT_FLAG )
  610. color = ColorRefs[color & MASKCOLOR].m_LightColor;
  611. SetAlpha( &color, 150 );
  612. rayon = m_Width >> 1;
  613. // for small via size on screen (rayon < 4 pixels) draw a simplified shape
  614. int radius_in_pixels = DC->LogicalToDeviceXRel( rayon );
  615. bool fast_draw = false;
  616. // Vias are drawn as a filled circle or a double circle. The hole will be drawn later
  617. int drill_rayon = GetDrillValue() / 2;
  618. int inner_rayon = rayon - DC->DeviceToLogicalXRel( 2 );
  619. if( radius_in_pixels < 3 )
  620. {
  621. fast_draw = true;
  622. fillvia = false;
  623. }
  624. if( fillvia )
  625. GRFilledCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  626. m_Start.y + aOffset.y, rayon, 0, color, color );
  627. else
  628. {
  629. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  630. m_Start.y + aOffset.y, rayon, color );
  631. if ( fast_draw )
  632. return;
  633. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  634. m_Start.y + aOffset.y,
  635. inner_rayon, color );
  636. }
  637. // Draw the via hole if the display option allows it
  638. if( DisplayOpt.m_DisplayViaMode != VIA_HOLE_NOT_SHOW )
  639. {
  640. if( (DisplayOpt.m_DisplayViaMode == ALL_VIA_HOLE_SHOW) // Display all drill holes requested
  641. || ( (drill_rayon > 0 ) && !IsDrillDefault() ) ) // Or Display non default holes requested
  642. {
  643. if( fillvia )
  644. {
  645. bool blackpenstate = false;
  646. if( screen->m_IsPrinting )
  647. {
  648. blackpenstate = GetGRForceBlackPenState();
  649. GRForceBlackPen( false );
  650. color = g_DrawBgColor;
  651. }
  652. else
  653. color = BLACK; // or DARKGRAY;
  654. if( draw_mode != GR_XOR )
  655. GRSetDrawMode( DC, GR_COPY );
  656. else
  657. GRSetDrawMode( DC, GR_XOR );
  658. if( DC->LogicalToDeviceXRel( drill_rayon ) > 1 ) // Draw hole if large enough.
  659. GRFilledCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  660. m_Start.y + aOffset.y, drill_rayon, 0, color, color );
  661. if( screen->m_IsPrinting )
  662. GRForceBlackPen( blackpenstate );
  663. }
  664. else
  665. {
  666. if( drill_rayon < inner_rayon ) // We can show the via hole
  667. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  668. m_Start.y + aOffset.y,
  669. drill_rayon, color );
  670. }
  671. }
  672. }
  673. if( DisplayOpt.ShowTrackClearanceMode == SHOW_CLEARANCE_ALWAYS )
  674. GRCircle( &panel->m_ClipBox, DC, m_Start.x + aOffset.x,
  675. m_Start.y + aOffset.y,
  676. rayon + GetClearance(), color );
  677. // for Micro Vias, draw a partial cross :
  678. // X on component layer, or + on copper layer
  679. // (so we can see 2 superimposed microvias ):
  680. if( Shape() == VIA_MICROVIA )
  681. {
  682. int ax, ay, bx, by;
  683. if( IsOnLayer( LAYER_N_BACK ) )
  684. {
  685. ax = rayon; ay = 0;
  686. bx = drill_rayon; by = 0;
  687. }
  688. else
  689. {
  690. ax = ay = (rayon * 707) / 1000;
  691. bx = by = (drill_rayon * 707) / 1000;
  692. }
  693. /* lines | or \ */
  694. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x - ax,
  695. m_Start.y + aOffset.y - ay,
  696. m_Start.x + aOffset.x - bx,
  697. m_Start.y + aOffset.y - by, 0, color );
  698. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x + bx,
  699. m_Start.y + aOffset.y + by,
  700. m_Start.x + aOffset.x + ax,
  701. m_Start.y + aOffset.y + ay, 0, color );
  702. /* lines - or / */
  703. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x + ay,
  704. m_Start.y + aOffset.y - ax,
  705. m_Start.x + aOffset.x + by,
  706. m_Start.y + aOffset.y - bx, 0, color );
  707. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x - by,
  708. m_Start.y + aOffset.y + bx,
  709. m_Start.x + aOffset.x - ay,
  710. m_Start.y + aOffset.y + ax, 0, color );
  711. }
  712. // for Buried Vias, draw a partial line :
  713. // orient depending on layer pair
  714. // (so we can see superimposed buried vias ):
  715. if( Shape() == VIA_BLIND_BURIED )
  716. {
  717. int ax = 0, ay = rayon, bx = 0, by = drill_rayon;
  718. int layer_top, layer_bottom;
  719. ( (SEGVIA*) this )->ReturnLayerPair( &layer_top, &layer_bottom );
  720. /* lines for the top layer */
  721. RotatePoint( &ax, &ay, layer_top * 3600 / brd->GetCopperLayerCount( ) );
  722. RotatePoint( &bx, &by, layer_top * 3600 / brd->GetCopperLayerCount( ) );
  723. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x - ax,
  724. m_Start.y + aOffset.y - ay,
  725. m_Start.x + aOffset.x - bx,
  726. m_Start.y + aOffset.y - by, 0, color );
  727. /* lines for the bottom layer */
  728. ax = 0; ay = rayon; bx = 0; by = drill_rayon;
  729. RotatePoint( &ax, &ay, layer_bottom * 3600 / brd->GetCopperLayerCount( ) );
  730. RotatePoint( &bx, &by, layer_bottom * 3600 / brd->GetCopperLayerCount( ) );
  731. GRLine( &panel->m_ClipBox, DC, m_Start.x + aOffset.x - ax,
  732. m_Start.y + aOffset.y - ay,
  733. m_Start.x + aOffset.x - bx,
  734. m_Start.y + aOffset.y - by, 0, color );
  735. }
  736. // Display the short netname:
  737. if( GetNet() == 0 )
  738. return;
  739. if( DisplayOpt.DisplayNetNamesMode == 0 || DisplayOpt.DisplayNetNamesMode == 1 )
  740. return;
  741. NETINFO_ITEM* net = ( (BOARD*) GetParent() )->FindNet( GetNet() );
  742. if( net == NULL )
  743. return;
  744. int len = net->GetShortNetname().Len();
  745. if( len > 0 )
  746. {
  747. // calculate a good size for the text
  748. int tsize = m_Width / len;
  749. if( DC->LogicalToDeviceXRel( tsize ) >= 6 )
  750. {
  751. tsize = (tsize * 8) / 10; // small reduction to give a better look, inside via
  752. DrawGraphicText( panel, DC, m_Start,
  753. WHITE, net->GetShortNetname(), 0, wxSize( tsize, tsize ),
  754. GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, tsize / 7,
  755. false, false );
  756. }
  757. }
  758. }
  759. // see class_track.h
  760. void TRACK::DisplayInfo( EDA_DRAW_FRAME* frame )
  761. {
  762. wxString msg;
  763. BOARD* board = ( (PCB_BASE_FRAME*) frame )->GetBoard();
  764. // Display basic infos
  765. DisplayInfoBase( frame );
  766. // Display full track length (in pcbnew)
  767. if( frame->m_Ident == PCB_FRAME )
  768. {
  769. int trackLen = 0;
  770. Marque_Une_Piste( board, this, NULL, &trackLen, false );
  771. msg = frame->CoordinateToString( trackLen );
  772. frame->AppendMsgPanel( _( "Track Length" ), msg, DARKCYAN );
  773. }
  774. NETCLASS* netclass = GetNetClass();
  775. if( netclass )
  776. {
  777. frame->AppendMsgPanel( _( "NC Name" ), netclass->GetName(), DARKMAGENTA );
  778. frame->AppendMsgPanel( _( "NC Clearance" ),
  779. frame->CoordinateToString( netclass->GetClearance(), true ),
  780. DARKMAGENTA );
  781. frame->AppendMsgPanel( _( "NC Width" ),
  782. frame->CoordinateToString( netclass->GetTrackWidth(), true ),
  783. DARKMAGENTA );
  784. frame->AppendMsgPanel( _( "NC Via Size"),
  785. frame->CoordinateToString( netclass->GetViaDiameter(), true ),
  786. DARKMAGENTA );
  787. frame->AppendMsgPanel( _( "NC Via Drill"),
  788. frame->CoordinateToString( netclass->GetViaDrill(), true ),
  789. DARKMAGENTA );
  790. }
  791. }
  792. /*
  793. * Function DisplayInfoBase
  794. * has knowledge about the frame and how and where to put status information
  795. * about this object into the frame's message panel.
  796. * Display info about the track segment only, and does not calculate the full track length
  797. * @param frame A EDA_DRAW_FRAME in which to print status information.
  798. */
  799. void TRACK::DisplayInfoBase( EDA_DRAW_FRAME* frame )
  800. {
  801. wxString msg;
  802. BOARD* board = ( (PCB_BASE_FRAME*) frame )->GetBoard();
  803. frame->ClearMsgPanel();
  804. switch( Type() )
  805. {
  806. case TYPE_VIA:
  807. msg = g_ViaType_Name[Shape()];
  808. break;
  809. case TYPE_TRACK:
  810. msg = _( "Track" );
  811. break;
  812. case TYPE_ZONE:
  813. msg = _( "Zone" ); break;
  814. default:
  815. msg = wxT( "????" ); break;
  816. }
  817. frame->AppendMsgPanel( _( "Type" ), msg, DARKCYAN );
  818. // Display Net Name (in pcbnew)
  819. if( frame->m_Ident == PCB_FRAME )
  820. {
  821. NETINFO_ITEM* net = board->FindNet( GetNet() );
  822. if( net )
  823. msg = net->GetNetname();
  824. else
  825. msg = wxT( "<noname>" );
  826. frame->AppendMsgPanel( _( "NetName" ), msg, RED );
  827. /* Display net code : (usefull in test or debug) */
  828. msg.Printf( wxT( "%d .%d" ), GetNet(), GetSubNet() );
  829. frame->AppendMsgPanel( _( "NetCode" ), msg, RED );
  830. }
  831. #if defined(DEBUG)
  832. /* Display the flags */
  833. msg.Printf( wxT( "0x%08X" ), m_Flags );
  834. frame->AppendMsgPanel( _( "Flags" ), msg, BLUE );
  835. #endif
  836. /* Display the State member */
  837. msg = wxT( ". . " );
  838. if( GetState( TRACK_LOCKED ) )
  839. msg[0] = 'F';
  840. if( GetState( TRACK_AR ) )
  841. msg[2] = 'A';
  842. frame->AppendMsgPanel( _( "Status" ), msg, MAGENTA );
  843. /* Display layer or layer pair) */
  844. if( Type() == TYPE_VIA )
  845. {
  846. SEGVIA* Via = (SEGVIA*) this;
  847. int top_layer, bottom_layer;
  848. Via->ReturnLayerPair( &top_layer, &bottom_layer );
  849. msg = board->GetLayerName( top_layer ) + wxT( "/" )
  850. + board->GetLayerName( bottom_layer );
  851. }
  852. else
  853. msg = board->GetLayerName( m_Layer );
  854. frame->AppendMsgPanel( _( "Layer" ), msg, BROWN );
  855. /* Display width */
  856. msg = frame->CoordinateToString( (unsigned) m_Width );
  857. if( Type() == TYPE_VIA ) // Display Diam and Drill values
  858. {
  859. // Display diameter value:
  860. frame->AppendMsgPanel( _( "Diam" ), msg, DARKCYAN );
  861. // Display drill value
  862. int drill_value = GetDrillValue();
  863. msg = frame->CoordinateToString( (unsigned) drill_value );
  864. wxString title = _( "Drill" );
  865. title += wxT( " " );
  866. if( m_Drill >= 0 )
  867. title += _( "(Specific)" );
  868. else
  869. title += _( "(Default)" );
  870. frame->AppendMsgPanel( title, msg, RED );
  871. }
  872. else
  873. {
  874. frame->AppendMsgPanel( _( "Width" ), msg, DARKCYAN );
  875. }
  876. // Display segment length
  877. if( Type() != TYPE_VIA ) // Display Diam and Drill values
  878. {
  879. msg = frame->CoordinateToString( wxRound( GetLength() ) );
  880. frame->AppendMsgPanel( _( "Segment Length" ), msg, DARKCYAN );
  881. }
  882. }
  883. /**
  884. * Function HitTest
  885. * tests if the given wxPoint is within the bounds of this object.
  886. * @param refPos A wxPoint to test
  887. * @return bool - true if a hit, else false
  888. */
  889. bool TRACK::HitTest( const wxPoint& refPos )
  890. {
  891. int radius = m_Width >> 1;
  892. // (dx, dy) is a vector from m_Start to m_End (an origin of m_Start)
  893. int dx = m_End.x - m_Start.x;
  894. int dy = m_End.y - m_Start.y;
  895. // (spot_cX, spot_cY) is a vector from m_Start to ref_pos (an origin of m_Start)
  896. int spot_cX = refPos.x - m_Start.x;
  897. int spot_cY = refPos.y - m_Start.y;
  898. if( Type() == TYPE_VIA )
  899. {
  900. return (double) spot_cX * spot_cX + (double) spot_cY * spot_cY <=
  901. (double) radius * radius;
  902. }
  903. else
  904. {
  905. if( DistanceTest( radius, dx, dy, spot_cX, spot_cY ) )
  906. return true;
  907. }
  908. return false;
  909. }
  910. /**
  911. * Function HitTest (overlaid)
  912. * tests if the given EDA_RECT intersect this object.
  913. * For now, an ending point must be inside this rect.
  914. * @param refArea an EDA_RECT to test
  915. * @return bool - true if a hit, else false
  916. */
  917. bool TRACK::HitTest( EDA_RECT& refArea )
  918. {
  919. if( refArea.Contains( m_Start ) )
  920. return true;
  921. if( refArea.Contains( m_End ) )
  922. return true;
  923. return false;
  924. }
  925. #if defined(DEBUG)
  926. /**
  927. * Function Show
  928. * is used to output the object tree, currently for debugging only.
  929. * @param nestLevel An aid to prettier tree indenting, and is the level
  930. * of nesting of this object within the overall tree.
  931. * @param os The ostream& to output to.
  932. */
  933. void TRACK::Show( int nestLevel, std::ostream& os )
  934. {
  935. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  936. // " shape=\"" << m_Shape << '"' <<
  937. " addr=\"" << std::hex << this << std::dec << '"' <<
  938. " layer=\"" << m_Layer << '"' <<
  939. " width=\"" << m_Width << '"' <<
  940. " flags=\"" << m_Flags << '"' <<
  941. " status=\"" << GetState( -1 ) << '"' <<
  942. // " drill=\"" << GetDrillValue() << '"' <<
  943. " netcode=\"" << GetNet() << "\">" <<
  944. "<start" << m_Start << "/>" <<
  945. "<end" << m_End << "/>";
  946. os << "</" << GetClass().Lower().mb_str() << ">\n";
  947. }
  948. /**
  949. * Function Show
  950. * is used to output the object tree, currently for debugging only.
  951. * @param nestLevel An aid to prettier tree indenting, and is the level
  952. * of nesting of this object within the overall tree.
  953. * @param os The ostream& to output to.
  954. */
  955. void SEGVIA::Show( int nestLevel, std::ostream& os )
  956. {
  957. const char* cp;
  958. switch( Shape() )
  959. {
  960. case VIA_THROUGH:
  961. cp = "through";
  962. break;
  963. case VIA_BLIND_BURIED:
  964. cp = "blind/buried";
  965. break;
  966. case VIA_MICROVIA:
  967. cp = "micro via";
  968. break;
  969. default:
  970. case VIA_NOT_DEFINED:
  971. cp = "undefined";
  972. break;
  973. }
  974. int topLayer;
  975. int botLayer;
  976. BOARD* board = (BOARD*) m_Parent;
  977. ReturnLayerPair( &topLayer, &botLayer );
  978. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  979. " type=\"" << cp << '"';
  980. if( board )
  981. os << " layers=\"" << board->GetLayerName( topLayer ).Trim().mb_str() << ","
  982. << board->GetLayerName( botLayer ).Trim().mb_str() << '"';
  983. os <<
  984. " width=\"" << m_Width << '"' <<
  985. " drill=\"" << GetDrillValue() << '"' <<
  986. " netcode=\"" << GetNet() << "\">" <<
  987. "<pos" << m_Start << "/>";
  988. os << "</" << GetClass().Lower().mb_str() << ">\n";
  989. }
  990. wxString TRACK::ShowState( int stateBits )
  991. {
  992. wxString ret;
  993. if( stateBits & IS_LINKED )
  994. ret << wxT( " | IS_LINKED" );
  995. if( stateBits & TRACK_AR )
  996. ret << wxT( " | TRACK_AR" );
  997. if( stateBits & TRACK_LOCKED )
  998. ret << wxT( " | TRACK_LOCKED" );
  999. if( stateBits & IN_EDIT )
  1000. ret << wxT( " | IN_EDIT" );
  1001. if( stateBits & IS_DRAGGED )
  1002. ret << wxT( " | IS_DRAGGED" );
  1003. if( stateBits & DO_NOT_DRAW )
  1004. ret << wxT( " | DO_NOT_DRAW" );
  1005. if( stateBits & IS_DELETED )
  1006. ret << wxT( " | IS_DELETED" );
  1007. if( stateBits & BUSY )
  1008. ret << wxT( " | BUSY" );
  1009. if( stateBits & END_ONPAD )
  1010. ret << wxT( " | END_ONPAD" );
  1011. if( stateBits & BEGIN_ONPAD )
  1012. ret << wxT( " | BEGIN_ONPAD" );
  1013. if( stateBits & FLAG0 )
  1014. ret << wxT( " | FLAG0" );
  1015. if( stateBits & FLAG1 )
  1016. ret << wxT( " | FLAG1" );
  1017. return ret;
  1018. }
  1019. #endif