KiCad PCB EDA Suite
Loading...
Searching...
No Matches
hash_eda.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <hash_eda.h>
23#include <hash.h>
24#include <footprint.h>
25#include <pcb_text.h>
26#include <pcb_table.h>
27#include <pcb_textbox.h>
28#include <pcb_shape.h>
29#include <pad.h>
30#include <pcb_track.h>
31#include <pcb_barcode.h>
32
33#include <macros.h>
34#include <functional>
35#include <algorithm>
36#include <vector>
37
38#include <wx/log.h>
39
40using namespace std;
41
42// Common calculation part for all BOARD_ITEMs
43static inline size_t hash_board_item( const BOARD_ITEM* aItem, int aFlags )
44{
45 size_t ret = 0;
46
47 if( aFlags & HASH_LAYER )
48 ret = hash<BASE_SET>{}( aItem->GetLayerSet() );
49
50 return ret;
51}
52
53
54size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
55{
56 size_t ret = 0;
57
58 switch( aItem->Type() )
59 {
60 case PCB_FOOTPRINT_T:
61 {
62 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
63
64 ret = hash_board_item( footprint, aFlags );
65
66 if( aFlags & HASH_POS )
67 hash_combine( ret, footprint->GetPosition().x, footprint->GetPosition().y );
68
69 if( aFlags & HASH_ROT )
70 hash_combine( ret, footprint->GetOrientation().AsDegrees() );
71
72 std::vector<size_t> hashes;
73
74 for( BOARD_ITEM* item : footprint->GraphicalItems() )
75 hashes.push_back( hash_fp_item( item, aFlags ) );
76
77 for( PAD* pad : footprint->Pads() )
78 hashes.push_back( hash_fp_item( static_cast<EDA_ITEM*>( pad ), aFlags ) );
79
80 std::sort( hashes.begin(), hashes.end() );
81
82 for( size_t h : hashes )
83 hash_combine( ret, h );
84 }
85 break;
86
87 case PCB_VIA_T:
88 {
89 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
90
91 ret = hash<int>{}( via->GetDrillValue() );
92 hash_combine( ret, via->TopLayer() );
93 hash_combine( ret, via->BottomLayer() );
94
95 via->GetLayerSet().RunOnLayers(
96 [&]( PCB_LAYER_ID layer )
97 {
98 hash_combine( ret, via->GetWidth( layer ) );
99 hash_combine( ret, via->FlashLayer( layer ) );
100 } );
101
102 break;
103 }
104
105 case PCB_PAD_T:
106 {
107 const PAD* pad = static_cast<const PAD*>( aItem );
108
109 ret = hash<int>{}( static_cast<int>( pad->GetAttribute() ) );
110
111 auto hashPadLayer =
112 [&]( PCB_LAYER_ID aLayer )
113 {
114 hash_combine( ret, pad->GetShape( aLayer ) );
115 hash_combine( ret, pad->GetSize( aLayer ).x, pad->GetSize( aLayer ).y );
116 hash_combine( ret, pad->GetOffset( aLayer ).x, pad->GetOffset( aLayer ).y );
117
118 switch( pad->GetShape( PADSTACK::ALL_LAYERS ) )
119 {
121 hash_combine( ret, pad->GetChamferPositions( aLayer ) );
122 hash_combine( ret, pad->GetChamferRectRatio( aLayer ) );
123 break;
124
126 hash_combine( ret, pad->GetRoundRectCornerRadius( aLayer ) );
127 break;
128
130 hash_combine( ret, pad->GetDelta( aLayer ).x, pad->GetDelta( aLayer ).y );
131 break;
132
134 {
135 auto poly = pad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
136
137 for( int ii = 0; ii < poly->VertexCount(); ++ii )
138 {
139 VECTOR2I point = poly->CVertex( ii ) - pad->GetPosition();
140 hash_combine( ret, point.x, point.y );
141 }
142
143 break;
144 }
145 default:
146 break;
147 }
148 };
149
150 pad->Padstack().ForEachUniqueLayer( hashPadLayer );
151
152 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
153 {
154 hash_combine( ret, pad->GetDrillSizeX(), pad->GetDrillSizeY() );
155 hash_combine( ret, pad->GetDrillShape() );
156
157 pad->GetLayerSet().RunOnLayers(
158 [&]( PCB_LAYER_ID layer )
159 {
160 hash_combine( ret, pad->FlashLayer( layer ) );
161 } );
162 }
163
164 hash_combine( ret, hash_board_item( pad, aFlags ) );
165
166 if( aFlags & HASH_POS )
167 {
168 if( aFlags & REL_COORD )
169 hash_combine( ret, pad->GetFPRelativePosition().x, pad->GetFPRelativePosition().y );
170 else
171 hash_combine( ret, pad->GetPosition().x, pad->GetPosition().y );
172 }
173
174 if( aFlags & HASH_ROT )
175 hash_combine( ret, pad->GetOrientation().AsDegrees() );
176
177 if( aFlags & HASH_NET )
178 hash_combine( ret, pad->GetNetCode() );
179 }
180 break;
181
182 case PCB_FIELD_T:
183 if( !( aFlags & HASH_REF ) && static_cast<const PCB_FIELD*>( aItem )->IsReference() )
184 break;
185
186 if( !( aFlags & HASH_VALUE ) && static_cast<const PCB_FIELD*>( aItem )->IsValue() )
187 break;
188
190 case PCB_TEXT_T:
191 {
192 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
193
194 ret = hash_board_item( text, aFlags );
195 hash_combine( ret, text->GetText().ToStdString() );
196 hash_combine( ret, text->IsItalic() );
197 hash_combine( ret, text->IsBold() );
198 hash_combine( ret, text->IsMirrored() );
199 hash_combine( ret, text->GetTextWidth() );
200 hash_combine( ret, text->GetTextHeight() );
201 hash_combine( ret, text->GetHorizJustify() );
202 hash_combine( ret, text->GetVertJustify() );
203
204 if( aFlags & HASH_POS )
205 {
206 VECTOR2I pos = ( aFlags & REL_COORD ) ? text->GetFPRelativePosition()
207 : text->GetPosition();
208
209 hash_combine( ret, pos.x, pos.y );
210 }
211
212 if( aFlags & HASH_ROT )
213 hash_combine( ret, text->GetTextAngle().AsDegrees() );
214
215 break;
216 }
217
218 case PCB_BARCODE_T:
219 {
220 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( aItem );
221
222 ret = hash_board_item( barcode, aFlags );
223 hash_combine( ret, barcode->GetWidth(), barcode->GetHeight() );
224 hash_combine( ret, barcode->GetPosition().x, barcode->GetPosition().y );
225 hash_combine( ret, barcode->GetMargin().x, barcode->GetMargin().y );
226 hash_combine( ret, barcode->GetText() );
227 hash_combine( ret, barcode->GetTextSize() );
228 hash_combine( ret, barcode->GetKind() );
229 hash_combine( ret, barcode->GetAngle().AsDegrees() );
230 hash_combine( ret, barcode->GetErrorCorrection() );
231 break;
232 }
233
234 case PCB_SHAPE_T:
235 {
236 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
237 ret = hash_board_item( shape, aFlags );
238 hash_combine( ret, shape->GetShape() );
239 hash_combine( ret, shape->GetWidth() );
240 hash_combine( ret, shape->GetFillMode() );
241 hash_combine( ret, shape->GetLineStyle() );
242
243 if( shape->GetShape() == SHAPE_T::ARC || shape->GetShape() == SHAPE_T::CIRCLE )
244 hash_combine( ret, shape->GetRadius() );
245
246 if( shape->GetShape() == SHAPE_T::ELLIPSE || shape->GetShape() == SHAPE_T::ELLIPSE_ARC )
247 {
248 hash_combine( ret, shape->GetEllipseMajorRadius() );
249 hash_combine( ret, shape->GetEllipseMinorRadius() );
250 hash_combine( ret, shape->GetEllipseRotation().AsDegrees() );
251
252 if( shape->GetShape() == SHAPE_T::ELLIPSE_ARC )
253 {
255 hash_combine( ret, shape->GetEllipseEndAngle().AsDegrees() );
256 }
257 }
258
259 if( aFlags & HASH_POS )
260 {
261 std::vector<VECTOR2I> points;
262
263 points.push_back( shape->GetStart() );
264 points.push_back( shape->GetEnd() );
265
266 if( shape->GetShape() == SHAPE_T::CIRCLE )
267 points.push_back( shape->GetCenter() );
268
269 if( shape->GetShape() == SHAPE_T::ARC )
270 points.push_back( shape->GetArcMid() );
271
272 if( shape->GetShape() == SHAPE_T::ELLIPSE || shape->GetShape() == SHAPE_T::ELLIPSE_ARC )
273 {
274 points.push_back( shape->GetEllipseCenter() );
275 }
276
277 FOOTPRINT* parentFP = shape->GetParentFootprint();
278
279 if( shape->GetShape() == SHAPE_T::POLY )
280 {
281 const SHAPE_POLY_SET& poly = shape->GetPolyShape();
282
283 for( auto it = poly.CIterateWithHoles(); it; it++ )
284 points.push_back( *it );
285 }
286
287 if( shape->GetShape() == SHAPE_T::BEZIER )
288 {
289 points.push_back( shape->GetBezierC1() );
290 points.push_back( shape->GetBezierC2() );
291 }
292
293 if( parentFP && ( aFlags & REL_COORD ) )
294 {
295 for( VECTOR2I& point : points )
296 {
297 point -= parentFP->GetPosition();
298 RotatePoint( point, -parentFP->GetOrientation() );
299 }
300 }
301
302 if( aFlags & REL_POS )
303 {
304 for( VECTOR2I& point : points )
305 point -= shape->GetPosition();
306 }
307
308 //Basic sort of start/end points to try to always draw the same direction (left to right, down to up)
309 //The hashes are summed, so it doesn't matter what order the lines are drawn, only that the same points are used
310 if( points.size() > 1 )
311 {
312 if( points[0].x > points[1].x || points[0].y > points[1].y )
313 {
314 std::swap( points[0], points[1] );
315 }
316 }
317
318 for( VECTOR2I& point : points )
319 hash_combine( ret, point.x, point.y );
320 }
321 }
322 break;
323
324 case PCB_TABLECELL_T:
325 case PCB_TEXTBOX_T:
326 {
327 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aItem );
328
329 ret = hash_board_item( textbox, aFlags );
330 hash_combine( ret, textbox->GetText().ToStdString() );
331 hash_combine( ret, textbox->IsItalic() );
332 hash_combine( ret, textbox->IsBold() );
333 hash_combine( ret, textbox->IsMirrored() );
334 hash_combine( ret, textbox->GetTextWidth() );
335 hash_combine( ret, textbox->GetTextHeight() );
336 hash_combine( ret, textbox->GetHorizJustify() );
337 hash_combine( ret, textbox->GetVertJustify() );
338
339 if( aFlags & HASH_ROT )
340 hash_combine( ret, textbox->GetTextAngle().AsDegrees() );
341
342 hash_combine( ret, textbox->GetShape() );
343 hash_combine( ret, textbox->GetWidth() );
344 hash_combine( ret, textbox->GetLineStyle() );
345
346 if( aFlags & HASH_POS )
347 {
348 VECTOR2I start = textbox->GetStart();
349 VECTOR2I end = textbox->GetEnd();
350
351 FOOTPRINT* parentFP = textbox->GetParentFootprint();
352
353 if( parentFP && ( aFlags & REL_COORD ) )
354 {
355 start -= parentFP->GetPosition();
356 end -= parentFP->GetPosition();
357
358 RotatePoint( start, -parentFP->GetOrientation() );
359 RotatePoint( end, -parentFP->GetOrientation() );
360 }
361
362 hash_combine( ret, start.x );
363 hash_combine( ret, start.y );
364 hash_combine( ret, end.x );
365 hash_combine( ret, end.y );
366 }
367 }
368 break;
369
370 case PCB_TABLE_T:
371 {
372 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( aItem );
373
374 ret = hash_board_item( table, aFlags );
375
376 hash_combine( ret, table->StrokeExternal() );
377 hash_combine( ret, table->StrokeHeaderSeparator() );
378 hash_combine( ret, table->StrokeColumns() );
379 hash_combine( ret, table->StrokeRows() );
380
381 auto hash_stroke =
382 [&]( const STROKE_PARAMS& stroke )
383 {
384 hash_combine( ret, stroke.GetColor() );
385 hash_combine( ret, stroke.GetWidth() );
386 hash_combine( ret, stroke.GetLineStyle() );
387 };
388
389 hash_stroke( table->GetSeparatorsStroke() );
390 hash_stroke( table->GetBorderStroke() );
391 }
392 break;
393
394 default:
395 UNIMPLEMENTED_FOR( aItem->GetClass() );
396 }
397
398 return ret;
399}
@ ERROR_INSIDE
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:285
double AsDegrees() const
Definition eda_angle.h:116
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
int GetEllipseMinorRadius() const
Definition eda_shape.h:310
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:283
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:292
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:338
FILL_T GetFillMode() const
Definition eda_shape.h:158
int GetEllipseMajorRadius() const
Definition eda_shape.h:301
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:319
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
LINE_STYLE GetLineStyle() const
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:329
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:280
VECTOR2I GetArcMid() const
bool IsItalic() const
Definition eda_text.h:190
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual int GetTextHeight() const
Definition eda_text.h:288
virtual int GetTextWidth() const
Definition eda_text.h:285
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:221
bool IsMirrored() const
Definition eda_text.h:211
bool IsBold() const
Definition eda_text.h:205
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:224
EDA_ANGLE GetOrientation() const
Definition footprint.h:406
std::deque< PAD * > & Pads()
Definition footprint.h:375
VECTOR2I GetPosition() const override
Definition footprint.h:403
DRAWINGS & GraphicalItems()
Definition footprint.h:378
virtual wxString GetClass() const =0
Return the class name.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:61
const VECTOR2I & GetMargin() const
Get the barcode margin (in internal units).
VECTOR2I GetPosition() const override
Get the position (center) of the barcode in internal units.
wxString GetText() const
int GetTextSize() const
int GetHeight() const
Get the barcode height (in internal units).
BARCODE_ECC_T GetErrorCorrection() const
EDA_ANGLE GetAngle() const
BARCODE_T GetKind() const
Returns the type of the barcode (QR, CODE_39, etc.).
int GetWidth() const
Get the barcode width (in internal units).
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
int GetWidth() const override
VECTOR2I GetPosition() const override
Definition pcb_shape.h:76
EDA_ANGLE GetTextAngle() const override
Represent a set of closed polygons.
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Simple container to manage line stroke parameters.
@ ELLIPSE
Definition eda_shape.h:52
@ ELLIPSE_ARC
Definition eda_shape.h:53
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:28
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Definition hash_eda.cpp:54
static size_t hash_board_item(const BOARD_ITEM *aItem, int aFlags)
Definition hash_eda.cpp:43
Hashing functions for EDA_ITEMs.
@ HASH_POS
Definition hash_eda.h:43
@ HASH_VALUE
Definition hash_eda.h:54
@ REL_COORD
Use coordinates relative to the parent object.
Definition hash_eda.h:46
@ HASH_LAYER
Definition hash_eda.h:51
@ HASH_REF
Definition hash_eda.h:53
@ REL_POS
Use coordinates relative to the shape position.
Definition hash_eda.h:49
@ HASH_ROT
Definition hash_eda.h:50
@ HASH_NET
Definition hash_eda.h:52
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
STL namespace.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
@ TRAPEZOID
Definition padstack.h:56
BARCODE class definition.
std::vector< std::vector< std::string > > table
VECTOR2I end
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:83
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:94
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683