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.

366 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <bitmaps.h>
  26. #include <base_units.h>
  27. #include <eda_draw_frame.h>
  28. #include <board.h>
  29. #include <board_design_settings.h>
  30. #include <pcb_marker.h>
  31. #include <layer_ids.h>
  32. #include <settings/color_settings.h>
  33. #include <settings/settings_manager.h>
  34. #include <geometry/shape_null.h>
  35. #include <widgets/ui_common.h>
  36. #include <pgm_base.h>
  37. #include <drc/drc_item.h>
  38. #include <trigo.h>
  39. /// Factor to convert the maker unit shape to internal units:
  40. #define SCALING_FACTOR pcbIUScale.mmToIU( 0.1625 )
  41. PCB_MARKER::PCB_MARKER( std::shared_ptr<RC_ITEM> aItem, const VECTOR2I& aPosition, int aLayer ) :
  42. BOARD_ITEM( nullptr, PCB_MARKER_T, F_Cu ), // parent set during BOARD::Add()
  43. MARKER_BASE( SCALING_FACTOR, aItem )
  44. {
  45. if( m_rcItem )
  46. {
  47. m_rcItem->SetParent( this );
  48. if( aLayer == LAYER_DRAWINGSHEET )
  49. {
  50. SetMarkerType( MARKER_BASE::MARKER_DRAWING_SHEET );
  51. }
  52. else
  53. {
  54. switch( m_rcItem->GetErrorCode() )
  55. {
  56. case DRCE_UNCONNECTED_ITEMS:
  57. SetMarkerType( MARKER_BASE::MARKER_RATSNEST );
  58. break;
  59. case DRCE_MISSING_FOOTPRINT:
  60. case DRCE_DUPLICATE_FOOTPRINT:
  61. case DRCE_EXTRA_FOOTPRINT:
  62. case DRCE_NET_CONFLICT:
  63. case DRCE_SCHEMATIC_PARITY_ISSUES:
  64. SetMarkerType( MARKER_BASE::MARKER_PARITY );
  65. break;
  66. default:
  67. SetMarkerType( MARKER_BASE::MARKER_DRC );
  68. break;
  69. }
  70. SetLayer( ToLAYER_ID( aLayer ) );
  71. }
  72. }
  73. m_Pos = aPosition;
  74. }
  75. /* destructor */
  76. PCB_MARKER::~PCB_MARKER()
  77. {
  78. if( m_rcItem )
  79. m_rcItem->SetParent( nullptr );
  80. }
  81. wxString PCB_MARKER::Serialize() const
  82. {
  83. if( m_rcItem->GetErrorCode() == DRCE_COPPER_SLIVER )
  84. {
  85. return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
  86. m_rcItem->GetSettingsKey(),
  87. m_Pos.x,
  88. m_Pos.y,
  89. m_rcItem->GetMainItemID().AsString(),
  90. LayerName( m_layer ) );
  91. }
  92. else if( m_rcItem->GetErrorCode() == DRCE_STARVED_THERMAL )
  93. {
  94. return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s" ),
  95. m_rcItem->GetSettingsKey(),
  96. m_Pos.x,
  97. m_Pos.y,
  98. m_rcItem->GetMainItemID().AsString(),
  99. m_rcItem->GetAuxItemID().AsString(),
  100. LayerName( m_layer ) );
  101. }
  102. else if( m_rcItem->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
  103. && m_rcItem->GetParent()->GetMarkerType() == MARKER_DRAWING_SHEET )
  104. {
  105. return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
  106. m_rcItem->GetSettingsKey(),
  107. m_Pos.x,
  108. m_Pos.y,
  109. // Drawing sheet KIIDs aren't preserved between runs
  110. wxEmptyString,
  111. wxEmptyString );
  112. }
  113. else
  114. {
  115. return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
  116. m_rcItem->GetSettingsKey(),
  117. m_Pos.x,
  118. m_Pos.y,
  119. m_rcItem->GetMainItemID().AsString(),
  120. m_rcItem->GetAuxItemID().AsString() );
  121. }
  122. }
  123. PCB_MARKER* PCB_MARKER::Deserialize( const wxString& data )
  124. {
  125. auto getMarkerLayer =
  126. []( const wxString& layerName ) -> int
  127. {
  128. for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
  129. {
  130. if( LayerName( ToLAYER_ID( layer ) ) == layerName )
  131. return layer;
  132. }
  133. return F_Cu;
  134. };
  135. wxArrayString props = wxSplit( data, '|' );
  136. int markerLayer = F_Cu;
  137. VECTOR2I markerPos( (int) strtol( props[1].c_str(), nullptr, 10 ),
  138. (int) strtol( props[2].c_str(), nullptr, 10 ) );
  139. std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( props[0] );
  140. if( !drcItem )
  141. return nullptr;
  142. if( drcItem->GetErrorCode() == DRCE_COPPER_SLIVER )
  143. {
  144. drcItem->SetItems( KIID( props[3] ) );
  145. markerLayer = getMarkerLayer( props[4] );
  146. }
  147. else if( drcItem->GetErrorCode() == DRCE_STARVED_THERMAL )
  148. {
  149. drcItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
  150. // Pre-7.0 versions didn't differentiate between layers
  151. if( props.size() == 6 )
  152. markerLayer = getMarkerLayer( props[5] );
  153. }
  154. else if( drcItem->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
  155. && props[3].IsEmpty() && props[4].IsEmpty() )
  156. {
  157. // Note: caller must load our item pointer with the drawing sheet proxy item
  158. markerLayer = LAYER_DRAWINGSHEET;
  159. }
  160. else
  161. {
  162. drcItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
  163. }
  164. return new PCB_MARKER( drcItem, markerPos, markerLayer );
  165. }
  166. void PCB_MARKER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  167. {
  168. aList.emplace_back( _( "Type" ), _( "Marker" ) );
  169. aList.emplace_back( _( "Violation" ), m_rcItem->GetErrorMessage() );
  170. switch( GetSeverity() )
  171. {
  172. case RPT_SEVERITY_IGNORE:
  173. aList.emplace_back( _( "Severity" ), _( "Ignore" ) );
  174. break;
  175. case RPT_SEVERITY_WARNING:
  176. aList.emplace_back( _( "Severity" ), _( "Warning" ) );
  177. break;
  178. case RPT_SEVERITY_ERROR:
  179. aList.emplace_back( _( "Severity" ), _( "Error" ) );
  180. break;
  181. default:
  182. break;
  183. }
  184. if( GetMarkerType() == MARKER_DRAWING_SHEET )
  185. {
  186. aList.emplace_back( _( "Drawing Sheet" ), wxEmptyString );
  187. }
  188. else
  189. {
  190. wxString mainText;
  191. wxString auxText;
  192. EDA_ITEM* mainItem = nullptr;
  193. EDA_ITEM* auxItem = nullptr;
  194. if( m_rcItem->GetMainItemID() != niluuid )
  195. mainItem = aFrame->GetItem( m_rcItem->GetMainItemID() );
  196. if( m_rcItem->GetAuxItemID() != niluuid )
  197. auxItem = aFrame->GetItem( m_rcItem->GetAuxItemID() );
  198. if( mainItem )
  199. mainText = mainItem->GetItemDescription( aFrame );
  200. if( auxItem )
  201. auxText = auxItem->GetItemDescription( aFrame );
  202. aList.emplace_back( mainText, auxText );
  203. }
  204. }
  205. void PCB_MARKER::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
  206. {
  207. // Marker geometry isn't user-editable
  208. }
  209. void PCB_MARKER::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
  210. {
  211. // Marker geometry isn't user-editable
  212. }
  213. std::shared_ptr<SHAPE> PCB_MARKER::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
  214. {
  215. // Markers do not participate in the board geometry space, and therefore have no
  216. // effectiven shape.
  217. return std::make_shared<SHAPE_NULL>();
  218. }
  219. wxString PCB_MARKER::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
  220. {
  221. // m_rcItem->GetErrorMessage() could be used instead, but is probably too long
  222. // for menu duty.
  223. return wxString::Format( _( "Marker (%s)" ), m_rcItem->GetErrorText() );
  224. }
  225. BITMAPS PCB_MARKER::GetMenuImage() const
  226. {
  227. return BITMAPS::drc;
  228. }
  229. SEVERITY PCB_MARKER::GetSeverity() const
  230. {
  231. if( IsExcluded() )
  232. return RPT_SEVERITY_EXCLUSION;
  233. DRC_ITEM* item = static_cast<DRC_ITEM*>( m_rcItem.get() );
  234. DRC_RULE* rule = item->GetViolatingRule();
  235. if( rule && rule->m_Severity != RPT_SEVERITY_UNDEFINED )
  236. return rule->m_Severity;
  237. return GetBoard()->GetDesignSettings().GetSeverity( item->GetErrorCode() );
  238. }
  239. void PCB_MARKER::ViewGetLayers( int aLayers[], int& aCount ) const
  240. {
  241. if( GetMarkerType() == MARKER_RATSNEST )
  242. {
  243. aCount = 0;
  244. return;
  245. }
  246. aCount = 2;
  247. aLayers[1] = LAYER_MARKER_SHADOWS;
  248. switch( GetSeverity() )
  249. {
  250. default:
  251. case SEVERITY::RPT_SEVERITY_ERROR: aLayers[0] = LAYER_DRC_ERROR; break;
  252. case SEVERITY::RPT_SEVERITY_WARNING: aLayers[0] = LAYER_DRC_WARNING; break;
  253. case SEVERITY::RPT_SEVERITY_EXCLUSION: aLayers[0] = LAYER_DRC_EXCLUSION; break;
  254. }
  255. }
  256. GAL_LAYER_ID PCB_MARKER::GetColorLayer() const
  257. {
  258. switch( GetSeverity() )
  259. {
  260. default:
  261. case SEVERITY::RPT_SEVERITY_ERROR: return LAYER_DRC_ERROR;
  262. case SEVERITY::RPT_SEVERITY_WARNING: return LAYER_DRC_WARNING;
  263. case SEVERITY::RPT_SEVERITY_EXCLUSION: return LAYER_DRC_EXCLUSION;
  264. }
  265. }
  266. KIGFX::COLOR4D PCB_MARKER::getColor() const
  267. {
  268. COLOR_SETTINGS* colors = Pgm().GetSettingsManager().GetColorSettings();
  269. return colors->GetColor( GetColorLayer() );
  270. }
  271. void PCB_MARKER::SetZoom( double aZoomFactor )
  272. {
  273. SetMarkerScale( SCALING_FACTOR * aZoomFactor );
  274. }
  275. const BOX2I PCB_MARKER::GetBoundingBox() const
  276. {
  277. return GetBoundingBoxMarker();
  278. }
  279. const BOX2I PCB_MARKER::ViewBBox() const
  280. {
  281. return GetBoundingBox();
  282. }
  283. static struct PCB_MARKER_DESC
  284. {
  285. PCB_MARKER_DESC()
  286. {
  287. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  288. REGISTER_TYPE( PCB_MARKER );
  289. propMgr.AddTypeCast( new TYPE_CAST<PCB_MARKER, BOARD_ITEM> );
  290. propMgr.AddTypeCast( new TYPE_CAST<PCB_MARKER, MARKER_BASE> );
  291. propMgr.InheritsAfter( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ) );
  292. propMgr.InheritsAfter( TYPE_HASH( PCB_MARKER ), TYPE_HASH( MARKER_BASE ) );
  293. // Markers cannot be locked and have no user-accessible layer control
  294. propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
  295. _HKI( "Layer" ),
  296. []( INSPECTABLE* aItem ) { return false; } );
  297. propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
  298. _HKI( "Locked" ),
  299. []( INSPECTABLE* aItem ) { return false; } );
  300. }
  301. } _PCB_MARKER_DESC;