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.

552 lines
16 KiB

  1. /*************************************
  2. * file class_gerber_draw_item.cpp
  3. *************************************/
  4. /*
  5. * This program source code file is part of KICAD, a free EDA CAD application.
  6. *
  7. * Copyright (C) 1992-2010 <Jean-Pierre Charras>
  8. * Copyright (C) 1992-2010 Kicad Developers, see change_log.txt for contributors.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include "fctsys.h"
  28. #include "polygons_defs.h"
  29. #include "gr_basic.h"
  30. #include "common.h"
  31. #include "trigo.h"
  32. #include "class_drawpanel.h"
  33. #include "drawtxt.h"
  34. #include "gerbview.h"
  35. #include "class_board_design_settings.h"
  36. #include "colors_selection.h"
  37. #include "class_gerber_draw_item.h"
  38. #include "class_GERBER.h"
  39. /**********************************************************/
  40. GERBER_DRAW_ITEM::GERBER_DRAW_ITEM( BOARD_ITEM* aParent, GERBER* aGerberparams ) :
  41. BOARD_ITEM( aParent, TYPE_GERBER_DRAW_ITEM )
  42. /**********************************************************/
  43. {
  44. m_imageParams = aGerberparams;
  45. m_Layer = 0;
  46. m_Shape = GBR_SEGMENT;
  47. m_Flashed = false;
  48. m_DCode = 0;
  49. m_UnitsMetric = false;
  50. m_ImageNegative = false;
  51. m_LayerNegative = false;
  52. m_swapAxis = false;
  53. m_mirrorA = false;
  54. m_mirrorB = false;
  55. m_drawScale.x = m_drawScale.y = 1.0;
  56. if( m_imageParams )
  57. SetLayerParameters();
  58. }
  59. // Copy constructor
  60. GERBER_DRAW_ITEM::GERBER_DRAW_ITEM( const GERBER_DRAW_ITEM& aSource ) :
  61. BOARD_ITEM( aSource )
  62. {
  63. m_imageParams = aSource.m_imageParams;
  64. m_Shape = aSource.m_Shape;
  65. m_Flags = aSource.m_Flags;
  66. m_TimeStamp = aSource.m_TimeStamp;
  67. SetStatus( aSource.ReturnStatus() );
  68. m_Start = aSource.m_Start;
  69. m_End = aSource.m_End;
  70. m_Size = aSource.m_Size;
  71. m_Layer = aSource.m_Layer;
  72. m_Shape = aSource.m_Shape;
  73. m_Flashed = aSource.m_Flashed;
  74. m_DCode = aSource.m_DCode;
  75. m_PolyCorners = aSource.m_PolyCorners;
  76. m_UnitsMetric = aSource.m_UnitsMetric;
  77. m_ImageNegative = aSource.m_ImageNegative;
  78. m_LayerNegative = aSource.m_LayerNegative;
  79. m_swapAxis = aSource.m_swapAxis;
  80. m_mirrorA = aSource.m_mirrorA;
  81. m_mirrorB = aSource.m_mirrorB;
  82. m_layerOffset = aSource.m_layerOffset;
  83. m_drawScale.x = aSource.m_drawScale.x;
  84. m_drawScale.y = aSource.m_drawScale.y;
  85. }
  86. GERBER_DRAW_ITEM::~GERBER_DRAW_ITEM()
  87. {
  88. }
  89. GERBER_DRAW_ITEM* GERBER_DRAW_ITEM::Copy() const
  90. {
  91. return new GERBER_DRAW_ITEM( *this );
  92. }
  93. /**
  94. * Function GetABPosition
  95. * returns the image position of aPosition for this object.
  96. * Image position is the value of aPosition, modified by image parameters:
  97. * offsets, axis selection, scale, rotation
  98. * @param aXYPosition = position in Y,X gerber axis
  99. * @return const wxPoint& - The position in A,B axis.
  100. * Because draw axis is top to bottom, the final y coordinates is negated
  101. */
  102. wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition )
  103. {
  104. /* Note: RS274Xrevd_e is obscure about the order of transforms:
  105. * For instance: Rotation must be made after or before mirroring ?
  106. * Note: if something is changed here, GetYXPosition must reflect changes
  107. */
  108. wxPoint abPos = aXYPosition;
  109. if( m_swapAxis )
  110. EXCHG( abPos.x, abPos.y );
  111. abPos += m_layerOffset + m_imageParams->m_ImageOffset;
  112. abPos.x = wxRound( abPos.x * m_drawScale.x );
  113. abPos.y = wxRound( abPos.y * m_drawScale.y );
  114. if( m_imageParams->m_Rotation )
  115. RotatePoint( &abPos, -m_imageParams->m_Rotation );
  116. if( m_mirrorA )
  117. NEGATE( abPos.x );
  118. // abPos.y must be negated, because draw axis is top to bottom
  119. if( !m_mirrorB )
  120. NEGATE( abPos.y );
  121. return abPos;
  122. }
  123. /**
  124. * Function GetXYPosition
  125. * returns the image position of aPosition for this object.
  126. * Image position is the value of aPosition, modified by image parameters:
  127. * offsets, axis selection, scale, rotation
  128. * @param aABPosition = position in A,B plotter axis
  129. * @return const wxPoint - The given position in X,Y axis.
  130. */
  131. wxPoint GERBER_DRAW_ITEM::GetXYPosition(const wxPoint& aABPosition )
  132. {
  133. // do the inverse tranform made by GetABPosition
  134. wxPoint xyPos = aABPosition;
  135. if( m_mirrorA )
  136. NEGATE( xyPos.x );
  137. if( !m_mirrorB )
  138. NEGATE( xyPos.y );
  139. if( m_imageParams->m_Rotation )
  140. RotatePoint( &xyPos, m_imageParams->m_Rotation );
  141. xyPos.x = wxRound( xyPos.x / m_drawScale.x );
  142. xyPos.y = wxRound( xyPos.y / m_drawScale.y );
  143. xyPos -= m_layerOffset + m_imageParams->m_ImageOffset;
  144. if( m_swapAxis )
  145. EXCHG( xyPos.x, xyPos.y );
  146. return xyPos;
  147. }
  148. /** function SetLayerParameters
  149. * Initialize draw parameters from Image and Layer parameters
  150. * found in the gerber file:
  151. * m_UnitsMetric,
  152. * m_MirrorA, m_MirrorB,
  153. * m_DrawScale, m_DrawOffset
  154. */
  155. void GERBER_DRAW_ITEM::SetLayerParameters()
  156. {
  157. m_UnitsMetric = m_imageParams->m_GerbMetric;
  158. m_swapAxis = m_imageParams->m_SwapAxis; // false if A = X, B = Y;
  159. // true if A =Y, B = Y
  160. m_mirrorA = m_imageParams->m_MirrorA; // true: mirror / axe A
  161. m_mirrorB = m_imageParams->m_MirrorB; // true: mirror / axe B
  162. m_drawScale = m_imageParams->m_LayerScale; // A and B scaling factor
  163. m_layerOffset = m_imageParams->m_Offset; // Offset from OF command
  164. }
  165. wxString GERBER_DRAW_ITEM::ShowGBRShape()
  166. {
  167. switch( m_Shape )
  168. {
  169. case GBR_SEGMENT:
  170. return _( "Line" );
  171. case GBR_ARC:
  172. return _( "Arc" );
  173. case GBR_CIRCLE:
  174. return _( "Circle" );
  175. case GBR_SPOT_OVAL:
  176. return wxT( "spot_oval" );
  177. case GBR_SPOT_CIRCLE:
  178. return wxT( "spot_circle" );
  179. case GBR_SPOT_RECT:
  180. return wxT( "spot_rect" );
  181. case GBR_SPOT_POLY:
  182. return wxT( "spot_poly" );
  183. case GBR_POLYGON:
  184. return wxT( "polygon" );
  185. case GBR_SPOT_MACRO:
  186. return wxT( "apt_macro" ); // TODO: add aperture macro name
  187. default:
  188. return wxT( "??" );
  189. }
  190. }
  191. /**
  192. * Function GetDcodeDescr
  193. * returns the GetDcodeDescr of this object, or NULL.
  194. * @return D_CODE* - a pointer to the DCode description (for flashed items).
  195. */
  196. D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr()
  197. {
  198. if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
  199. return NULL;
  200. GERBER* gerber = g_GERBER_List[m_Layer];
  201. if( gerber == NULL )
  202. return NULL;
  203. D_CODE* d_code = gerber->GetDCODE( m_DCode, false );
  204. return d_code;
  205. }
  206. EDA_Rect GERBER_DRAW_ITEM::GetBoundingBox()
  207. {
  208. // return a rectangle which is (pos,dim) in nature. therefore the +1
  209. EDA_Rect bbox( m_Start, wxSize( 1, 1 ) );
  210. bbox.Inflate( m_Size.x / 2, m_Size.y / 2 );
  211. bbox.SetOrigin(GetXYPosition( bbox.GetOrigin() ) );
  212. bbox.SetEnd(GetXYPosition( bbox.GetEnd() ) );
  213. return bbox;
  214. }
  215. /**
  216. * Function Move
  217. * move this object.
  218. * @param const wxPoint& aMoveVector - the move vector for this object, in AB plotter axis.
  219. */
  220. void GERBER_DRAW_ITEM::Move( const wxPoint& aMoveVector )
  221. {
  222. wxPoint xymove = GetXYPosition( aMoveVector );
  223. m_Start += xymove;
  224. m_End += xymove;
  225. m_ArcCentre += xymove;
  226. for( unsigned ii = 0; ii < m_PolyCorners.size(); ii++ )
  227. m_PolyCorners[ii] += xymove;
  228. }
  229. /** function Save.
  230. * currently: no nothing, but must be defined to meet requirements
  231. * of the basic class
  232. */
  233. bool GERBER_DRAW_ITEM::Save( FILE* aFile ) const
  234. {
  235. return true;
  236. }
  237. /*********************************************************************/
  238. void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode,
  239. const wxPoint& aOffset )
  240. /*********************************************************************/
  241. {
  242. static D_CODE dummyD_CODE( 0 ); // used when a D_CODE is not found. default D_CODE to draw a flashed item
  243. int color, alt_color;
  244. bool isFilled;
  245. int radius;
  246. int halfPenWidth;
  247. static bool show_err;
  248. BOARD* brd = GetBoard();
  249. D_CODE* d_codeDescr = GetDcodeDescr();
  250. if( d_codeDescr == NULL )
  251. d_codeDescr = &dummyD_CODE;
  252. if( brd->IsLayerVisible( GetLayer() ) == false )
  253. return;
  254. color = brd->GetLayerColor( GetLayer() );
  255. if( aDrawMode & GR_SURBRILL )
  256. {
  257. if( aDrawMode & GR_AND )
  258. color &= ~HIGHT_LIGHT_FLAG;
  259. else
  260. color |= HIGHT_LIGHT_FLAG;
  261. }
  262. if( color & HIGHT_LIGHT_FLAG )
  263. color = ColorRefs[color & MASKCOLOR].m_LightColor;
  264. alt_color = g_DrawBgColor;
  265. if( m_Flags & DRAW_ERASED ) // draw in background color ("negative" color)
  266. {
  267. EXCHG( color, alt_color );
  268. }
  269. GRSetDrawMode( aDC, aDrawMode );
  270. isFilled = DisplayOpt.DisplayPcbTrackFill ? true : false;
  271. switch( m_Shape )
  272. {
  273. case GBR_POLYGON:
  274. isFilled = (g_DisplayPolygonsModeSketch == false);
  275. if( m_Flags & DRAW_ERASED )
  276. isFilled = true;
  277. DrawGbrPoly( &aPanel->m_ClipBox, aDC, color, aOffset, isFilled );
  278. break;
  279. case GBR_CIRCLE:
  280. radius = (int) hypot( (double) ( m_End.x - m_Start.x ),
  281. (double) ( m_End.y - m_Start.y ) );
  282. halfPenWidth = m_Size.x >> 1;
  283. if( !isFilled )
  284. {
  285. // draw the border of the pen's path using two circles, each as narrow as possible
  286. GRCircle( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  287. radius - halfPenWidth, 0, color );
  288. GRCircle( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  289. radius + halfPenWidth, 0, color );
  290. }
  291. else // Filled mode
  292. {
  293. GRCircle( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  294. radius, m_Size.x, color );
  295. }
  296. break;
  297. case GBR_ARC:
  298. if( !isFilled )
  299. {
  300. GRArc1( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  301. GetABPosition( m_End ), GetABPosition( m_ArcCentre ),
  302. 0, color );
  303. }
  304. else
  305. {
  306. GRArc1( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  307. GetABPosition( m_End ), GetABPosition( m_ArcCentre ),
  308. m_Size.x, color );
  309. }
  310. break;
  311. case GBR_SPOT_CIRCLE:
  312. case GBR_SPOT_RECT:
  313. case GBR_SPOT_OVAL:
  314. case GBR_SPOT_POLY:
  315. case GBR_SPOT_MACRO:
  316. isFilled = DisplayOpt.DisplayPadFill ? true : false;
  317. d_codeDescr->DrawFlashedShape( this, &aPanel->m_ClipBox, aDC, color, alt_color,
  318. m_Start, isFilled );
  319. break;
  320. case GBR_SEGMENT:
  321. if( !isFilled )
  322. GRCSegm( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  323. GetABPosition( m_End ), m_Size.x, color );
  324. else
  325. GRFilledSegment( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
  326. GetABPosition( m_End ), m_Size.x, color );
  327. break;
  328. default:
  329. if( !show_err )
  330. {
  331. wxMessageBox( wxT( "Trace_Segment() type error" ) );
  332. show_err = TRUE;
  333. }
  334. break;
  335. }
  336. }
  337. /** function DrawGbrPoly
  338. * a helper function used id ::Draw to draw the polygon stored ion m_PolyCorners
  339. * Draw filled polygons
  340. */
  341. void GERBER_DRAW_ITEM::DrawGbrPoly( EDA_Rect* aClipBox,
  342. wxDC* aDC,
  343. int aColor,
  344. const wxPoint& aOffset,
  345. bool aFilledShape )
  346. {
  347. std::vector<wxPoint> points;
  348. points = m_PolyCorners;
  349. for( unsigned ii = 0; ii < points.size(); ii++ )
  350. {
  351. points[ii] += aOffset;
  352. points[ii] = GetABPosition( points[ii] );
  353. }
  354. GRClosedPoly( aClipBox, aDC, points.size(), &points[0], aFilledShape, aColor, aColor );
  355. }
  356. /** Function DisplayInfo
  357. * has knowledge about the frame and how and where to put status information
  358. * about this object into the frame's message panel.
  359. * Display info about the track segment only, and does not calculate the full track length
  360. * @param frame A WinEDA_DrawFrame in which to print status information.
  361. */
  362. void GERBER_DRAW_ITEM::DisplayInfo( WinEDA_DrawFrame* frame )
  363. {
  364. wxString msg;
  365. frame->ClearMsgPanel();
  366. msg = ShowGBRShape();
  367. frame->AppendMsgPanel( _( "Type" ), msg, DARKCYAN );
  368. // Display D_Code value:
  369. msg.Printf( wxT("%d"), m_DCode);
  370. frame->AppendMsgPanel( _( "D Code" ), msg, RED );
  371. // Display Image name
  372. if(m_imageParams)
  373. {
  374. msg = m_imageParams->m_ImageName;
  375. frame->AppendMsgPanel( _( "Image name" ), msg, BROWN );
  376. }
  377. // Display graphic layer number
  378. msg.Printf( wxT("%d"), GetLayer()+1);
  379. frame->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );
  380. // This next info can be see as debug info, so it can be disabled
  381. #if 1
  382. // Display offset
  383. wxPoint tmp = m_layerOffset + m_imageParams->m_ImageOffset;
  384. msg.Printf( wxT("X=%f Y=%f"), (double)tmp.x/10000, (double)tmp.y/10000);
  385. frame->AppendMsgPanel( _( "Offset" ), msg, DARKRED );
  386. // Display rotation
  387. msg.Printf( wxT("%d"), m_imageParams->m_Rotation/10);
  388. frame->AppendMsgPanel( _( "Image rotation" ), msg, DARKRED );
  389. // Display mirroring
  390. msg.Printf( wxT("X%d Y%d"), m_mirrorA, m_mirrorB);
  391. frame->AppendMsgPanel( _( "Mirror" ), msg, DARKRED );
  392. // Display AB axis swap
  393. msg = m_swapAxis ? wxT("A=Y B=X") : wxT("A=X B=Y");
  394. frame->AppendMsgPanel( _( "AB axis" ), msg, DARKRED );
  395. #endif
  396. }
  397. /**
  398. * Function HitTest
  399. * tests if the given wxPoint is within the bounds of this object.
  400. * @param aRefPos A wxPoint to test in AB axis
  401. * @return bool - true if a hit, else false
  402. */
  403. bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos )
  404. {
  405. wxPoint ref_pos = GetXYPosition( aRefPos );
  406. // TODO: a better analyse of the shape (perhaps create a D_CODE::HitTest for flashed items)
  407. int radius = MIN( m_Size.x, m_Size.y ) >> 1;
  408. // delta is a vector from m_Start to m_End (an origin of m_Start)
  409. wxPoint delta = m_End - m_Start;
  410. // dist is a vector from m_Start to ref_pos (an origin of m_Start)
  411. wxPoint dist = ref_pos - m_Start;
  412. if( m_Flashed )
  413. {
  414. return (double) dist.x * dist.x + (double) dist.y * dist.y <=
  415. (double) radius * radius;
  416. }
  417. else
  418. {
  419. if( DistanceTest( radius, delta.x, delta.y, dist.x, dist.y ) )
  420. return true;
  421. }
  422. return false;
  423. }
  424. /**
  425. * Function HitTest (overlayed)
  426. * tests if the given EDA_Rect intersect this object.
  427. * For now, an ending point must be inside this rect.
  428. * @param refArea : the given EDA_Rect in AB plotter axis
  429. * @return bool - true if a hit, else false
  430. */
  431. bool GERBER_DRAW_ITEM::HitTest( EDA_Rect& refArea )
  432. {
  433. wxPoint pos = GetABPosition( m_Start );
  434. if( refArea.Inside( pos ) )
  435. return true;
  436. pos = GetABPosition( m_End );
  437. if( refArea.Inside( pos ) )
  438. return true;
  439. return false;
  440. }
  441. #if defined(DEBUG)
  442. /**
  443. * Function Show
  444. * is used to output the object tree, currently for debugging only.
  445. * @param nestLevel An aid to prettier tree indenting, and is the level
  446. * of nesting of this object within the overall tree.
  447. * @param os The ostream& to output to.
  448. */
  449. void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os )
  450. {
  451. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  452. " shape=\"" << m_Shape << '"' <<
  453. " addr=\"" << std::hex << this << std::dec << '"' <<
  454. " layer=\"" << m_Layer << '"' <<
  455. " size=\"" << m_Size << '"' <<
  456. " flags=\"" << m_Flags << '"' <<
  457. " status=\"" << GetState( -1 ) << '"' <<
  458. "<start" << m_Start << "/>" <<
  459. "<end" << m_End << "/>";
  460. os << "</" << GetClass().Lower().mb_str() << ">\n";
  461. }
  462. #endif