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.

459 lines
16 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file gbr_layout.cpp
  26. * @brief GBR_LAYOUT class functions.
  27. */
  28. #include <fctsys.h>
  29. #include <gr_basic.h>
  30. #include <draw_graphic_text.h>
  31. #include <gerbview_frame.h>
  32. #include <class_drawpanel.h>
  33. #include <gbr_layout.h>
  34. #include <gerber_file_image.h>
  35. #include <gerber_file_image_list.h>
  36. GBR_LAYOUT::GBR_LAYOUT() :
  37. EDA_ITEM( (EDA_ITEM*)NULL, GERBER_LAYOUT_T )
  38. {
  39. }
  40. GBR_LAYOUT::~GBR_LAYOUT()
  41. {
  42. }
  43. // Accessor to the list of gerber files (and drill files) images
  44. GERBER_FILE_IMAGE_LIST* GBR_LAYOUT::GetImagesList() const
  45. {
  46. return &GERBER_FILE_IMAGE_LIST::GetImagesList();
  47. }
  48. bool GBR_LAYOUT::IsLayerPrintable( int aLayer ) const
  49. {
  50. for( unsigned ii = 0; ii < m_printLayersList.size(); ++ii )
  51. {
  52. if( m_printLayersList[ii] == aLayer )
  53. return true;
  54. }
  55. return false;
  56. }
  57. EDA_RECT GBR_LAYOUT::ComputeBoundingBox() const
  58. {
  59. EDA_RECT bbox;
  60. bool first_item = true;
  61. for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
  62. {
  63. GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
  64. if( gerber == NULL ) // Graphic layer not yet used
  65. continue;
  66. for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item; item = item->Next() )
  67. {
  68. if( first_item )
  69. {
  70. bbox = item->GetBoundingBox();
  71. first_item = false;
  72. }
  73. else
  74. bbox.Merge( item->GetBoundingBox() );
  75. }
  76. }
  77. bbox.Inflate( ( bbox.GetWidth() / 10 ) + 100 );
  78. bbox.Normalize();
  79. m_BoundingBox = bbox;
  80. return bbox;
  81. }
  82. // Redraw All GerbView layers, using a buffered mode or not
  83. void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
  84. const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aDisplayOptions )
  85. {
  86. GERBVIEW_FRAME* gerbFrame = (GERBVIEW_FRAME*) aPanel->GetParent();
  87. // Collect the highlight selections
  88. wxString cmpHighlight;
  89. if( gerbFrame->m_SelComponentBox->GetSelection() > 0 )
  90. cmpHighlight = gerbFrame->m_SelComponentBox->GetStringSelection();
  91. wxString netHighlight;
  92. if( gerbFrame->m_SelNetnameBox->GetSelection() > 0 )
  93. netHighlight = gerbFrame->m_SelNetnameBox->GetStringSelection();
  94. wxString aperAttrHighlight = gerbFrame->m_SelAperAttributesBox->GetStringSelection();
  95. if( gerbFrame->m_SelAperAttributesBox->GetSelection() > 0 )
  96. aperAttrHighlight = gerbFrame->m_SelAperAttributesBox->GetStringSelection();
  97. // Because Images can be negative (i.e with background filled in color) items are drawn
  98. // graphic layer per graphic layer, after the background is filled
  99. // to a temporary bitmap
  100. // at least when aDrawMode = GR_COPY or aDrawMode = GR_OR
  101. // If aDrawMode = UNSPECIFIED_DRAWMODE, items are drawn to the main screen, and therefore
  102. // artifacts can happen with negative items or negative images
  103. int bitmapWidth, bitmapHeight;
  104. wxDC* plotDC = aDC;
  105. aPanel->GetClientSize( &bitmapWidth, &bitmapHeight );
  106. wxBitmap* layerBitmap = NULL;
  107. wxBitmap* screenBitmap = NULL;
  108. wxMemoryDC layerDC; // used sequentially for each gerber layer
  109. wxMemoryDC screenDC;
  110. // When each image must be drawn using GR_OR (transparency mode)
  111. // or GR_COPY (stacked mode) we must use a temporary bitmap
  112. // to draw gerber images.
  113. // this is due to negative objects (drawn using background color) that create artifacts
  114. // on other images when drawn on screen
  115. bool useBufferBitmap = false;
  116. #ifndef __WXMAC__
  117. // Can't work with MAC
  118. // Don't try this with retina display
  119. if( (aDrawMode == GR_COPY) || ( aDrawMode == GR_OR ) )
  120. useBufferBitmap = true;
  121. #endif
  122. // these parameters are saved here, because they are modified
  123. // and restored later
  124. EDA_RECT drawBox = *aPanel->GetClipBox();
  125. double scale;
  126. aDC->GetUserScale(&scale, &scale);
  127. wxPoint dev_org = aDC->GetDeviceOrigin();
  128. wxPoint logical_org = aDC->GetLogicalOrigin( );
  129. COLOR4D bgColor = aDisplayOptions->m_BgDrawColor;
  130. wxBrush bgBrush( bgColor.ToColour(), wxBRUSHSTYLE_SOLID );
  131. if( useBufferBitmap )
  132. {
  133. layerBitmap = new wxBitmap( bitmapWidth, bitmapHeight );
  134. screenBitmap = new wxBitmap( bitmapWidth, bitmapHeight );
  135. layerDC.SelectObject( *layerBitmap );
  136. aPanel->DoPrepareDC( layerDC );
  137. aPanel->SetClipBox( drawBox );
  138. layerDC.SetBackground( bgBrush );
  139. layerDC.SetBackgroundMode( wxSOLID );
  140. layerDC.Clear();
  141. screenDC.SelectObject( *screenBitmap );
  142. screenDC.SetBackground( bgBrush );
  143. screenDC.SetBackgroundMode( wxSOLID );
  144. screenDC.Clear();
  145. plotDC = &layerDC;
  146. }
  147. bool doBlit = false; // this flag requests an image transfer to actual screen when true.
  148. bool end = false;
  149. // Draw graphic layers from bottom to top, and the active layer is on the top of others.
  150. // In non transparent modes, the last layer drawn masks others layers
  151. for( int layer = GERBER_DRAWLAYERS_COUNT-1; !end; --layer )
  152. {
  153. int active_layer = gerbFrame->GetActiveLayer();
  154. if( layer == active_layer ) // active layer will be drawn after other layers
  155. continue;
  156. if( layer < 0 ) // last loop: draw active layer
  157. {
  158. end = true;
  159. layer = active_layer;
  160. }
  161. GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
  162. if( gerber == NULL ) // Graphic layer not yet used
  163. continue;
  164. if( aDisplayOptions->m_IsPrinting )
  165. gerber->m_IsVisible = IsLayerPrintable( layer );
  166. else
  167. gerber->m_IsVisible = gerbFrame->IsLayerVisible( layer );
  168. if( !gerber->m_IsVisible )
  169. continue;
  170. gerber->m_PositiveDrawColor = gerbFrame->GetLayerColor( GERBER_DRAW_LAYER( layer ) );
  171. // Force black and white draw mode on request:
  172. if( aDisplayOptions->m_ForceBlackAndWhite )
  173. gerber->m_PositiveDrawColor = ( aDisplayOptions->m_BgDrawColor == BLACK ) ? WHITE : BLACK;
  174. if( useBufferBitmap )
  175. {
  176. // Draw each layer into a bitmap first. Negative Gerber
  177. // layers are drawn in background color.
  178. if( gerber->HasNegativeItems() && doBlit )
  179. {
  180. // Set Device origin, logical origin and scale to default values
  181. // This is needed by Blit function when using a mask.
  182. // Beside, for Blit call, both layerDC and screenDc must have the same settings
  183. layerDC.SetDeviceOrigin(0,0);
  184. layerDC.SetLogicalOrigin( 0, 0 );
  185. layerDC.SetUserScale( 1, 1 );
  186. if( aDrawMode == GR_COPY )
  187. {
  188. // Use the layer bitmap itself as a mask when blitting. The bitmap
  189. // cannot be referenced by a device context when setting the mask.
  190. layerDC.SelectObject( wxNullBitmap );
  191. layerBitmap->SetMask( new wxMask( *layerBitmap, bgColor.ToColour() ) );
  192. layerDC.SelectObject( *layerBitmap );
  193. screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxCOPY, true );
  194. }
  195. else if( aDrawMode == GR_OR )
  196. {
  197. // On Linux with a large screen, this version is much faster and without
  198. // flicker, but gives a Pcbnew look where layer colors blend together.
  199. // Plus it works only because the background color is black. But it may
  200. // be more usable for some. The difference is due in part because of
  201. // the cpu cycles needed to create the monochromatic bitmap above, and
  202. // the extra time needed to do bit indexing into the monochromatic bitmap
  203. // on the blit above.
  204. screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxOR );
  205. }
  206. // Restore actual values and clear bitmap for next drawing
  207. layerDC.SetDeviceOrigin( dev_org.x, dev_org.y );
  208. layerDC.SetLogicalOrigin( logical_org.x, logical_org.y );
  209. layerDC.SetUserScale( scale, scale );
  210. layerDC.SetBackground( bgBrush );
  211. layerDC.SetBackgroundMode( wxSOLID );
  212. layerDC.Clear();
  213. doBlit = false;
  214. }
  215. }
  216. if( gerber->m_ImageNegative )
  217. {
  218. // Draw background negative (i.e. in graphic layer color) for negative images.
  219. COLOR4D neg_color = gerber->GetPositiveDrawColor();
  220. GRSetDrawMode( &layerDC, GR_COPY );
  221. GRFilledRect( &drawBox, plotDC, drawBox.GetX(), drawBox.GetY(),
  222. drawBox.GetRight(), drawBox.GetBottom(),
  223. 0, neg_color, neg_color );
  224. GRSetDrawMode( plotDC, GR_COPY );
  225. doBlit = true;
  226. }
  227. int dcode_highlight = 0;
  228. if( layer == gerbFrame->GetActiveLayer() )
  229. dcode_highlight = gerber->m_Selected_Tool;
  230. GR_DRAWMODE layerdrawMode = GR_COPY;
  231. if( aDrawMode == GR_OR && !gerber->HasNegativeItems() )
  232. layerdrawMode = GR_OR;
  233. // Now we can draw the current layer to the bitmap buffer
  234. // When needed, the previous bitmap is already copied to the screen buffer.
  235. for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item; item = item->Next() )
  236. {
  237. if( item->GetLayer() != layer )
  238. continue;
  239. GR_DRAWMODE drawMode = layerdrawMode;
  240. if( dcode_highlight && dcode_highlight == item->m_DCode )
  241. DrawModeAddHighlight( &drawMode);
  242. if( !aperAttrHighlight.IsEmpty() && item->GetDcodeDescr() &&
  243. item->GetDcodeDescr()->m_AperFunction == aperAttrHighlight )
  244. DrawModeAddHighlight( &drawMode);
  245. if( !cmpHighlight.IsEmpty() &&
  246. cmpHighlight == item->GetNetAttributes().m_Cmpref )
  247. DrawModeAddHighlight( &drawMode);
  248. if( !netHighlight.IsEmpty() &&
  249. netHighlight == item->GetNetAttributes().m_Netname )
  250. DrawModeAddHighlight( &drawMode);
  251. item->Draw( aPanel, plotDC, drawMode, wxPoint(0,0), aDisplayOptions );
  252. doBlit = true;
  253. }
  254. }
  255. if( doBlit && useBufferBitmap ) // Blit is used only if aDrawMode >= 0
  256. {
  257. // For this Blit call, layerDC and screenDC must have the same settings
  258. // So we set device origin, logical origin and scale to default values
  259. // in layerDC
  260. layerDC.SetDeviceOrigin(0,0);
  261. layerDC.SetLogicalOrigin( 0, 0 );
  262. layerDC.SetUserScale( 1, 1 );
  263. // this is the last transfer to screenDC. If there are no negative items, this is
  264. // the only one
  265. if( aDrawMode == GR_COPY )
  266. {
  267. layerDC.SelectObject( wxNullBitmap );
  268. layerBitmap->SetMask( new wxMask( *layerBitmap, bgColor.ToColour() ) );
  269. layerDC.SelectObject( *layerBitmap );
  270. screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxCOPY, true );
  271. }
  272. else if( aDrawMode == GR_OR )
  273. {
  274. screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxOR );
  275. }
  276. }
  277. if( useBufferBitmap )
  278. {
  279. // For this Blit call, aDC and screenDC must have the same settings
  280. // So we set device origin, logical origin and scale to default values
  281. // in aDC
  282. aDC->SetDeviceOrigin( 0, 0);
  283. aDC->SetLogicalOrigin( 0, 0 );
  284. aDC->SetUserScale( 1, 1 );
  285. aDC->Blit( 0, 0, bitmapWidth, bitmapHeight, &screenDC, 0, 0, wxCOPY );
  286. // Restore aDC values
  287. aDC->SetDeviceOrigin(dev_org.x, dev_org.y);
  288. aDC->SetLogicalOrigin( logical_org.x, logical_org.y );
  289. aDC->SetUserScale( scale, scale );
  290. layerDC.SelectObject( wxNullBitmap );
  291. screenDC.SelectObject( wxNullBitmap );
  292. delete layerBitmap;
  293. delete screenBitmap;
  294. }
  295. }
  296. void GBR_LAYOUT::DrawItemsDCodeID( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  297. GR_DRAWMODE aDrawMode, COLOR4D aDrawColor )
  298. {
  299. wxString Line;
  300. GRSetDrawMode( aDC, aDrawMode );
  301. for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
  302. {
  303. GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
  304. if( gerber == NULL ) // Graphic layer not yet used
  305. continue;
  306. if( ! gerber->m_IsVisible )
  307. continue;
  308. for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item != NULL; item = item->Next() )
  309. {
  310. wxPoint pos;
  311. int size;
  312. double orient;
  313. if( ! item->GetTextD_CodePrms( size, pos, orient ) )
  314. continue;
  315. Line.Printf( wxT( "D%d" ), item->m_DCode );
  316. // Avoid to draw text, if it is too small (size in pixel < 5 pixels)
  317. // to be readable:
  318. int size_pixel = aDC->LogicalToDeviceXRel( size );
  319. const int threshold = 5;
  320. if( size_pixel >= threshold )
  321. {
  322. DrawGraphicText( aPanel->GetClipBox(), aDC, pos, aDrawColor, Line,
  323. orient, wxSize( size, size ),
  324. GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER,
  325. 0, false, false );
  326. }
  327. }
  328. }
  329. }
  330. SEARCH_RESULT GBR_LAYOUT::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
  331. {
  332. KICAD_T stype;
  333. SEARCH_RESULT result = SEARCH_CONTINUE;
  334. const KICAD_T* p = scanTypes;
  335. bool done = false;
  336. #if 0 && defined(DEBUG)
  337. std::cout << GetClass().mb_str() << ' ';
  338. #endif
  339. while( !done )
  340. {
  341. stype = *p;
  342. switch( stype )
  343. {
  344. case GERBER_IMAGE_LIST_T:
  345. for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
  346. {
  347. GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
  348. if( gerber == NULL ) // Graphic layer not yet used
  349. continue;
  350. result = gerber->Visit( inspector, testData, p );
  351. if( result == SEARCH_QUIT )
  352. break;
  353. }
  354. ++p;
  355. break;
  356. default: // catch EOT or ANY OTHER type here and return.
  357. done = true;
  358. break;
  359. }
  360. if( result == SEARCH_QUIT )
  361. break;
  362. }
  363. return result;
  364. }