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.

581 lines
16 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) 2011 Wayne Stambaugh <stambaughw@gmail.com>
  7. * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <bitmaps.h>
  27. #include <core/mirror.h>
  28. #include <macros.h>
  29. #include <pcb_edit_frame.h>
  30. #include <board_design_settings.h>
  31. #include <footprint.h>
  32. #include <base_units.h>
  33. #include <geometry/shape_compound.h>
  34. #include <pcb_shape.h>
  35. #include <pcb_painter.h>
  36. PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ) :
  37. BOARD_CONNECTED_ITEM( aParent, aItemType ),
  38. EDA_SHAPE( aShapeType, pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL )
  39. {
  40. }
  41. PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, SHAPE_T shapetype ) :
  42. BOARD_CONNECTED_ITEM( aParent, PCB_SHAPE_T ),
  43. EDA_SHAPE( shapetype, pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL )
  44. {
  45. }
  46. PCB_SHAPE::~PCB_SHAPE()
  47. {
  48. }
  49. bool PCB_SHAPE::IsType( const std::vector<KICAD_T>& aScanTypes ) const
  50. {
  51. if( BOARD_ITEM::IsType( aScanTypes ) )
  52. return true;
  53. bool sametype = false;
  54. for( KICAD_T scanType : aScanTypes )
  55. {
  56. if( scanType == PCB_LOCATE_BOARD_EDGE_T )
  57. sametype = m_layer == Edge_Cuts;
  58. else if( scanType == PCB_SHAPE_LOCATE_ARC_T )
  59. sametype = m_shape == SHAPE_T::ARC;
  60. else if( scanType == PCB_SHAPE_LOCATE_CIRCLE_T )
  61. sametype = m_shape == SHAPE_T::CIRCLE;
  62. else if( scanType == PCB_SHAPE_LOCATE_RECT_T )
  63. sametype = m_shape == SHAPE_T::RECTANGLE;
  64. else if( scanType == PCB_SHAPE_LOCATE_SEGMENT_T )
  65. sametype = m_shape == SHAPE_T::SEGMENT;
  66. else if( scanType == PCB_SHAPE_LOCATE_POLY_T )
  67. sametype = m_shape == SHAPE_T::POLY;
  68. else if( scanType == PCB_SHAPE_LOCATE_BEZIER_T )
  69. sametype = m_shape == SHAPE_T::BEZIER;
  70. if( sametype )
  71. return true;
  72. }
  73. return false;
  74. }
  75. bool PCB_SHAPE::IsConnected() const
  76. {
  77. // Only board-level copper shapes are connectable
  78. return IsOnCopperLayer() && !GetParentFootprint();
  79. }
  80. void PCB_SHAPE::SetLayer( PCB_LAYER_ID aLayer )
  81. {
  82. BOARD_ITEM::SetLayer( aLayer );
  83. if( !IsOnCopperLayer() )
  84. SetNetCode( -1 );
  85. }
  86. std::vector<VECTOR2I> PCB_SHAPE::GetConnectionPoints() const
  87. {
  88. std::vector<VECTOR2I> ret;
  89. // For filled shapes, we may as well use a centroid
  90. if( IsFilled() )
  91. {
  92. ret.emplace_back( GetCenter() );
  93. return ret;
  94. }
  95. switch( m_shape )
  96. {
  97. case SHAPE_T::ARC:
  98. ret.emplace_back( GetArcMid() );
  99. KI_FALLTHROUGH;
  100. case SHAPE_T::SEGMENT:
  101. case SHAPE_T::BEZIER:
  102. ret.emplace_back( GetStart() );
  103. ret.emplace_back( GetEnd() );
  104. break;
  105. case SHAPE_T::POLY:
  106. for( auto iter = GetPolyShape().CIterate(); iter; ++iter )
  107. ret.emplace_back( *iter );
  108. break;
  109. case SHAPE_T::RECTANGLE:
  110. for( const VECTOR2I& pt : GetRectCorners() )
  111. ret.emplace_back( pt );
  112. break;
  113. default:
  114. break;
  115. }
  116. return ret;
  117. }
  118. void PCB_SHAPE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings )
  119. {
  120. m_stroke.SetWidth( settings.GetLineThickness( GetLayer() ) );
  121. }
  122. const VECTOR2I PCB_SHAPE::GetFocusPosition() const
  123. {
  124. // For some shapes return the visual center, but for not filled polygonal shapes,
  125. // the center is usually far from the shape: a point on the outline is better
  126. switch( m_shape )
  127. {
  128. case SHAPE_T::CIRCLE:
  129. if( !IsFilled() )
  130. return VECTOR2I( GetCenter().x + GetRadius(), GetCenter().y );
  131. else
  132. return GetCenter();
  133. case SHAPE_T::RECTANGLE:
  134. if( !IsFilled() )
  135. return GetStart();
  136. else
  137. return GetCenter();
  138. case SHAPE_T::POLY:
  139. if( !IsFilled() )
  140. {
  141. VECTOR2I pos = GetPolyShape().Outline(0).CPoint(0);
  142. return VECTOR2I( pos.x, pos.y );
  143. }
  144. else
  145. {
  146. return GetCenter();
  147. }
  148. case SHAPE_T::ARC:
  149. return GetArcMid();
  150. case SHAPE_T::BEZIER:
  151. return GetStart();
  152. default:
  153. return GetCenter();
  154. }
  155. }
  156. std::vector<VECTOR2I> PCB_SHAPE::GetCorners() const
  157. {
  158. std::vector<VECTOR2I> pts;
  159. if( GetShape() == SHAPE_T::RECTANGLE )
  160. {
  161. pts = GetRectCorners();
  162. }
  163. else if( GetShape() == SHAPE_T::POLY )
  164. {
  165. for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
  166. {
  167. for( const VECTOR2I& pt : GetPolyShape().Outline( ii ).CPoints() )
  168. pts.emplace_back( pt );
  169. }
  170. }
  171. else
  172. {
  173. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  174. }
  175. while( pts.size() < 4 )
  176. pts.emplace_back( pts.back() + VECTOR2I( 10, 10 ) );
  177. return pts;
  178. }
  179. void PCB_SHAPE::Move( const VECTOR2I& aMoveVector )
  180. {
  181. move( aMoveVector );
  182. }
  183. void PCB_SHAPE::Scale( double aScale )
  184. {
  185. scale( aScale );
  186. }
  187. void PCB_SHAPE::NormalizeRect()
  188. {
  189. if( m_shape == SHAPE_T::RECTANGLE )
  190. {
  191. VECTOR2I start = GetStart();
  192. VECTOR2I end = GetEnd();
  193. BOX2I rect( start, end - start );
  194. rect.Normalize();
  195. SetStart( rect.GetPosition() );
  196. SetEnd( rect.GetEnd() );
  197. }
  198. else if( m_shape == SHAPE_T::POLY )
  199. {
  200. auto horizontal =
  201. []( const SEG& seg )
  202. {
  203. return seg.A.y == seg.B.y;
  204. };
  205. auto vertical =
  206. []( const SEG& seg )
  207. {
  208. return seg.A.x == seg.B.x;
  209. };
  210. // Convert a poly back to a rectangle if appropriate
  211. if( m_poly.OutlineCount() == 1 && m_poly.Outline( 0 ).SegmentCount() == 4 )
  212. {
  213. SHAPE_LINE_CHAIN& outline = m_poly.Outline( 0 );
  214. if( horizontal( outline.Segment( 0 ) )
  215. && vertical( outline.Segment( 1 ) )
  216. && horizontal( outline.Segment( 2 ) )
  217. && vertical( outline.Segment( 3 ) ) )
  218. {
  219. m_shape = SHAPE_T::RECTANGLE;
  220. m_start.x = std::min( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x );
  221. m_start.y = std::min( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y );
  222. m_end.x = std::max( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x );
  223. m_end.y = std::max( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y );
  224. }
  225. else if( vertical( outline.Segment( 0 ) )
  226. && horizontal( outline.Segment( 1 ) )
  227. && vertical( outline.Segment( 2 ) )
  228. && horizontal( outline.Segment( 3 ) ) )
  229. {
  230. m_shape = SHAPE_T::RECTANGLE;
  231. m_start.x = std::min( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x );
  232. m_start.y = std::min( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y );
  233. m_end.x = std::max( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x );
  234. m_end.y = std::max( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y );
  235. }
  236. }
  237. }
  238. }
  239. void PCB_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
  240. {
  241. rotate( aRotCentre, aAngle );
  242. }
  243. void PCB_SHAPE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
  244. {
  245. flip( aCentre, aFlipLeftRight );
  246. SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
  247. }
  248. void PCB_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
  249. {
  250. // Mirror an edge of the footprint. the layer is not modified
  251. // This is a footprint shape modification.
  252. switch( GetShape() )
  253. {
  254. case SHAPE_T::ARC:
  255. case SHAPE_T::SEGMENT:
  256. case SHAPE_T::RECTANGLE:
  257. case SHAPE_T::CIRCLE:
  258. case SHAPE_T::BEZIER:
  259. if( aMirrorAroundXAxis )
  260. {
  261. MIRROR( m_start.y, aCentre.y );
  262. MIRROR( m_end.y, aCentre.y );
  263. MIRROR( m_arcCenter.y, aCentre.y );
  264. MIRROR( m_bezierC1.y, aCentre.y );
  265. MIRROR( m_bezierC2.y, aCentre.y );
  266. }
  267. else
  268. {
  269. MIRROR( m_start.x, aCentre.x );
  270. MIRROR( m_end.x, aCentre.x );
  271. MIRROR( m_arcCenter.x, aCentre.x );
  272. MIRROR( m_bezierC1.x, aCentre.x );
  273. MIRROR( m_bezierC2.x, aCentre.x );
  274. }
  275. if( GetShape() == SHAPE_T::ARC )
  276. std::swap( m_start, m_end );
  277. if( GetShape() == SHAPE_T::BEZIER )
  278. RebuildBezierToSegmentsPointsList( GetWidth() );
  279. break;
  280. case SHAPE_T::POLY:
  281. m_poly.Mirror( !aMirrorAroundXAxis, aMirrorAroundXAxis, aCentre );
  282. break;
  283. default:
  284. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  285. }
  286. }
  287. double PCB_SHAPE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
  288. {
  289. constexpr double HIDE = std::numeric_limits<double>::max();
  290. constexpr double SHOW = 0.0;
  291. KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
  292. KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
  293. if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
  294. {
  295. // Hide shadow if the main layer is not shown
  296. if( !aView->IsLayerVisible( m_layer ) )
  297. return HIDE;
  298. // Hide shadow on dimmed tracks
  299. if( renderSettings->GetHighContrast() )
  300. {
  301. if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
  302. return HIDE;
  303. }
  304. }
  305. if( FOOTPRINT* parent = GetParentFootprint() )
  306. {
  307. if( parent->GetLayer() == F_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
  308. return HIDE;
  309. if( parent->GetLayer() == B_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
  310. return HIDE;
  311. }
  312. return SHOW;
  313. }
  314. void PCB_SHAPE::ViewGetLayers( int aLayers[], int& aCount ) const
  315. {
  316. aLayers[0] = GetLayer();
  317. if( IsOnCopperLayer() )
  318. {
  319. aLayers[1] = GetNetnameLayer( aLayers[0] );
  320. aCount = 2;
  321. }
  322. else
  323. {
  324. aCount = 1;
  325. }
  326. if( IsLocked() )
  327. aLayers[ aCount++ ] = LAYER_LOCKED_ITEM_SHADOW;
  328. }
  329. void PCB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  330. {
  331. if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
  332. {
  333. if( FOOTPRINT* parent = GetParentFootprint() )
  334. aList.emplace_back( _( "Footprint" ), parent->GetReference() );
  335. }
  336. aList.emplace_back( _( "Type" ), _( "Drawing" ) );
  337. if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
  338. aList.emplace_back( _( "Status" ), _( "Locked" ) );
  339. ShapeGetMsgPanelInfo( aFrame, aList );
  340. aList.emplace_back( _( "Layer" ), GetLayerName() );
  341. }
  342. wxString PCB_SHAPE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
  343. {
  344. if( GetNetCode() > 0 )
  345. {
  346. return wxString::Format( _( "%s %s on %s" ), GetFriendlyName(), GetNetnameMsg(),
  347. GetLayerName() );
  348. }
  349. else
  350. {
  351. return wxString::Format( _( "%s on %s" ), GetFriendlyName(), GetLayerName() );
  352. }
  353. }
  354. BITMAPS PCB_SHAPE::GetMenuImage() const
  355. {
  356. if( GetParentFootprint() )
  357. return BITMAPS::show_mod_edge;
  358. else
  359. return BITMAPS::add_dashed_line;
  360. }
  361. EDA_ITEM* PCB_SHAPE::Clone() const
  362. {
  363. return new PCB_SHAPE( *this );
  364. }
  365. const BOX2I PCB_SHAPE::ViewBBox() const
  366. {
  367. BOX2I return_box = EDA_ITEM::ViewBBox();
  368. // Inflate the bounding box by just a bit more for safety.
  369. return_box.Inflate( GetWidth() );
  370. return return_box;
  371. }
  372. std::shared_ptr<SHAPE> PCB_SHAPE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
  373. {
  374. return std::make_shared<SHAPE_COMPOUND>( MakeEffectiveShapes() );
  375. }
  376. void PCB_SHAPE::swapData( BOARD_ITEM* aImage )
  377. {
  378. PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
  379. wxCHECK( image, /* void */ );
  380. SwapShape( image );
  381. // Swap params not handled by SwapShape( image )
  382. std::swap( m_layer, image->m_layer );
  383. std::swap( m_isKnockout, image->m_isKnockout );
  384. std::swap( m_isLocked, image->m_isLocked );
  385. std::swap( m_flags, image->m_flags );
  386. std::swap( m_parent, image->m_parent );
  387. std::swap( m_forceVisible, image->m_forceVisible );
  388. std::swap( m_netinfo, image->m_netinfo );
  389. }
  390. bool PCB_SHAPE::cmp_drawings::operator()( const BOARD_ITEM* aFirst,
  391. const BOARD_ITEM* aSecond ) const
  392. {
  393. if( aFirst->Type() != aSecond->Type() )
  394. return aFirst->Type() < aSecond->Type();
  395. if( aFirst->GetLayer() != aSecond->GetLayer() )
  396. return aFirst->GetLayer() < aSecond->GetLayer();
  397. if( aFirst->Type() == PCB_SHAPE_T )
  398. {
  399. const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( aFirst );
  400. const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( aSecond );
  401. if( dwgA->GetShape() != dwgB->GetShape() )
  402. return dwgA->GetShape() < dwgB->GetShape();
  403. }
  404. return aFirst->m_Uuid < aSecond->m_Uuid;
  405. }
  406. void PCB_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
  407. int aClearance, int aError, ERROR_LOC aErrorLoc,
  408. bool ignoreLineWidth ) const
  409. {
  410. EDA_SHAPE::TransformShapeToPolygon( aBuffer, aClearance, aError, aErrorLoc, ignoreLineWidth );
  411. }
  412. static struct PCB_SHAPE_DESC
  413. {
  414. PCB_SHAPE_DESC()
  415. {
  416. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  417. REGISTER_TYPE( PCB_SHAPE );
  418. propMgr.AddTypeCast( new TYPE_CAST<PCB_SHAPE, BOARD_CONNECTED_ITEM> );
  419. propMgr.AddTypeCast( new TYPE_CAST<PCB_SHAPE, EDA_SHAPE> );
  420. propMgr.InheritsAfter( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
  421. propMgr.InheritsAfter( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ) );
  422. // Need to initialise enum_map before we can use a Property enum for it
  423. ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
  424. if( layerEnum.Choices().GetCount() == 0 )
  425. {
  426. layerEnum.Undefined( UNDEFINED_LAYER );
  427. for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
  428. layerEnum.Map( *seq, LSET::Name( *seq ) );
  429. }
  430. void ( PCB_SHAPE::*shapeLayerSetter )( PCB_LAYER_ID ) = &PCB_SHAPE::SetLayer;
  431. PCB_LAYER_ID ( PCB_SHAPE::*shapeLayerGetter )() const = &PCB_SHAPE::GetLayer;
  432. auto layerProperty = new PROPERTY_ENUM<PCB_SHAPE, PCB_LAYER_ID>(
  433. _HKI( "Layer" ), shapeLayerSetter, shapeLayerGetter );
  434. propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ), layerProperty );
  435. // Only polygons have meaningful Position properties.
  436. // On other shapes, these are duplicates of the Start properties.
  437. auto isPolygon =
  438. []( INSPECTABLE* aItem ) -> bool
  439. {
  440. if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
  441. return shape->GetShape() == SHAPE_T::POLY;
  442. return false;
  443. };
  444. propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ),
  445. _HKI( "Position X" ), isPolygon );
  446. propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ),
  447. _HKI( "Position Y" ), isPolygon );
  448. auto isCopper =
  449. []( INSPECTABLE* aItem ) -> bool
  450. {
  451. if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
  452. return shape->IsOnCopperLayer();
  453. return false;
  454. };
  455. propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_CONNECTED_ITEM ),
  456. _HKI( "Net" ), isCopper );
  457. }
  458. } _PCB_SHAPE_DESC;