KiCad PCB EDA Suite
footprint.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 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6  * Copyright (C) 2015 Wayne Stambaugh <[email protected]>
7  * Copyright (C) 1992-2021 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 
27 #include <core/mirror.h>
28 #include <confirm.h>
29 #include <refdes_utils.h>
30 #include <bitmaps.h>
31 #include <unordered_set>
32 #include <string_utils.h>
33 #include <pcb_edit_frame.h>
34 #include <board.h>
35 #include <board_design_settings.h>
36 #include <fp_shape.h>
37 #include <macros.h>
38 #include <pad.h>
39 #include <pcb_text.h>
40 #include <pcb_marker.h>
41 #include <pcb_group.h>
42 #include <pcb_track.h>
43 #include <footprint.h>
44 #include <zone.h>
45 #include <view/view.h>
46 #include <geometry/shape_null.h>
47 #include <i18n_utility.h>
49 #include <geometry/convex_hull.h>
50 
53  m_boundingBoxCacheTimeStamp( 0 ),
54  m_visibleBBoxCacheTimeStamp( 0 ),
55  m_textExcludedBBoxCacheTimeStamp( 0 ),
56  m_hullCacheTimeStamp( 0 ),
57  m_initial_comments( nullptr )
58 {
59  m_attributes = 0;
60  m_layer = F_Cu;
61  m_orient = 0;
63  m_arflag = 0;
65  m_link = 0;
66  m_lastEditTime = 0;
67  m_localClearance = 0;
71  m_zoneConnection = ZONE_CONNECTION::INHERITED; // Use zone setting by default
72  m_thermalWidth = 0; // Use zone setting by default
73  m_thermalGap = 0; // Use zone setting by default
74 
75  // These are special and mandatory text fields
77  m_value = new FP_TEXT( this, FP_TEXT::TEXT_is_VALUE );
78 
79  m_3D_Drawings.clear();
80 }
81 
82 
83 FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
84  BOARD_ITEM_CONTAINER( aFootprint )
85 {
86  m_pos = aFootprint.m_pos;
87  m_fpid = aFootprint.m_fpid;
88  m_attributes = aFootprint.m_attributes;
89  m_fpStatus = aFootprint.m_fpStatus;
90  m_orient = aFootprint.m_orient;
91  m_rot90Cost = aFootprint.m_rot90Cost;
92  m_rot180Cost = aFootprint.m_rot180Cost;
93  m_lastEditTime = aFootprint.m_lastEditTime;
94  m_link = aFootprint.m_link;
95  m_path = aFootprint.m_path;
96 
103  m_cachedHull = aFootprint.m_cachedHull;
105 
106  m_localClearance = aFootprint.m_localClearance;
110  m_zoneConnection = aFootprint.m_zoneConnection;
111  m_thermalWidth = aFootprint.m_thermalWidth;
112  m_thermalGap = aFootprint.m_thermalGap;
113 
114  std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
115 
116  // Copy reference and value.
117  m_reference = new FP_TEXT( *aFootprint.m_reference );
118  m_reference->SetParent( this );
119  ptrMap[ aFootprint.m_reference ] = m_reference;
120 
121  m_value = new FP_TEXT( *aFootprint.m_value );
122  m_value->SetParent( this );
123  ptrMap[ aFootprint.m_value ] = m_value;
124 
125  // Copy pads
126  for( PAD* pad : aFootprint.Pads() )
127  {
128  PAD* newPad = static_cast<PAD*>( pad->Clone() );
129  ptrMap[ pad ] = newPad;
130  Add( newPad, ADD_MODE::APPEND ); // Append to ensure indexes are identical
131  }
132 
133  // Copy zones
134  for( FP_ZONE* zone : aFootprint.Zones() )
135  {
136  FP_ZONE* newZone = static_cast<FP_ZONE*>( zone->Clone() );
137  ptrMap[ zone ] = newZone;
138  Add( newZone, ADD_MODE::APPEND ); // Append to ensure indexes are identical
139 
140  // Ensure the net info is OK and especially uses the net info list
141  // living in the current board
142  // Needed when copying a fp from fp editor that has its own board
143  // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
144  newZone->SetNetCode( -1 );
145  }
146 
147  // Copy drawings
148  for( BOARD_ITEM* item : aFootprint.GraphicalItems() )
149  {
150  BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
151  ptrMap[ item ] = newItem;
152  Add( newItem, ADD_MODE::APPEND ); // Append to ensure indexes are identical
153  }
154 
155  // Copy groups
156  for( PCB_GROUP* group : aFootprint.Groups() )
157  {
158  PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
159  ptrMap[ group ] = newGroup;
160  Add( newGroup, ADD_MODE::APPEND ); // Append to ensure indexes are identical
161  }
162 
163  // Rebuild groups
164  for( PCB_GROUP* group : aFootprint.Groups() )
165  {
166  PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( ptrMap[ group ] );
167 
168  newGroup->GetItems().clear();
169 
170  for( BOARD_ITEM* member : group->GetItems() )
171  {
172  if( ptrMap.count( member ) )
173  newGroup->AddItem( ptrMap[ member ] );
174  }
175  }
176 
177  // Copy auxiliary data: 3D_Drawings info
178  m_3D_Drawings = aFootprint.m_3D_Drawings;
179 
180  m_doc = aFootprint.m_doc;
181  m_keywords = aFootprint.m_keywords;
182  m_properties = aFootprint.m_properties;
183 
184  m_arflag = 0;
185 
187  new wxArrayString( *aFootprint.m_initial_comments ) : nullptr;
188 }
189 
190 
192  BOARD_ITEM_CONTAINER( aFootprint )
193 {
194  *this = std::move( aFootprint );
195 }
196 
197 
199 {
200  // Clean up the owned elements
201  delete m_reference;
202  delete m_value;
203  delete m_initial_comments;
204 
205  for( PAD* p : m_pads )
206  delete p;
207 
208  m_pads.clear();
209 
210  for( FP_ZONE* zone : m_fp_zones )
211  delete zone;
212 
213  m_fp_zones.clear();
214 
215  for( PCB_GROUP* group : m_fp_groups )
216  delete group;
217 
218  m_fp_groups.clear();
219 
220  for( BOARD_ITEM* d : m_drawings )
221  delete d;
222 
223  m_drawings.clear();
224 }
225 
226 
228 {
229  // replace null UUIDs if any by a valid uuid
230  std::vector< BOARD_ITEM* > item_list;
231 
232  item_list.push_back( m_reference );
233  item_list.push_back( m_value );
234 
235  for( PAD* pad : m_pads )
236  item_list.push_back( pad );
237 
238  for( BOARD_ITEM* gr_item : m_drawings )
239  item_list.push_back( gr_item );
240 
241  // Note: one cannot fix null UUIDs inside the group, but it should not happen
242  // because null uuids can be found in old footprints, therefore without group
243  for( PCB_GROUP* group : m_fp_groups )
244  item_list.push_back( group );
245 
246  // Probably notneeded, because old fp do not have zones. But just in case.
247  for( FP_ZONE* zone : m_fp_zones )
248  item_list.push_back( zone );
249 
250  bool changed = false;
251 
252  for( BOARD_ITEM* item : item_list )
253  {
254  if( item->m_Uuid == niluuid )
255  {
256  const_cast<KIID&>( item->m_Uuid ) = KIID();
257  changed = true;
258  }
259  }
260 
261  return changed;
262 }
263 
264 
266 {
267  BOARD_ITEM::operator=( aOther );
268 
269  m_pos = aOther.m_pos;
270  m_fpid = aOther.m_fpid;
271  m_attributes = aOther.m_attributes;
272  m_fpStatus = aOther.m_fpStatus;
273  m_orient = aOther.m_orient;
274  m_rot90Cost = aOther.m_rot90Cost;
275  m_rot180Cost = aOther.m_rot180Cost;
276  m_lastEditTime = aOther.m_lastEditTime;
277  m_link = aOther.m_link;
278  m_path = aOther.m_path;
279 
280  m_cachedBoundingBox = aOther.m_cachedBoundingBox;
281  m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp;
282  m_cachedVisibleBBox = aOther.m_cachedVisibleBBox;
283  m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp;
284  m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox;
285  m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp;
286  m_cachedHull = aOther.m_cachedHull;
287  m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp;
288 
289  m_localClearance = aOther.m_localClearance;
290  m_localSolderMaskMargin = aOther.m_localSolderMaskMargin;
291  m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
292  m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
293  m_zoneConnection = aOther.m_zoneConnection;
294  m_thermalWidth = aOther.m_thermalWidth;
295  m_thermalGap = aOther.m_thermalGap;
296 
297  // Move reference and value
298  m_reference = aOther.m_reference;
299  m_reference->SetParent( this );
300  m_value = aOther.m_value;
301  m_value->SetParent( this );
302 
303 
304  // Move the pads
305  m_pads.clear();
306 
307  for( PAD* pad : aOther.Pads() )
308  Add( pad );
309 
310  aOther.Pads().clear();
311 
312  // Move the zones
313  m_fp_zones.clear();
314 
315  for( FP_ZONE* item : aOther.Zones() )
316  {
317  Add( item );
318 
319  // Ensure the net info is OK and especially uses the net info list
320  // living in the current board
321  // Needed when copying a fp from fp editor that has its own board
322  // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
323  item->SetNetCode( -1 );
324  }
325 
326  aOther.Zones().clear();
327 
328  // Move the drawings
329  m_drawings.clear();
330 
331  for( BOARD_ITEM* item : aOther.GraphicalItems() )
332  Add( item );
333 
334  aOther.GraphicalItems().clear();
335 
336  // Move the groups
337  m_fp_groups.clear();
338 
339  for( PCB_GROUP* group : aOther.Groups() )
340  Add( group );
341 
342  aOther.Groups().clear();
343 
344  // Copy auxiliary data: 3D_Drawings info
345  m_3D_Drawings.clear();
346  m_3D_Drawings = aOther.m_3D_Drawings;
347  m_doc = aOther.m_doc;
348  m_keywords = aOther.m_keywords;
349  m_properties = aOther.m_properties;
350 
351  m_initial_comments = aOther.m_initial_comments;
352 
353  // Clear the other item's containers since this is a move
354  aOther.Pads().clear();
355  aOther.Zones().clear();
356  aOther.GraphicalItems().clear();
357  aOther.m_value = nullptr;
358  aOther.m_reference = nullptr;
359  aOther.m_initial_comments = nullptr;
360 
361  return *this;
362 }
363 
364 
366 {
367  BOARD_ITEM::operator=( aOther );
368 
369  m_pos = aOther.m_pos;
370  m_fpid = aOther.m_fpid;
371  m_attributes = aOther.m_attributes;
372  m_fpStatus = aOther.m_fpStatus;
373  m_orient = aOther.m_orient;
374  m_rot90Cost = aOther.m_rot90Cost;
375  m_rot180Cost = aOther.m_rot180Cost;
377  m_link = aOther.m_link;
378  m_path = aOther.m_path;
379 
386  m_cachedHull = aOther.m_cachedHull;
388 
395  m_thermalGap = aOther.m_thermalGap;
396 
397  // Copy reference and value
398  *m_reference = *aOther.m_reference;
399  m_reference->SetParent( this );
400  *m_value = *aOther.m_value;
401  m_value->SetParent( this );
402 
403  std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
404 
405  // Copy pads
406  m_pads.clear();
407 
408  for( PAD* pad : aOther.Pads() )
409  {
410  PAD* newPad = new PAD( *pad );
411  ptrMap[ pad ] = newPad;
412  Add( newPad );
413  }
414 
415  // Copy zones
416  m_fp_zones.clear();
417 
418  for( FP_ZONE* zone : aOther.Zones() )
419  {
420  FP_ZONE* newZone = static_cast<FP_ZONE*>( zone->Clone() );
421  ptrMap[ zone ] = newZone;
422  Add( newZone );
423 
424  // Ensure the net info is OK and especially uses the net info list
425  // living in the current board
426  // Needed when copying a fp from fp editor that has its own board
427  // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
428  newZone->SetNetCode( -1 );
429  }
430 
431  // Copy drawings
432  m_drawings.clear();
433 
434  for( BOARD_ITEM* item : aOther.GraphicalItems() )
435  {
436  BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
437  ptrMap[ item ] = newItem;
438  Add( newItem );
439  }
440 
441  // Copy groups
442  m_fp_groups.clear();
443 
444  for( PCB_GROUP* group : aOther.Groups() )
445  {
446  PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
447  newGroup->GetItems().clear();
448 
449  for( BOARD_ITEM* member : group->GetItems() )
450  newGroup->AddItem( ptrMap[ member ] );
451 
452  Add( newGroup );
453  }
454 
455  // Copy auxiliary data: 3D_Drawings info
456  m_3D_Drawings.clear();
457  m_3D_Drawings = aOther.m_3D_Drawings;
458  m_doc = aOther.m_doc;
459  m_keywords = aOther.m_keywords;
460  m_properties = aOther.m_properties;
461 
463  new wxArrayString( *aOther.m_initial_comments ) : nullptr;
464 
465  return *this;
466 }
467 
468 
469 void FOOTPRINT::GetContextualTextVars( wxArrayString* aVars ) const
470 {
471  aVars->push_back( wxT( "REFERENCE" ) );
472  aVars->push_back( wxT( "VALUE" ) );
473  aVars->push_back( wxT( "LAYER" ) );
474 }
475 
476 
477 bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
478 {
479  if( token->IsSameAs( wxT( "REFERENCE" ) ) )
480  {
481  *token = m_reference->GetShownText( aDepth + 1 );
482  return true;
483  }
484  else if( token->IsSameAs( wxT( "VALUE" ) ) )
485  {
486  *token = m_value->GetShownText( aDepth + 1 );
487  return true;
488  }
489  else if( token->IsSameAs( wxT( "LAYER" ) ) )
490  {
491  *token = GetLayerName();
492  return true;
493  }
494  else if( m_properties.count( *token ) )
495  {
496  *token = m_properties.at( *token );
497  return true;
498  }
499 
500  return false;
501 }
502 
503 
505 {
506  // Force the ORPHANED dummy net info for all pads.
507  // ORPHANED dummy net does not depend on a board
508  for( PAD* pad : m_pads )
509  pad->SetNetCode( NETINFO_LIST::ORPHANED );
510 }
511 
512 
513 void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
514 {
515  switch( aBoardItem->Type() )
516  {
517  case PCB_FP_TEXT_T:
518  // Only user text can be added this way.
519  wxASSERT( static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS );
521 
522  case PCB_FP_SHAPE_T:
523  if( aMode == ADD_MODE::APPEND )
524  m_drawings.push_back( aBoardItem );
525  else
526  m_drawings.push_front( aBoardItem );
527  break;
528 
529  case PCB_PAD_T:
530  if( aMode == ADD_MODE::APPEND )
531  m_pads.push_back( static_cast<PAD*>( aBoardItem ) );
532  else
533  m_pads.push_front( static_cast<PAD*>( aBoardItem ) );
534  break;
535 
536  case PCB_FP_ZONE_T:
537  if( aMode == ADD_MODE::APPEND )
538  m_fp_zones.push_back( static_cast<FP_ZONE*>( aBoardItem ) );
539  else
540  m_fp_zones.insert( m_fp_zones.begin(), static_cast<FP_ZONE*>( aBoardItem ) );
541  break;
542 
543  case PCB_GROUP_T:
544  if( aMode == ADD_MODE::APPEND )
545  m_fp_groups.push_back( static_cast<PCB_GROUP*>( aBoardItem ) );
546  else
547  m_fp_groups.insert( m_fp_groups.begin(), static_cast<PCB_GROUP*>( aBoardItem ) );
548  break;
549 
550  default:
551  {
552  wxString msg;
553  msg.Printf( wxT( "FOOTPRINT::Add() needs work: BOARD_ITEM type (%d) not handled" ),
554  aBoardItem->Type() );
555  wxFAIL_MSG( msg );
556 
557  return;
558  }
559  }
560 
561  aBoardItem->ClearEditFlags();
562  aBoardItem->SetParent( this );
563 }
564 
565 
566 void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
567 {
568  switch( aBoardItem->Type() )
569  {
570  case PCB_FP_TEXT_T:
571  // Only user text can be removed this way.
572  wxCHECK_RET(
573  static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS,
574  "Please report this bug: Invalid remove operation on required text" );
576 
577  case PCB_FP_SHAPE_T:
578  for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
579  {
580  if( *it == aBoardItem )
581  {
582  m_drawings.erase( it );
583  break;
584  }
585  }
586 
587  break;
588 
589  case PCB_PAD_T:
590  for( auto it = m_pads.begin(); it != m_pads.end(); ++it )
591  {
592  if( *it == static_cast<PAD*>( aBoardItem ) )
593  {
594  m_pads.erase( it );
595  break;
596  }
597  }
598 
599  break;
600 
601  case PCB_FP_ZONE_T:
602  for( auto it = m_fp_zones.begin(); it != m_fp_zones.end(); ++it )
603  {
604  if( *it == static_cast<FP_ZONE*>( aBoardItem ) )
605  {
606  m_fp_zones.erase( it );
607  break;
608  }
609  }
610 
611  break;
612 
613  case PCB_GROUP_T:
614  for( auto it = m_fp_groups.begin(); it != m_fp_groups.end(); ++it )
615  {
616  if( *it == static_cast<PCB_GROUP*>( aBoardItem ) )
617  {
618  m_fp_groups.erase( it );
619  break;
620  }
621  }
622 
623  break;
624 
625  default:
626  {
627  wxString msg;
628  msg.Printf( wxT( "FOOTPRINT::Remove() needs work: BOARD_ITEM type (%d) not handled" ),
629  aBoardItem->Type() );
630  wxFAIL_MSG( msg );
631  }
632  }
633 
634  aBoardItem->SetFlags( STRUCT_DELETED );
635 
636  PCB_GROUP* parentGroup = aBoardItem->GetParentGroup();
637 
638  if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
639  parentGroup->RemoveItem( aBoardItem );
640 }
641 
642 
643 double FOOTPRINT::GetArea( int aPadding ) const
644 {
645  EDA_RECT bbox = GetBoundingBox( false, false );
646 
647  double w = std::abs( static_cast<double>( bbox.GetWidth() ) ) + aPadding;
648  double h = std::abs( static_cast<double>( bbox.GetHeight() ) ) + aPadding;
649  return w * h;
650 }
651 
652 
654 {
655  int smd_count = 0;
656  int tht_count = 0;
657 
658  for( PAD* pad : m_pads )
659  {
660  switch( pad->GetProperty() )
661  {
664  continue;
665 
666  case PAD_PROP::HEATSINK:
668  continue;
669 
670  case PAD_PROP::NONE:
671  case PAD_PROP::BGA:
672  case PAD_PROP::TESTPOINT:
673  break;
674  }
675 
676  switch( pad->GetAttribute() )
677  {
678  case PAD_ATTRIB::PTH:
679  tht_count++;
680  break;
681 
682  case PAD_ATTRIB::SMD:
683  smd_count++;
684  break;
685 
686  default:
687  break;
688  }
689  }
690 
691  if( tht_count > 0 )
692  return FP_THROUGH_HOLE;
693 
694  if( smd_count > 0 )
695  return FP_SMD;
696 
697  return 0;
698 }
699 
700 
701 wxString FOOTPRINT::GetTypeName() const
702 {
703  if( ( m_attributes & FP_SMD ) == FP_SMD )
704  return _( "SMD" );
705 
707  return _( "Through hole" );
708 
709  return _( "Other" );
710 }
711 
712 
714 {
715  EDA_RECT area;
716 
717  // We want the bounding box of the footprint pads at rot 0, not flipped
718  // Create such a image:
719  FOOTPRINT dummy( *this );
720 
721  dummy.SetPosition( wxPoint( 0, 0 ) );
722 
723  if( dummy.IsFlipped() )
724  dummy.Flip( wxPoint( 0, 0 ) , false );
725 
726  if( dummy.GetOrientation() )
727  dummy.SetOrientation( 0 );
728 
729  for( PAD* pad : dummy.Pads() )
730  area.Merge( pad->GetBoundingBox() );
731 
732  return area;
733 }
734 
735 
737 {
738  return GetBoundingBox( true, true );
739 }
740 
741 
742 const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const
743 {
744  const BOARD* board = GetBoard();
745 
746  if( board )
747  {
748  if( aIncludeText && aIncludeInvisibleText )
749  {
750  if( m_boundingBoxCacheTimeStamp >= board->GetTimeStamp() )
751  return m_cachedBoundingBox;
752  }
753  else if( aIncludeText )
754  {
755  if( m_visibleBBoxCacheTimeStamp >= board->GetTimeStamp() )
756  return m_cachedVisibleBBox;
757  }
758  else
759  {
762  }
763  }
764 
765  EDA_RECT area;
766 
767  area.SetOrigin( m_pos );
768  area.SetEnd( m_pos );
769  area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area
770 
771  for( BOARD_ITEM* item : m_drawings )
772  {
773  if( item->Type() == PCB_FP_SHAPE_T )
774  area.Merge( item->GetBoundingBox() );
775  }
776 
777  for( PAD* pad : m_pads )
778  area.Merge( pad->GetBoundingBox() );
779 
780  for( FP_ZONE* zone : m_fp_zones )
781  area.Merge( zone->GetBoundingBox() );
782 
783  bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_fp_zones.empty() );
784 
785  // Groups do not contribute to the rect, only their members
786  if( aIncludeText || noDrawItems )
787  {
788  for( BOARD_ITEM* item : m_drawings )
789  {
790  if( item->Type() == PCB_FP_TEXT_T )
791  area.Merge( item->GetBoundingBox() );
792  }
793 
794  // This can be further optimized when aIncludeInvisibleText is true, but currently
795  // leaving this as is until it's determined there is a noticeable speed hit.
796  bool valueLayerIsVisible = true;
797  bool refLayerIsVisible = true;
798 
799  if( board )
800  {
801  // The first "&&" conditional handles the user turning layers off as well as layers
802  // not being present in the current PCB stackup. Values, references, and all
803  // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
804  // 3rd "&&" conditionals handle that.
805  valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() )
807  && board->IsElementVisible( LAYER_MOD_TEXT );
808 
809  refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() )
811  && board->IsElementVisible( LAYER_MOD_TEXT );
812  }
813 
814 
815  if( ( m_value->IsVisible() && valueLayerIsVisible )
816  || aIncludeInvisibleText || noDrawItems )
817  area.Merge( m_value->GetBoundingBox() );
818 
819  if( ( m_reference->IsVisible() && refLayerIsVisible )
820  || aIncludeInvisibleText || noDrawItems )
821  area.Merge( m_reference->GetBoundingBox() );
822  }
823 
824  if( board )
825  {
826  if( ( aIncludeText && aIncludeInvisibleText ) || noDrawItems )
827  {
829  m_cachedBoundingBox = area;
830  }
831  else if( aIncludeText )
832  {
834  m_cachedVisibleBBox = area;
835  }
836  else
837  {
840  }
841  }
842 
843  return area;
844 }
845 
846 
848 {
849  const BOARD* board = GetBoard();
850 
851  if( board )
852  {
853  if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
854  return m_cachedHull;
855  }
856 
857  SHAPE_POLY_SET rawPolys;
858  SHAPE_POLY_SET hull;
859 
860  for( BOARD_ITEM* item : m_drawings )
861  {
862  if( item->Type() == PCB_FP_SHAPE_T )
863  {
864  item->TransformShapeWithClearanceToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
865  ERROR_OUTSIDE );
866  }
867 
868  // We intentionally exclude footprint text from the bounding hull.
869  }
870 
871  for( PAD* pad : m_pads )
872  {
873  pad->TransformShapeWithClearanceToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
874  ERROR_OUTSIDE );
875  // In case hole is larger than pad
876  pad->TransformHoleWithClearanceToPolygon( rawPolys, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
877  }
878 
879  for( FP_ZONE* zone : m_fp_zones )
880  {
881  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
882  {
883  SHAPE_POLY_SET layerPoly = zone->GetFilledPolysList( layer );
884 
885  for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
886  {
887  const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
888  rawPolys.AddOutline( poly );
889  }
890  }
891  }
892 
893  // If there are some graphic items, build the actual hull.
894  // However if no items, create a minimal polygon (can happen if a footprint
895  // is created with no item: it contains only 2 texts.
896  if( rawPolys.OutlineCount() == 0 )
897  {
898  // generate a small dummy rectangular outline around the anchor
899  const int halfsize = Millimeter2iu( 1.0 );
900 
901  rawPolys.NewOutline();
902 
903  // add a square:
904  rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
905  rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
906  rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
907  rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
908  }
909 
910  std::vector<wxPoint> convex_hull;
911  BuildConvexHull( convex_hull, rawPolys );
912 
915 
916  for( const wxPoint& pt : convex_hull )
917  m_cachedHull.Append( pt );
918 
919  if( board )
921 
922  return m_cachedHull;
923 }
924 
925 
926 void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
927 {
928  wxString msg, msg2;
929 
930  aList.emplace_back( m_reference->GetShownText(), m_value->GetShownText() );
931 
932  if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
934  || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
935  {
936  wxDateTime date( static_cast<time_t>( m_lastEditTime ) );
937 
938  // Date format: see http://www.cplusplus.com/reference/ctime/strftime
939  if( m_lastEditTime && date.IsValid() )
940  msg = date.Format( wxT( "%b %d, %Y" ) ); // Abbreviated_month_name Day, Year
941  else
942  msg = _( "Unknown" );
943 
944  aList.emplace_back( _( "Last Change" ), msg );
945  }
946  else if( aFrame->IsType( FRAME_PCB_EDITOR ) )
947  {
948  aList.emplace_back( _( "Board Side" ), IsFlipped() ? _( "Back (Flipped)" ) : _( "Front" ) );
949  }
950 
951  auto addToken = []( wxString* aStr, const wxString& aAttr )
952  {
953  if( !aStr->IsEmpty() )
954  *aStr += wxT( ", " );
955 
956  *aStr += aAttr;
957  };
958 
959  wxString status;
960  wxString attrs;
961 
962  if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
963  addToken( &status, _( "Locked" ) );
964 
965  if( m_fpStatus & FP_is_PLACED )
966  addToken( &status, _( "autoplaced" ) );
967 
969  addToken( &attrs, _( "not in schematic" ) );
970 
972  addToken( &attrs, _( "exclude from pos files" ) );
973 
975  addToken( &attrs, _( "exclude from BOM" ) );
976 
977  aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
978 
979  aList.emplace_back( _( "Rotation" ), wxString::Format( "%.4g", GetOrientationDegrees() ) );
980 
981  msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
982  msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
983  : m_3D_Drawings.front().m_Filename );
984  aList.emplace_back( msg, msg2 );
985 
986  msg.Printf( _( "Doc: %s" ), m_doc );
987  msg2.Printf( _( "Keywords: %s" ), m_keywords );
988  aList.emplace_back( msg, msg2 );
989 }
990 
991 
992 bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer ) const
993 {
994  // If we have any pads, fall back on normal checking
995  if( !m_pads.empty() )
996  return m_layer == aLayer;
997 
998  // No pads? Check if this entire footprint exists on the given layer
999  for( FP_ZONE* zone : m_fp_zones )
1000  {
1001  if( !zone->IsOnLayer( aLayer ) )
1002  return false;
1003  }
1004 
1005  for( BOARD_ITEM* item : m_drawings )
1006  {
1007  if( !item->IsOnLayer( aLayer ) )
1008  return false;
1009  }
1010 
1011  return true;
1012 }
1013 
1014 
1015 bool FOOTPRINT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1016 {
1017  EDA_RECT rect = GetBoundingBox( false, false );
1018  return rect.Inflate( aAccuracy ).Contains( aPosition );
1019 }
1020 
1021 
1022 bool FOOTPRINT::HitTestAccurate( const wxPoint& aPosition, int aAccuracy ) const
1023 {
1024  return GetBoundingHull().Collide( aPosition, aAccuracy );
1025 }
1026 
1027 
1028 bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1029 {
1030  EDA_RECT arect = aRect;
1031  arect.Inflate( aAccuracy );
1032 
1033  if( aContained )
1034  {
1035  return arect.Contains( GetBoundingBox( false, false ) );
1036  }
1037  else
1038  {
1039  // If the rect does not intersect the bounding box, skip any tests
1040  if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
1041  return false;
1042 
1043  // The empty footprint dummy rectangle intersects the selection area.
1044  if( m_pads.empty() && m_fp_zones.empty() && m_drawings.empty() )
1045  return GetBoundingBox( true, false ).Intersects( arect );
1046 
1047  // Determine if any elements in the FOOTPRINT intersect the rect
1048  for( PAD* pad : m_pads )
1049  {
1050  if( pad->HitTest( arect, false, 0 ) )
1051  return true;
1052  }
1053 
1054  for( FP_ZONE* zone : m_fp_zones )
1055  {
1056  if( zone->HitTest( arect, false, 0 ) )
1057  return true;
1058  }
1059 
1060  for( BOARD_ITEM* item : m_drawings )
1061  {
1062  if( item->Type() != PCB_FP_TEXT_T && item->HitTest( arect, false, 0 ) )
1063  return true;
1064  }
1065 
1066  // Groups are not hit-tested; only their members
1067 
1068  // No items were hit
1069  return false;
1070  }
1071 }
1072 
1073 
1074 PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
1075 {
1076  bool can_select = aSearchAfterMe ? false : true;
1077 
1078  for( PAD* pad : m_pads )
1079  {
1080  if( !can_select && pad == aSearchAfterMe )
1081  {
1082  can_select = true;
1083  continue;
1084  }
1085 
1086  if( can_select && pad->GetNumber() == aPadNumber )
1087  return pad;
1088  }
1089 
1090  return nullptr;
1091 }
1092 
1093 
1094 PAD* FOOTPRINT::GetPad( const wxPoint& aPosition, LSET aLayerMask )
1095 {
1096  for( PAD* pad : m_pads )
1097  {
1098  // ... and on the correct layer.
1099  if( !( pad->GetLayerSet() & aLayerMask ).any() )
1100  continue;
1101 
1102  if( pad->HitTest( aPosition ) )
1103  return pad;
1104  }
1105 
1106  return nullptr;
1107 }
1108 
1109 
1111 {
1112  PAD* topLeftPad = m_pads.front();
1113 
1114  for( PAD* p : m_pads )
1115  {
1116  wxPoint pnt = p->GetPosition(); // GetPosition() returns the center of the pad
1117 
1118  if( ( pnt.x < topLeftPad->GetPosition().x ) ||
1119  ( topLeftPad->GetPosition().x == pnt.x && pnt.y < topLeftPad->GetPosition().y ) )
1120  {
1121  topLeftPad = p;
1122  }
1123  }
1124 
1125  return topLeftPad;
1126 }
1127 
1128 
1129 unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1130 {
1131  if( aIncludeNPTH )
1132  return m_pads.size();
1133 
1134  unsigned cnt = 0;
1135 
1136  for( PAD* pad : m_pads )
1137  {
1138  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1139  continue;
1140 
1141  cnt++;
1142  }
1143 
1144  return cnt;
1145 }
1146 
1147 
1148 unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1149 {
1150  std::set<wxString> usedNumbers;
1151 
1152  // Create a set of used pad numbers
1153  for( PAD* pad : m_pads )
1154  {
1155  // Skip pads not on copper layers (used to build complex
1156  // solder paste shapes for instance)
1157  if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1158  continue;
1159 
1160  // Skip pads with no name, because they are usually "mechanical"
1161  // pads, not "electrical" pads
1162  if( pad->GetNumber().IsEmpty() )
1163  continue;
1164 
1165  if( !aIncludeNPTH )
1166  {
1167  // skip NPTH
1168  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1169  continue;
1170  }
1171 
1172  usedNumbers.insert( pad->GetNumber() );
1173  }
1174 
1175  return usedNumbers.size();
1176 }
1177 
1178 
1180 {
1181  if( nullptr == a3DModel )
1182  return;
1183 
1184  if( !a3DModel->m_Filename.empty() )
1185  m_3D_Drawings.push_back( *a3DModel );
1186 }
1187 
1188 
1189 // see footprint.h
1190 SEARCH_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
1191 {
1192  KICAD_T stype;
1194  const KICAD_T* p = scanTypes;
1195  bool done = false;
1196 
1197 #if 0 && defined(DEBUG)
1198  std::cout << GetClass().mb_str() << ' ';
1199 #endif
1200 
1201  while( !done )
1202  {
1203  stype = *p;
1204 
1205  switch( stype )
1206  {
1207  case PCB_FOOTPRINT_T:
1208  result = inspector( this, testData ); // inspect me
1209  ++p;
1210  break;
1211 
1212  case PCB_PAD_T:
1213  result = IterateForward<PAD*>( m_pads, inspector, testData, p );
1214  ++p;
1215  break;
1216 
1217  case PCB_FP_ZONE_T:
1218  result = IterateForward<FP_ZONE*>( m_fp_zones, inspector, testData, p );
1219  ++p;
1220  break;
1221 
1222  case PCB_FP_TEXT_T:
1223  result = inspector( m_reference, testData );
1224 
1225  if( result == SEARCH_RESULT::QUIT )
1226  break;
1227 
1228  result = inspector( m_value, testData );
1229 
1230  if( result == SEARCH_RESULT::QUIT )
1231  break;
1232 
1233  // Intentionally fall through since m_Drawings can hold PCB_FP_SHAPE_T also
1235 
1236  case PCB_FP_SHAPE_T:
1237  result = IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, p );
1238 
1239  // skip over any types handled in the above call.
1240  for( ; ; )
1241  {
1242  switch( stype = *++p )
1243  {
1244  case PCB_FP_TEXT_T:
1245  case PCB_FP_SHAPE_T:
1246  continue;
1247 
1248  default:
1249  ;
1250  }
1251 
1252  break;
1253  }
1254 
1255  break;
1256 
1257  case PCB_GROUP_T:
1258  result = IterateForward<PCB_GROUP*>( m_fp_groups, inspector, testData, p );
1259  ++p;
1260  break;
1261 
1262  default:
1263  done = true;
1264  break;
1265  }
1266 
1267  if( result == SEARCH_RESULT::QUIT )
1268  break;
1269  }
1270 
1271  return result;
1272 }
1273 
1274 
1275 wxString FOOTPRINT::GetSelectMenuText( EDA_UNITS aUnits ) const
1276 {
1277  wxString reference = GetReference();
1278 
1279  if( reference.IsEmpty() )
1280  reference = _( "<no reference designator>" );
1281 
1282  return wxString::Format( _( "Footprint %s" ), reference );
1283 }
1284 
1285 
1287 {
1288  return BITMAPS::module;
1289 }
1290 
1291 
1293 {
1294  return new FOOTPRINT( *this );
1295 }
1296 
1297 
1298 void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFunction ) const
1299 {
1300  try
1301  {
1302  for( PAD* pad : m_pads )
1303  aFunction( static_cast<BOARD_ITEM*>( pad ) );
1304 
1305  for( FP_ZONE* zone : m_fp_zones )
1306  aFunction( static_cast<FP_ZONE*>( zone ) );
1307 
1308  for( PCB_GROUP* group : m_fp_groups )
1309  aFunction( static_cast<PCB_GROUP*>( group ) );
1310 
1311  for( BOARD_ITEM* drawing : m_drawings )
1312  aFunction( static_cast<BOARD_ITEM*>( drawing ) );
1313 
1314  aFunction( static_cast<BOARD_ITEM*>( m_reference ) );
1315  aFunction( static_cast<BOARD_ITEM*>( m_value ) );
1316  }
1317  catch( std::bad_function_call& )
1318  {
1319  wxFAIL_MSG( "Error running FOOTPRINT::RunOnChildren" );
1320  }
1321 }
1322 
1323 
1324 void FOOTPRINT::GetAllDrawingLayers( int aLayers[], int& aCount, bool aIncludePads ) const
1325 {
1326  std::unordered_set<int> layers;
1327 
1328  for( BOARD_ITEM* item : m_drawings )
1329  layers.insert( static_cast<int>( item->GetLayer() ) );
1330 
1331  if( aIncludePads )
1332  {
1333  for( PAD* pad : m_pads )
1334  {
1335  int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count;
1336  pad->ViewGetLayers( pad_layers, pad_layers_count );
1337 
1338  for( int i = 0; i < pad_layers_count; i++ )
1339  layers.insert( pad_layers[i] );
1340  }
1341  }
1342 
1343  aCount = layers.size();
1344  int i = 0;
1345 
1346  for( int layer : layers )
1347  aLayers[i++] = layer;
1348 }
1349 
1350 
1351 void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
1352 {
1353  aCount = 2;
1354  aLayers[0] = LAYER_ANCHOR;
1355 
1356  switch( m_layer )
1357  {
1358  default:
1359  wxASSERT_MSG( false, "Illegal layer" ); // do you really have footprints placed on
1360  // other layers?
1362 
1363  case F_Cu:
1364  aLayers[1] = LAYER_MOD_FR;
1365  break;
1366 
1367  case B_Cu:
1368  aLayers[1] = LAYER_MOD_BK;
1369  break;
1370  }
1371 
1372  // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
1373  // layer as well so that the component can be edited with the silkscreen layer
1374  bool f_silk = false, b_silk = false, non_silk = false;
1375 
1376  for( BOARD_ITEM* item : m_drawings )
1377  {
1378  if( item->GetLayer() == F_SilkS )
1379  f_silk = true;
1380  else if( item->GetLayer() == B_SilkS )
1381  b_silk = true;
1382  else
1383  non_silk = true;
1384  }
1385 
1386  if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
1387  {
1388  if( f_silk )
1389  aLayers[ aCount++ ] = F_SilkS;
1390 
1391  if( b_silk )
1392  aLayers[ aCount++ ] = B_SilkS;
1393  }
1394 }
1395 
1396 
1397 double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1398 {
1399  int layer = ( m_layer == F_Cu ) ? LAYER_MOD_FR :
1401 
1402  // Currently this is only pertinent for the anchor layer; everything else is drawn from the
1403  // children.
1404  // The "good" value is experimentally chosen.
1405  #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
1406 
1407  if( aView->IsLayerVisible( layer ) )
1409 
1410  return std::numeric_limits<double>::max();
1411 }
1412 
1413 
1415 {
1416  EDA_RECT area = GetBoundingBox( true, true );
1417 
1418  // Add the Clearance shape size: (shape around the pads when the clearance is shown. Not
1419  // optimized, but the draw cost is small (perhaps smaller than optimization).
1420  const BOARD* board = GetBoard();
1421 
1422  if( board )
1423  {
1424  int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
1425  area.Inflate( biggest_clearance );
1426  }
1427 
1428  return area;
1429 }
1430 
1431 
1432 bool FOOTPRINT::IsLibNameValid( const wxString & aName )
1433 {
1434  const wxChar * invalids = StringLibNameInvalidChars( false );
1435 
1436  if( aName.find_first_of( invalids ) != std::string::npos )
1437  return false;
1438 
1439  return true;
1440 }
1441 
1442 
1443 const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
1444 {
1445  // This list of characters is also duplicated in validators.cpp and
1446  // lib_id.cpp
1447  // TODO: Unify forbidden character lists
1448  static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
1449  static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
1450 
1451  if( aUserReadable )
1452  return invalidCharsReadable;
1453  else
1454  return invalidChars;
1455 }
1456 
1457 
1458 void FOOTPRINT::Move( const wxPoint& aMoveVector )
1459 {
1460  wxPoint newpos = m_pos + aMoveVector;
1461  SetPosition( newpos );
1462 }
1463 
1464 
1465 void FOOTPRINT::Rotate( const wxPoint& aRotCentre, double aAngle )
1466 {
1467  double orientation = GetOrientation();
1468  double newOrientation = orientation + aAngle;
1469  wxPoint newpos = m_pos;
1470  RotatePoint( &newpos, aRotCentre, aAngle );
1471  SetPosition( newpos );
1472  SetOrientation( newOrientation );
1473 
1474  m_reference->KeepUpright( orientation, newOrientation );
1475  m_value->KeepUpright( orientation, newOrientation );
1476 
1477  for( BOARD_ITEM* item : m_drawings )
1478  {
1479  if( item->Type() == PCB_FP_TEXT_T )
1480  static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation );
1481  }
1482 
1487 }
1488 
1489 
1490 void FOOTPRINT::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
1491 {
1492  // Move footprint to its final position:
1493  wxPoint finalPos = m_pos;
1494 
1495  // Now Flip the footprint.
1496  // Flipping a footprint is a specific transform: it is not mirrored like a text.
1497  // We have to change the side, and ensure the footprint rotation is modified according to the
1498  // transform, because this parameter is used in pick and place files, and when updating the
1499  // footprint from library.
1500  // When flipped around the X axis (Y coordinates changed) orientation is negated
1501  // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
1502  // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
1503 
1504  MIRROR( finalPos.y, aCentre.y );
1505 
1506  SetPosition( finalPos );
1507 
1508  // Flip layer
1509  SetLayer( FlipLayer( GetLayer() ) );
1510 
1511  // Reverse mirror orientation.
1512  m_orient = -m_orient;
1513 
1515 
1516  // Mirror pads to other side of board.
1517  for( PAD* pad : m_pads )
1518  pad->Flip( m_pos, false );
1519 
1520  // Mirror zones to other side of board.
1521  for( ZONE* zone : m_fp_zones )
1522  zone->Flip( m_pos, false );
1523 
1524  // Mirror reference and value.
1525  m_reference->Flip( m_pos, false );
1526  m_value->Flip( m_pos, false );
1527 
1528  // Reverse mirror footprint graphics and texts.
1529  for( BOARD_ITEM* item : m_drawings )
1530  {
1531  switch( item->Type() )
1532  {
1533  case PCB_FP_SHAPE_T:
1534  static_cast<FP_SHAPE*>( item )->Flip( m_pos, false );
1535  break;
1536 
1537  case PCB_FP_TEXT_T:
1538  static_cast<FP_TEXT*>( item )->Flip( m_pos, false );
1539  break;
1540 
1541  default:
1542  wxMessageBox( wxT( "FOOTPRINT::Flip() error: Unknown Draw Type" ) );
1543  break;
1544  }
1545  }
1546 
1547  // Now rotate 180 deg if required
1548  if( aFlipLeftRight )
1549  Rotate( aCentre, 1800.0 );
1550 
1554 
1555  m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
1556 
1558 }
1559 
1560 
1561 void FOOTPRINT::SetPosition( const wxPoint& aPos )
1562 {
1563  wxPoint delta = aPos - m_pos;
1564 
1565  m_pos += delta;
1566 
1567  m_reference->EDA_TEXT::Offset( delta );
1568  m_value->EDA_TEXT::Offset( delta );
1569 
1570  for( PAD* pad : m_pads )
1571  pad->SetPosition( pad->GetPosition() + delta );
1572 
1573  for( ZONE* zone : m_fp_zones )
1574  zone->Move( delta );
1575 
1576  for( BOARD_ITEM* item : m_drawings )
1577  {
1578  switch( item->Type() )
1579  {
1580  case PCB_FP_SHAPE_T:
1581  {
1582  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1583  shape->SetDrawCoord();
1584  break;
1585  }
1586 
1587  case PCB_FP_TEXT_T:
1588  {
1589  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1590  text->EDA_TEXT::Offset( delta );
1591  break;
1592  }
1593 
1594  default:
1595  wxMessageBox( wxT( "Draw type undefined." ) );
1596  break;
1597  }
1598  }
1599 
1603  m_cachedHull.Move( delta );
1604 }
1605 
1606 
1607 void FOOTPRINT::MoveAnchorPosition( const wxPoint& aMoveVector )
1608 {
1609  /* Move the reference point of the footprint
1610  * the footprints elements (pads, outlines, edges .. ) are moved
1611  * but:
1612  * - the footprint position is not modified.
1613  * - the relative (local) coordinates of these items are modified
1614  * - Draw coordinates are updated
1615  */
1616 
1617 
1618  // Update (move) the relative coordinates relative to the new anchor point.
1619  wxPoint moveVector = aMoveVector;
1620  RotatePoint( &moveVector, -GetOrientation() );
1621 
1622  // Update of the reference and value.
1623  m_reference->SetPos0( m_reference->GetPos0() + moveVector );
1625  m_value->SetPos0( m_value->GetPos0() + moveVector );
1626  m_value->SetDrawCoord();
1627 
1628  // Update the pad local coordinates.
1629  for( PAD* pad : m_pads )
1630  {
1631  pad->SetPos0( pad->GetPos0() + moveVector );
1632  pad->SetDrawCoord();
1633  }
1634 
1635  // Update the draw element coordinates.
1636  for( BOARD_ITEM* item : GraphicalItems() )
1637  {
1638  switch( item->Type() )
1639  {
1640  case PCB_FP_SHAPE_T:
1641  {
1642  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1643  shape->Move( moveVector );
1644  }
1645  break;
1646 
1647  case PCB_FP_TEXT_T:
1648  {
1649  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1650  text->SetPos0( text->GetPos0() + moveVector );
1651  text->SetDrawCoord();
1652  }
1653  break;
1654 
1655  default:
1656  break;
1657  }
1658  }
1659 
1660  // Update the keepout zones
1661  for( ZONE* zone : Zones() )
1662  {
1663  zone->Move( moveVector );
1664  }
1665 
1666  // Update the 3D models
1667  for( FP_3DMODEL& model : Models() )
1668  {
1669  model.m_Offset.x += Iu2Millimeter( moveVector.x );
1670  model.m_Offset.y -= Iu2Millimeter( moveVector.y );
1671  }
1672 
1673  m_cachedBoundingBox.Move( moveVector );
1674  m_cachedVisibleBBox.Move( moveVector );
1675  m_cachedTextExcludedBBox.Move( moveVector );
1676  m_cachedHull.Move( moveVector );
1677 }
1678 
1679 
1680 void FOOTPRINT::SetOrientation( double aNewAngle )
1681 {
1682  double angleChange = aNewAngle - m_orient; // change in rotation
1683 
1684  NORMALIZE_ANGLE_180( aNewAngle );
1685 
1686  m_orient = aNewAngle;
1687 
1688  for( PAD* pad : m_pads )
1689  {
1690  pad->SetOrientation( pad->GetOrientation() + angleChange );
1691  pad->SetDrawCoord();
1692  }
1693 
1694  for( ZONE* zone : m_fp_zones )
1695  {
1696  zone->Rotate( GetPosition(), angleChange );
1697  }
1698 
1699  // Update of the reference and value.
1701  m_value->SetDrawCoord();
1702 
1703  // Displace contours and text of the footprint.
1704  for( BOARD_ITEM* item : m_drawings )
1705  {
1706  if( item->Type() == PCB_FP_SHAPE_T )
1707  {
1708  static_cast<FP_SHAPE*>( item )->SetDrawCoord();
1709  }
1710  else if( item->Type() == PCB_FP_TEXT_T )
1711  {
1712  static_cast<FP_TEXT*>( item )->SetDrawCoord();
1713  }
1714  }
1715 
1719 
1720  m_cachedHull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() );
1721 }
1722 
1723 
1725 {
1726  FOOTPRINT* dupe = (FOOTPRINT*) Clone();
1727  const_cast<KIID&>( dupe->m_Uuid ) = KIID();
1728 
1729  dupe->RunOnChildren( [&]( BOARD_ITEM* child )
1730  {
1731  const_cast<KIID&>( child->m_Uuid ) = KIID();
1732  });
1733 
1734  return static_cast<BOARD_ITEM*>( dupe );
1735 }
1736 
1737 
1738 BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootprint )
1739 {
1740  BOARD_ITEM* new_item = nullptr;
1741  FP_ZONE* new_zone = nullptr;
1742 
1743  switch( aItem->Type() )
1744  {
1745  case PCB_PAD_T:
1746  {
1747  PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
1748  const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
1749 
1750  if( aAddToFootprint )
1751  m_pads.push_back( new_pad );
1752 
1753  new_item = new_pad;
1754  break;
1755  }
1756 
1757  case PCB_FP_ZONE_T:
1758  {
1759  new_zone = new FP_ZONE( *static_cast<const FP_ZONE*>( aItem ) );
1760  const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
1761 
1762  if( aAddToFootprint )
1763  m_fp_zones.push_back( new_zone );
1764 
1765  new_item = new_zone;
1766  break;
1767  }
1768 
1769  case PCB_FP_TEXT_T:
1770  {
1771  FP_TEXT* new_text = new FP_TEXT( *static_cast<const FP_TEXT*>( aItem ) );
1772  const_cast<KIID&>( new_text->m_Uuid ) = KIID();
1773 
1774  if( new_text->GetType() == FP_TEXT::TEXT_is_REFERENCE )
1775  {
1776  new_text->SetText( wxT( "${REFERENCE}" ) );
1777  new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1778  }
1779  else if( new_text->GetType() == FP_TEXT::TEXT_is_VALUE )
1780  {
1781  new_text->SetText( wxT( "${VALUE}" ) );
1782  new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1783  }
1784 
1785  if( aAddToFootprint )
1786  Add( new_text );
1787 
1788  new_item = new_text;
1789 
1790  break;
1791  }
1792 
1793  case PCB_FP_SHAPE_T:
1794  {
1795  FP_SHAPE* new_shape = new FP_SHAPE( *static_cast<const FP_SHAPE*>( aItem ) );
1796  const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
1797 
1798  if( aAddToFootprint )
1799  Add( new_shape );
1800 
1801  new_item = new_shape;
1802  break;
1803  }
1804 
1805  case PCB_GROUP_T:
1806  new_item = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate();
1807  break;
1808 
1809  case PCB_FOOTPRINT_T:
1810  // Ignore the footprint itself
1811  break;
1812 
1813  default:
1814  // Un-handled item for duplication
1815  wxFAIL_MSG( "Duplication not supported for items of class " + aItem->GetClass() );
1816  break;
1817  }
1818 
1819  return new_item;
1820 }
1821 
1822 
1823 wxString FOOTPRINT::GetNextPadNumber( const wxString& aLastPadNumber ) const
1824 {
1825  std::set<wxString> usedNumbers;
1826 
1827  // Create a set of used pad numbers
1828  for( PAD* pad : m_pads )
1829  usedNumbers.insert( pad->GetNumber() );
1830 
1831  // Pad numbers aren't technically reference designators, but the formatting is close enough
1832  // for these to give us what we need.
1833  wxString prefix = UTIL::GetRefDesPrefix( aLastPadNumber );
1834  int num = GetTrailingInt( aLastPadNumber );
1835 
1836  while( usedNumbers.count( wxString::Format( "%s%d", prefix, num ) ) )
1837  num++;
1838 
1839  return wxString::Format( "%s%d", prefix, num );
1840 }
1841 
1842 
1844 {
1845  const wxString& refdes = GetReference();
1846 
1847  SetReference( wxString::Format( wxT( "%s%i" ),
1848  UTIL::GetRefDesPrefix( refdes ),
1849  GetTrailingInt( refdes ) + aDelta ) );
1850 }
1851 
1852 
1853 // Calculate the area of a PolySet, polygons with hole are allowed.
1854 static double polygonArea( SHAPE_POLY_SET& aPolySet )
1855 {
1856  // Ensure all outlines are closed, before calculating the SHAPE_POLY_SET area
1857  for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
1858  {
1859  SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
1860  outline.SetClosed( true );
1861 
1862  for( int jj = 0; jj < aPolySet.HoleCount( ii ); jj++ )
1863  aPolySet.Hole( ii, jj ).SetClosed( true );
1864  }
1865 
1866  return aPolySet.Area();
1867 }
1868 
1869 
1870 double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
1871 {
1872  int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
1873  SHAPE_POLY_SET poly;
1874 
1875  if( aItem->Type() == PCB_MARKER_T )
1876  {
1877  const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
1878  SHAPE_LINE_CHAIN markerShape;
1879 
1880  marker->ShapeToPolygon( markerShape );
1881  return markerShape.Area();
1882  }
1883  else if( aItem->Type() == PCB_GROUP_T )
1884  {
1885  double combinedArea = 0.0;
1886 
1887  for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
1888  combinedArea += GetCoverageArea( member, aCollector );
1889 
1890  return combinedArea;
1891  }
1892  if( aItem->Type() == PCB_FOOTPRINT_T )
1893  {
1894  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
1895 
1896  poly = footprint->GetBoundingHull();
1897  }
1898  else if( aItem->Type() == PCB_FP_TEXT_T )
1899  {
1900  const FP_TEXT* text = static_cast<const FP_TEXT*>( aItem );
1901 
1902  text->TransformTextShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, textMargin,
1903  ARC_LOW_DEF, ERROR_OUTSIDE );
1904  }
1905  else if( aItem->Type() == PCB_SHAPE_T )
1906  {
1907  // Approximate "linear" shapes with just their width squared, as we don't want to consider
1908  // a linear shape as being much bigger than another for purposes of selection filtering
1909  // just because it happens to be really long.
1910 
1911  const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
1912 
1913  switch( shape->GetShape() )
1914  {
1915  case SHAPE_T::SEGMENT:
1916  case SHAPE_T::ARC:
1917  case SHAPE_T::BEZIER:
1918  return shape->GetWidth() * shape->GetWidth();
1919 
1920  case SHAPE_T::RECT:
1921  case SHAPE_T::CIRCLE:
1922  case SHAPE_T::POLY:
1923  {
1924  if( !shape->IsFilled() )
1925  return shape->GetWidth() * shape->GetWidth();
1926 
1928  }
1929 
1930  default:
1932  ARC_LOW_DEF, ERROR_OUTSIDE );
1933  }
1934  }
1935  else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
1936  {
1937  double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
1938  return width * width;
1939  }
1940  else
1941  {
1943  ARC_LOW_DEF, ERROR_OUTSIDE );
1944  }
1945 
1946  return polygonArea( poly );
1947 }
1948 
1949 
1950 double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
1951 {
1952  int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
1953 
1954  SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
1955  SHAPE_POLY_SET coveredRegion;
1956 
1957  TransformPadsWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1958  ERROR_OUTSIDE );
1959 
1960  TransformFPShapesWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, textMargin,
1961  ARC_LOW_DEF, ERROR_OUTSIDE,
1962  true, /* include text */
1963  false /* include shapes */ );
1964 
1965  for( int i = 0; i < aCollector.GetCount(); ++i )
1966  {
1967  const BOARD_ITEM* item = aCollector[i];
1968 
1969  switch( item->Type() )
1970  {
1971  case PCB_FP_TEXT_T:
1972  case PCB_FP_SHAPE_T:
1973  if( item->GetParent() != this )
1974  {
1975  item->TransformShapeWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0,
1976  ARC_LOW_DEF, ERROR_OUTSIDE );
1977  }
1978  break;
1979 
1980  case PCB_TEXT_T:
1981  case PCB_SHAPE_T:
1982  case PCB_TRACE_T:
1983  case PCB_ARC_T:
1984  case PCB_VIA_T:
1985  item->TransformShapeWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0,
1986  ARC_LOW_DEF, ERROR_OUTSIDE );
1987  break;
1988 
1989  case PCB_FOOTPRINT_T:
1990  if( item != this )
1991  {
1992  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
1993  coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
1994  }
1995  break;
1996 
1997  default:
1998  break;
1999  }
2000  }
2001 
2002  double footprintRegionArea = polygonArea( footprintRegion );
2003  double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
2004  double coveredArea = footprintRegionArea - uncoveredRegionArea;
2005  double ratio = ( coveredArea / footprintRegionArea );
2006 
2007  // Test for negative ratio (should not occur).
2008  // better to be conservative (this will result in the disambiguate dialog)
2009  if( ratio < 0.0 )
2010  return 1.0;
2011 
2012  return std::min( ratio, 1.0 );
2013 }
2014 
2015 
2016 std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
2017 {
2018  std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
2019 
2020  // There are several possible interpretations here:
2021  // 1) the bounding box (without or without invisible items)
2022  // 2) just the pads and "edges" (ie: non-text graphic items)
2023  // 3) the courtyard
2024 
2025  // We'll go with (2) for now....
2026 
2027  for( PAD* pad : Pads() )
2028  shape->AddShape( pad->GetEffectiveShape( aLayer )->Clone() );
2029 
2030  for( BOARD_ITEM* item : GraphicalItems() )
2031  {
2032  if( item->Type() == PCB_FP_SHAPE_T )
2033  shape->AddShape( item->GetEffectiveShape( aLayer )->Clone() );
2034  }
2035 
2036  return shape;
2037 }
2038 
2039 
2041 {
2045 
2046  // Build the courtyard area from graphic items on the courtyard.
2047  // Only PCB_FP_SHAPE_T have meaning, graphic texts are ignored.
2048  // Collect items:
2049  std::vector<PCB_SHAPE*> list_front;
2050  std::vector<PCB_SHAPE*> list_back;
2051 
2052  for( BOARD_ITEM* item : GraphicalItems() )
2053  {
2054  if( item->GetLayer() == B_CrtYd && item->Type() == PCB_FP_SHAPE_T )
2055  list_back.push_back( static_cast<PCB_SHAPE*>( item ) );
2056 
2057  if( item->GetLayer() == F_CrtYd && item->Type() == PCB_FP_SHAPE_T )
2058  list_front.push_back( static_cast<PCB_SHAPE*>( item ) );
2059  }
2060 
2061  if( !list_front.size() && !list_back.size() )
2062  return;
2063 
2064  int errorMax = Millimeter2iu( 0.02 ); // max error for polygonization
2065  int chainingEpsilon = Millimeter2iu( 0.02 ); // max dist from one endPt to next startPt
2066 
2067  if( ConvertOutlineToPolygon( list_front, m_poly_courtyard_front, errorMax, chainingEpsilon,
2068  aErrorHandler ) )
2069  {
2070  // Touching courtyards, or courtyards -at- the clearance distance are legal.
2072 
2074  }
2075  else
2076  {
2078  }
2079 
2080  if( ConvertOutlineToPolygon( list_back, m_poly_courtyard_back, errorMax, chainingEpsilon,
2081  aErrorHandler ) )
2082  {
2083  // Touching courtyards, or courtyards -at- the clearance distance are legal.
2085 
2087  }
2088  else
2089  {
2091  }
2092 }
2093 
2094 
2095 void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& msg )>* aErrorHandler )
2096 {
2097 
2098  int likelyAttr = GetLikelyAttribute();
2099  int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
2100 
2101  // This is only valid if the footprint doesn't have FP_SMD and FP_THROUGH_HOLE set
2102  // Which is, unfortunately, possible in theory but not in the UI (I think)
2103  if( aErrorHandler && likelyAttr != setAttr )
2104  {
2105  wxString msg;
2106 
2107  if( likelyAttr == FP_THROUGH_HOLE )
2108  {
2109  msg.Printf( _( "Expected \"Through hole\" type but set to \"%s\"" ), GetTypeName() );
2110  }
2111  else if( likelyAttr == FP_SMD )
2112  {
2113  msg.Printf( _( "Expected \"SMD\" type but set to \"%s\"" ), GetTypeName() );
2114  }
2115  else
2116  {
2117  msg.Printf( _( "Expected \"Other\" type but set to \"%s\"" ), GetTypeName() );
2118  }
2119 
2120  msg = "(" + msg + ")";
2121 
2122  (*aErrorHandler)( msg );
2123  }
2124 }
2125 
2127  const std::function<void( const wxString& msg, const wxPoint& position )>*
2128  aErrorHandler )
2129 {
2130  if( aErrorHandler == nullptr )
2131  return;
2132 
2133  for( const PAD* pad: Pads() )
2134  {
2135 
2136  if( pad->GetAttribute() != PAD_ATTRIB::PTH
2137  && pad->GetAttribute() != PAD_ATTRIB::NPTH )
2138  continue;
2139 
2140  if( pad->GetDrillSizeX() < 1 || pad->GetDrillSizeX() < 1 )
2141  {
2142  wxString msg;
2143  msg.Printf( _( "(pad \"%s\")" ), pad->GetNumber() );
2144 
2145  (*aErrorHandler)( msg, pad->GetPosition() );
2146  }
2147  }
2148 }
2149 
2150 
2152 {
2153  wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );
2154 
2155  std::swap( *((FOOTPRINT*) this), *((FOOTPRINT*) aImage) );
2156 }
2157 
2158 
2160 {
2161  for( PAD* pad : Pads() )
2162  {
2163  if( pad->GetAttribute() != PAD_ATTRIB::SMD )
2164  return true;
2165  }
2166 
2167  return false;
2168 }
2169 
2170 
2172  const BOARD_ITEM* aSecond ) const
2173 {
2174  if( aFirst->Type() != aSecond->Type() )
2175  return aFirst->Type() < aSecond->Type();
2176 
2177  if( aFirst->GetLayer() != aSecond->GetLayer() )
2178  return aFirst->GetLayer() < aSecond->GetLayer();
2179 
2180  if( aFirst->Type() == PCB_FP_SHAPE_T )
2181  {
2182  const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( aFirst );
2183  const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( aSecond );
2184 
2185  if( dwgA->GetShape() != dwgB->GetShape() )
2186  return dwgA->GetShape() < dwgB->GetShape();
2187  }
2188 
2189  if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards
2190  return aFirst->m_Uuid < aSecond->m_Uuid;
2191 
2192  return aFirst < aSecond;
2193 }
2194 
2195 
2196 bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
2197 {
2198  if( aFirst->GetNumber() != aSecond->GetNumber() )
2199  return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
2200 
2201  if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards
2202  return aFirst->m_Uuid < aSecond->m_Uuid;
2203 
2204  return aFirst < aSecond;
2205 }
2206 
2207 
2209  PCB_LAYER_ID aLayer, int aClearance,
2210  int aMaxError, ERROR_LOC aErrorLoc,
2211  bool aSkipNPTHPadsWihNoCopper,
2212  bool aSkipPlatedPads,
2213  bool aSkipNonPlatedPads ) const
2214 {
2215  for( const PAD* pad : m_pads )
2216  {
2217  if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
2218  continue;
2219 
2220  if( !pad->FlashLayer( aLayer ) && IsCopperLayer( aLayer ) )
2221  continue;
2222 
2223  // NPTH pads are not drawn on layers if the shape size and pos is the same
2224  // as their hole:
2225  if( aSkipNPTHPadsWihNoCopper && pad->GetAttribute() == PAD_ATTRIB::NPTH )
2226  {
2227  if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
2228  {
2229  switch( pad->GetShape() )
2230  {
2231  case PAD_SHAPE::CIRCLE:
2232  if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
2233  continue;
2234 
2235  break;
2236 
2237  case PAD_SHAPE::OVAL:
2238  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
2239  continue;
2240 
2241  break;
2242 
2243  default:
2244  break;
2245  }
2246  }
2247  }
2248 
2249  const bool isPlated = ( ( aLayer == F_Cu ) && pad->FlashLayer( F_Mask ) ) ||
2250  ( ( aLayer == B_Cu ) && pad->FlashLayer( B_Mask ) );
2251 
2252  if( aSkipPlatedPads && isPlated )
2253  continue;
2254 
2255  if( aSkipNonPlatedPads && !isPlated )
2256  continue;
2257 
2258  wxSize clearance( aClearance, aClearance );
2259 
2260  switch( aLayer )
2261  {
2262  case F_Mask:
2263  case B_Mask:
2264  clearance.x += pad->GetSolderMaskMargin();
2265  clearance.y += pad->GetSolderMaskMargin();
2266  break;
2267 
2268  case F_Paste:
2269  case B_Paste:
2270  clearance += pad->GetSolderPasteMargin();
2271  break;
2272 
2273  default:
2274  break;
2275  }
2276 
2277  // Our standard TransformShapeWithClearanceToPolygon() routines can't handle differing
2278  // x:y clearance values (which get generated when a relative paste margin is used with
2279  // an oblong pad). So we apply this huge hack and fake a larger pad to run the transform
2280  // on.
2281  // Of course being a hack it falls down when dealing with custom shape pads (where the
2282  // size is only the size of the anchor), so for those we punt and just use clearance.x.
2283 
2284  if( ( clearance.x < 0 || clearance.x != clearance.y )
2285  && pad->GetShape() != PAD_SHAPE::CUSTOM )
2286  {
2287  wxSize dummySize = pad->GetSize() + clearance + clearance;
2288 
2289  if( dummySize.x <= 0 || dummySize.y <= 0 )
2290  continue;
2291 
2292  PAD dummy( *pad );
2293  dummy.SetSize( dummySize );
2294  dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0,
2295  aMaxError, aErrorLoc );
2296  }
2297  else
2298  {
2299  pad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, clearance.x,
2300  aMaxError, aErrorLoc );
2301  }
2302  }
2303 }
2304 
2305 
2307  PCB_LAYER_ID aLayer, int aClearance,
2308  int aError, ERROR_LOC aErrorLoc,
2309  bool aIncludeText,
2310  bool aIncludeShapes ) const
2311 {
2312  std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert
2313 
2314  for( BOARD_ITEM* item : GraphicalItems() )
2315  {
2316  if( item->Type() == PCB_FP_TEXT_T && aIncludeText )
2317  {
2318  FP_TEXT* text = static_cast<FP_TEXT*>( item );
2319 
2320  if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
2321  texts.push_back( text );
2322  }
2323 
2324  if( item->Type() == PCB_FP_SHAPE_T && aIncludeShapes )
2325  {
2326  const FP_SHAPE* outline = static_cast<FP_SHAPE*>( item );
2327 
2328  if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
2329  {
2330  outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0,
2331  aError, aErrorLoc );
2332  }
2333  }
2334  }
2335 
2336  if( aIncludeText )
2337  {
2338  if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
2339  texts.push_back( &Reference() );
2340 
2341  if( Value().GetLayer() == aLayer && Value().IsVisible() )
2342  texts.push_back( &Value() );
2343  }
2344 
2345  for( const FP_TEXT* text : texts )
2346  {
2347  text->TransformTextShapeWithClearanceToPolygon( aCornerBuffer, aLayer, aClearance,
2348  aError, aErrorLoc );
2349  }
2350 }
2351 
2352 
2353 static struct FOOTPRINT_DESC
2354 {
2356  {
2358 
2359  if( layerEnum.Choices().GetCount() == 0 )
2360  {
2361  layerEnum.Undefined( UNDEFINED_LAYER );
2362 
2363  for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
2364  layerEnum.Map( *seq, LSET::Name( *seq ) );
2365  }
2366 
2367  wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
2368  fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
2369  fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
2370 
2377 
2378  auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID, BOARD_ITEM>( _HKI( "Layer" ),
2380  layer->SetChoices( fpLayers );
2381  propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2382 
2383  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
2385  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
2387  propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
2390  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Clearance Override" ),
2393  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Solderpaste Margin Override" ),
2396  propMgr.AddProperty( new PROPERTY<FOOTPRINT,
2397  double>( _HKI( "Solderpaste Margin Ratio Override" ),
2400  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Width" ),
2404  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Gap" ),
2408  // TODO zone connection, FPID?
2409  }
2410 } _FOOTPRINT_DESC;
void SetReference(const wxString &aReference)
Definition: footprint.h:473
void BuildPolyCourtyards(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2040
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:759
Display value expressed in degrees.
Definition: property.h:54
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:60
int m_localSolderPasteMargin
Definition: footprint.h:769
BOARD_ITEM * DuplicateItem(const BOARD_ITEM *aItem, bool aAddToFootprint=false)
Duplicate a given item within the footprint, optionally adding it to the board.
Definition: footprint.cpp:1738
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Return the initial comments block or NULL if none, without transfer of ownership.
Definition: footprint.cpp:1870
bool IsLocked() const override
Definition: footprint.h:294
bool AddItem(BOARD_ITEM *aItem)
Add item to group.
Definition: pcb_group.cpp:39
double GetArea(int aPadding=0) const
Definition: footprint.cpp:643
void ClearAllNets()
Clear (i.e.
Definition: footprint.cpp:504
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: footprint.cpp:1397
void KeepUpright(double aOldOrientation, double aNewOrientation)
Called when rotating the parent footprint.
Definition: fp_text.cpp:105
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:65
EDA_RECT m_cachedVisibleBBox
Definition: footprint.h:757
int GetWidth() const
Definition: eda_shape.h:89
#define TYPE_HASH(x)
Definition: property.h:59
void Move(const wxPoint &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: eda_rect.cpp:51
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:847
int OutlineCount() const
Return the number of vertices in a given outline/hole.
KIID niluuid(0)
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
void Merge(const EDA_RECT &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: eda_rect.cpp:432
bool FixUuids()
Old footprints do not alway have a valid UUID (some can be set to null uuid) However null UUIDs,...
Definition: footprint.cpp:227
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: footprint.cpp:1275
#define MALFORMED_B_COURTYARD
std::list< FP_3DMODEL > & Models()
Definition: footprint.h:183
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition: footprint.cpp:926
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
A special IsOnLayer for footprints: return true if the footprint contains only items on the given lay...
Definition: footprint.cpp:992
const wxString & GetValue() const
Definition: footprint.h:486
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1129
ZONE_CONNECTION m_zoneConnection
Definition: footprint.h:764
double m_localSolderPasteMarginRatio
Definition: footprint.h:770
SHAPE_POLY_SET m_poly_courtyard_back
Definition: footprint.h:787
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:163
This file is part of the common library.
virtual void SetPosition(const wxPoint &aPos)
Definition: eda_item.h:252
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
int GetTimeStamp() const
Definition: board.h:215
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
show footprints values (when texts are visible)
Definition: layer_ids.h:206
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
virtual double OnePixelInIU() const =0
ENUM_MAP & Undefined(T aValue)
Definition: property.h:523
#define FP_PADS_are_LOCKED
Definition: footprint.h:291
double m_orient
Definition: footprint.h:737
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Definition: footprint.cpp:477
#define MALFORMED_F_COURTYARD
void CheckFootprintAttributes(const std::function< void(const wxString &msg)> *aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:2095
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:530
Smd pad, appears on the solder paste layer (default)
timestamp_t m_lastEditTime
Definition: footprint.h:775
Collection of utility functions for component reference designators (refdes)
int GetWidth() const
Definition: eda_rect.h:109
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:566
static ENUM_MAP< T > & Instance()
Definition: property.h:510
double GetOrientation() const
Definition: footprint.h:191
static void isPlated(LIBEVAL::CONTEXT *aCtx, void *self)
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:152
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:197
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
double CoverageRatio(const GENERAL_COLLECTOR &aCollector) const
Calculate the ratio of total area of the footprint pads and graphical items to the area of the footpr...
Definition: footprint.cpp:1950
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
void SetDrawCoord()
Set relative coordinates.
Definition: fp_text.cpp:190
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:121
double Area()
Count the number of arc shapes present.
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: footprint.h:225
static struct FOOTPRINT_DESC _FOOTPRINT_DESC
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:190
FP_TEXT * m_reference
Definition: footprint.h:739
show footprints on back
Definition: layer_ids.h:205
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
int m_visibleBBoxCacheTimeStamp
Definition: footprint.h:758
double Area(bool aAbsolute=true) const
Return the area of this chain.
INCLUDE_NPTH_T
Definition: footprint.h:55
void NORMALIZE_ANGLE_180(T &Angle)
Definition: trigo.h:398
wxPGChoices & Choices()
Definition: property.h:559
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void SetThermalGap(int aGap)
Definition: footprint.h:233
The base class for create windows for drawing purpose.
void SetType(TEXT_TYPE aType)
Definition: fp_text.h:140
a test point pad
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
#define REGISTER_TYPE(x)
Definition: property_mgr.h:248
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: footprint.cpp:1286
void CheckFootprintTHPadNoHoles(const std::function< void(const wxString &msg, const wxPoint &position)> *aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:2126
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:93
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
bool operator()(const PAD *aFirst, const PAD *aSecond) const
Definition: footprint.cpp:2196
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:115
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:711
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
int m_rot90Cost
Definition: footprint.h:778
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
PADS & Pads()
Definition: footprint.h:169
Plated through hole pad.
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
This file contains miscellaneous commonly used macros and functions.
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
Definition: footprint.cpp:2151
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
Definition: footprint.cpp:1179
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:500
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
FP_TEXT * m_value
Definition: footprint.h:740
PAD * GetTopLeftPad()
Definition: footprint.cpp:1110
void SetThermalWidth(int aWidth)
Definition: footprint.h:230
int m_arflag
Definition: footprint.h:776
bool IsFilled() const
Definition: eda_shape.h:81
KIID m_link
Definition: footprint.h:777
FP_TEXT & Reference()
Definition: footprint.h:501
a pad used as heat sink, usually in SMD footprints
int m_localSolderMaskMargin
Definition: footprint.h:768
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
EDA_RECT m_cachedBoundingBox
Definition: footprint.h:755
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
int GetLikelyAttribute() const
Returns the most likely attribute based on pads Either FP_THROUGH_HOLE/FP_SMD/OTHER(0)
Definition: footprint.cpp:653
FP_ZONES & Zones()
Definition: footprint.h:175
Definition: kiid.h:44
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int m_fpStatus
Definition: footprint.h:743
like PAD_PTH, but not plated
Display value expressed in distance units (mm/inch)
Definition: property.h:53
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: footprint.cpp:1414
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:339
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:505
FP_ZONES m_fp_zones
Definition: footprint.h:734
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
void Move(const VECTOR2I &aVector) override
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip entity during footprint flip.
Definition: fp_text.cpp:137
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: footprint.cpp:1351
SHAPE_POLY_SET m_poly_courtyard_front
Definition: footprint.h:786
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
Definition: footprint.cpp:1843
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
TEXT_TYPE GetType() const
Definition: fp_text.h:141
Represent a set of closed polygons.
SHAPE_POLY_SET m_cachedHull
Definition: footprint.h:761
SHAPE_LINE_CHAIN & Outline(int aIndex)
virtual bool IsVisible() const
Definition: eda_text.h:207
void SetEnd(int x, int y)
Definition: eda_rect.h:182
PAD * GetPad(const wxPoint &aPosition, LSET aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
Definition: footprint.cpp:1094
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY
void SetOrientation(double aNewAngle)
Definition: footprint.cpp:1680
void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: footprint.cpp:1458
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1490
Smd pad, used in BGA footprints.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
show footprints on front
Definition: layer_ids.h:204
const wxString & GetNumber() const
Definition: pad.h:129
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition: footprint.cpp:1074
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition: footprint.cpp:1190
int GetLocalClearance() const
Definition: footprint.h:210
void SetLocalClearance(int aClearance)
Definition: footprint.h:211
int m_thermalGap
Definition: footprint.h:766
const wxString & GetReference() const
Definition: footprint.h:464
a fiducial (usually a smd) local to the parent footprint
#define STRUCT_DELETED
flag indication structures to be erased
#define _(s)
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:153
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:1724
DRAWINGS & GraphicalItems()
Definition: footprint.h:172
void MoveAnchorPosition(const wxPoint &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1607
static LSET AllLayersMask()
Definition: lset.cpp:796
bool RemoveItem(BOARD_ITEM *aItem)
Remove item from group.
Definition: pcb_group.cpp:51
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
Definition: footprint.cpp:1823
wxPoint m_pos
Definition: footprint.h:738
void SetValue(const wxString &aValue)
Definition: footprint.h:494
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate this object.
Definition: footprint.cpp:1465
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
int NewOutline()
Creates a new hole in a given outline.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
Acute angles are chamfered.
void TransformPadsWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aSkipNPTHPadsWihNoCopper=false, bool aSkipPlatedPads=false, bool aSkipNonPlatedPads=false) const
Generate pads shapes on layer aLayer as polygons and adds these polygons to aCornerBuffer.
Definition: footprint.cpp:2208
int GetThermalWidth() const
Definition: footprint.h:231
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:243
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:466
int GetHeight() const
Definition: eda_rect.h:110
void SetPos0(const wxPoint &aPos)
Definition: fp_text.h:165
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:797
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:756
static const int ORPHANED
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition: netinfo.h:376
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:154
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
KIID_PATH m_path
Definition: footprint.h:774
const KIID m_Uuid
Definition: eda_item.h:474
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:533
Some functions to handle hotkeys in KiCad.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:98
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
const wxPoint & GetPos0() const
Definition: fp_text.h:166
EDA_UNITS
Definition: eda_units.h:38
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition: footprint.cpp:2171
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars for this footprint.
Definition: footprint.cpp:469
bool IsFlipped() const
Definition: footprint.h:278
FP_GROUPS & Groups()
Definition: footprint.h:178
show footprints references (when texts are visible)
Definition: layer_ids.h:207
double GetOrientationDegrees() const
Definition: footprint.h:192
int m_thermalWidth
Definition: footprint.h:765
wxString m_keywords
Definition: footprint.h:773
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:473
const EDA_RECT GetBoundingBox() const override
Set absolute coordinates.
Definition: fp_text.cpp:227
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:98
FOOTPRINT(BOARD *parent)
Definition: footprint.cpp:51
int m_localClearance
Definition: footprint.h:767
virtual wxString GetClass() const =0
Return the class name.
int GetAttributes() const
Definition: footprint.h:236
bool IsType(FRAME_T aType) const
a fiducial (usually a smd) for the full board
int m_rot180Cost
Definition: footprint.h:779
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:760
wxPoint GetPosition() const override
Definition: pad.h:178
wxString GetClass() const override
Return the class name.
Definition: footprint.h:603
no special fabrication property
void TransformFPShapesWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIncludeText=true, bool aIncludeShapes=true) const
Generate shapes of graphic items (outlines) on layer aLayer as polygons and adds these polygons to aC...
Definition: footprint.cpp:2306
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
LIB_ID m_fpid
Definition: footprint.h:741
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:736
Definition: layer_ids.h:71
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
void AddProperty(PROPERTY_BASE *aProperty)
Register a property.
class ZONE, managed by a footprint
Definition: typeinfo.h:94
Handle the component boundary box.
Definition: eda_rect.h:42
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
FOOTPRINT & operator=(const FOOTPRINT &aOther)
Definition: footprint.cpp:365
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1148
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
EDA_RECT m_cachedTextExcludedBBox
Definition: footprint.h:759
wxString GetTypeName() const
Get the type of footprint.
Definition: footprint.cpp:701
wxPoint GetPosition() const override
Definition: footprint.h:187
double GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:224
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
PCB_LAYER_ID m_layer
Definition: board_item.h:318
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
DRAWINGS m_drawings
Definition: footprint.h:732
void ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew)
Replace an existing property for a specific type.
void GetAllDrawingLayers(int aLayers[], int &aCount, bool aIncludePads=true) const
Return a set of all layers that this footprint has drawings on similar to ViewGetLayers().
Definition: footprint.cpp:1324
constexpr int delta
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:36
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:62
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const wxPoint &pt)> OUTLINE_ERROR_HANDLER
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all BOARD_ITEMs that belong to the footprint (pads, drawings,...
Definition: footprint.cpp:1298
a pad with a castellated through hole
void CacheTriangulation(bool aPartition=true)
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void Move(const wxPoint &aMoveVector) override
Move an edge of the footprint.
Definition: fp_shape.cpp:338
virtual void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Definition: board_item.cpp:144
std::map< wxString, wxString > m_properties
Definition: footprint.h:782
#define PCB_EDIT_FRAME_NAME
wxString GetUniStringLibId() const
Definition: lib_id.h:134
static bool IsLibNameValid(const wxString &aName)
Test for validity of a name of a footprint to be used in a footprint library ( no spaces,...
Definition: footprint.cpp:1432
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: footprint.cpp:1015
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
SHAPE_T GetShape() const
Definition: eda_shape.h:92
bool ConvertOutlineToPolygon(std::vector< PCB_SHAPE * > &aSegList, SHAPE_POLY_SET &aPolygons, int aErrorMax, int aChainingEpsilon, OUTLINE_ERROR_HANDLER *aErrorHandler)
Function ConvertOutlineToPolygon Build a polygon (with holes) from a PCB_SHAPE list,...
Abstract interface for BOARD_ITEMs capable of storing other items inside.
int GetLocalSolderPasteMargin() const
Definition: footprint.h:221
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Removes an item from the container.
Definition: footprint.cpp:513
wxArrayString * m_initial_comments
Definition: footprint.h:783
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition: footprint.h:289
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:516
Definition: pad.h:57
void SetPosition(const wxPoint &aPos) override
Definition: footprint.cpp:1561
void ClearEditFlags()
Definition: eda_item.h:171
SEARCH_RESULT
Definition: eda_item.h:41
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:236
FP_GROUPS m_fp_groups
Definition: footprint.h:735
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1292
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:135
#define MALFORMED_COURTYARDS
virtual wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: fp_text.cpp:416
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:75
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
static constexpr int Millimeter2iu(double mm)
#define _HKI(x)
bool HasThroughHolePads() const
Definition: footprint.cpp:2159
wxString m_doc
Definition: footprint.h:772
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:142
bool HitTestAccurate(const wxPoint &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:1022
int GetThermalGap() const
Definition: footprint.h:234
std::list< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:781
A specialization of ZONE for use in footprints.
Definition: zone.h:945
PADS m_pads
Definition: footprint.h:733
static const wxChar * StringLibNameInvalidChars(bool aUserReadable)
Test for validity of the name in a library of the footprint ( no spaces, dir separators ....
Definition: footprint.cpp:1443
int m_hullCacheTimeStamp
Definition: footprint.h:762
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
int m_attributes
Definition: footprint.h:742
EDA_RECT GetFpPadsLocalBbox() const
Return the bounding box containing pads when the footprint is on the front side, orientation 0,...
Definition: footprint.cpp:713
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:405
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: footprint.cpp:2016
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
static double polygonArea(SHAPE_POLY_SET &aPolySet)
Definition: footprint.cpp:1854
void BuildConvexHull(std::vector< wxPoint > &aResult, const std::vector< wxPoint > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
Definition: convex_hull.cpp:87
void SetLocalSolderPasteMargin(int aMargin)
Definition: footprint.h:222