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.

589 lines
15 KiB

18 years ago
  1. /****************************************************/
  2. /* class_module.cpp : EDGE_MODULE class definition. */
  3. /****************************************************/
  4. #include "fctsys.h"
  5. #include "gr_basic.h"
  6. #include "wxstruct.h"
  7. #include "common.h"
  8. #include "trigo.h"
  9. #include "class_drawpanel.h"
  10. #include "confirm.h"
  11. #include "kicad_string.h"
  12. #include "pcbnew.h"
  13. #include "class_board_design_settings.h"
  14. #define MAX_WIDTH 10000 /* Thickness (in 1 / 10000 ") of maximum reasonable
  15. * features, text... */
  16. /*********************/
  17. /* class EDGE_MODULE */
  18. /*********************/
  19. EDGE_MODULE::EDGE_MODULE( MODULE* parent ) :
  20. BOARD_ITEM( parent, TYPE_EDGE_MODULE )
  21. {
  22. m_Width = 0;
  23. m_Shape = S_SEGMENT;
  24. m_Angle = 0;
  25. m_Width = 120;
  26. }
  27. EDGE_MODULE::~EDGE_MODULE()
  28. {
  29. }
  30. void EDGE_MODULE::Copy( EDGE_MODULE* source )
  31. {
  32. if( source == NULL )
  33. return;
  34. m_Start = source->m_Start;
  35. m_End = source->m_End;
  36. m_Shape = source->m_Shape;
  37. m_Start0 = source->m_Start0;
  38. m_End0 = source->m_End0;
  39. m_Angle = source->m_Angle;
  40. m_Layer = source->m_Layer;
  41. m_Width = source->m_Width;
  42. m_PolyPoints = source->m_PolyPoints; // std::vector copy
  43. }
  44. /**
  45. * Function GetBoundingBox
  46. * returns the orthogonal, bounding box of this object for display purposes.
  47. * This box should be an enclosing perimeter for visible components of this
  48. * object, and the units should be in the pcb or schematic coordinate system.
  49. * It is OK to overestimate the size by a few counts.
  50. */
  51. EDA_Rect EDGE_MODULE::GetBoundingBox()
  52. {
  53. EDA_Rect bbox;
  54. bbox.SetOrigin( m_Start );
  55. switch( m_Shape )
  56. {
  57. case S_SEGMENT:
  58. bbox.SetEnd( m_End );
  59. bbox.Inflate( (m_Width / 2) + 1 );
  60. break;
  61. case S_CIRCLE:
  62. {
  63. int rayon = (int) hypot( (double) (m_End.x - m_Start.x), (double) (m_End.y - m_Start.y) );
  64. bbox.Inflate( rayon + 1 );
  65. }
  66. break;
  67. case S_ARC:
  68. {
  69. int rayon = (int) hypot( (double) (m_End.x - m_Start.x), (double) (m_End.y - m_Start.y) );
  70. bbox.Inflate( rayon + 1 );
  71. }
  72. break;
  73. case S_POLYGON:
  74. {
  75. // We must compute true coordinates from m_PolyPoints
  76. // which are relative to module position, orientation 0
  77. std::vector<wxPoint> points = m_PolyPoints;
  78. wxPoint p_end = m_Start;
  79. MODULE* Module = (MODULE*) m_Parent;
  80. for( unsigned ii = 0; ii < points.size(); ii++ )
  81. {
  82. wxPoint& pt = points[ii];
  83. if( Module )
  84. {
  85. RotatePoint( &pt.x, &pt.y, Module->m_Orient );
  86. pt.x += Module->m_Pos.x;
  87. pt.y += Module->m_Pos.y;
  88. }
  89. pt.x += m_Start0.x;
  90. pt.y += m_Start0.y;
  91. bbox.m_Pos.x = MIN( bbox.m_Pos.x, pt.x );
  92. bbox.m_Pos.y = MIN( bbox.m_Pos.y, pt.y );
  93. p_end.x = MAX( p_end.x, pt.x );
  94. p_end.y = MAX( p_end.y, pt.y );
  95. }
  96. bbox.SetEnd(p_end);
  97. bbox.Inflate( 1 );
  98. break;
  99. }
  100. }
  101. return bbox;
  102. }
  103. void EDGE_MODULE::SetDrawCoord()
  104. {
  105. MODULE* Module = (MODULE*) m_Parent;
  106. m_Start = m_Start0;
  107. m_End = m_End0;
  108. if( Module )
  109. {
  110. RotatePoint( &m_Start.x, &m_Start.y, Module->m_Orient );
  111. RotatePoint( &m_End.x, &m_End.y, Module->m_Orient );
  112. m_Start += Module->m_Pos;
  113. m_End += Module->m_Pos;
  114. }
  115. }
  116. /* Draw EDGE_MODULE:
  117. * Entry: offset = offset trace
  118. * Draw_mode mode = trace (GR_OR, GR_XOR, GR_AND)
  119. * The contours are of different types:
  120. * - Segment
  121. * - Circles
  122. * - Arcs
  123. */
  124. void EDGE_MODULE::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
  125. int draw_mode, const wxPoint& offset )
  126. {
  127. int ux0, uy0, dx, dy, rayon, StAngle, EndAngle;
  128. int color, type_trace;
  129. int typeaff;
  130. PCB_SCREEN* screen;
  131. WinEDA_BasePcbFrame* frame;
  132. MODULE* Module = NULL;
  133. if( m_Parent && ( m_Parent->Type() == TYPE_MODULE ) )
  134. Module = (MODULE*) m_Parent;
  135. if( g_DesignSettings.IsLayerVisible( m_Layer ) == false )
  136. return;
  137. color = g_DesignSettings.m_LayerColor[m_Layer];
  138. frame = (WinEDA_BasePcbFrame*) panel->GetParent();
  139. screen = frame->GetScreen();
  140. type_trace = m_Shape;
  141. ux0 = m_Start.x - offset.x;
  142. uy0 = m_Start.y - offset.y;
  143. dx = m_End.x - offset.x;
  144. dy = m_End.y - offset.y;
  145. GRSetDrawMode( DC, draw_mode );
  146. typeaff = frame->m_DisplayModEdge;
  147. if( m_Layer <= LAST_COPPER_LAYER )
  148. {
  149. typeaff = frame->m_DisplayPcbTrackFill;
  150. if( !typeaff )
  151. typeaff = SKETCH;
  152. }
  153. if( screen->Scale( m_Width ) < L_MIN_DESSIN )
  154. typeaff = FILAIRE;
  155. switch( type_trace )
  156. {
  157. case S_SEGMENT:
  158. if( typeaff == FILAIRE )
  159. GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, 0, color );
  160. else if( typeaff == FILLED )
  161. GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, m_Width, color );
  162. else
  163. // SKETCH Mode
  164. GRCSegm( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, m_Width, color );
  165. break;
  166. case S_CIRCLE:
  167. rayon = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
  168. if( typeaff == FILAIRE )
  169. {
  170. GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon, color );
  171. }
  172. else
  173. {
  174. if( typeaff == FILLED )
  175. {
  176. GRCircle( &panel->m_ClipBox, DC, ux0, uy0, rayon,
  177. m_Width, color );
  178. }
  179. else // SKETCH Mode
  180. {
  181. GRCircle( &panel->m_ClipBox, DC, ux0, uy0,
  182. rayon + (m_Width / 2), color );
  183. GRCircle( &panel->m_ClipBox, DC, ux0, uy0,
  184. rayon - (m_Width / 2), color );
  185. }
  186. }
  187. break;
  188. case S_ARC:
  189. rayon = (int) hypot( (double) (dx - ux0), (double) (dy - uy0) );
  190. StAngle = (int) ArcTangente( dy - uy0, dx - ux0 );
  191. EndAngle = StAngle + m_Angle;
  192. if( StAngle > EndAngle )
  193. EXCHG( StAngle, EndAngle );
  194. if( typeaff == FILAIRE )
  195. {
  196. GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
  197. rayon, color );
  198. }
  199. else if( typeaff == FILLED )
  200. {
  201. GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle, rayon,
  202. m_Width, color );
  203. }
  204. else // SKETCH Mode
  205. {
  206. GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
  207. rayon + (m_Width / 2), color );
  208. GRArc( &panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
  209. rayon - (m_Width / 2), color );
  210. }
  211. break;
  212. case S_POLYGON:
  213. // We must compute true coordinates from m_PolyPoints
  214. // which are relative to module position, orientation 0
  215. std::vector<wxPoint> points = m_PolyPoints;
  216. for( unsigned ii = 0; ii < points.size(); ii++ )
  217. {
  218. wxPoint& pt = points[ii];
  219. if( Module )
  220. {
  221. RotatePoint( &pt.x, &pt.y, Module->m_Orient );
  222. pt.x += Module->m_Pos.x;
  223. pt.y += Module->m_Pos.y;
  224. }
  225. pt.x += m_Start0.x - offset.x;
  226. pt.y += m_Start0.y - offset.y;
  227. }
  228. GRPoly( &panel->m_ClipBox, DC, points.size(), &points[0],
  229. TRUE, m_Width, color, color );
  230. break;
  231. }
  232. }
  233. // see class_edge_mod.h
  234. void EDGE_MODULE::DisplayInfo( WinEDA_DrawFrame* frame )
  235. {
  236. wxString msg;
  237. MODULE* module = (MODULE*) m_Parent;
  238. if( !module )
  239. return;
  240. BOARD* board = (BOARD*) module->GetParent();
  241. if( !board )
  242. return;
  243. frame->ClearMsgPanel();
  244. frame->AppendMsgPanel( _( "Graphic Item" ), wxEmptyString, DARKCYAN );
  245. frame->AppendMsgPanel( _( "Module" ), module->m_Reference->m_Text,
  246. DARKCYAN );
  247. frame->AppendMsgPanel( _( "Value" ), module->m_Value->m_Text, BLUE );
  248. msg.Printf( wxT( "%8.8lX" ), module->m_TimeStamp );
  249. frame->AppendMsgPanel( _( "TimeStamp" ), msg, BROWN );
  250. frame->AppendMsgPanel( _( "Mod Layer" ),
  251. board->GetLayerName( module->GetLayer() ), RED );
  252. frame->AppendMsgPanel( _( "Seg Layer" ),
  253. board->GetLayerName( GetLayer() ), RED );
  254. valeur_param( m_Width, msg );
  255. frame->AppendMsgPanel( _( "Width" ), msg, BLUE );
  256. }
  257. /*******************************************/
  258. bool EDGE_MODULE::Save( FILE* aFile ) const
  259. /*******************************************/
  260. {
  261. int ret = -1;
  262. switch( m_Shape )
  263. {
  264. case S_SEGMENT:
  265. ret = fprintf( aFile, "DS %d %d %d %d %d %d\n",
  266. m_Start0.x, m_Start0.y,
  267. m_End0.x, m_End0.y,
  268. m_Width, m_Layer );
  269. break;
  270. case S_CIRCLE:
  271. ret = fprintf( aFile, "DC %d %d %d %d %d %d\n",
  272. m_Start0.x, m_Start0.y,
  273. m_End0.x, m_End0.y,
  274. m_Width, m_Layer );
  275. break;
  276. case S_ARC:
  277. ret = fprintf( aFile, "DA %d %d %d %d %d %d %d\n",
  278. m_Start0.x, m_Start0.y,
  279. m_End0.x, m_End0.y,
  280. m_Angle,
  281. m_Width, m_Layer );
  282. break;
  283. case S_POLYGON:
  284. ret = fprintf( aFile, "DP %d %d %d %d %d %d %d\n",
  285. m_Start0.x, m_Start0.y,
  286. m_End0.x, m_End0.y,
  287. (int) m_PolyPoints.size(),
  288. m_Width, m_Layer );
  289. for( unsigned i = 0; i<m_PolyPoints.size(); ++i )
  290. fprintf( aFile, "Dl %d %d\n", m_PolyPoints[i].x,
  291. m_PolyPoints[i].y );
  292. break;
  293. default:
  294. // future: throw an exception here
  295. #if defined(DEBUG)
  296. printf( "EDGE_MODULE::Save(): unexpected m_Shape: %d\n", m_Shape );
  297. #endif
  298. break;
  299. }
  300. return ret > 5;
  301. }
  302. /* Read a description line like:
  303. * DS 2600 0 2600 -600 120 21
  304. * this description line is in Line
  305. * EDGE_MODULE type can be:
  306. * - Circle,
  307. * - Segment (line)
  308. * - Arc
  309. * - Polygon
  310. *
  311. */
  312. int EDGE_MODULE::ReadDescr( char* Line, FILE* File,
  313. int* LineNum )
  314. {
  315. int ii;
  316. int error = 0;
  317. char Buf[1024];
  318. switch( Line[1] )
  319. {
  320. case 'S':
  321. m_Shape = S_SEGMENT;
  322. break;
  323. case 'C':
  324. m_Shape = S_CIRCLE;
  325. break;
  326. case 'A':
  327. m_Shape = S_ARC;
  328. break;
  329. case 'P':
  330. m_Shape = S_POLYGON;
  331. break;
  332. default:
  333. wxString msg;
  334. msg.Printf( wxT( "Unknown EDGE_MODULE type <%s>" ), Line );
  335. DisplayError( NULL, msg );
  336. error = 1;
  337. break;
  338. }
  339. switch( m_Shape )
  340. {
  341. case S_ARC:
  342. sscanf( Line + 3, "%d %d %d %d %d %d %d",
  343. &m_Start0.x, &m_Start0.y,
  344. &m_End0.x, &m_End0.y,
  345. &m_Angle, &m_Width, &m_Layer );
  346. break;
  347. case S_SEGMENT:
  348. case S_CIRCLE:
  349. sscanf( Line + 3, "%d %d %d %d %d %d",
  350. &m_Start0.x, &m_Start0.y,
  351. &m_End0.x, &m_End0.y,
  352. &m_Width, &m_Layer );
  353. break;
  354. case S_POLYGON:
  355. int pointCount;
  356. sscanf( Line + 3, "%d %d %d %d %d %d %d",
  357. &m_Start0.x, &m_Start0.y,
  358. &m_End0.x, &m_End0.y,
  359. &pointCount, &m_Width, &m_Layer );
  360. (*LineNum)++;
  361. m_PolyPoints.clear();
  362. m_PolyPoints.reserve( pointCount );
  363. for( ii = 0; ii<pointCount; ii++ )
  364. {
  365. if( GetLine( File, Buf, LineNum, sizeof(Buf) - 1 ) != NULL )
  366. {
  367. if( strncmp( Buf, "Dl", 2 ) != 0 )
  368. {
  369. error = 1;
  370. break;
  371. }
  372. int x;
  373. int y;
  374. sscanf( Buf + 3, "%d %d\n", &x, &y );
  375. m_PolyPoints.push_back( wxPoint( x, y ) );
  376. (*LineNum)++;
  377. }
  378. else
  379. {
  380. error = 1;
  381. break;
  382. }
  383. }
  384. break;
  385. default:
  386. sscanf( Line + 3, "%d %d %d %d %d %d",
  387. &m_Start0.x, &m_Start0.y,
  388. &m_End0.x, &m_End0.y,
  389. &m_Width, &m_Layer );
  390. break;
  391. }
  392. // Check for a reasonable width:
  393. if( m_Width <= 1 )
  394. m_Width = 1;
  395. if( m_Width > MAX_WIDTH )
  396. m_Width = MAX_WIDTH;
  397. // Check for a reasonable layer:
  398. // m_Layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints
  399. // can use the copper layers m_Layer < FIRST_NON_COPPER_LAYER is allowed.
  400. // @todo: changes use of EDGE_MODULE these footprints and allows only m_Layer >= FIRST_NON_COPPER_LAYER
  401. if( (m_Layer < 0) || (m_Layer > LAST_NON_COPPER_LAYER) )
  402. m_Layer = SILKSCREEN_N_FRONT;
  403. return error;
  404. }
  405. /**
  406. * Function HitTest
  407. * tests if the given wxPoint is within the bounds of this object.
  408. * @param refPos A wxPoint to test
  409. * @return bool - true if a hit, else false
  410. */
  411. bool EDGE_MODULE::HitTest( const wxPoint& ref_pos )
  412. {
  413. int uxf, uyf;
  414. int rayon, dist;
  415. int dx, dy, spot_cX, spot_cY;
  416. int ux0, uy0;
  417. ux0 = m_Start.x;
  418. uy0 = m_Start.y;
  419. uxf = m_End.x;
  420. uyf = m_End.y;
  421. switch( m_Shape )
  422. {
  423. case S_SEGMENT:
  424. spot_cX = ref_pos.x - ux0;
  425. spot_cY = ref_pos.y - uy0;
  426. dx = uxf - ux0;
  427. dy = uyf - uy0;
  428. if( DistanceTest( m_Width / 2, dx, dy, spot_cX, spot_cY ) )
  429. return true;
  430. break;
  431. case S_CIRCLE:
  432. rayon = (int) hypot( (double) (uxf - ux0), (double) (uyf - uy0) );
  433. dist = (int) hypot( (double) (ref_pos.x - ux0),
  434. (double) (ref_pos.y - uy0) );
  435. if( abs( rayon - dist ) <= m_Width )
  436. return true;
  437. break;
  438. case S_ARC:
  439. rayon = (int) hypot( (double) (uxf - ux0), (double) (uyf - uy0) );
  440. dist = (int) hypot( (double) (ref_pos.x - ux0),
  441. (double) (ref_pos.y - uy0) );
  442. if( abs( rayon - dist ) > m_Width )
  443. break;
  444. int mouseAngle = (int) ArcTangente( ref_pos.y - uy0, ref_pos.x - ux0 );
  445. int stAngle = (int) ArcTangente( uyf - uy0, uxf - ux0 );
  446. int endAngle = stAngle + m_Angle;
  447. if( endAngle > 3600 )
  448. {
  449. stAngle -= 3600;
  450. endAngle -= 3600;
  451. }
  452. if( (mouseAngle >= stAngle) && (mouseAngle <= endAngle) )
  453. return true;
  454. break;
  455. }
  456. return false; // an unknown m_Shape also returns false
  457. }
  458. #if defined(DEBUG)
  459. /**
  460. * Function Show
  461. * is used to output the object tree, currently for debugging only.
  462. * @param nestLevel An aid to prettier tree indenting, and is the level
  463. * of nesting of this object within the overall tree.
  464. * @param os The ostream& to output to.
  465. */
  466. void EDGE_MODULE::Show( int nestLevel, std::ostream& os )
  467. {
  468. wxString shape = ShowShape( (Track_Shapes) m_Shape );
  469. // for now, make it look like XML:
  470. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  471. " type=\"" << CONV_TO_UTF8( shape ) << "\">";
  472. os << " <start" << m_Start0 << "/>";
  473. os << " <end" << m_End0 << "/>";
  474. os << " </" << GetClass().Lower().mb_str() << ">\n";
  475. }
  476. #endif