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.

424 lines
12 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2022 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 <core/wx_stl_compat.h>
  27. #include <bitmaps.h>
  28. #include <core/mirror.h>
  29. #include <macros.h>
  30. #include <math/util.h> // for KiROUND
  31. #include <settings/color_settings.h>
  32. #include <settings/settings_manager.h>
  33. #include <pcb_edit_frame.h>
  34. #include <footprint.h>
  35. #include <fp_shape.h>
  36. #include <view/view.h>
  37. FP_SHAPE::FP_SHAPE( FOOTPRINT* parent, SHAPE_T aShape, KICAD_T aItemType ) :
  38. PCB_SHAPE( parent, aItemType, aShape )
  39. {
  40. m_layer = F_SilkS;
  41. }
  42. FP_SHAPE::~FP_SHAPE()
  43. {
  44. }
  45. void FP_SHAPE::SetLocalCoord()
  46. {
  47. FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent );
  48. if( fp == NULL )
  49. {
  50. m_start0 = m_start;
  51. m_end0 = m_end;
  52. m_arcCenter0 = m_arcCenter;
  53. m_bezierC1_0 = m_bezierC1;
  54. m_bezierC2_0 = m_bezierC2;
  55. return;
  56. }
  57. m_start0 = m_start - fp->GetPosition();
  58. m_end0 = m_end - fp->GetPosition();
  59. m_arcCenter0 = m_arcCenter - fp->GetPosition();
  60. m_bezierC1_0 = m_bezierC1 - fp->GetPosition();
  61. m_bezierC2_0 = m_bezierC2 - fp->GetPosition();
  62. RotatePoint( &m_start0.x, &m_start0.y, - fp->GetOrientation() );
  63. RotatePoint( &m_end0.x, &m_end0.y, - fp->GetOrientation() );
  64. RotatePoint( &m_arcCenter0.x, &m_arcCenter0.y, - fp->GetOrientation() );
  65. RotatePoint( &m_bezierC1_0.x, &m_bezierC1_0.y, - fp->GetOrientation() );
  66. RotatePoint( &m_bezierC2_0.x, &m_bezierC2_0.y, - fp->GetOrientation() );
  67. }
  68. void FP_SHAPE::SetDrawCoord()
  69. {
  70. FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent );
  71. m_start = m_start0;
  72. m_end = m_end0;
  73. m_arcCenter = m_arcCenter0;
  74. m_bezierC1 = m_bezierC1_0;
  75. m_bezierC2 = m_bezierC2_0;
  76. if( fp )
  77. {
  78. RotatePoint( &m_start.x, &m_start.y, fp->GetOrientation() );
  79. RotatePoint( &m_end.x, &m_end.y, fp->GetOrientation() );
  80. RotatePoint( &m_arcCenter.x, &m_arcCenter.y, fp->GetOrientation() );
  81. RotatePoint( &m_bezierC1.x, &m_bezierC1.y, fp->GetOrientation() );
  82. RotatePoint( &m_bezierC2.x, &m_bezierC2.y, fp->GetOrientation() );
  83. m_start += fp->GetPosition();
  84. m_end += fp->GetPosition();
  85. m_arcCenter += fp->GetPosition();
  86. m_bezierC1 += fp->GetPosition();
  87. m_bezierC2 += fp->GetPosition();
  88. }
  89. RebuildBezierToSegmentsPointsList( GetWidth() );
  90. }
  91. void FP_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  92. {
  93. if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
  94. {
  95. FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent );
  96. if( fp )
  97. aList.emplace_back( _( "Footprint" ), fp->GetReference() );
  98. }
  99. // append the features shared with the base class
  100. PCB_SHAPE::GetMsgPanelInfo( aFrame, aList );
  101. }
  102. wxString FP_SHAPE::GetSelectMenuText( UNITS_PROVIDER* aUnitsProvider ) const
  103. {
  104. return wxString::Format( _( "%s on %s" ),
  105. ShowShape(),
  106. GetLayerName() );
  107. }
  108. BITMAPS FP_SHAPE::GetMenuImage() const
  109. {
  110. return BITMAPS::show_mod_edge;
  111. }
  112. EDA_ITEM* FP_SHAPE::Clone() const
  113. {
  114. return new FP_SHAPE( *this );
  115. }
  116. VECTOR2I FP_SHAPE::GetCenter0() const
  117. {
  118. switch( m_shape )
  119. {
  120. case SHAPE_T::ARC:
  121. return m_arcCenter0;
  122. case SHAPE_T::CIRCLE:
  123. return m_start0;
  124. default:
  125. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  126. return VECTOR2I();
  127. }
  128. }
  129. void FP_SHAPE::SetCenter0( const VECTOR2I& aCenter )
  130. {
  131. switch( m_shape )
  132. {
  133. case SHAPE_T::ARC:
  134. m_arcCenter0 = aCenter;
  135. break;
  136. case SHAPE_T::CIRCLE:
  137. m_start0 = aCenter;
  138. break;
  139. default:
  140. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  141. }
  142. }
  143. VECTOR2I FP_SHAPE::GetArcMid0() const
  144. {
  145. // If none of the input data have changed since we loaded the arc,
  146. // keep the original mid point data to minimize churn
  147. if( m_arcMidData_0.start == m_start && m_arcMidData_0.end == m_end
  148. && m_arcMidData_0.center == m_arcCenter )
  149. return m_arcMidData_0.mid;
  150. VECTOR2I mid0 = m_start0;
  151. RotatePoint( mid0, m_arcCenter0, -GetArcAngle() / 2.0 );
  152. return mid0;
  153. }
  154. void FP_SHAPE::SetArcAngleAndEnd0( const EDA_ANGLE& aAngle, bool aCheckNegativeAngle )
  155. {
  156. EDA_ANGLE angle( aAngle );
  157. m_end0 = m_start0;
  158. RotatePoint( m_end0, m_arcCenter0, -angle.Normalize720() );
  159. if( aCheckNegativeAngle && aAngle < ANGLE_0 )
  160. std::swap( m_start0, m_end0 );
  161. }
  162. void FP_SHAPE::SetArcGeometry0( const VECTOR2I& aStart0, const VECTOR2I& aMid0,
  163. const VECTOR2I& aEnd0 )
  164. {
  165. m_start0 = aStart0;
  166. m_end0 = aEnd0;
  167. m_arcCenter0 = CalcArcCenter( aStart0, aMid0, aEnd0 );
  168. m_arcMidData_0.center = m_arcCenter0;
  169. m_arcMidData_0.end = m_end0;
  170. m_arcMidData_0.mid = aMid0;
  171. m_arcMidData_0.start = m_start0;
  172. }
  173. void FP_SHAPE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
  174. {
  175. VECTOR2I pt( 0, 0 );
  176. switch( GetShape() )
  177. {
  178. case SHAPE_T::ARC:
  179. case SHAPE_T::SEGMENT:
  180. case SHAPE_T::RECT:
  181. case SHAPE_T::CIRCLE:
  182. case SHAPE_T::BEZIER:
  183. // If Start0 and Start are equal (ie: Footprint Editor), then flip both sets around the
  184. // centre point.
  185. if( m_start == m_start0 )
  186. pt = aCentre;
  187. if( aFlipLeftRight )
  188. {
  189. MIRROR( m_start.x, aCentre.x );
  190. MIRROR( m_end.x, aCentre.x );
  191. MIRROR( m_arcCenter.x, aCentre.x );
  192. MIRROR( m_bezierC1.x, aCentre.x );
  193. MIRROR( m_bezierC2.x, aCentre.x );
  194. MIRROR( m_start0.x, pt.x );
  195. MIRROR( m_end0.x, pt.x );
  196. MIRROR( m_arcCenter0.x, pt.x );
  197. MIRROR( m_bezierC1_0.x, pt.x );
  198. MIRROR( m_bezierC2_0.x, pt.x );
  199. }
  200. else
  201. {
  202. MIRROR( m_start.y, aCentre.y );
  203. MIRROR( m_end.y, aCentre.y );
  204. MIRROR( m_arcCenter.y, aCentre.y );
  205. MIRROR( m_bezierC1.y, aCentre.y );
  206. MIRROR( m_bezierC2.y, aCentre.y );
  207. MIRROR( m_start0.y, pt.y );
  208. MIRROR( m_end0.y, pt.y );
  209. MIRROR( m_arcCenter0.y, pt.y );
  210. MIRROR( m_bezierC1_0.y, pt.y );
  211. MIRROR( m_bezierC2_0.y, pt.y );
  212. }
  213. if( GetShape() == SHAPE_T::BEZIER )
  214. RebuildBezierToSegmentsPointsList( GetWidth() );
  215. if( GetShape() == SHAPE_T::ARC )
  216. {
  217. std::swap( m_start, m_end );
  218. std::swap( m_start0, m_end0 );
  219. }
  220. break;
  221. case SHAPE_T::POLY:
  222. // polygon corners coordinates are relative to the footprint position, orientation 0
  223. m_poly.Mirror( aFlipLeftRight, !aFlipLeftRight );
  224. break;
  225. default:
  226. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  227. }
  228. SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
  229. }
  230. bool FP_SHAPE::IsParentFlipped() const
  231. {
  232. if( GetParent() && GetParent()->GetLayer() == B_Cu )
  233. return true;
  234. return false;
  235. }
  236. void FP_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
  237. {
  238. // Mirror an edge of the footprint. the layer is not modified
  239. // This is a footprint shape modification.
  240. switch( GetShape() )
  241. {
  242. case SHAPE_T::ARC:
  243. case SHAPE_T::SEGMENT:
  244. case SHAPE_T::RECT:
  245. case SHAPE_T::CIRCLE:
  246. case SHAPE_T::BEZIER:
  247. if( aMirrorAroundXAxis )
  248. {
  249. MIRROR( m_start0.y, aCentre.y );
  250. MIRROR( m_end0.y, aCentre.y );
  251. MIRROR( m_arcCenter0.y, aCentre.y );
  252. MIRROR( m_bezierC1_0.y, aCentre.y );
  253. MIRROR( m_bezierC2_0.y, aCentre.y );
  254. }
  255. else
  256. {
  257. MIRROR( m_start0.x, aCentre.x );
  258. MIRROR( m_end0.x, aCentre.x );
  259. MIRROR( m_arcCenter0.x, aCentre.x );
  260. MIRROR( m_bezierC1_0.x, aCentre.x );
  261. MIRROR( m_bezierC2_0.x, aCentre.x );
  262. }
  263. if( GetShape() == SHAPE_T::ARC )
  264. {
  265. std::swap( m_start, m_end );
  266. std::swap( m_start0, m_end0 );
  267. }
  268. if( GetShape() == SHAPE_T::BEZIER )
  269. RebuildBezierToSegmentsPointsList( GetWidth() );
  270. break;
  271. case SHAPE_T::POLY:
  272. m_poly.Mirror( !aMirrorAroundXAxis, aMirrorAroundXAxis, aCentre );
  273. break;
  274. default:
  275. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  276. }
  277. SetDrawCoord();
  278. }
  279. void FP_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
  280. {
  281. // We should rotate the relative coordinates, but to avoid duplicate code do the base class
  282. // rotation of draw coordinates, which is acceptable because in the footprint editor
  283. // m_Pos0 = m_Pos
  284. PCB_SHAPE::Rotate( aRotCentre, aAngle );
  285. // and now update the relative coordinates, which are the reference in most transforms.
  286. SetLocalCoord();
  287. }
  288. void FP_SHAPE::Move( const VECTOR2I& aMoveVector )
  289. {
  290. // Move an edge of the footprint.
  291. // This is a footprint shape modification.
  292. switch( GetShape() )
  293. {
  294. case SHAPE_T::ARC:
  295. case SHAPE_T::SEGMENT:
  296. case SHAPE_T::RECT:
  297. case SHAPE_T::CIRCLE:
  298. case SHAPE_T::BEZIER:
  299. m_start0 += aMoveVector;
  300. m_end0 += aMoveVector;
  301. m_arcCenter0 += aMoveVector;
  302. m_bezierC1_0 += aMoveVector;
  303. m_bezierC2_0 += aMoveVector;
  304. break;
  305. case SHAPE_T::POLY:
  306. // polygon corners coordinates are always relative to the
  307. // footprint position, orientation 0
  308. m_poly.Move( VECTOR2I( aMoveVector ) );
  309. break;
  310. default:
  311. UNIMPLEMENTED_FOR( SHAPE_T_asString() );
  312. }
  313. SetDrawCoord();
  314. }
  315. double FP_SHAPE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
  316. {
  317. constexpr double HIDE = std::numeric_limits<double>::max();
  318. if( !aView )
  319. return 0;
  320. // Handle Render tab switches
  321. if( !IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_FR ) )
  322. return HIDE;
  323. if( IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_BK ) )
  324. return HIDE;
  325. // Other layers are shown without any conditions
  326. return 0.0;
  327. }
  328. static struct FP_SHAPE_DESC
  329. {
  330. FP_SHAPE_DESC()
  331. {
  332. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  333. REGISTER_TYPE( FP_SHAPE );
  334. propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, BOARD_ITEM> );
  335. propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, EDA_SHAPE> );
  336. propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, PCB_SHAPE> );
  337. propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( BOARD_ITEM ) );
  338. propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( EDA_SHAPE ) );
  339. propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( PCB_SHAPE ) );
  340. propMgr.AddProperty( new PROPERTY<FP_SHAPE, wxString>( _HKI( "Parent" ),
  341. NO_SETTER( FP_SHAPE, wxString ), &FP_SHAPE::GetParentAsString ) );
  342. }
  343. } _FP_SHAPE_DESC;