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.

326 lines
10 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 CERN
  5. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
  6. * @author Maciej Suminski <maciej.suminski@cern.ch>
  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 <hash_eda.h>
  26. #include <hash.h>
  27. #include <footprint.h>
  28. #include <pcb_text.h>
  29. #include <pcb_textbox.h>
  30. #include <pcb_shape.h>
  31. #include <pad.h>
  32. #include <pcb_track.h>
  33. #include <macros.h>
  34. #include <functional>
  35. #include <wx/log.h>
  36. using namespace std;
  37. // Common calculation part for all BOARD_ITEMs
  38. static inline size_t hash_board_item( const BOARD_ITEM* aItem, int aFlags )
  39. {
  40. size_t ret = 0;
  41. if( aFlags & HASH_LAYER )
  42. ret = hash<BASE_SET>{}( aItem->GetLayerSet() );
  43. return ret;
  44. }
  45. size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
  46. {
  47. size_t ret = 0;
  48. switch( aItem->Type() )
  49. {
  50. case PCB_FOOTPRINT_T:
  51. {
  52. const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
  53. ret = hash_board_item( footprint, aFlags );
  54. if( aFlags & HASH_POS )
  55. hash_combine( ret, footprint->GetPosition().x, footprint->GetPosition().y );
  56. if( aFlags & HASH_ROT )
  57. hash_combine( ret, footprint->GetOrientation().AsDegrees() );
  58. for( BOARD_ITEM* item : footprint->GraphicalItems() )
  59. hash_combine( ret, hash_fp_item( item, aFlags ) );
  60. for( PAD* pad : footprint->Pads() )
  61. hash_combine( ret, hash_fp_item( static_cast<EDA_ITEM*>( pad ), aFlags ) );
  62. }
  63. break;
  64. case PCB_VIA_T:
  65. {
  66. const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
  67. ret = hash<int>{}( via->GetDrillValue() );
  68. hash_combine( ret, via->TopLayer() );
  69. hash_combine( ret, via->BottomLayer() );
  70. via->GetLayerSet().RunOnLayers(
  71. [&]( PCB_LAYER_ID layer )
  72. {
  73. hash_combine( ret, via->GetWidth( layer ) );
  74. hash_combine( ret, via->FlashLayer( layer ) );
  75. } );
  76. break;
  77. }
  78. case PCB_PAD_T:
  79. {
  80. const PAD* pad = static_cast<const PAD*>( aItem );
  81. ret = hash<int>{}( static_cast<int>( pad->GetAttribute() ) );
  82. auto hashPadLayer =
  83. [&]( PCB_LAYER_ID aLayer )
  84. {
  85. hash_combine( ret, pad->GetShape( aLayer ) );
  86. hash_combine( ret, pad->GetSize( aLayer ).x, pad->GetSize( aLayer ).y );
  87. hash_combine( ret, pad->GetOffset( aLayer ).x, pad->GetOffset( aLayer ).y );
  88. switch( pad->GetShape( PADSTACK::ALL_LAYERS ) )
  89. {
  90. case PAD_SHAPE::CHAMFERED_RECT:
  91. hash_combine( ret, pad->GetChamferPositions( aLayer ) );
  92. hash_combine( ret, pad->GetChamferRectRatio( aLayer ) );
  93. break;
  94. case PAD_SHAPE::ROUNDRECT:
  95. hash_combine( ret, pad->GetRoundRectCornerRadius( aLayer ) );
  96. break;
  97. case PAD_SHAPE::TRAPEZOID:
  98. hash_combine( ret, pad->GetDelta( aLayer ).x, pad->GetDelta( aLayer ).y );
  99. break;
  100. case PAD_SHAPE::CUSTOM:
  101. {
  102. auto poly = pad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
  103. for( int ii = 0; ii < poly->VertexCount(); ++ii )
  104. {
  105. VECTOR2I point = poly->CVertex( ii ) - pad->GetPosition();
  106. hash_combine( ret, point.x, point.y );
  107. }
  108. break;
  109. }
  110. default:
  111. break;
  112. }
  113. };
  114. pad->Padstack().ForEachUniqueLayer( hashPadLayer );
  115. if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
  116. {
  117. hash_combine( ret, pad->GetDrillSizeX(), pad->GetDrillSizeY() );
  118. hash_combine( ret, pad->GetDrillShape() );
  119. pad->GetLayerSet().RunOnLayers(
  120. [&]( PCB_LAYER_ID layer )
  121. {
  122. hash_combine( ret, pad->FlashLayer( layer ) );
  123. } );
  124. }
  125. hash_combine( ret, hash_board_item( pad, aFlags ) );
  126. if( aFlags & HASH_POS )
  127. {
  128. if( aFlags & REL_COORD )
  129. hash_combine( ret, pad->GetFPRelativePosition().x, pad->GetFPRelativePosition().y );
  130. else
  131. hash_combine( ret, pad->GetPosition().x, pad->GetPosition().y );
  132. }
  133. if( aFlags & HASH_ROT )
  134. hash_combine( ret, pad->GetOrientation().AsDegrees() );
  135. if( aFlags & HASH_NET )
  136. hash_combine( ret, pad->GetNetCode() );
  137. }
  138. break;
  139. case PCB_FIELD_T:
  140. if( !( aFlags & HASH_REF ) && static_cast<const PCB_FIELD*>( aItem )->IsReference() )
  141. break;
  142. if( !( aFlags & HASH_VALUE ) && static_cast<const PCB_FIELD*>( aItem )->IsValue() )
  143. break;
  144. KI_FALLTHROUGH;
  145. case PCB_TEXT_T:
  146. {
  147. const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
  148. ret = hash_board_item( text, aFlags );
  149. hash_combine( ret, text->GetText().ToStdString() );
  150. hash_combine( ret, text->IsItalic() );
  151. hash_combine( ret, text->IsBold() );
  152. hash_combine( ret, text->IsMirrored() );
  153. hash_combine( ret, text->GetTextWidth() );
  154. hash_combine( ret, text->GetTextHeight() );
  155. hash_combine( ret, text->GetHorizJustify() );
  156. hash_combine( ret, text->GetVertJustify() );
  157. if( aFlags & HASH_POS )
  158. {
  159. VECTOR2I pos = ( aFlags & REL_COORD ) ? text->GetFPRelativePosition()
  160. : text->GetPosition();
  161. hash_combine( ret, pos.x, pos.y );
  162. }
  163. if( aFlags & HASH_ROT )
  164. hash_combine( ret, text->GetTextAngle().AsDegrees() );
  165. }
  166. break;
  167. case PCB_SHAPE_T:
  168. {
  169. const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
  170. ret = hash_board_item( shape, aFlags );
  171. hash_combine( ret, shape->GetShape() );
  172. hash_combine( ret, shape->GetWidth() );
  173. hash_combine( ret, shape->IsFilled() );
  174. hash_combine( ret, shape->GetLineStyle() );
  175. if( shape->GetShape() == SHAPE_T::ARC || shape->GetShape() == SHAPE_T::CIRCLE )
  176. hash_combine( ret, shape->GetRadius() );
  177. if( aFlags & HASH_POS )
  178. {
  179. std::vector<VECTOR2I> points;
  180. points.push_back( shape->GetStart() );
  181. points.push_back( shape->GetEnd() );
  182. if( shape->GetShape() == SHAPE_T::CIRCLE )
  183. points.push_back( shape->GetCenter() );
  184. if( shape->GetShape() == SHAPE_T::ARC )
  185. points.push_back( shape->GetArcMid() );
  186. FOOTPRINT* parentFP = shape->GetParentFootprint();
  187. if( shape->GetShape() == SHAPE_T::POLY )
  188. {
  189. const SHAPE_POLY_SET& poly = shape->GetPolyShape();
  190. for( auto it = poly.CIterateWithHoles(); it; it++ )
  191. points.push_back( *it );
  192. }
  193. if( shape->GetShape() == SHAPE_T::BEZIER )
  194. {
  195. points.push_back( shape->GetBezierC1() );
  196. points.push_back( shape->GetBezierC2() );
  197. }
  198. if( parentFP && ( aFlags & REL_COORD ) )
  199. {
  200. for( VECTOR2I& point : points )
  201. {
  202. point -= parentFP->GetPosition();
  203. RotatePoint( point, -parentFP->GetOrientation() );
  204. }
  205. }
  206. if( aFlags & REL_POS )
  207. {
  208. for( VECTOR2I& point : points )
  209. point -= shape->GetPosition();
  210. }
  211. for( VECTOR2I& point : points )
  212. hash_combine( ret, point.x, point.y );
  213. }
  214. }
  215. break;
  216. case PCB_TEXTBOX_T:
  217. {
  218. const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aItem );
  219. ret = hash_board_item( textbox, aFlags );
  220. hash_combine( ret, textbox->GetText().ToStdString() );
  221. hash_combine( ret, textbox->IsItalic() );
  222. hash_combine( ret, textbox->IsBold() );
  223. hash_combine( ret, textbox->IsMirrored() );
  224. hash_combine( ret, textbox->GetTextWidth() );
  225. hash_combine( ret, textbox->GetTextHeight() );
  226. hash_combine( ret, textbox->GetHorizJustify() );
  227. hash_combine( ret, textbox->GetVertJustify() );
  228. if( aFlags & HASH_ROT )
  229. hash_combine( ret, textbox->GetTextAngle().AsDegrees() );
  230. hash_combine( ret, textbox->GetShape() );
  231. hash_combine( ret, textbox->GetWidth() );
  232. hash_combine( ret, textbox->GetLineStyle() );
  233. if( aFlags & HASH_POS )
  234. {
  235. VECTOR2I start = textbox->GetStart();
  236. VECTOR2I end = textbox->GetEnd();
  237. FOOTPRINT* parentFP = textbox->GetParentFootprint();
  238. if( parentFP && ( aFlags & REL_COORD ) )
  239. {
  240. start -= parentFP->GetPosition();
  241. end -= parentFP->GetPosition();
  242. RotatePoint( start, -parentFP->GetOrientation() );
  243. RotatePoint( end, -parentFP->GetOrientation() );
  244. }
  245. hash_combine( ret, start.x );
  246. hash_combine( ret, start.y );
  247. hash_combine( ret, end.x );
  248. hash_combine( ret, end.y );
  249. }
  250. }
  251. break;
  252. case PCB_TABLE_T:
  253. // JEY TODO: tables
  254. break;
  255. default:
  256. wxASSERT_MSG( false, "Unhandled type in function hash_fp_item() (exporter_gencad.cpp)" );
  257. }
  258. return ret;
  259. }